OLD | NEW |
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 /** | 5 /** |
6 * The [CompileTimeConstantHandler] keeps track of compile-time constants, and | 6 * The [CompileTimeConstantHandler] keeps track of compile-time constants, |
7 * initializations of global and static fields. | 7 * initializations of global and static fields, and default values of |
| 8 * optional parameters. |
8 */ | 9 */ |
9 class CompileTimeConstantHandler extends CompilerTask { | 10 class CompileTimeConstantHandler extends CompilerTask { |
10 // Contains the initial value of fields. Must contain all static and global | 11 // Contains the initial value of fields. Must contain all static and global |
11 // initializations of used fields. May contain caches for instance fields. | 12 // initializations of used fields. May contain caches for instance fields. |
12 final Map<VariableElement, Dynamic> initialFieldValues; | 13 final Map<VariableElement, Dynamic> initialVariableValues; |
13 | 14 |
14 CompileTimeConstantHandler(Compiler compiler) | 15 CompileTimeConstantHandler(Compiler compiler) |
15 : initialFieldValues = new Map<VariableElement, Dynamic>(), | 16 : initialVariableValues = new Map<VariableElement, Dynamic>(), |
16 super(compiler); | 17 super(compiler); |
17 String get name() => 'CompileTimeConstantHandler'; | 18 String get name() => 'CompileTimeConstantHandler'; |
18 | 19 |
19 /** | 20 /** |
20 * Compiles the initial value of the given field and stores it in an internal | 21 * Compiles the initial value of the given field and stores it in an internal |
21 * map. | 22 * map. |
22 * | 23 * |
23 * [WorkItem] must contain a [VariableElement] refering to a global or | 24 * [WorkItem] must contain a [VariableElement] refering to a global or |
24 * static field. | 25 * static field. |
25 */ | 26 */ |
26 void compileWorkItem(WorkItem work) { | 27 void compileWorkItem(WorkItem work) { |
27 assert(work.element.kind == ElementKind.FIELD); | 28 assert(work.element.kind == ElementKind.FIELD |
| 29 || work.element.kind == ElementKind.PARAMETER); |
28 VariableElement element = work.element; | 30 VariableElement element = work.element; |
29 // Shortcut if it has already been compiled. | 31 // Shortcut if it has already been compiled. |
30 if (initialFieldValues.containsKey(element)) return; | 32 if (initialVariableValues.containsKey(element)) return; |
31 compileFieldWithDefinitions(element, work.resolutionTree); | 33 compileVariableWithDefinitions(element, work.resolutionTree); |
32 } | 34 } |
33 | 35 |
34 compileField(VariableElement element) { | 36 compileVariable(VariableElement element) { |
35 if (initialFieldValues.containsKey(element)) { | 37 if (initialVariableValues.containsKey(element)) { |
36 return initialFieldValues[element]; | 38 return initialVariableValues[element]; |
37 } | 39 } |
38 // TODO(floitsch): keep track of currently compiling elements so that we | 40 // TODO(floitsch): keep track of currently compiling elements so that we |
39 // don't end up in an infinite loop: final x = y; final y = x; | 41 // don't end up in an infinite loop: final x = y; final y = x; |
40 TreeElements definitions = compiler.analyzeElement(element); | 42 TreeElements definitions = compiler.analyzeElement(element); |
41 return compileFieldWithDefinitions(element, definitions); | 43 return compileVariableWithDefinitions(element, definitions); |
42 } | 44 } |
43 | 45 |
44 compileFieldWithDefinitions(VariableElement element, | 46 compileVariableWithDefinitions(VariableElement element, |
45 TreeElements definitions) { | 47 TreeElements definitions) { |
46 return measure(() { | 48 return measure(() { |
47 Node node = element.parseNode(compiler); | 49 Node node = element.parseNode(compiler); |
48 assert(node !== null); | 50 assert(node !== null); |
49 SendSet assignment = node.asSendSet(); | 51 SendSet assignment = node.asSendSet(); |
50 var value; | 52 var value; |
51 if (assignment === null) { | 53 if (assignment === null) { |
52 // No initial value. | 54 // No initial value. |
53 value = null; | 55 value = null; |
54 } else { | 56 } else { |
55 Node right = assignment.arguments.head; | 57 Node right = assignment.arguments.head; |
56 CompileTimeConstantEvaluator evaluator = | 58 CompileTimeConstantEvaluator evaluator = |
57 new CompileTimeConstantEvaluator(this, definitions, compiler); | 59 new CompileTimeConstantEvaluator(this, definitions, compiler); |
58 value = evaluator.evaluate(right); | 60 value = evaluator.evaluate(right); |
59 } | 61 } |
60 initialFieldValues[element] = value; | 62 initialVariableValues[element] = value; |
61 return value; | 63 return value; |
62 }); | 64 }); |
63 } | 65 } |
64 | 66 |
65 /** | 67 /** |
66 * Returns a [List] of static non final fields that need to be initialized. | 68 * Returns a [List] of static non final fields that need to be initialized. |
67 * The list must be evaluated in order since the fields might depend on each | 69 * The list must be evaluated in order since the fields might depend on each |
68 * other. | 70 * other. |
69 */ | 71 */ |
70 List<VariableElement> getStaticNonFinalFieldsForEmission() { | 72 List<VariableElement> getStaticNonFinalFieldsForEmission() { |
71 return initialFieldValues.getKeys().filter((element) { | 73 return initialVariableValues.getKeys().filter((element) { |
72 return !element.isInstanceMember() && !element.modifiers.isFinal(); | 74 return element.kind == ElementKind.FIELD |
| 75 && !element.isInstanceMember() |
| 76 && !element.modifiers.isFinal(); |
73 }); | 77 }); |
74 } | 78 } |
75 | 79 |
76 /** | 80 /** |
77 * Returns a [List] of static final fields that need to be initialized. The | 81 * Returns a [List] of static final fields that need to be initialized. The |
78 * list must be evaluated in order since the fields might depend on each | 82 * list must be evaluated in order since the fields might depend on each |
79 * other. | 83 * other. |
80 */ | 84 */ |
81 List<VariableElement> getStaticFinalFieldsForEmission() { | 85 List<VariableElement> getStaticFinalFieldsForEmission() { |
82 return initialFieldValues.getKeys().filter((element) { | 86 return initialVariableValues.getKeys().filter((element) { |
83 return !element.isInstanceMember() && element.modifiers.isFinal(); | 87 return element.kind == ElementKind.FIELD |
| 88 && !element.isInstanceMember() |
| 89 && element.modifiers.isFinal(); |
84 }); | 90 }); |
85 } | 91 } |
86 | 92 |
87 void emitJsCodeForField(VariableElement element, StringBuffer buffer) { | 93 String getJsCodeForVariable(VariableElement element) { |
88 var value = initialFieldValues[element]; | 94 var value = initialVariableValues[element]; |
89 if (value === null) { | 95 if (value === null) return "(void 0)"; |
90 buffer.add("(void 0)"); | 96 if (value is num) return "$value"; |
91 } else if (value is num) { | 97 if (value === true) return "true"; |
92 buffer.add("$value"); | 98 if (value === false) return "false"; |
93 } else if (value === true) { | 99 |
94 buffer.add("true"); | 100 // TODO(floitsch): support more values. |
95 } else if (value === false) { | 101 compiler.unimplemented("CompileTimeConstantHandler.getJsCodeForVariable", |
96 buffer.add("false"); | 102 node: element.parseNode(compiler)); |
97 } else { | |
98 // TODO(floitsch): support more values. | |
99 compiler.unimplemented("CompileTimeConstantHandler.emitJsCodeForField", | |
100 node: element.parseNode(compiler)); | |
101 } | |
102 } | 103 } |
103 } | 104 } |
104 | 105 |
105 class CompileTimeConstantEvaluator extends AbstractVisitor { | 106 class CompileTimeConstantEvaluator extends AbstractVisitor { |
106 final CompileTimeConstantHandler constantHandler; | 107 final CompileTimeConstantHandler constantHandler; |
107 final TreeElements definitions; | 108 final TreeElements definitions; |
108 final Compiler compiler; | 109 final Compiler compiler; |
109 | 110 |
110 CompileTimeConstantEvaluator(this.constantHandler, | 111 CompileTimeConstantEvaluator(this.constantHandler, |
111 this.definitions, | 112 this.definitions, |
(...skipping 12 matching lines...) Expand all Loading... |
124 } | 125 } |
125 | 126 |
126 visitSend(Send send) { | 127 visitSend(Send send) { |
127 Element element = definitions[send]; | 128 Element element = definitions[send]; |
128 if (element !== null && element.kind == ElementKind.FIELD) { | 129 if (element !== null && element.kind == ElementKind.FIELD) { |
129 if (element.isInstanceMember() || | 130 if (element.isInstanceMember() || |
130 element.modifiers === null || | 131 element.modifiers === null || |
131 !element.modifiers.isFinal()) { | 132 !element.modifiers.isFinal()) { |
132 error(element); | 133 error(element); |
133 } | 134 } |
134 return constantHandler.compileField(element); | 135 return constantHandler.compileVariable(element); |
135 } | 136 } |
136 return super.visitSend(send); | 137 return super.visitSend(send); |
137 } | 138 } |
138 | 139 |
139 error(Element element) { | 140 error(Element element) { |
140 // TODO(floitsch): get the list of constants that are currently compiled | 141 // TODO(floitsch): get the list of constants that are currently compiled |
141 // and present some kind of stack-trace. | 142 // and present some kind of stack-trace. |
142 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; | 143 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; |
143 List arguments = [element.name]; | 144 List arguments = [element.name]; |
144 Node node = element.parseNode(compiler); | 145 Node node = element.parseNode(compiler); |
145 compiler.reportError(node, new CompileTimeConstantError(kind, arguments)); | 146 compiler.reportError(node, new CompileTimeConstantError(kind, arguments)); |
146 } | 147 } |
147 } | 148 } |
OLD | NEW |