Chromium Code Reviews| Index: frog/gen.dart |
| diff --git a/frog/gen.dart b/frog/gen.dart |
| index 76b41ce001df129684f17291b68c220d816b9c45..efb962a2a6358948d3a2a79e2bbe85091ae7c652 100644 |
| --- a/frog/gen.dart |
| +++ b/frog/gen.dart |
| @@ -131,27 +131,32 @@ class WorldGenerator { |
| return types; |
| } |
| - GlobalValue globalForStaticField(FieldMember field, Value fieldValue, |
| + GlobalValue globalForStaticField(FieldMember field, Value exp, |
| List<Value> dependencies) { |
| hasStatics = true; |
| - var fullname = "${field.declaringType.jsname}.${field.jsname}"; |
| - if (!globals.containsKey(fullname)) { |
| - globals[fullname] = new GlobalValue.fromStatic( |
| - field, fieldValue, dependencies); |
| + var key = "${field.declaringType.jsname}.${field.jsname}"; |
| + var ret = globals[key]; |
| + if (ret === null) { |
| + ret = new GlobalValue(exp.type, exp.code, field.isFinal, field, null, |
| + exp, exp.span, dependencies); |
| + globals[key] = ret; |
| } |
| - return globals[fullname]; |
| + return ret; |
| } |
| GlobalValue globalForConst(EvaluatedValue exp, List<Value> dependencies) { |
| // Include type name to ensure unique constants - this matches |
| // the code above that includes the type name for static fields. |
| - var key = exp.type.jsname + ':' + exp.canonicalCode; |
| - if (!globals.containsKey(key)) { |
| - globals[key] = |
| - new GlobalValue.fromConst(globals.length, exp, dependencies); |
| - } |
| - assert(globals[key].type == exp.type); |
| - return globals[key]; |
| + var key = exp.type.jsname + ':' + exp.code; |
| + var ret = globals[key]; |
| + if (ret === null) { |
| + var name = "const\$${globals.length}"; |
| + ret = new GlobalValue(exp.type, name, true, null, name, exp, |
| + exp.span, dependencies); |
| + globals[key] = ret; |
| + } |
| + assert(ret.type == exp.type); |
| + return ret; |
| } |
| writeTypes(Library lib) { |
| @@ -1935,12 +1940,7 @@ class MethodGenerator implements TreeVisitor { |
| var name = ':call'; |
| if (node.target is DotExpression) { |
| DotExpression dot = node.target; |
| - // ???? |
| - if (dot.self is LiteralExpression) { |
| - target = (new ParenExpression(dot.self, dot.self.span)).visit(this); |
| - } else { |
| - target = dot.self.visit(this); |
| - } |
| + target = dot.self.visit(this); |
| name = dot.name.name; |
| position = dot.name; |
| } else if (node.target is VarExpression) { |
| @@ -1978,52 +1978,18 @@ class MethodGenerator implements TreeVisitor { |
| if (kind == TokenKind.AND || kind == TokenKind.OR) { |
| var x = visitTypedValue(node.x, world.nonNullBool); |
| var y = visitTypedValue(node.y, world.nonNullBool); |
| - final code = '${x.code} ${node.op} ${y.code}'; |
| - if (x.isConst && y.isConst) { |
| - var value = (kind == TokenKind.AND) |
| - ? x.actualValue && y.actualValue : x.actualValue || y.actualValue; |
| - return Value.fromBool(value, node.span); |
| - } |
| - return new Value(world.nonNullBool, code, node.span); |
| + return x.binop(kind, y, this, node); |
|
Jennifer Messerly
2012/01/09 19:06:54
so nice!
|
| } else if (kind == TokenKind.EQ_STRICT || kind == TokenKind.NE_STRICT) { |
| var x = visitValue(node.x); |
| var y = visitValue(node.y); |
| - if (x.isConst && y.isConst) { |
| - var xVal = x.actualValue; |
| - var yVal = y.actualValue; |
| - |
| - // Note: it is ok to use == and not === here since all of these |
| - // constant comparisons are applied to doubles, bool, or strings. |
| - // We need it for the compile-time evaluator because |
| - // (9).toDouble() === 9.0 is false in dartvm. |
| - var value = kind == TokenKind.EQ_STRICT ? xVal == yVal : xVal != yVal; |
| - return Value.fromBool(value, node.span); |
| - } |
| - if (x.code == 'null' || y.code == 'null') { |
| - // Switching to == ensures that null and undefined are interchangable. |
| - final op = node.op.toString().substring(0,2); |
| - return new Value(world.nonNullBool, '${x.code} $op ${y.code}', |
| - node.span); |
| - } else { |
| - // TODO(jimhug): Resolve issue with undefined and null here. |
| - return new Value(world.nonNullBool, '${x.code} ${node.op} ${y.code}', |
| - node.span); |
| - } |
| + return x.binop(kind, y, this, node); |
| } |
| final assignKind = TokenKind.kindFromAssign(node.op.kind); |
| if (assignKind == -1) { |
| final x = visitValue(node.x); |
| final y = visitValue(node.y); |
| - var name = TokenKind.binaryMethodName(node.op.kind); |
| - if (node.op.kind == TokenKind.NE) { |
| - name = ':ne'; |
| - } |
| - if (name == null) { |
| - world.internalError('unimplemented binary op ${node.op}', node.span); |
| - return; |
| - } |
| - return x.invoke(this, name, node, new Arguments(null, [y])); |
| + return x.binop(kind, y, this, node); |
| } else if ((assignKind != 0) && _expressionNeedsParens(node.y)) { |
| return _visitAssign(assignKind, node.x, |
| new ParenExpression(node.y, node.y.span), node, null, isVoid); |
| @@ -2202,6 +2168,7 @@ class MethodGenerator implements TreeVisitor { |
| switch (node.op.kind) { |
| case TokenKind.INCR: |
| case TokenKind.DECR: |
| + // TODO(jimhug): Requires non-null num to be correct. |
| if (value.type.isNum) { |
| return new Value(value.type, '${node.op}${value.code}', node.span); |
| } else { |
| @@ -2222,7 +2189,7 @@ class MethodGenerator implements TreeVisitor { |
| // TODO(jimhug): Issue #359 seeks to clarify this behavior. |
| if (value.type.isBool && value.isConst) { |
| var newVal = !value.actualValue; |
| - return new EvaluatedValue(value.type, newVal, '${newVal}', node.span); |
| + return Value.fromBool(newVal, node.span); |
| } else { |
| var newVal = value.convertTo(this, world.nonNullBool); |
| return new Value(newVal.type, '!${newVal.code}', node.span); |
| @@ -2360,47 +2327,30 @@ class MethodGenerator implements TreeVisitor { |
| } |
| visitListExpression(ListExpression node) { |
| - // TODO(jimhug): Use node.type or other type inference here. |
| - var argsCode = []; |
| var argValues = []; |
| - var type = null; |
| - if (node.type != null) { |
| - // The parser makes node.type a list type, we extract its type argument. |
| - type = method.resolveType(node.type, true).typeArgsInOrder[0]; |
| + //var listType = node.isConst ? world.immutableListType : world.listType; |
|
Jennifer Messerly
2012/01/09 19:06:54
remove?
jimhug
2012/01/09 21:34:30
Done.
|
| + var listType = world.listType; |
| + var type = world.varType; |
| + if (node.itemType != null) { |
| + type = method.resolveType(node.itemType, true); |
| if (node.isConst && (type is ParameterType || type.hasTypeParams)) { |
| world.error('type parameter cannot be used in const list literals'); |
| } |
| + listType = listType.getOrMakeConcreteType([type]); |
|
Jennifer Messerly
2012/01/09 19:06:54
correct generic List type, awesome :)
|
| } |
| for (var item in node.values) { |
| var arg = visitTypedValue(item, type); |
| argValues.add(arg); |
| - if (node.isConst) { |
| - if (!arg.isConst) { |
| - world.error('const list can only contain const values', item.span); |
| - argsCode.add(arg.code); |
| - } else { |
| - argsCode.add(arg.canonicalCode); |
| - } |
| - } else { |
| - argsCode.add(arg.code); |
| + if (node.isConst && !arg.isConst) { |
| + world.error('const list can only contain const values', arg.span); |
| } |
| } |
| world.listFactoryType.markUsed(); |
| - final code = '[${Strings.join(argsCode, ", ")}]'; |
| - var value = new Value(world.listType, code, node.span); |
| - if (node.isConst) { |
| - final immutableList = world.immutableListType; |
| - final immutableListCtor = immutableList.getConstructor('from'); |
| - final result = immutableListCtor.invoke(this, node, |
| - new Value.type(value.type, node.span), new Arguments(null, [value])); |
| - value = world.gen.globalForConst( |
| - new ConstListValue(immutableList, argValues, 'const $code', |
| - result.code, node.span), |
| - argValues); |
| - } |
| - return value; |
| + var ret = new ListValue(argValues, node.isConst, listType, node.span); |
| + if (ret.isConst) return ret.getGlobalValue(); |
| + return ret; |
| } |
| @@ -2411,56 +2361,48 @@ class MethodGenerator implements TreeVisitor { |
| new Value.type(world.mapType, node.span), Arguments.EMPTY); |
| } |
| - var argValues = []; |
| - var argsCode = []; |
| - var type = null; |
| - if (node.type != null) { |
| - // node.type is a map type, extract the type argument for the values. |
| - type = method.resolveType(node.type, true).typeArgsInOrder[1]; |
| - if (node.isConst && (type is ParameterType || type.hasTypeParams)) { |
| + var values = new List<Value>(); |
|
Jennifer Messerly
2012/01/09 19:06:54
perhaps:
var values = <Value>[];
?
jimhug
2012/01/09 21:34:30
Done.
|
| + var valueType = world.varType, keyType = world.stringType; |
| + var mapType = world.mapType; // TODO(jimhug): immutable type? |
| + if (node.valueType !== null) { |
| + if (node.keyType !== null) { |
| + keyType = method.resolveType(node.keyType, true); |
| + // TODO(jimhug): Would be nice to allow arbitrary keys here (this is |
| + // currently not allowed by the spec). |
| + if (!keyType.isString) { |
| + world.error('the key type of a map literal must be "String"', |
| + keyType.span); |
| + } |
| + if (node.isConst && (keyType is ParameterType || keyType.hasTypeParams)) { |
|
Jennifer Messerly
2012/01/09 19:06:54
long line
Jennifer Messerly
2012/01/09 19:06:54
keyType.isUnboundType, or something like that? Whe
jimhug
2012/01/09 21:34:30
Done.
jimhug
2012/01/09 21:34:30
Good idea - for longer-term cleanup.
On 2012/01/09
|
| + world.error('type parameter cannot be used in const map literals'); |
| + } |
| + } |
| + |
| + valueType = method.resolveType(node.valueType, true); |
| + if (node.isConst && (valueType is ParameterType || valueType.hasTypeParams)) { |
| world.error('type parameter cannot be used in const map literals'); |
| } |
| + |
| + mapType = mapType.getOrMakeConcreteType([keyType, valueType]); |
| } |
| + |
| for (int i = 0; i < node.items.length; i += 2) { |
| - // TODO(jimhug): Use node.type or other type inference here. |
| - // TODO(jimhug): Would be nice to allow arbitrary keys here (this is |
| - // currently not allowed by the spec). |
| - var key = visitTypedValue(node.items[i], world.stringType); |
| - final valueItem = node.items[i+1]; |
| - var value = visitTypedValue(valueItem, type); |
| - argValues.add(key); |
| - argValues.add(value); |
| - |
| - if (node.isConst) { |
| - if (!key.isConst || !value.isConst) { |
| - world.error('const map can only contain const values', |
| - valueItem.span); |
| - argsCode.add(key.code); |
| - argsCode.add(value.code); |
| - } else { |
| - argsCode.add(key.canonicalCode); |
| - argsCode.add(value.canonicalCode); |
| - } |
| - } else { |
| - argsCode.add(key.code); |
| - argsCode.add(value.code); |
| + var key = visitTypedValue(node.items[i], keyType); |
| + if (node.isConst && !key.isConst) { |
| + world.error('const map can only contain const keys', key.span); |
| } |
| - } |
| - |
| - var argList = '[${Strings.join(argsCode, ", ")}]'; |
| - var items = new Value(world.listType, argList, node.span); |
| - var tp = world.corelib.topType; |
| - Member f = node.isConst ? tp.getMember('_constMap') : tp.getMember('_map'); |
| - var value = f.invoke(this, node, new Value.type(tp, null), |
| - new Arguments(null, [items])); |
| + values.add(key); |
| - if (node.isConst) { |
| - value = new ConstMapValue(value.type, argValues, value.code, |
| - value.code, value.span); |
| - return world.gen.globalForConst(value, argValues); |
| - } else { |
| - return value; |
| + var value = visitTypedValue(node.items[i+1], valueType); |
|
Jennifer Messerly
2012/01/09 19:06:54
nit: spacing on i + 1
jimhug
2012/01/09 21:34:30
Done.
|
| + if (node.isConst && !value.isConst) { |
| + world.error('const map can only contain const values', value.span); |
| + } |
| + values.add(value); |
| } |
| + |
| + var ret = new MapValue(values, node.isConst, mapType, node.span); |
| + if (ret.isConst) return ret.getGlobalValue(); |
| + return ret; |
| } |
| visitConditionalExpression(ConditionalExpression node) { |
| @@ -2481,10 +2423,8 @@ class MethodGenerator implements TreeVisitor { |
| visitParenExpression(ParenExpression node) { |
| var body = visitValue(node.body); |
| - if (body.isConst) { |
| - return new EvaluatedValue(body.type, body.actualValue, |
| - '(${body.canonicalCode})', node.span); |
| - } |
| + // Assumption implicit here that const values never need parens... |
| + if (body.isConst) return body; |
| return new Value(body.type, '(${body.code})', node.span); |
| } |