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

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: cosmetic change. 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 4199c4faea516bd6cc862eee5615f554ed81c367..6564dd57cb871f41c0c86e6abdf275b79b63d624 100644
--- a/frog/leg/compile_time_constants.dart
+++ b/frog/leg/compile_time_constants.dart
@@ -20,6 +20,19 @@ class Constant implements Hashable {
bool isObject() => false;
abstract void writeJsCode(StringBuffer buffer, ConstantHandler handler);
+
+ /**
+ * Recursively adds the constants dependencies unless the dependency is
+ * already in the [seenConstants] list. Does not add itself to the [list].
ngeoffray 2012/03/10 18:33:55 [seenConstants] list -> [seenConstants] set.
floitsch 2012/03/10 19:58:54 has been removed.
+ *
+ * The dependent constants must always be added before the user of the
+ * constant.
+ *
+ * Any constant that is added to the list must also be added to the set.
+ */
+ // TODO(floitsch): this should take an ordered set.
+ abstract void addDependencies(List<Constant> list,
ngeoffray 2012/03/10 18:33:55 Maybe rename list to orderedList. 'list' is too ge
floitsch 2012/03/10 19:58:54 has been removed.
+ Set<Constant> seenConstants);
}
class PrimitiveConstant extends Constant {
@@ -34,6 +47,9 @@ class PrimitiveConstant extends Constant {
}
String toString() => value.toString();
+ void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
+ // Primitive constants don't have dependencies.
+ }
abstract DartString toDartString();
}
@@ -238,6 +254,16 @@ class ObjectConstant extends Constant {
ObjectConstant(this.type);
bool isObject() => true;
+
+ void addDependency(Constant constant,
ngeoffray 2012/03/10 18:33:55 Instead of putting addDependeny on a Constant clas
floitsch 2012/03/10 19:58:54 replaced with getDependencies().
+ List<Constant> list,
+ Set<Constant> seenConstants) {
+ if (!seenConstants.contains(constant)) {
+ constant.addDependencies(list, seenConstants);
+ list.add(constant);
+ seenConstants.add(constant);
+ }
+ }
}
class ListConstant extends ObjectConstant {
@@ -275,7 +301,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 +310,115 @@ class ListConstant extends ObjectConstant {
}
int hashCode() => _hashCode;
+
+ void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
+ for (Constant constant in entries) {
+ addDependency(constant, list, seenConstants);
+ }
+ }
+}
+
+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;
+
+ void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
+ addDependency(keys, list, seenConstants);
+ for (Constant constant in values) {
+ addDependency(constant, list, seenConstants);
+ }
+ }
}
class ConstructedConstant extends ObjectConstant {
@@ -312,7 +447,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 +470,12 @@ class ConstructedConstant extends ObjectConstant {
}
int hashCode() => _hashCode;
+
+ void addDependencies(List<Constant> list, Set<Constant> seenConstants) {
+ for (Constant constant in fields) {
+ addDependency(constant, list, seenConstants);
+ }
+ }
}
/**
@@ -466,7 +607,17 @@ class ConstantHandler extends CompilerTask {
}
List<Constant> getConstantsForEmission() {
- return compiledConstants.getKeys();
+ // TODO(floitsch): Improve the creation of the dependencies.
+ Set<Constant> seenConstants = new Set<Constant>();
+ List<Constant> result = new List<Constant>();
+ compiledConstants.forEach((Constant key, ignored) {
+ if (seenConstants.contains(key)) return;
+ key.addDependencies(result, seenConstants);
+ assert(!seenConstants.contains(key));
+ seenConstants.add(key);
+ result.add(key);
+ });
+ return result;
}
String getNameForConstant(Constant constant) {
@@ -592,7 +743,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 +755,48 @@ 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 &&
+ entry.key.asStringInterpolation() === null)) {
ngeoffray 2012/03/10 18:33:55 AFAIK, string interpolation for constants is still
floitsch 2012/03/10 19:58:54 This is in preparation for future changes. Since s
ngeoffray 2012/03/10 22:28:03 I'd prefer that you remove it. I have a strong ave
floitsch 2012/03/10 22:58:22 Done.
+ MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL;
+ // TODO(floitsch): is resolution error the correct error?
+ 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