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

Side by Side Diff: frog/leg/compile_time_constants.dart

Issue 9475021: Refactor Constants. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: cosmetic changes. 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/ssa/builder.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 // TODO(floitsch): finish implementation.
6 class Constant implements Hashable { 5 class Constant implements Hashable {
7 // TODO(floitsch): remove the direct access to the string. 6 const Constant();
8 final String jsCode; 7
ngeoffray 2012/02/28 09:46:12 I would put extra spaces between things that shoul
floitsch 2012/02/28 13:13:01 done.
9 Constant(this.jsCode); 8 bool isNull() => false;
10 9 /** [isInt] implies [isNum]. */
11 int hashCode() => jsCode.hashCode(); 10 bool isInt() => false;
12 bool operator ==(var other) { 11 /** [isDouble] implies [isNum]. */
13 if (other is !Constant) return false; 12 bool isDouble() => false;
14 Constant otherConstant = other; 13 bool isNum() => isInt() || isDouble();
15 return jsCode == otherConstant.jsCode; 14 bool isBool() => false;
16 } 15 bool isString() => false;
17 } 16 /** [isList] implies [isObject]. */
18 17 bool isList() => false;
18 /** [isMap] implies [isObject]. */
19 bool isMap() => false;
20 bool isUser() => false;
karlklose 2012/02/28 12:46:25 Can you find a better name? Perhaps isNonLiteral o
floitsch 2012/02/28 13:13:01 Done.
21 bool isObject() => isList() || isMap();
ngeoffray 2012/02/28 09:46:12 || isUser()?
floitsch 2012/02/28 13:13:01 Done.
22
23 /**
24 * Returns [:null:] if the operation is not supported on this constant.
25 * The [op] operator is assumed to be a prefix operator.
26 */
27 Constant unaryFold(String op) => null;
28
29 /**
30 * Returns [:null:] if the operation is not supported on this constant, or
31 * if the operation would have thrown an exception.
32 */
33 Constant binaryFold(String op, Constant other) {
34 if (op == "==" || op == "===") {
35 return new BoolConstant(this == other);
ngeoffray 2012/02/28 09:46:12 Shouldn't those be canonicalized?
floitsch 2012/02/28 13:13:01 The BoolConstant constructor will be a factory tha
36 } else if (op == "!=" || op == "!==") {
37 return new BoolConstant(this != other);
38 }
39 }
40
41 abstract void writeJsCode(StringBuffer buffer,
42 CompileTimeConstantHandler handler);
43 }
44
45 class PrimitiveConstant extends Constant {
46 // TODO(floitsch): this should be an abstract getter, but there is a bug in
47 // the VM.
48 get value() => null;
49 const PrimitiveConstant();
50 int hashCode() => value.hashCode();
51
52 bool operator ==(var other) {
53 if (other is !PrimitiveConstant) return false;
54 PrimitiveConstant otherPrimitive = other;
55 // We use == instead of === so that DartStrings compare correctly.
56 return value == otherPrimitive.value;
57 }
58 }
59
60 class NullConstant extends PrimitiveConstant {
61 const NullConstant();
62 bool isNull() => true;
63 get value() => null;
64
65 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
66 buffer.add("(void 0)");
67 }
68
69 int hashCode() => 142341;
ngeoffray 2012/02/28 09:46:12 Please comment on that magic value.
floitsch 2012/02/28 13:13:01 Done.
70 }
71
72 class IntConstant extends PrimitiveConstant {
73 final int value;
74 // TODO(floitsch): cache the most common integer values.
75 const IntConstant(this.value);
76 bool isInt() => true;
77
78 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
79 buffer.add("($value)");
80 }
81
82 IntConstant unaryFold(String op) {
83 if (op == "-") return new IntConstant(-value);
84 if (op == "~") return new IntConstant(~value);
85 return null;
86 }
87
88 Constant binaryFold(String op, Constant other) {
89 if (other.isNum()) {
90 PrimitiveConstant otherPrimitive = other;
91 num rightNum = otherPrimitive.value;
92 switch (op) {
93 case "<": return new BoolConstant(value < rightNum);
94 case "<=": return new BoolConstant(value <= rightNum);
95 case ">": return new BoolConstant(value > rightNum);
96 case ">=": return new BoolConstant(value >= rightNum);
97 case "/": return new DoubleConstant(value / rightNum);
98 // We have to treat '==' and '!=' here in case rightNum is a double.
99 case "==": return new BoolConstant(value == rightNum);
100 case "!=": return new BoolConstant(value != rightNum);
101 }
102 if (other.isInt()) {
103 int right = rightNum;
104 switch (op) {
105 case "+": return new IntConstant(value + right);
106 case "-": return new IntConstant(value - right);
107 case "*": return new IntConstant(value * right);
108 case "%": return new IntConstant(value % right);
109 case "~/": return new IntConstant(value ~/ right);
110 case "|": return new IntConstant(value | right);
111 case "&": return new IntConstant(value & right);
112 case "^": return new IntConstant(value ^ right);
113 case "<<":
114 // TODO(floitsch): find a better way to guard against shifts to the
115 // left.
116 if (right > 100) null;
117 if (right < 0) null;
118 return new IntConstant(value << right);
119 case ">>":
120 if (right < 0) return null;
121 return new IntConstant(value >> right);
122 }
123 } else if (other.isDouble()) {
124 double right = rightNum;
125 switch (op) {
126 case "+": return new DoubleConstant(value + right);
127 case "-": return new DoubleConstant(value - right);
128 case "*": return new DoubleConstant(value * right);
129 case "~/": return new DoubleConstant(value ~/ right);
130 case "%": return new DoubleConstant(value % right);
131 }
132 }
133 }
134 // Visit super in case the [op] was "==", "===", "!=" or "!===".
ngeoffray 2012/02/28 09:46:12 -> !==
floitsch 2012/02/28 13:13:01 Done.
135 return super.binaryFold(op, other);
136 }
137
138 // We have to override the equality operator so that ints and doubles are
139 // treated as separate constants.
ngeoffray 2012/02/28 09:46:12 Please add: 'The is !IntConstant check at the begi
floitsch 2012/02/28 13:13:01 Done.
140 bool operator ==(var other) {
141 if (other is !IntConstant) return false;
142 IntConstant otherInt = other;
143 return value == otherInt.value;
144 }
145 }
146
147 class DoubleConstant extends PrimitiveConstant {
148 final double value;
149 const DoubleConstant(this.value);
150 bool isDouble() => true;
151
152 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
153 if (value.isNaN()) {
154 buffer.add("(0/0)");
155 } else if (value == double.INFINITY) {
156 buffer.add("(1/0)");
157 } else if (value == -double.INFINITY) {
158 buffer.add("(-1/0)");
159 } else {
160 buffer.add("($value)");
161 }
162 }
163
164 DoubleConstant unaryFold(String op) {
165 if (op == "-") return new DoubleConstant(-value);
166 return null;
167 }
168
169 Constant binaryFold(String op, Constant other) {
170 if (other.isNum()) {
171 PrimitiveConstant otherPrimitive = other;
172 num right = otherPrimitive.value;
173 switch (op) {
174 case "<": return new BoolConstant(value < right);
175 case "<=": return new BoolConstant(value <= right);
176 case ">": return new BoolConstant(value > right);
177 case ">=": return new BoolConstant(value >= right);
178 case "+": return new DoubleConstant(value + right);
179 case "-": return new DoubleConstant(value - right);
180 case "*": return new DoubleConstant(value * right);
181 case "~/": return new DoubleConstant(value ~/ right);
182 case "/": return new DoubleConstant(value / right);
183 case "%": return new DoubleConstant(value % right);
184 // We have to handle '==' and '!=' here in case right is an integer,
185 // or one of the operands is NaN, -0.0 or 0.0.
186 case "==": return new BoolConstant(value == right);
187 case "!=": return new BoolConstant(value != right);
188 }
189 }
190 // Visit super in case the [op] was "==", "===", "!=" or "!===".
191 return super.binaryFold(op, other);
192 }
193
194 bool operator ==(var other) {
195 if (other is !DoubleConstant) return false;
196 DoubleConstant otherDouble = other;
197 double otherValue = otherDouble.value;
198 if (value == 0.0 && otherValue == 0.0) {
199 return value.isNegative() == otherValue.isNegative();
200 } else if (value.isNaN()) {
201 return otherValue.isNaN();
202 } else {
203 return value == otherValue;
204 }
205 }
206 }
207
208 class BoolConstant extends PrimitiveConstant {
209 final bool value;
210 const BoolConstant(this.value);
211 bool isBool() => true;
212
213 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
214 buffer.add(value ? "true" : "false");
215 }
216
217 BoolConstant unaryFold(String op) {
218 if (op == "!") return new BoolConstant(!value);
219 return null;
220 }
221
222 bool operator ==(var other) {
223 if (other is !BoolConstant) return false;
224 BoolConstant otherBool = other;
225 return value == otherBool.value;
226 }
227
228 int hashCode() => value ? 499 : 42;
ngeoffray 2012/02/28 09:46:12 comments please
floitsch 2012/02/28 13:13:01 Done.
229 }
230
231 class StringConstant extends PrimitiveConstant {
232 final DartString value;
233 int _hashCode;
234
235 StringConstant(this.value) {
236 int hash = 0;
237 // TODO(floitsch): implement real hash, or delegate to DartString.
238 for (int charCode in value) {
239 hash ^= charCode;
240 }
241 _hashCode = hash;
242 }
243 bool isString() => true;
244
245 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
246 buffer.add("'");
247 CompileTimeConstantHandler.writeEscapedString(value, buffer, (reason) {
248 throw new CompilerCancelledException(reason);
249 });
250 buffer.add("'");
251 }
252
253 StringConstant binaryFold(String op, Constant other) {
254 if (other.isString() && op == "+") {
255 StringConstant otherString = other;
256 DartString right = otherString.value;
257 return new StringConstant(new ConsDartString(value, right));
258 }
259 // Visit super in case the [op] was "==", "===", "!=" or "!===".
260 return super.binaryFold(op, other);
261 }
262
263 bool operator ==(var other) {
264 if (other is !StringConstant) return false;
265 StringConstant otherString = other;
266 return value == otherString.value;
ngeoffray 2012/02/28 09:46:12 Check hashCode first?
floitsch 2012/02/28 13:13:01 Done.
267 }
268
269 int hashCode() => _hashCode;
270 }
271
272 class ObjectConstant extends Constant {
273 final Type type;
274
275 ObjectConstant(this.type);
276 bool isObject() => true;
ngeoffray 2012/02/28 09:46:12 I think you should remove that one.
floitsch 2012/02/28 13:13:01 Done.
277 }
278
279 class ListConstant extends ObjectConstant {
ngeoffray 2012/02/28 09:46:12 Missing isList in this class.
floitsch 2012/02/28 13:13:01 Done.
280 final List<Constant> entries;
281 int _hashCode;
282
283 ListConstant(Type type, this.entries) : super(type) {
284 // TODO(floitsch): create a better hash.
285 int hash = 0;
286 for (Constant input in entries) hash ^= input.hashCode();
287 _hashCode = hash;
288 }
289 int hashCode() => _hashCode;
ngeoffray 2012/02/28 09:46:12 Consistency: I would put this method at the end of
floitsch 2012/02/28 13:13:01 Done.
290
291 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
292 // TODO(floitsch): we should not need to go through the compiler to make
293 // the list constant.
294 buffer.add(handler.compiler.namer.ISOLATE);
295 buffer.add(".prototype.makeConstantList");
296 buffer.add("([");
297 for (int i = 0; i < entries.length; i++) {
298 if (i != 0) buffer.add(", ");
299 Constant entry = entries[i];
300 if (entry.isObject()) {
301 handler.getNameForConstant(entry);
302 } else {
303 entry.writeJsCode(buffer, handler);
304 }
305 }
306 buffer.add("])");
307 }
308
309 bool operator ==(var other) {
310 if (other is !ListConstant) return false;
311 ListConstant otherList = other;
312 if (hashCode() != otherList.hashCode()) return false;
313 // TODO(floitsch): verify that the types are the same.
314 if (entries.length != otherList.entries.length) return false;
315 for (int i = 0; i < entries.length; i++) {
316 if (entries[i] != otherList.entries[i]) return false;
317 }
318 return true;
319 }
320 }
321
322 class ConstructedConstant extends ObjectConstant {
ngeoffray 2012/02/28 09:46:12 Missing isUser in this class.
floitsch 2012/02/28 13:13:01 Done.
323 final List<Constant> fields;
324 int _hashCode;
325
326 ConstructedConstant(Type type, this.fields) : super(type) {
327 assert(type !== null);
328 // TODO(floitsch): create a better hash.
329 int hash = 0;
330 for (Constant field in fields) {
331 hash ^= field.hashCode();
332 }
333 hash ^= type.element.hashCode();
334 _hashCode = hash;
335 }
336 int hashCode() => _hashCode;
ngeoffray 2012/02/28 09:46:12 ditto.
floitsch 2012/02/28 13:13:01 Done.
337
338 void writeJsCode(StringBuffer buffer, CompileTimeConstantHandler handler) {
339 buffer.add("new ");
340 buffer.add(handler.getJsConstructor(type.element));
341 buffer.add("(");
342 for (int i = 0; i < fields.length; i++) {
343 if (i != 0) buffer.add(", ");
344 Constant field = fields[i];
345 // TODO(floitsch): share this code with the ListConstant.
346 if (field.isObject()) {
347 handler.getNameForConstant(field);
348 } else {
349 field.writeJsCode(buffer, handler);
350 }
351 }
352 buffer.add(")");
353 }
354
355 bool operator ==(var otherVar) {
356 if (otherVar is !ConstructedConstant) return false;
357 ConstructedConstant other = otherVar;
358 if (hashCode() != other.hashCode()) return false;
359 // TODO(floitsch): verify that the (generic) types are the same.
360 if (type.element != other.type.element) return false;
361 if (fields.length != other.fields.length) return false;
362 for (int i = 0; i < fields.length; i++) {
363 if (fields[i] != other.fields[i]) return false;
364 }
365 return true;
366 }
367 }
368
19 /** 369 /**
20 * The [CompileTimeConstantHandler] keeps track of compile-time constants, 370 * The [CompileTimeConstantHandler] keeps track of compile-time constants,
21 * initializations of global and static fields, and default values of 371 * initializations of global and static fields, and default values of
22 * optional parameters. 372 * optional parameters.
23 */ 373 */
24 class CompileTimeConstantHandler extends CompilerTask { 374 class CompileTimeConstantHandler extends CompilerTask {
25 // Contains the initial value of fields. Must contain all static and global 375 // Contains the initial value of fields. Must contain all static and global
26 // initializations of used fields. May contain caches for instance fields. 376 // initializations of used fields. May contain caches for instance fields.
27 final Map<VariableElement, Dynamic> initialVariableValues; 377 final Map<VariableElement, Dynamic> initialVariableValues;
28 378
(...skipping 22 matching lines...) Expand all
51 assert(work.element.kind == ElementKind.FIELD 401 assert(work.element.kind == ElementKind.FIELD
52 || work.element.kind == ElementKind.PARAMETER); 402 || work.element.kind == ElementKind.PARAMETER);
53 VariableElement element = work.element; 403 VariableElement element = work.element;
54 // Shortcut if it has already been compiled. 404 // Shortcut if it has already been compiled.
55 if (initialVariableValues.containsKey(element)) return; 405 if (initialVariableValues.containsKey(element)) return;
56 compileVariableWithDefinitions(element, work.resolutionTree); 406 compileVariableWithDefinitions(element, work.resolutionTree);
57 } 407 }
58 408
59 compileVariable(VariableElement element) { 409 compileVariable(VariableElement element) {
60 if (initialVariableValues.containsKey(element)) { 410 if (initialVariableValues.containsKey(element)) {
61 return initialVariableValues[element]; 411 Constant result = initialVariableValues[element];
412 // TODO(floitsch): remove the following line once the rest of the
413 // compiler has been adapted.
414 if (!result.isObject()) return result.dynamic.value;
415 return result;
62 } 416 }
63 // TODO(floitsch): keep track of currently compiling elements so that we 417 // TODO(floitsch): keep track of currently compiling elements so that we
64 // don't end up in an infinite loop: final x = y; final y = x; 418 // don't end up in an infinite loop: final x = y; final y = x;
65 TreeElements definitions = compiler.analyzeElement(element); 419 TreeElements definitions = compiler.analyzeElement(element);
66 return compileVariableWithDefinitions(element, definitions); 420 Constant constant = compileVariableWithDefinitions(element, definitions);
421 // TODO(floitsch): remove the following line once the rest of the
422 // compiler has been adapted.
423 if (!constant.isObject()) return constant.dynamic.value;
424 return constant;
67 } 425 }
68 426
69 compileVariableWithDefinitions(VariableElement element, 427 compileVariableWithDefinitions(VariableElement element,
70 TreeElements definitions) { 428 TreeElements definitions) {
71 return measure(() { 429 return measure(() {
72 Node node = element.parseNode(compiler); 430 Node node = element.parseNode(compiler);
73 assert(node !== null); 431 assert(node !== null);
74 SendSet assignment = node.asSendSet(); 432 SendSet assignment = node.asSendSet();
75 var value; 433 var value;
76 if (assignment === null) { 434 if (assignment === null) {
77 // No initial value. 435 // No initial value.
78 value = null; 436 value = const NullConstant();
79 } else { 437 } else {
80 Node right = assignment.arguments.head; 438 Node right = assignment.arguments.head;
81 CompileTimeConstantEvaluator evaluator = 439 CompileTimeConstantEvaluator evaluator =
82 new CompileTimeConstantEvaluator(this, definitions, compiler); 440 new CompileTimeConstantEvaluator(this, definitions, compiler);
83 value = evaluator.evaluate(right); 441 value = evaluator.evaluate(right);
84 } 442 }
85 initialVariableValues[element] = value; 443 initialVariableValues[element] = value;
86 return value; 444 return value;
87 }); 445 });
88 } 446 }
89 447
90 compileObjectCreation(Node node, Element constructor, List arguments) { 448 ConstructedConstant compileObjectConstruction(Node node,
449 Type type,
450 List arguments) {
91 if (!arguments.isEmpty()) { 451 if (!arguments.isEmpty()) {
92 compiler.unimplemented("CompileTimeConstantHandler with arguments", 452 compiler.unimplemented("CompileTimeConstantHandler with arguments",
93 node: node); 453 node: node);
94 } 454 }
95 ClassElement classElement = constructor.enclosingElement; 455 ClassElement classElement = type.element;
96 for (Element member in classElement.members) { 456 for (Element member in classElement.members) {
97 if (Elements.isInstanceField(member)) { 457 if (Elements.isInstanceField(member)) {
98 compiler.unimplemented("CompileTimeConstantHandler with fields", 458 compiler.unimplemented("CompileTimeConstantHandler with fields",
99 node: node); 459 node: node);
100 } 460 }
101 } 461 }
102 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) { 462 if (classElement.superclass != compiler.coreLibrary.find(Types.OBJECT)) {
103 compiler.unimplemented("CompileTimeConstantHandler with super", 463 compiler.unimplemented("CompileTimeConstantHandler with super",
104 node: node); 464 node: node);
105 } 465 }
106 compiler.registerInstantiatedClass(classElement); 466 compiler.registerInstantiatedClass(classElement);
107 Namer namer = compiler.namer; 467 Constant constant = new ConstructedConstant(type, arguments);
108 String instantiation = "new ${namer.isolatePropertyAccess(classElement)}()";
109 Constant constant = new Constant(instantiation);
110 registerCompileTimeConstant(constant); 468 registerCompileTimeConstant(constant);
111 return constant; 469 return constant;
112 } 470 }
113 471
114 compileListLiteral(Node node, List arguments) { 472 ListConstant compileListLiteral(Node node,
115 StringBuffer buffer = new StringBuffer(); 473 Type type,
116 buffer.add(compiler.namer.ISOLATE); 474 List<Constant> arguments) {
117 buffer.add(".prototype.makeConstantList"); 475 Constant constant = new ListConstant(type, arguments);
118 buffer.add("([");
119 for (int i = 0; i < arguments.length; i++) {
120 if (i != 0) buffer.add(", ");
121 // TODO(floitsch): canonicalize if the constant is in the
122 // [compiledConstant] set.
123 writeJsCode(buffer, arguments[i]);
124 }
125 buffer.add("])");
126 // TODO(floitsch): do we have to register 'List' as instantiated class?
127 String array = buffer.toString();
128 Constant constant = new Constant(array);
129 registerCompileTimeConstant(constant); 476 registerCompileTimeConstant(constant);
130 return constant; 477 return constant;
131 } 478 }
132 479
133 /** 480 /**
134 * Returns a [List] of static non final fields that need to be initialized. 481 * Returns a [List] of static non final fields that need to be initialized.
135 * The list must be evaluated in order since the fields might depend on each 482 * The list must be evaluated in order since the fields might depend on each
136 * other. 483 * other.
137 */ 484 */
138 List<VariableElement> getStaticNonFinalFieldsForEmission() { 485 List<VariableElement> getStaticNonFinalFieldsForEmission() {
(...skipping 18 matching lines...) Expand all
157 } 504 }
158 505
159 List<Constant> getConstantsForEmission() { 506 List<Constant> getConstantsForEmission() {
160 return compiledConstants.getKeys(); 507 return compiledConstants.getKeys();
161 } 508 }
162 509
163 String getNameForConstant(Constant constant) { 510 String getNameForConstant(Constant constant) {
164 return compiledConstants[constant]; 511 return compiledConstants[constant];
165 } 512 }
166 513
167 StringBuffer writeJsCode(StringBuffer buffer, var value) { 514 StringBuffer writeJsCode(StringBuffer buffer, Constant value) {
168 if (value === null) { 515 value.writeJsCode(buffer, this);
169 buffer.add("(void 0)");
170 } else if (value is num) {
171 if (value.isNaN()) {
172 buffer.add("(0/0)");
173 } else if (value == double.INFINITY) {
174 buffer.add("(1/0)");
175 } else if (value == -double.INFINITY) {
176 buffer.add("(-1/0)");
177 } else {
178 buffer.add("($value)");
179 }
180 } else if (value === true) {
181 buffer.add("true");
182 } else if (value === false) {
183 buffer.add("false");
184 } else if (value is DartString) {
185 buffer.add("'");
186 writeEscapedString(value, buffer, (reason) {
187 compiler.cancel("failed to write escaped string: $value");
188 });
189 buffer.add("'");
190 } else if (value is Constant) {
191 Constant constant = value;
192 buffer.add(constant.jsCode);
193 } else {
194 // TODO(floitsch): support more values.
195 compiler.unimplemented("CompileTimeConstantHandler writeJsCode",
196 element: element);
197 }
198 return buffer; 516 return buffer;
199 } 517 }
200 518
201 StringBuffer writeJsCodeForVariable(StringBuffer buffer, 519 StringBuffer writeJsCodeForVariable(StringBuffer buffer,
202 VariableElement element) { 520 VariableElement element) {
203 var value = initialVariableValues[element]; 521 if (!initialVariableValues.containsKey(element)) {
204 if (value is Constant) { 522 buffer.add("(void 0)");
205 String name = compiledConstants[value]; 523 return buffer;
524 // TODO(floitsch): reenable the following lines, once we fixed the rest
525 // of the compiler.
526 /*
527 compiler.internalError("No initial value for given element",
528 element: element);
529 */
530 }
531 Constant constant = initialVariableValues[element];
532 if (constant.isObject()) {
533 String name = compiledConstants[constant];
206 buffer.add("${compiler.namer.ISOLATE}.prototype.$name"); 534 buffer.add("${compiler.namer.ISOLATE}.prototype.$name");
207 } else { 535 } else {
208 return writeJsCode(buffer, initialVariableValues[element]); 536 writeJsCode(buffer, constant);
209 } 537 }
538 return buffer;
210 } 539 }
211 540
212 /** 541 /**
213 * Write the contents of the quoted string to a [StringBuffer] in 542 * Write the contents of the quoted string to a [StringBuffer] in
214 * a form that is valid as JavaScript string literal content. 543 * a form that is valid as JavaScript string literal content.
215 * The string is assumed quoted by single quote characters. 544 * The string is assumed quoted by single quote characters.
216 */ 545 */
217 static void writeEscapedString(DartString string, 546 static void writeEscapedString(DartString string,
218 StringBuffer buffer, 547 StringBuffer buffer,
219 void cancel(String reason)) { 548 void cancel(String reason)) {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 buffer.add('0'); 584 buffer.add('0');
256 } 585 }
257 buffer.add(code.toRadixString(16)); 586 buffer.add(code.toRadixString(16));
258 } 587 }
259 } else { 588 } else {
260 buffer.add(new String.fromCharCodes(<int>[code])); 589 buffer.add(new String.fromCharCodes(<int>[code]));
261 } 590 }
262 } 591 }
263 } 592 }
264 } 593 }
594
595 String getJsConstructor(ClassElement element) {
596 return compiler.namer.isolatePropertyAccess(element);
597 }
265 } 598 }
266 599
267 class CompileTimeConstantEvaluator extends AbstractVisitor { 600 class CompileTimeConstantEvaluator extends AbstractVisitor {
268 final CompileTimeConstantHandler constantHandler; 601 final CompileTimeConstantHandler constantHandler;
269 final TreeElements definitions; 602 final TreeElements definitions;
270 final Compiler compiler; 603 final Compiler compiler;
271 604
272 CompileTimeConstantEvaluator(this.constantHandler, 605 CompileTimeConstantEvaluator(this.constantHandler,
273 this.definitions, 606 this.definitions,
274 this.compiler); 607 this.compiler);
275 608
276 evaluate(Node node) { 609 Constant evaluate(Node node) {
277 return node.accept(this); 610 return node.accept(this);
278 } 611 }
279 612
280 visitNode(Node node) { 613 visitNode(Node node) {
281 compiler.unimplemented("CompileTimeConstantEvaluator", node: node); 614 compiler.unimplemented("CompileTimeConstantEvaluator", node: node);
282 } 615 }
283 616
284 visitLiteral(Literal literal) { 617 Constant visitLiteralBool(LiteralBool node) {
285 if (literal is LiteralString) { 618 // TODO(floitsch): make BoolConstant a factory and cache the two values
286 assert(literal.asLiteralString().isValidated()); 619 // there.
287 return literal.asLiteralString().dartString; 620 return node.value ? const BoolConstant(true) : const BoolConstant(false);
621 }
622
623 Constant visitLiteralDouble(LiteralDouble node) {
624 return new DoubleConstant(node.value);
625 }
626
627 Constant visitLiteralInt(LiteralInt node) {
628 return new IntConstant(node.value);
629 }
630
631 Constant visitLiteralList(LiteralList node) {
632 if (!node.isConst()) error(node);
633 List arguments = [];
634 for (Link<Node> link = node.elements.nodes;
635 !link.isEmpty();
636 link = link.tail) {
637 arguments.add(evaluate(link.head));
288 } 638 }
289 return literal.value; 639 // TODO(floitsch): get type from somewhere.
640 Type type = null;
641 return constantHandler.compileListLiteral(node, type, arguments);
642 }
643
644 Constant visitLiteralMap(LiteralMap node) {
645 compiler.unimplemented("CompileTimeConstantEvaluator map", node: node);
646 }
647
648 Constant visitLiteralNull(LiteralNull node) {
649 return const NullConstant();
650 }
651
652 Constant visitLiteralString(LiteralString node) {
653 return new StringConstant(node.dartString);
290 } 654 }
291 655
292 // TODO(floitsch): provide better error-messages. 656 // TODO(floitsch): provide better error-messages.
293 visitSend(Send send) { 657 visitSend(Send send) {
294 Element element = definitions[send]; 658 Element element = definitions[send];
295 if (Elements.isStaticOrTopLevelField(element)) { 659 if (Elements.isStaticOrTopLevelField(element)) {
296 if (element.modifiers === null || 660 if (element.modifiers === null ||
297 !element.modifiers.isFinal()) { 661 !element.modifiers.isFinal()) {
298 error(send); 662 error(send);
299 } 663 }
300 return constantHandler.compileVariable(element); 664 // TODO(floitsch): compileVariable temporarily returns primitives, so
665 // that the rest of the compiler can be adapted incrementally. Therefore
666 // we have to get the constant from the hashtable instead of using the
667 // returned result directly.
668 constantHandler.compileVariable(element);
669 return constantHandler.initialVariableValues[element];
301 } else if (send.isPrefix) { 670 } else if (send.isPrefix) {
302 assert(send.isOperator); 671 assert(send.isOperator);
303 var receiverValue = evaluate(send.receiver); 672 Constant receiverConstant = evaluate(send.receiver);
304 Operator op = send.selector; 673 Operator op = send.selector;
305 switch (op.source.stringValue) { 674 Constant folded = receiverConstant.unaryFold(op.source.stringValue);
306 case "-": 675 if (folded === null) error(send);
307 if (receiverValue is !num) error(send); 676 return folded;
308 return -receiverValue;
309 case "~":
310 if (receiverValue is !int) error(send);
311 return ~receiverValue;
312 case "!":
313 if (receiverValue is !bool) error(send);
314 return !receiverValue;
315 default:
316 error(send);
317 }
318 } else if (send.isOperator && !send.isPostfix) { 677 } else if (send.isOperator && !send.isPostfix) {
319 assert(send.argumentCount() == 1); 678 assert(send.argumentCount() == 1);
320 var left = evaluate(send.receiver); 679 Constant left = evaluate(send.receiver);
321 var right = evaluate(send.argumentsNode.nodes.head); 680 Constant right = evaluate(send.argumentsNode.nodes.head);
322 String op = send.selector.asOperator().source.stringValue; 681 String op = send.selector.asOperator().source.stringValue;
323 682 Constant folded = left.binaryFold(op, right);
324 if (op == "==" || op == "===") { 683 if (folded === null) error(send);
325 // We use == instead of === so that non-canonicalized DartStrings can 684 return folded;
326 // use their equality operator.
327 return left == right;
328 } else if (op == "!=" || op == "!==") {
329 return left != right;
330 }
331 if (left is num && right is num) {
332 switch (op) {
333 case "+": return left + right;
334 case "-": return left - right;
335 case "*": return left * right;
336 case "/": return left / right;
337 case "~/":
338 case "%":
339 if (left is int && right is int && right == 0) {
340 error(send);
341 }
342 return op == "~/" ? left ~/ right : left % right;
343 case "<": return left < right;
344 case "<=": return left <= right;
345 case ">": return left > right;
346 case ">=": return left >= right;
347 }
348 }
349 if (left is int && right is int) {
350 switch (op) {
351 case "|": return left | right;
352 case "&": return left & right;
353 case "<<":
354 // TODO(floitsch): find a better way to guard against shifts to the
355 // left.
356 if (right > 100) error(send);
357 if (right < 0) error(send);
358 return left << right;
359 case ">>":
360 if (right < 0) error(send);
361 return left >> right;
362 case "^": return left ^ right;
363 }
364 }
365 if (left is DartString && right is DartString && op == "+") {
366 return new ConsDartString(left, right);
367 }
368 } 685 }
369 return super.visitSend(send); 686 return super.visitSend(send);
370 } 687 }
371 688
372 visitSendSet(SendSet node) { 689 visitSendSet(SendSet node) {
373 error(node); 690 error(node);
374 } 691 }
375 692
376 visitNewExpression(NewExpression node) { 693 visitNewExpression(NewExpression node) {
377 if (!node.isConst()) error(node); 694 if (!node.isConst()) error(node);
378 Send send = node.send; 695 Send send = node.send;
379 List arguments; 696 List arguments;
380 if (send.arguments.isEmpty()) { 697 if (send.arguments.isEmpty()) {
381 arguments = const []; 698 arguments = const [];
382 } else { 699 } else {
383 arguments = []; 700 arguments = [];
384 for (Link<Node> link = send.arguments; 701 for (Link<Node> link = send.arguments;
385 !link.isEmpty(); 702 !link.isEmpty();
386 link = link.tail) { 703 link = link.tail) {
387 arguments.add(evaluate(link.head)); 704 arguments.add(evaluate(link.head));
388 } 705 }
389 } 706 }
390 return constantHandler.compileObjectCreation(node, definitions[node.send], 707 // TODO(floitsch): get the type from somewhere.
391 arguments); 708 Element constructorElement = definitions[node.send];
392 } 709 ClassElement classElement = constructorElement.enclosingElement;
393 710 Type type = new SimpleType(classElement.name, classElement);
394 visitLiteralList(LiteralList node) { 711 return constantHandler.compileObjectConstruction(node,
395 if (!node.isConst()) error(node); 712 type,
396 List arguments = []; 713 arguments);
397 for (Link<Node> link = node.elements.nodes;
398 !link.isEmpty();
399 link = link.tail) {
400 arguments.add(evaluate(link.head));
401 }
402 return constantHandler.compileListLiteral(node, arguments);
403 } 714 }
404 715
405 error(Node node) { 716 error(Node node) {
406 // TODO(floitsch): get the list of constants that are currently compiled 717 // TODO(floitsch): get the list of constants that are currently compiled
407 // and present some kind of stack-trace. 718 // and present some kind of stack-trace.
408 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT; 719 MessageKind kind = MessageKind.NOT_A_COMPILE_TIME_CONSTANT;
409 compiler.reportError(node, new CompileTimeConstantError(kind, const [])); 720 compiler.reportError(node, new CompileTimeConstantError(kind, const []));
410 } 721 }
411 } 722 }
OLDNEW
« no previous file with comments | « no previous file | frog/leg/ssa/builder.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698