Index: frog/leg/compile_time_constants.dart |
diff --git a/frog/leg/compile_time_constants.dart b/frog/leg/compile_time_constants.dart |
index 4199c4faea516bd6cc862eee5615f554ed81c367..8967bb5cf19df6cd47f6b4ac1bf346980b6bb21c 100644 |
--- a/frog/leg/compile_time_constants.dart |
+++ b/frog/leg/compile_time_constants.dart |
@@ -275,7 +275,7 @@ class ListConstant extends ObjectConstant { |
if (other is !ListConstant) return false; |
ListConstant otherList = other; |
if (hashCode() != otherList.hashCode()) return false; |
- // TODO(floitsch): verify that the types are the same. |
+ // TODO(floitsch): verify that the generic types are the same. |
if (entries.length != otherList.entries.length) return false; |
for (int i = 0; i < entries.length; i++) { |
if (entries[i] != otherList.entries[i]) return false; |
@@ -286,6 +286,93 @@ class ListConstant extends ObjectConstant { |
int hashCode() => _hashCode; |
} |
+class MapConstant extends ObjectConstant { |
+ /** The dart class implementing constant map literals. */ |
+ static final SourceString DART_CLASS = const SourceString("ConstantMap"); |
+ static final SourceString LENGTH_NAME = const SourceString("length"); |
+ static final SourceString JS_OBJECT_NAME = const SourceString("_jsObject"); |
+ static final SourceString KEYS_NAME = const SourceString("_keys"); |
+ |
+ final ListConstant keys; |
+ final List<Constant> values; |
+ int _hashCode; |
+ |
+ MapConstant(Type type, this.keys, this.values) : super(type) { |
+ // TODO(floitsch): create a better hash. |
+ int hash = 0; |
+ for (Constant value in values) hash ^= value.hashCode(); |
+ _hashCode = hash; |
+ } |
+ bool isMap() => true; |
+ |
+ void writeJsCode(StringBuffer buffer, ConstantHandler handler) { |
+ void writeJsMap() { |
+ String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype"; |
+ buffer.add("{"); |
+ for (int i = 0; i < keys.entries.length; i++) { |
+ if (i != 0) buffer.add(", "); |
+ |
+ StringConstant key = keys.entries[i]; |
+ key.writeJsCode(buffer, handler); |
+ buffer.add(": "); |
+ Constant value = values[i]; |
+ // TODO(floitsch): share this code with the ListConstant and |
+ // ConstructedConstant. |
+ if (value.isObject()) { |
+ String name = handler.getNameForConstant(value); |
+ buffer.add("$isolatePrototype.$name"); |
+ } else { |
+ value.writeJsCode(buffer, handler); |
+ } |
+ } |
+ buffer.add("}"); |
+ } |
+ |
+ buffer.add("new "); |
+ buffer.add(handler.getJsConstructor(type.element)); |
+ buffer.add("("); |
+ // We have to send the arguments in the same order as they appear in the |
+ // class element. |
ngeoffray
2012/03/09 18:08:50
Please also say that it's because we emit the orde
floitsch
2012/03/10 17:40:24
Done.
|
+ int emittedArgumentCount = 0; |
+ ClassElement classElement = type.element; |
ngeoffray
2012/03/09 18:08:50
Share that with line 332.
floitsch
2012/03/10 17:40:24
Done.
|
+ for (Element element in classElement.members) { |
+ if (element.name == LENGTH_NAME) { |
+ buffer.add(keys.entries.length); |
+ } else if (element.name == JS_OBJECT_NAME) { |
+ writeJsMap(); |
+ } else if (element.name == KEYS_NAME) { |
+ keys.writeJsCode(buffer, handler); |
+ } else { |
+ continue; |
ngeoffray
2012/03/09 18:08:50
Please add a comment that this is for methods.
floitsch
2012/03/10 17:40:24
Done.
|
+ } |
+ emittedArgumentCount++; |
+ if (emittedArgumentCount == 3) { |
+ break; // All arguments have been emitted. |
+ } else { |
+ buffer.add(", "); |
+ } |
+ } |
+ if (emittedArgumentCount != 3) { |
+ handler.compiler.internalError("Could not generate constant map"); |
ngeoffray
2012/03/09 18:08:50
Maybe say something more explicit like: "compiler
floitsch
2012/03/10 17:40:24
Done.
|
+ } |
+ buffer.add(")"); |
+ } |
+ |
+ bool operator ==(var other) { |
+ if (other is !MapConstant) return false; |
+ MapConstant otherMap = other; |
+ if (hashCode() != otherMap.hashCode()) return false; |
+ // TODO(floitsch): verify that the generic types are the same. |
+ if (keys != otherMap.keys) return false; |
+ for (int i = 0; i < values.length; i++) { |
+ if (values[i] != otherMap.values[i]) return false; |
+ } |
+ return true; |
+ } |
+ |
+ int hashCode() => _hashCode; |
+} |
+ |
class ConstructedConstant extends ObjectConstant { |
final List<Constant> fields; |
int _hashCode; |
@@ -312,7 +399,7 @@ class ConstructedConstant extends ObjectConstant { |
Constant field = fields[i]; |
// TODO(floitsch): share this code with the ListConstant. |
if (field.isObject()) { |
- String name = handler.getNameForConstant(entry); |
+ String name = handler.getNameForConstant(field); |
buffer.add("$isolatePrototype.$name"); |
} else { |
field.writeJsCode(buffer, handler); |
@@ -592,7 +679,7 @@ class CompileTimeConstantEvaluator extends AbstractVisitor { |
Constant visitLiteralList(LiteralList node) { |
if (!node.isConst()) error(node); |
- List arguments = []; |
+ List<Constant> arguments = <Constant>[]; |
for (Link<Node> link = node.elements.nodes; |
!link.isEmpty(); |
link = link.tail) { |
@@ -604,7 +691,37 @@ class CompileTimeConstantEvaluator extends AbstractVisitor { |
} |
Constant visitLiteralMap(LiteralMap node) { |
- compiler.unimplemented("CompileTimeConstantEvaluator map", node: node); |
+ // TODO(floitsch): check for isConst, once the parser adds it into the node. |
+ // if (!node.isConst()) error(node); |
+ List<StringConstant> keys = <StringConstant>[]; |
+ List<Constant> values = <Constant>[]; |
+ for (Link<Node> link = node.entries.nodes; |
+ !link.isEmpty(); |
+ link = link.tail) { |
+ LiteralMapEntry entry = link.head; |
+ Constant key = evaluate(entry.key); |
+ if (!key.isString()) { |
+ compiler.internalError("Key for literal map not a String", |
+ node: entry.key); |
+ } |
+ keys.add(key); |
+ values.add(evaluate(entry.value)); |
+ } |
+ // TODO(floitsch): this should be a List<String> type. |
+ Type keysType = null; |
+ ListConstant keysList = new ListConstant(keysType, keys); |
+ // We don't actually need to register the constant, but there is no reason |
+ // not to. |
+ constantHandler.registerCompileTimeConstant(keysList); |
+ ClassElement classElement = |
+ compiler.jsHelperLibrary.find(MapConstant.DART_CLASS); |
+ classElement.resolve(compiler); |
+ // TODO(floitsch): copy over the generic type. |
+ Type type = new SimpleType(classElement.name, classElement); |
+ compiler.registerInstantiatedClass(classElement); |
+ Constant constant = new MapConstant(type, keysList, values); |
+ constantHandler.registerCompileTimeConstant(constant); |
+ return constant; |
} |
Constant visitLiteralNull(LiteralNull node) { |