Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(32)

Unified Diff: frog/leg/compile_time_constants.dart

Issue 9665001: Implement constant maps. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove trailing whitespace. Created 8 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | frog/leg/lib/constant_map.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/leg/compile_time_constants.dart
diff --git a/frog/leg/compile_time_constants.dart b/frog/leg/compile_time_constants.dart
index 0cfe424704fd64bc4eb3aff8d67ff9f76859b9cd..54388c91b29b87da2145c400b9b2b6e6f72080ca 100644
--- a/frog/leg/compile_time_constants.dart
+++ b/frog/leg/compile_time_constants.dart
@@ -20,6 +20,7 @@ class Constant implements Hashable {
bool isObject() => false;
abstract void writeJsCode(StringBuffer buffer, ConstantHandler handler);
+ abstract List<Constant> getDependencies();
}
class PrimitiveConstant extends Constant {
@@ -34,6 +35,8 @@ class PrimitiveConstant extends Constant {
}
String toString() => value.toString();
+ // Primitive constants don't have dependencies.
+ List<Constant> getDependencies() => const <Constant>[];
abstract DartString toDartString();
}
@@ -275,7 +278,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;
@@ -284,6 +287,110 @@ class ListConstant extends ObjectConstant {
}
int hashCode() => _hashCode;
+
+ List<Constant> getDependencies() => entries;
+}
+
+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) {
+ String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype";
+
+ void writeJsMap() {
+ 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("}");
+ }
+
+ void badFieldCountError() {
+ handler.compiler.internalError(
+ "Compiler and ConstantMap disagree on number of fields.");
+ }
+
+ ClassElement classElement = type.element;
+ buffer.add("new ");
+ buffer.add(handler.getJsConstructor(classElement));
+ buffer.add("(");
+ // The arguments of the JavaScript constructor for any given Dart class
+ // are in the same order as the members of the class element.
+ int emittedArgumentCount = 0;
+ 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) {
+ // TODO(floitsch): share this code with the ListConstant and
+ // ConstructedConstant.
+ String name = handler.getNameForConstant(keys);
+ buffer.add("$isolatePrototype.$name");
+ } else {
+ // Skip methods.
+ if (element.kind == ElementKind.FIELD) badFieldCountError();
+ continue;
+ }
+ emittedArgumentCount++;
+ if (emittedArgumentCount == 3) {
+ break; // All arguments have been emitted.
+ } else {
+ buffer.add(", ");
+ }
+ }
+ if (emittedArgumentCount != 3) badFieldCountError();
+ 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;
+
+ List<Constant> getDependencies() {
+ List<Constant> result = <Constant>[keys];
+ result.addAll(values);
+ return result;
+ }
}
class ConstructedConstant extends ObjectConstant {
@@ -312,7 +419,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);
@@ -335,6 +442,7 @@ class ConstructedConstant extends ObjectConstant {
}
int hashCode() => _hashCode;
+ List<Constant> getDependencies() => fields;
}
/**
@@ -466,7 +574,21 @@ class ConstantHandler extends CompilerTask {
}
List<Constant> getConstantsForEmission() {
- return compiledConstants.getKeys();
+ // We must emit dependencies before their uses.
+ Set<Constant> seenConstants = new Set<Constant>();
+ List<Constant> result = new List<Constant>();
+
+ void addConstant(Constant constant) {
+ if (!seenConstants.contains(constant)) {
+ constant.getDependencies().forEach(addConstant);
+ assert(!seenConstants.contains(constant));
+ result.add(constant);
+ seenConstants.add(constant);
+ }
+ }
+
+ compiledConstants.forEach((Constant key, ignored) => addConstant(key));
+ return result;
}
String getNameForConstant(Constant constant) {
@@ -586,7 +708,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) {
@@ -598,7 +720,45 @@ 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>[];
+ bool hasProtoKey = false;
+ for (Link<Node> link = node.entries.nodes;
+ !link.isEmpty();
+ link = link.tail) {
+ LiteralMapEntry entry = link.head;
+ Constant key = evaluate(entry.key);
+ if (!key.isString() || entry.key.asLiteralString() === null) {
+ MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL;
+ compiler.reportError(entry.key, new ResolutionError(kind, const []));
+ }
+ // TODO(floitsch): make this faster.
+ StringConstant keyConstant = key;
+ if (keyConstant.value == new LiteralDartString("__proto__")) {
+ hasProtoKey = true;
+ }
+ keys.add(key);
+ values.add(evaluate(entry.value));
+ }
+ if (hasProtoKey) {
+ compiler.unimplemented("visitLiteralMap with __proto__ key",
+ node: node);
+ }
+ // TODO(floitsch): this should be a List<String> type.
+ Type keysType = null;
+ ListConstant keysList = new ListConstant(keysType, keys);
+ constantHandler.registerCompileTimeConstant(keysList);
+ ClassElement classElement =
+ compiler.jsHelperLibrary.find(MapConstant.DART_CLASS);
+ classElement.ensureResolved(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) {
« no previous file with comments | « no previous file | frog/leg/lib/constant_map.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698