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

Side by Side 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | frog/leg/lib/constant_map.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 class Constant implements Hashable { 5 class Constant implements Hashable {
6 const Constant(); 6 const Constant();
7 7
8 bool isNull() => false; 8 bool isNull() => false;
9 bool isBool() => false; 9 bool isBool() => false;
10 bool isTrue() => false; 10 bool isTrue() => false;
11 bool isFalse() => false; 11 bool isFalse() => false;
12 bool isInt() => false; 12 bool isInt() => false;
13 bool isDouble() => false; 13 bool isDouble() => false;
14 bool isNum() => false; 14 bool isNum() => false;
15 bool isString() => false; 15 bool isString() => false;
16 bool isList() => false; 16 bool isList() => false;
17 bool isMap() => false; 17 bool isMap() => false;
18 bool isConstructedObject() => false; 18 bool isConstructedObject() => false;
19 /** Returns true if the constant is a list, a map or a constructed object. */ 19 /** Returns true if the constant is a list, a map or a constructed object. */
20 bool isObject() => false; 20 bool isObject() => false;
21 21
22 abstract void writeJsCode(StringBuffer buffer, ConstantHandler handler); 22 abstract void writeJsCode(StringBuffer buffer, ConstantHandler handler);
23 abstract List<Constant> getDependencies();
23 } 24 }
24 25
25 class PrimitiveConstant extends Constant { 26 class PrimitiveConstant extends Constant {
26 abstract get value(); 27 abstract get value();
27 const PrimitiveConstant(); 28 const PrimitiveConstant();
28 29
29 bool operator ==(var other) { 30 bool operator ==(var other) {
30 if (other is !PrimitiveConstant) return false; 31 if (other is !PrimitiveConstant) return false;
31 PrimitiveConstant otherPrimitive = other; 32 PrimitiveConstant otherPrimitive = other;
32 // We use == instead of === so that DartStrings compare correctly. 33 // We use == instead of === so that DartStrings compare correctly.
33 return value == otherPrimitive.value; 34 return value == otherPrimitive.value;
34 } 35 }
35 36
36 String toString() => value.toString(); 37 String toString() => value.toString();
38 // Primitive constants don't have dependencies.
39 List<Constant> getDependencies() => const <Constant>[];
37 abstract DartString toDartString(); 40 abstract DartString toDartString();
38 } 41 }
39 42
40 class NullConstant extends PrimitiveConstant { 43 class NullConstant extends PrimitiveConstant {
41 factory NullConstant() => const NullConstant._internal(); 44 factory NullConstant() => const NullConstant._internal();
42 const NullConstant._internal(); 45 const NullConstant._internal();
43 bool isNull() => true; 46 bool isNull() => true;
44 get value() => null; 47 get value() => null;
45 48
46 void writeJsCode(StringBuffer buffer, ConstantHandler handler) { 49 void writeJsCode(StringBuffer buffer, ConstantHandler handler) {
(...skipping 221 matching lines...) Expand 10 before | Expand all | Expand 10 after
268 entry.writeJsCode(buffer, handler); 271 entry.writeJsCode(buffer, handler);
269 } 272 }
270 } 273 }
271 buffer.add("])"); 274 buffer.add("])");
272 } 275 }
273 276
274 bool operator ==(var other) { 277 bool operator ==(var other) {
275 if (other is !ListConstant) return false; 278 if (other is !ListConstant) return false;
276 ListConstant otherList = other; 279 ListConstant otherList = other;
277 if (hashCode() != otherList.hashCode()) return false; 280 if (hashCode() != otherList.hashCode()) return false;
278 // TODO(floitsch): verify that the types are the same. 281 // TODO(floitsch): verify that the generic types are the same.
279 if (entries.length != otherList.entries.length) return false; 282 if (entries.length != otherList.entries.length) return false;
280 for (int i = 0; i < entries.length; i++) { 283 for (int i = 0; i < entries.length; i++) {
281 if (entries[i] != otherList.entries[i]) return false; 284 if (entries[i] != otherList.entries[i]) return false;
282 } 285 }
283 return true; 286 return true;
284 } 287 }
285 288
286 int hashCode() => _hashCode; 289 int hashCode() => _hashCode;
290
291 List<Constant> getDependencies() => entries;
292 }
293
294 class MapConstant extends ObjectConstant {
295 /** The dart class implementing constant map literals. */
296 static final SourceString DART_CLASS = const SourceString("ConstantMap");
297 static final SourceString LENGTH_NAME = const SourceString("length");
298 static final SourceString JS_OBJECT_NAME = const SourceString("_jsObject");
299 static final SourceString KEYS_NAME = const SourceString("_keys");
300
301 final ListConstant keys;
302 final List<Constant> values;
303 int _hashCode;
304
305 MapConstant(Type type, this.keys, this.values) : super(type) {
306 // TODO(floitsch): create a better hash.
307 int hash = 0;
308 for (Constant value in values) hash ^= value.hashCode();
309 _hashCode = hash;
310 }
311 bool isMap() => true;
312
313 void writeJsCode(StringBuffer buffer, ConstantHandler handler) {
314 String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype";
315
316 void writeJsMap() {
317 buffer.add("{");
318 for (int i = 0; i < keys.entries.length; i++) {
319 if (i != 0) buffer.add(", ");
320
321 StringConstant key = keys.entries[i];
322 key.writeJsCode(buffer, handler);
323 buffer.add(": ");
324 Constant value = values[i];
325 // TODO(floitsch): share this code with the ListConstant and
326 // ConstructedConstant.
327 if (value.isObject()) {
328 String name = handler.getNameForConstant(value);
329 buffer.add("$isolatePrototype.$name");
330 } else {
331 value.writeJsCode(buffer, handler);
332 }
333 }
334 buffer.add("}");
335 }
336
337 void badFieldCountError() {
338 handler.compiler.internalError(
339 "Compiler and ConstantMap disagree on number of fields.");
340 }
341
342 ClassElement classElement = type.element;
343 buffer.add("new ");
344 buffer.add(handler.getJsConstructor(classElement));
345 buffer.add("(");
346 // The arguments of the JavaScript constructor for any given Dart class
347 // are in the same order as the members of the class element.
348 int emittedArgumentCount = 0;
349 for (Element element in classElement.members) {
350 if (element.name == LENGTH_NAME) {
351 buffer.add(keys.entries.length);
352 } else if (element.name == JS_OBJECT_NAME) {
353 writeJsMap();
354 } else if (element.name == KEYS_NAME) {
355 // TODO(floitsch): share this code with the ListConstant and
356 // ConstructedConstant.
357 String name = handler.getNameForConstant(keys);
358 buffer.add("$isolatePrototype.$name");
359 } else {
360 // Skip methods.
361 if (element.kind == ElementKind.FIELD) badFieldCountError();
362 continue;
363 }
364 emittedArgumentCount++;
365 if (emittedArgumentCount == 3) {
366 break; // All arguments have been emitted.
367 } else {
368 buffer.add(", ");
369 }
370 }
371 if (emittedArgumentCount != 3) badFieldCountError();
372 buffer.add(")");
373 }
374
375 bool operator ==(var other) {
376 if (other is !MapConstant) return false;
377 MapConstant otherMap = other;
378 if (hashCode() != otherMap.hashCode()) return false;
379 // TODO(floitsch): verify that the generic types are the same.
380 if (keys != otherMap.keys) return false;
381 for (int i = 0; i < values.length; i++) {
382 if (values[i] != otherMap.values[i]) return false;
383 }
384 return true;
385 }
386
387 int hashCode() => _hashCode;
388
389 List<Constant> getDependencies() {
390 List<Constant> result = <Constant>[keys];
391 result.addAll(values);
392 return result;
393 }
287 } 394 }
288 395
289 class ConstructedConstant extends ObjectConstant { 396 class ConstructedConstant extends ObjectConstant {
290 final List<Constant> fields; 397 final List<Constant> fields;
291 int _hashCode; 398 int _hashCode;
292 399
293 ConstructedConstant(Type type, this.fields) : super(type) { 400 ConstructedConstant(Type type, this.fields) : super(type) {
294 assert(type !== null); 401 assert(type !== null);
295 // TODO(floitsch): create a better hash. 402 // TODO(floitsch): create a better hash.
296 int hash = 0; 403 int hash = 0;
297 for (Constant field in fields) { 404 for (Constant field in fields) {
298 hash ^= field.hashCode(); 405 hash ^= field.hashCode();
299 } 406 }
300 hash ^= type.element.hashCode(); 407 hash ^= type.element.hashCode();
301 _hashCode = hash; 408 _hashCode = hash;
302 } 409 }
303 bool isConstructedObject() => true; 410 bool isConstructedObject() => true;
304 411
305 void writeJsCode(StringBuffer buffer, ConstantHandler handler) { 412 void writeJsCode(StringBuffer buffer, ConstantHandler handler) {
306 buffer.add("new "); 413 buffer.add("new ");
307 buffer.add(handler.getJsConstructor(type.element)); 414 buffer.add(handler.getJsConstructor(type.element));
308 buffer.add("("); 415 buffer.add("(");
309 String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype"; 416 String isolatePrototype = "${handler.compiler.namer.ISOLATE}.prototype";
310 for (int i = 0; i < fields.length; i++) { 417 for (int i = 0; i < fields.length; i++) {
311 if (i != 0) buffer.add(", "); 418 if (i != 0) buffer.add(", ");
312 Constant field = fields[i]; 419 Constant field = fields[i];
313 // TODO(floitsch): share this code with the ListConstant. 420 // TODO(floitsch): share this code with the ListConstant.
314 if (field.isObject()) { 421 if (field.isObject()) {
315 String name = handler.getNameForConstant(entry); 422 String name = handler.getNameForConstant(field);
316 buffer.add("$isolatePrototype.$name"); 423 buffer.add("$isolatePrototype.$name");
317 } else { 424 } else {
318 field.writeJsCode(buffer, handler); 425 field.writeJsCode(buffer, handler);
319 } 426 }
320 } 427 }
321 buffer.add(")"); 428 buffer.add(")");
322 } 429 }
323 430
324 bool operator ==(var otherVar) { 431 bool operator ==(var otherVar) {
325 if (otherVar is !ConstructedConstant) return false; 432 if (otherVar is !ConstructedConstant) return false;
326 ConstructedConstant other = otherVar; 433 ConstructedConstant other = otherVar;
327 if (hashCode() != other.hashCode()) return false; 434 if (hashCode() != other.hashCode()) return false;
328 // TODO(floitsch): verify that the (generic) types are the same. 435 // TODO(floitsch): verify that the (generic) types are the same.
329 if (type.element != other.type.element) return false; 436 if (type.element != other.type.element) return false;
330 if (fields.length != other.fields.length) return false; 437 if (fields.length != other.fields.length) return false;
331 for (int i = 0; i < fields.length; i++) { 438 for (int i = 0; i < fields.length; i++) {
332 if (fields[i] != other.fields[i]) return false; 439 if (fields[i] != other.fields[i]) return false;
333 } 440 }
334 return true; 441 return true;
335 } 442 }
336 443
337 int hashCode() => _hashCode; 444 int hashCode() => _hashCode;
445 List<Constant> getDependencies() => fields;
338 } 446 }
339 447
340 /** 448 /**
341 * The [ConstantHandler] keeps track of compile-time constants, 449 * The [ConstantHandler] keeps track of compile-time constants,
342 * initializations of global and static fields, and default values of 450 * initializations of global and static fields, and default values of
343 * optional parameters. 451 * optional parameters.
344 */ 452 */
345 class ConstantHandler extends CompilerTask { 453 class ConstantHandler extends CompilerTask {
346 // Contains the initial value of fields. Must contain all static and global 454 // Contains the initial value of fields. Must contain all static and global
347 // initializations of used fields. May contain caches for instance fields. 455 // initializations of used fields. May contain caches for instance fields.
(...skipping 111 matching lines...) Expand 10 before | Expand all | Expand 10 after
459 */ 567 */
460 List<VariableElement> getStaticFinalFieldsForEmission() { 568 List<VariableElement> getStaticFinalFieldsForEmission() {
461 return initialVariableValues.getKeys().filter((element) { 569 return initialVariableValues.getKeys().filter((element) {
462 return element.kind == ElementKind.FIELD 570 return element.kind == ElementKind.FIELD
463 && !element.isInstanceMember() 571 && !element.isInstanceMember()
464 && element.modifiers.isFinal(); 572 && element.modifiers.isFinal();
465 }); 573 });
466 } 574 }
467 575
468 List<Constant> getConstantsForEmission() { 576 List<Constant> getConstantsForEmission() {
469 return compiledConstants.getKeys(); 577 // We must emit dependencies before their uses.
578 Set<Constant> seenConstants = new Set<Constant>();
579 List<Constant> result = new List<Constant>();
580
581 void addConstant(Constant constant) {
582 if (!seenConstants.contains(constant)) {
583 constant.getDependencies().forEach(addConstant);
584 assert(!seenConstants.contains(constant));
585 result.add(constant);
586 seenConstants.add(constant);
587 }
588 }
589
590 compiledConstants.forEach((Constant key, ignored) => addConstant(key));
591 return result;
470 } 592 }
471 593
472 String getNameForConstant(Constant constant) { 594 String getNameForConstant(Constant constant) {
473 return compiledConstants[constant]; 595 return compiledConstants[constant];
474 } 596 }
475 597
476 StringBuffer writeJsCode(StringBuffer buffer, Constant value) { 598 StringBuffer writeJsCode(StringBuffer buffer, Constant value) {
477 value.writeJsCode(buffer, this); 599 value.writeJsCode(buffer, this);
478 return buffer; 600 return buffer;
479 } 601 }
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
579 Constant visitLiteralDouble(LiteralDouble node) { 701 Constant visitLiteralDouble(LiteralDouble node) {
580 return new DoubleConstant(node.value); 702 return new DoubleConstant(node.value);
581 } 703 }
582 704
583 Constant visitLiteralInt(LiteralInt node) { 705 Constant visitLiteralInt(LiteralInt node) {
584 return new IntConstant(node.value); 706 return new IntConstant(node.value);
585 } 707 }
586 708
587 Constant visitLiteralList(LiteralList node) { 709 Constant visitLiteralList(LiteralList node) {
588 if (!node.isConst()) error(node); 710 if (!node.isConst()) error(node);
589 List arguments = []; 711 List<Constant> arguments = <Constant>[];
590 for (Link<Node> link = node.elements.nodes; 712 for (Link<Node> link = node.elements.nodes;
591 !link.isEmpty(); 713 !link.isEmpty();
592 link = link.tail) { 714 link = link.tail) {
593 arguments.add(evaluate(link.head)); 715 arguments.add(evaluate(link.head));
594 } 716 }
595 // TODO(floitsch): get type from somewhere. 717 // TODO(floitsch): get type from somewhere.
596 Type type = null; 718 Type type = null;
597 return constantHandler.compileListLiteral(node, type, arguments); 719 return constantHandler.compileListLiteral(node, type, arguments);
598 } 720 }
599 721
600 Constant visitLiteralMap(LiteralMap node) { 722 Constant visitLiteralMap(LiteralMap node) {
601 compiler.unimplemented("CompileTimeConstantEvaluator map", node: node); 723 // TODO(floitsch): check for isConst, once the parser adds it into the node.
724 // if (!node.isConst()) error(node);
725 List<StringConstant> keys = <StringConstant>[];
726 List<Constant> values = <Constant>[];
727 bool hasProtoKey = false;
728 for (Link<Node> link = node.entries.nodes;
729 !link.isEmpty();
730 link = link.tail) {
731 LiteralMapEntry entry = link.head;
732 Constant key = evaluate(entry.key);
733 if (!key.isString() || entry.key.asLiteralString() === null) {
734 MessageKind kind = MessageKind.KEY_NOT_A_STRING_LITERAL;
735 compiler.reportError(entry.key, new ResolutionError(kind, const []));
736 }
737 // TODO(floitsch): make this faster.
738 StringConstant keyConstant = key;
739 if (keyConstant.value == new LiteralDartString("__proto__")) {
740 hasProtoKey = true;
741 }
742 keys.add(key);
743 values.add(evaluate(entry.value));
744 }
745 if (hasProtoKey) {
746 compiler.unimplemented("visitLiteralMap with __proto__ key",
747 node: node);
748 }
749 // TODO(floitsch): this should be a List<String> type.
750 Type keysType = null;
751 ListConstant keysList = new ListConstant(keysType, keys);
752 constantHandler.registerCompileTimeConstant(keysList);
753 ClassElement classElement =
754 compiler.jsHelperLibrary.find(MapConstant.DART_CLASS);
755 classElement.ensureResolved(compiler);
756 // TODO(floitsch): copy over the generic type.
757 Type type = new SimpleType(classElement.name, classElement);
758 compiler.registerInstantiatedClass(classElement);
759 Constant constant = new MapConstant(type, keysList, values);
760 constantHandler.registerCompileTimeConstant(constant);
761 return constant;
602 } 762 }
603 763
604 Constant visitLiteralNull(LiteralNull node) { 764 Constant visitLiteralNull(LiteralNull node) {
605 return new NullConstant(); 765 return new NullConstant();
606 } 766 }
607 767
608 Constant visitLiteralString(LiteralString node) { 768 Constant visitLiteralString(LiteralString node) {
609 return new StringConstant(node.dartString); 769 return new StringConstant(node.dartString);
610 } 770 }
611 771
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
756 arguments); 916 arguments);
757 } 917 }
758 918
759 error(Node node) { 919 error(Node node) {
760 // TODO(floitsch): get the list of constants that are currently compiled 920 // TODO(floitsch): get the list of constants that are currently compiled
761 // and present some kind of stack-trace. 921 // and present some kind of stack-trace.
762 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; 922 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT;
763 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); 923 compiler.reportError(node, new CompileTimeConstantError(kind, const []));
764 } 924 }
765 } 925 }
OLDNEW
« 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