OLD | NEW |
| (Empty) |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 // SExpressionUnstringifier implements the inverse operation to | |
6 // [SExpressionStringifier]. | |
7 | |
8 library sexpr_unstringifier; | |
9 | |
10 import 'package:compiler/src/constants/expressions.dart'; | |
11 import 'package:compiler/src/constants/values.dart'; | |
12 import 'package:compiler/src/dart_types.dart' as dart_types | |
13 show DartType; | |
14 import 'package:compiler/src/diagnostics/messages.dart' | |
15 show MessageKind; | |
16 import 'package:compiler/src/elements/elements.dart'; | |
17 import 'package:compiler/src/elements/modelx.dart' | |
18 show ErroneousElementX, TypeVariableElementX; | |
19 import 'package:compiler/src/tree/tree.dart' show LiteralDartString; | |
20 import 'package:compiler/src/universe/call_structure.dart' | |
21 show CallStructure; | |
22 import 'package:compiler/src/universe/selector.dart' | |
23 show Selector, SelectorKind; | |
24 import 'package:compiler/src/cps_ir/cps_ir_nodes.dart'; | |
25 | |
26 /// Used whenever a node constructed by [SExpressionUnstringifier] needs a | |
27 /// named entity. | |
28 class DummyEntity extends Entity { | |
29 final String name; | |
30 DummyEntity(this.name); | |
31 } | |
32 | |
33 /// Used whenever a node constructed by [SExpressionUnstringifier] needs a | |
34 /// local. | |
35 class DummyLocal extends DummyEntity implements Local { | |
36 DummyLocal(String name) : super(name); | |
37 | |
38 ExecutableElement get executableContext => null; | |
39 } | |
40 | |
41 // TODO(karlklose): we should remove all references to [ErroneousElement] from | |
42 // the CPS IR. Instead, the builder must construct appropriate terms for ASTs | |
43 // that could not be resolved correctly. Perhaps the IR should not rely on | |
44 // elements at all for naming. | |
45 /// Used whenever a node constructed by [SExpressionUnstringifier] requires | |
46 /// an [Element] or [FunctionElement]. Extends [ErroneousElementX] since there | |
47 /// is currently a large amount of overhead when extending the base abstract | |
48 /// classes, and erroneous elements conveniently also skip several assertion | |
49 /// checks in CPS IR nodes that are irrelevant to us. | |
50 class DummyElement extends ErroneousElementX | |
51 implements TypeVariableElement, FieldElement { | |
52 DummyElement(String name) | |
53 : super(MessageKind.GENERIC, {}, name, null); | |
54 | |
55 final dart_types.DartType bound = null; | |
56 final TypeDeclarationElement typeDeclaration = null; | |
57 | |
58 noSuchMethod(inv) => super.noSuchMethod(inv); | |
59 } | |
60 | |
61 /// Used whenever a node constructed by [SExpressionUnstringifier] requires | |
62 /// a named type. | |
63 class DummyNamedType extends dart_types.DartType { | |
64 final String name; | |
65 | |
66 final kind = null; | |
67 final element = null; | |
68 | |
69 DummyNamedType(this.name); | |
70 | |
71 subst(arguments, parameters) => null; | |
72 unalias(compiler) => null; | |
73 accept(visitor, argument) => null; | |
74 | |
75 String toString() => name; | |
76 } | |
77 | |
78 /// Represents a list of tokens, but is basically a partial view into a list | |
79 /// with appropriate convenience methods. | |
80 class Tokens { | |
81 final List<String> _list; | |
82 int _index; // Current index into the list. | |
83 | |
84 Tokens(List<String> this._list) : _index = 0; | |
85 | |
86 String get current => _list[_index]; | |
87 String get next => _list[_index + 1]; | |
88 | |
89 String read([String expected]) { | |
90 if (expected != null) { | |
91 if (current != expected) { | |
92 print('expected "$expected", found "$current"'); | |
93 int start = _index - 15; | |
94 String dotdotdot = '... '; | |
95 if (start < 0) { | |
96 start = 0; | |
97 dotdotdot = ''; | |
98 } | |
99 print('${dotdotdot}${_list.sublist(start, _index + 1).join(' ')}'); | |
100 assert(current == expected); | |
101 } | |
102 } | |
103 return _list[_index++]; | |
104 } | |
105 | |
106 /// Consumes the preamble to a new node, consisting of an opening parenthesis | |
107 /// and a tag. | |
108 void consumeStart([String tag]) { | |
109 read("("); | |
110 if (tag != null) { | |
111 read(tag); | |
112 } | |
113 } | |
114 | |
115 void consumeEnd() { | |
116 read(")"); | |
117 } | |
118 | |
119 bool get hasNext => _index < _list.length; | |
120 String toString() => _list.sublist(_index).toString(); | |
121 } | |
122 | |
123 /// Constructs a minimal in-memory representation of the IR represented | |
124 /// by the given string. Many fields are currently simply set to null. | |
125 class SExpressionUnstringifier { | |
126 | |
127 // Expressions | |
128 static const String BRANCH = "Branch"; | |
129 static const String CONCATENATE_STRINGS = "ConcatenateStrings"; | |
130 static const String DECLARE_FUNCTION = "DeclareFunction"; | |
131 static const String INVOKE_CONSTRUCTOR = "InvokeConstructor"; | |
132 static const String INVOKE_CONTINUATION = "InvokeContinuation"; | |
133 static const String INVOKE_STATIC = "InvokeStatic"; | |
134 static const String INVOKE_METHOD_DIRECTLY = "InvokeMethodDirectly"; | |
135 static const String INVOKE_METHOD = "InvokeMethod"; | |
136 static const String LET_PRIM = "LetPrim"; | |
137 static const String LET_CONT = "LetCont"; | |
138 static const String LET_MUTABLE = "LetMutable"; | |
139 static const String TYPE_CAST = "TypeCast"; | |
140 static const String GET_LAZY_STATIC = "GetLazyStatic"; | |
141 static const String UNREACHABLE = "Unreachable"; | |
142 | |
143 // Primitives | |
144 static const String CONSTANT = "Constant"; | |
145 static const String CREATE_FUNCTION = "CreateFunction"; | |
146 static const String GET_MUTABLE = "GetMutable"; | |
147 static const String SET_MUTABLE = "SetMutable"; | |
148 static const String LITERAL_LIST = "LiteralList"; | |
149 static const String LITERAL_MAP = "LiteralMap"; | |
150 static const String REIFY_TYPE_VAR = "ReifyTypeVar"; | |
151 static const String GET_STATIC = "GetStatic"; | |
152 static const String SET_STATIC = "SetStatic"; | |
153 static const String TYPE_TEST = "TypeTest"; | |
154 static const String APPLY_BUILTIN_OPERATOR = "ApplyBuiltinOperator"; | |
155 static const String GET_LENGTH = "GetLength"; | |
156 static const String GET_INDEX = "GetIndex"; | |
157 static const String SET_INDEX = "SetIndex"; | |
158 static const String GET_FIELD = "GetField"; | |
159 static const String SET_FIELD = "SetField"; | |
160 | |
161 // Other | |
162 static const String FUNCTION_DEFINITION = "FunctionDefinition"; | |
163 static const String IS_TRUE = "IsTrue"; | |
164 | |
165 // Constants | |
166 static const String BOOL = "Bool"; | |
167 static const String DOUBLE = "Double"; | |
168 static const String INT = "Int"; | |
169 static const String NULL = "Null"; | |
170 static const String STRING = "String"; | |
171 | |
172 final Map<String, Definition> name2variable = | |
173 <String, Definition>{ "return": new Continuation.retrn() }; | |
174 | |
175 // Operator names used for canonicalization. In theory, we could simply use | |
176 // Elements.isOperatorName() on the parsed tokens; however, comparisons are | |
177 // done using identical() for performance reasons, which are reliable only for | |
178 // compile-time literal strings. | |
179 static Set<String> OPERATORS = new Set<String>.from( | |
180 [ '~', '==', '[]', '*', '/', '%', '~/', '+', '<<', 'unary-' | |
181 , '>>', '>=', '>', '<=', '<', '&', '^', '|', '[]=', '-' | |
182 ]); | |
183 | |
184 // The tokens currently being parsed. | |
185 Tokens tokens; | |
186 | |
187 FunctionDefinition unstringify(String s) { | |
188 tokens = tokenize(s); | |
189 FunctionDefinition def = parseFunctionDefinition(); | |
190 assert(!tokens.hasNext); | |
191 return def; | |
192 } | |
193 | |
194 /// Returns a new named dummy selector with a roughly appropriate kind. | |
195 Selector dummySelector(String name, int argumentCount) { | |
196 SelectorKind kind; | |
197 if (name == "[]") { | |
198 kind = SelectorKind.INDEX; | |
199 } else if (Elements.isOperatorName(name)) { | |
200 kind = SelectorKind.OPERATOR; | |
201 } else { | |
202 kind = SelectorKind.CALL; | |
203 } | |
204 return new Selector(kind, new PublicName(name), | |
205 new CallStructure.unnamed(argumentCount)); | |
206 } | |
207 | |
208 /// Returns the tokens in s. Note that string literals are not necessarily | |
209 /// preserved; for instance, "(literalString)" is transformed to | |
210 /// " ( literalString ) ". | |
211 Tokens tokenize(String s) => | |
212 new Tokens( | |
213 s.replaceAll("(", " ( ") | |
214 .replaceAll(")", " ) ") | |
215 .replaceAll("{", " { ") | |
216 .replaceAll("}", " } ") | |
217 .replaceAll(new RegExp(r"[ \t\n]+"), " ") | |
218 .trim() | |
219 .split(" ") | |
220 .map(canonicalizeOperators) | |
221 .toList()); | |
222 | |
223 /// Canonicalizes strings containing operator names. | |
224 String canonicalizeOperators(String token) { | |
225 String opname = OPERATORS.lookup(token); | |
226 if (opname != null) { | |
227 return opname; | |
228 } | |
229 return token; | |
230 } | |
231 | |
232 Expression parseExpression() { | |
233 assert(tokens.current == "("); | |
234 | |
235 switch (tokens.next) { | |
236 case BRANCH: | |
237 return parseBranch(); | |
238 case CONCATENATE_STRINGS: | |
239 return parseConcatenateStrings(); | |
240 case DECLARE_FUNCTION: | |
241 return parseDeclareFunction(); | |
242 case INVOKE_CONSTRUCTOR: | |
243 return parseInvokeConstructor(); | |
244 case INVOKE_CONTINUATION: | |
245 return parseInvokeContinuation(); | |
246 case INVOKE_METHOD: | |
247 return parseInvokeMethod(); | |
248 case INVOKE_STATIC: | |
249 return parseInvokeStatic(); | |
250 case INVOKE_METHOD_DIRECTLY: | |
251 return parseInvokeMethodDirectly(); | |
252 case LET_PRIM: | |
253 return parseLetPrim(); | |
254 case LET_CONT: | |
255 return parseLetCont(); | |
256 case LET_MUTABLE: | |
257 return parseLetMutable(); | |
258 case TYPE_CAST: | |
259 return parseTypeCast(); | |
260 case GET_LAZY_STATIC: | |
261 return parseGetLazyStatic(); | |
262 case UNREACHABLE: | |
263 return parseUnreachable(); | |
264 default: | |
265 assert(false); | |
266 } | |
267 | |
268 return null; | |
269 } | |
270 | |
271 /// (prim1 prim2 ... primn) | |
272 List<Primitive> parsePrimitiveList() { | |
273 tokens.consumeStart(); | |
274 List<Primitive> prims = <Primitive>[]; | |
275 while (tokens.current != ")") { | |
276 Primitive prim = name2variable[tokens.read()]; | |
277 assert(prim != null); | |
278 prims.add(prim); | |
279 } | |
280 tokens.consumeEnd(); | |
281 return prims; | |
282 } | |
283 | |
284 /// (FunctionDefinition name (parameters) continuation body) | |
285 FunctionDefinition parseFunctionDefinition() { | |
286 tokens.consumeStart(FUNCTION_DEFINITION); | |
287 | |
288 // name | |
289 Element element = new DummyElement(""); | |
290 if (tokens.current != '(') { | |
291 // This is a named function. | |
292 element = new DummyElement(tokens.read()); | |
293 } | |
294 | |
295 // (this) or () | |
296 Definition thisParameter = null; | |
297 tokens.consumeStart(); | |
298 if (tokens.current != ')') { | |
299 String thisName = tokens.read(); | |
300 if (name2variable.containsKey(thisName)) { | |
301 thisParameter = name2variable[thisName]; | |
302 } else { | |
303 thisParameter = new Parameter(new DummyElement(thisName)); | |
304 name2variable[thisName] = thisParameter; | |
305 } | |
306 } | |
307 tokens.consumeEnd(); | |
308 | |
309 // (parameters) | |
310 List<Definition> parameters = <Definition>[]; | |
311 tokens.consumeStart(); | |
312 while (tokens.current != ")") { | |
313 String paramName = tokens.read(); | |
314 if (name2variable.containsKey(paramName)) { | |
315 parameters.add(name2variable[paramName]); | |
316 } else { | |
317 Parameter param = new Parameter(new DummyElement(paramName)); | |
318 name2variable[paramName] = param; | |
319 parameters.add(param); | |
320 } | |
321 } | |
322 tokens.consumeEnd(); | |
323 | |
324 // continuation | |
325 String contName = tokens.read("return"); | |
326 Continuation cont = name2variable[contName]; | |
327 assert(cont != null); | |
328 | |
329 // body | |
330 Expression body = parseExpression(); | |
331 | |
332 tokens.consumeEnd(); | |
333 return new FunctionDefinition(element, thisParameter, parameters, | |
334 new Body(body, cont), null, null); | |
335 } | |
336 | |
337 /// (IsTrue arg) | |
338 Condition parseCondition() { | |
339 // Handles IsTrue only for now. | |
340 tokens.consumeStart(IS_TRUE); | |
341 | |
342 Definition value = name2variable[tokens.read()]; | |
343 assert(value != null); | |
344 | |
345 tokens.consumeEnd(); | |
346 return new IsTrue(value); | |
347 } | |
348 | |
349 /// (Branch condition cont cont) | |
350 Branch parseBranch() { | |
351 tokens.consumeStart(BRANCH); | |
352 | |
353 Condition cond = parseCondition(); | |
354 Continuation trueCont = name2variable[tokens.read()]; | |
355 Continuation falseCont = name2variable[tokens.read()]; | |
356 assert(trueCont != null && falseCont != null); | |
357 | |
358 tokens.consumeEnd(); | |
359 return new Branch(cond, trueCont, falseCont); | |
360 } | |
361 | |
362 /// (ConcatenateStrings (args) cont) | |
363 ConcatenateStrings parseConcatenateStrings() { | |
364 tokens.consumeStart(CONCATENATE_STRINGS); | |
365 | |
366 List<Primitive> args = parsePrimitiveList(); | |
367 | |
368 Continuation cont = name2variable[tokens.read()]; | |
369 assert(cont != null); | |
370 | |
371 tokens.consumeEnd(); | |
372 return new ConcatenateStrings(args, cont); | |
373 } | |
374 | |
375 /// (DeclareFunction name = function in body) | |
376 DeclareFunction parseDeclareFunction() { | |
377 tokens.consumeStart(DECLARE_FUNCTION); | |
378 | |
379 // name = | |
380 MutableVariable local = addMutableVariable(tokens.read()); | |
381 tokens.read("="); | |
382 | |
383 // function in | |
384 FunctionDefinition def = parseFunctionDefinition(); | |
385 tokens.read("in"); | |
386 | |
387 // body | |
388 Expression body = parseExpression(); | |
389 | |
390 tokens.consumeEnd(); | |
391 return new DeclareFunction(local, def)..plug(body); | |
392 } | |
393 | |
394 /// (InvokeConstructor name (args) cont) | |
395 InvokeConstructor parseInvokeConstructor() { | |
396 tokens.consumeStart(INVOKE_CONSTRUCTOR); | |
397 | |
398 String constructorName = tokens.read(); | |
399 List<String> split = constructorName.split("."); | |
400 assert(split.length < 3); | |
401 | |
402 dart_types.DartType type = new DummyNamedType(split[0]); | |
403 Element element = new DummyElement((split.length == 1) ? "" : split[1]); | |
404 | |
405 List<Primitive> args = parsePrimitiveList(); | |
406 | |
407 Continuation cont = name2variable[tokens.read()]; | |
408 assert(cont != null); | |
409 | |
410 tokens.consumeEnd(); | |
411 Selector selector = dummySelector(constructorName, args.length); | |
412 return new InvokeConstructor(type, element, selector, args, cont); | |
413 } | |
414 | |
415 /// (InvokeContinuation rec? name (args)) | |
416 InvokeContinuation parseInvokeContinuation() { | |
417 tokens.consumeStart(INVOKE_CONTINUATION); | |
418 String name = tokens.read(); | |
419 bool isRecursive = name == "rec"; | |
420 if (isRecursive) name = tokens.read(); | |
421 | |
422 Continuation cont = name2variable[name]; | |
423 assert(cont != null); | |
424 | |
425 List<Primitive> args = parsePrimitiveList(); | |
426 | |
427 tokens.consumeEnd(); | |
428 return new InvokeContinuation(cont, args, isRecursive: isRecursive); | |
429 } | |
430 | |
431 /// (InvokeMethod receiver method (args) cont) | |
432 InvokeMethod parseInvokeMethod() { | |
433 tokens.consumeStart(INVOKE_METHOD); | |
434 | |
435 Definition receiver = name2variable[tokens.read()]; | |
436 assert(receiver != null); | |
437 | |
438 String methodName = tokens.read(); | |
439 | |
440 List<Primitive> args = parsePrimitiveList(); | |
441 | |
442 Continuation cont = name2variable[tokens.read()]; | |
443 assert(cont != null); | |
444 | |
445 tokens.consumeEnd(); | |
446 Selector selector = dummySelector(methodName, args.length); | |
447 return new InvokeMethod(receiver, selector, args, cont); | |
448 } | |
449 | |
450 /// (InvokeStatic method (args) cont) | |
451 InvokeStatic parseInvokeStatic() { | |
452 tokens.consumeStart(INVOKE_STATIC); | |
453 | |
454 String methodName = tokens.read(); | |
455 | |
456 List<Primitive> args = parsePrimitiveList(); | |
457 | |
458 Continuation cont = name2variable[tokens.read()]; | |
459 assert(cont != null); | |
460 | |
461 Entity entity = new DummyEntity(methodName); | |
462 Selector selector = dummySelector(methodName, args.length); | |
463 | |
464 tokens.consumeEnd(); | |
465 return new InvokeStatic(entity, selector, args, cont, null); | |
466 } | |
467 | |
468 /// (InvokeMethodDirectly receiver method (args) cont) | |
469 InvokeMethodDirectly parseInvokeMethodDirectly() { | |
470 tokens.consumeStart(INVOKE_METHOD_DIRECTLY); | |
471 | |
472 Definition receiver = name2variable[tokens.read()]; | |
473 assert(receiver != null); | |
474 | |
475 String methodName = tokens.read(); | |
476 | |
477 List<Primitive> args = parsePrimitiveList(); | |
478 | |
479 Continuation cont = name2variable[tokens.read()]; | |
480 assert(cont != null); | |
481 | |
482 tokens.consumeEnd(); | |
483 Element element = new DummyElement(methodName); | |
484 Selector selector = dummySelector(methodName, args.length); | |
485 return new InvokeMethodDirectly(receiver, element, selector, args, cont); | |
486 } | |
487 | |
488 // (rec? name (args) body) | |
489 Continuation parseContinuation() { | |
490 // (rec? name | |
491 tokens.consumeStart(); | |
492 String name = tokens.read(); | |
493 bool isRecursive = name == "rec"; | |
494 if (isRecursive) name = tokens.read(); | |
495 | |
496 // (args) | |
497 tokens.consumeStart(); | |
498 List<Parameter> params = <Parameter>[]; | |
499 while (tokens.current != ")") { | |
500 String paramName = tokens.read(); | |
501 Parameter param = new Parameter(new DummyElement(paramName)); | |
502 name2variable[paramName] = param; | |
503 params.add(param); | |
504 } | |
505 tokens.consumeEnd(); | |
506 | |
507 Continuation cont = new Continuation(params); | |
508 name2variable[name] = cont; | |
509 | |
510 cont.isRecursive = isRecursive; | |
511 // cont_body | |
512 cont.body = parseExpression(); | |
513 tokens.consumeEnd(); | |
514 return cont; | |
515 } | |
516 | |
517 /// (LetCont (continuations) body) | |
518 LetCont parseLetCont() { | |
519 tokens.consumeStart(LET_CONT); | |
520 tokens.consumeStart(); | |
521 List<Continuation> continuations = <Continuation>[]; | |
522 while (tokens.current != ")") { | |
523 continuations.add(parseContinuation()); | |
524 } | |
525 tokens.consumeEnd(); | |
526 | |
527 // body) | |
528 Expression body = parseExpression(); | |
529 tokens.consumeEnd(); | |
530 | |
531 return new LetCont.many(continuations, body); | |
532 } | |
533 | |
534 /// (LetMutable (name value) body) | |
535 LetMutable parseLetMutable() { | |
536 tokens.consumeStart(LET_MUTABLE); | |
537 | |
538 tokens.consumeStart(); | |
539 String name = tokens.read(); | |
540 MutableVariable local = addMutableVariable(name); | |
541 Primitive value = name2variable[tokens.read()]; | |
542 tokens.consumeEnd(); | |
543 | |
544 Expression body = parseExpression(); | |
545 tokens.consumeEnd(); | |
546 return new LetMutable(local, value)..plug(body); | |
547 } | |
548 | |
549 /// (SetMutable name value) | |
550 SetMutable parseSetMutable() { | |
551 tokens.consumeStart(SET_MUTABLE); | |
552 | |
553 MutableVariable local = name2variable[tokens.read()]; | |
554 Primitive value = name2variable[tokens.read()]; | |
555 assert(value != null); | |
556 | |
557 tokens.consumeEnd(); | |
558 return new SetMutable(local, value); | |
559 } | |
560 | |
561 /// (TypeCast value type args cont) | |
562 TypeCast parseTypeCast() { | |
563 tokens.consumeStart(TYPE_CAST); | |
564 | |
565 Primitive value = name2variable[tokens.read()]; | |
566 assert(value != null); | |
567 | |
568 dart_types.DartType type = new DummyNamedType(tokens.read()); | |
569 | |
570 List<ir.Primitive> typeArguments = parsePrimitiveList(); | |
571 | |
572 Continuation cont = name2variable[tokens.read()]; | |
573 assert(cont != null); | |
574 | |
575 tokens.consumeEnd(); | |
576 return new TypeCast(value, type, typeArguments, cont); | |
577 } | |
578 | |
579 /// (TypeTest value type args) | |
580 TypeTest parseTypeTest() { | |
581 tokens.consumeStart(TYPE_TEST); | |
582 | |
583 Primitive value = name2variable[tokens.read()]; | |
584 assert(value != null); | |
585 | |
586 dart_types.DartType type = new DummyNamedType(tokens.read()); | |
587 | |
588 List<ir.Primitive> typeArguments = parsePrimitiveList(); | |
589 | |
590 tokens.consumeEnd(); | |
591 return new TypeTest(value, type, typeArguments); | |
592 } | |
593 | |
594 /// (ApplyBuiltinOperator operator args) | |
595 ApplyBuiltinOperator parseApplyBuiltinOperator() { | |
596 tokens.consumeStart(APPLY_BUILTIN_OPERATOR); | |
597 | |
598 String operatorName = tokens.read(); | |
599 BuiltinOperator operator; | |
600 for (BuiltinOperator op in BuiltinOperator.values) { | |
601 if (op.toString() == operatorName) { | |
602 operator = op; | |
603 break; | |
604 } | |
605 } | |
606 assert(operator != null); | |
607 List<ir.Primitive> arguments = parsePrimitiveList(); | |
608 | |
609 tokens.consumeEnd(); | |
610 return new ApplyBuiltinOperator(operator, arguments); | |
611 } | |
612 | |
613 /// (GetLength object) | |
614 GetLength parseGetLength() { | |
615 tokens.consumeStart(GET_LENGTH); | |
616 Primitive object = name2variable[tokens.read()]; | |
617 tokens.consumeEnd(); | |
618 return new GetLength(object); | |
619 } | |
620 | |
621 /// (GetIndex object index) | |
622 GetIndex parseGetIndex() { | |
623 tokens.consumeStart(GET_INDEX); | |
624 Primitive object = name2variable[tokens.read()]; | |
625 Primitive index = name2variable[tokens.read()]; | |
626 tokens.consumeEnd(); | |
627 return new GetIndex(object, index); | |
628 } | |
629 | |
630 /// (SetIndex object index value) | |
631 SetIndex parseSetIndex() { | |
632 tokens.consumeStart(SET_INDEX); | |
633 Primitive object = name2variable[tokens.read()]; | |
634 Primitive index = name2variable[tokens.read()]; | |
635 Primitive value = name2variable[tokens.read()]; | |
636 tokens.consumeEnd(); | |
637 return new SetIndex(object, index, value); | |
638 } | |
639 | |
640 /// (SetStatic field value) | |
641 SetStatic parseSetStatic() { | |
642 tokens.consumeStart(SET_STATIC); | |
643 | |
644 Element fieldElement = new DummyElement(tokens.read()); | |
645 Primitive value = name2variable[tokens.read()]; | |
646 assert(value != null); | |
647 | |
648 tokens.consumeEnd(); | |
649 return new SetStatic(fieldElement, value, null); | |
650 } | |
651 | |
652 /// (GetLazyStatic field cont) | |
653 GetLazyStatic parseGetLazyStatic() { | |
654 tokens.consumeStart(GET_LAZY_STATIC); | |
655 | |
656 Element fieldElement = new DummyElement(tokens.read()); | |
657 Continuation cont = name2variable[tokens.read()]; | |
658 assert(cont != null); | |
659 | |
660 tokens.consumeEnd(); | |
661 return new GetLazyStatic(fieldElement, cont, null); | |
662 } | |
663 | |
664 /// (Unreachable) | |
665 Unreachable parseUnreachable() { | |
666 tokens.consumeStart(UNREACHABLE); | |
667 tokens.consumeEnd(); | |
668 return new Unreachable(); | |
669 } | |
670 | |
671 /// (LetPrim (name primitive) body) | |
672 LetPrim parseLetPrim() { | |
673 tokens.consumeStart(LET_PRIM); | |
674 | |
675 // (name | |
676 tokens.consumeStart(); | |
677 String name = tokens.read(); | |
678 | |
679 // primitive) | |
680 Primitive primitive = parsePrimitive(); | |
681 name2variable[name] = primitive; | |
682 tokens.consumeEnd(); | |
683 | |
684 // body) | |
685 Expression body = parseExpression(); | |
686 tokens.consumeEnd(); | |
687 | |
688 return new LetPrim(primitive)..plug(body); | |
689 } | |
690 | |
691 Primitive parsePrimitive() { | |
692 assert(tokens.current == "("); | |
693 | |
694 switch (tokens.next) { | |
695 case CONSTANT: | |
696 return parseConstant(); | |
697 case CREATE_FUNCTION: | |
698 return parseCreateFunction(); | |
699 case GET_MUTABLE: | |
700 return parseGetMutable(); | |
701 case SET_MUTABLE: | |
702 return parseSetMutable(); | |
703 case LITERAL_LIST: | |
704 return parseLiteralList(); | |
705 case LITERAL_MAP: | |
706 return parseLiteralMap(); | |
707 case REIFY_TYPE_VAR: | |
708 return parseReifyTypeVar(); | |
709 case GET_STATIC: | |
710 return parseGetStatic(); | |
711 case SET_STATIC: | |
712 return parseSetStatic(); | |
713 case TYPE_TEST: | |
714 return parseTypeTest(); | |
715 case APPLY_BUILTIN_OPERATOR: | |
716 return parseApplyBuiltinOperator(); | |
717 case GET_LENGTH: | |
718 return parseGetLength(); | |
719 case GET_INDEX: | |
720 return parseGetIndex(); | |
721 case SET_INDEX: | |
722 return parseSetIndex(); | |
723 case GET_FIELD: | |
724 return parseGetField(); | |
725 case SET_FIELD: | |
726 return parseSetField(); | |
727 default: | |
728 assert(false); | |
729 } | |
730 | |
731 return null; | |
732 } | |
733 | |
734 /// (Constant (constant)) | |
735 Constant parseConstant() { | |
736 tokens.consumeStart(CONSTANT); | |
737 tokens.consumeStart(); | |
738 Constant result; | |
739 String tag = tokens.read(); | |
740 switch (tag) { | |
741 case NULL: | |
742 result = new Constant( | |
743 new NullConstantExpression(new NullConstantValue())); | |
744 break; | |
745 case BOOL: | |
746 String value = tokens.read(); | |
747 if (value == "true") { | |
748 result = new Constant( | |
749 new BoolConstantExpression(true, new TrueConstantValue())); | |
750 } else if (value == "false") { | |
751 result = new Constant( | |
752 new BoolConstantExpression(false, new FalseConstantValue())); | |
753 } else { | |
754 throw "Invalid Boolean value '$value'."; | |
755 } | |
756 break; | |
757 case STRING: | |
758 List<String> strings = <String>[]; | |
759 do { | |
760 strings.add(tokens.read()); | |
761 } while (tokens.current != ")"); | |
762 String string = strings.join(" "); | |
763 assert(string.startsWith('"') && string.endsWith('"')); | |
764 String text = string.substring(1, string.length - 1); | |
765 StringConstantValue value = new StringConstantValue( | |
766 new LiteralDartString(text)); | |
767 result = new Constant(new StringConstantExpression(text, value)); | |
768 break; | |
769 case INT: | |
770 String value = tokens.read(); | |
771 int intValue = int.parse(value, onError: (_) => null); | |
772 if (intValue == null) { | |
773 throw "Invalid int value 'value'."; | |
774 } | |
775 result = new Constant(new IntConstantExpression( | |
776 intValue, new IntConstantValue(intValue))); | |
777 break; | |
778 case DOUBLE: | |
779 String value = tokens.read(); | |
780 double doubleValue = double.parse(value, (_) => null); | |
781 if (doubleValue == null) { | |
782 throw "Invalid double value '$value'."; | |
783 } | |
784 result = new Constant(new DoubleConstantExpression( | |
785 doubleValue, new DoubleConstantValue(doubleValue))); | |
786 break; | |
787 default: | |
788 throw "Unexpected constant tag '$tag'."; | |
789 } | |
790 tokens.consumeEnd(); | |
791 tokens.consumeEnd(); | |
792 return result; | |
793 } | |
794 | |
795 /// (CreateFunction (definition)) | |
796 CreateFunction parseCreateFunction() { | |
797 tokens.consumeStart(CREATE_FUNCTION); | |
798 FunctionDefinition def = parseFunctionDefinition(); | |
799 tokens.consumeEnd(); | |
800 return new CreateFunction(def); | |
801 } | |
802 | |
803 MutableVariable addMutableVariable(String name) { | |
804 assert(!name2variable.containsKey(name)); | |
805 MutableVariable variable = new MutableVariable(new DummyElement(name)); | |
806 name2variable[name] = variable; | |
807 return variable; | |
808 } | |
809 | |
810 /// (GetMutable name) | |
811 GetMutable parseGetMutable() { | |
812 tokens.consumeStart(GET_MUTABLE); | |
813 MutableVariable local = name2variable[tokens.read()]; | |
814 tokens.consumeEnd(); | |
815 | |
816 return new GetMutable(local); | |
817 } | |
818 | |
819 /// (LiteralList (values)) | |
820 LiteralList parseLiteralList() { | |
821 tokens.consumeStart(LITERAL_LIST); | |
822 List<Primitive> values = parsePrimitiveList(); | |
823 tokens.consumeEnd(); | |
824 return new LiteralList(null, values); | |
825 } | |
826 | |
827 /// (LiteralMap (keys) (values)) | |
828 LiteralMap parseLiteralMap() { | |
829 tokens.consumeStart(LITERAL_MAP); | |
830 | |
831 List<Primitive> keys = parsePrimitiveList(); | |
832 List<Primitive> values = parsePrimitiveList(); | |
833 | |
834 List<LiteralMapEntry> entries = <LiteralMapEntry>[]; | |
835 for (int i = 0; i < keys.length; i++) { | |
836 entries.add(new LiteralMapEntry(keys[i], values[i])); | |
837 } | |
838 | |
839 tokens.consumeEnd(); | |
840 return new LiteralMap(null, entries); | |
841 } | |
842 | |
843 /// (ReifyTypeVar type) | |
844 ReifyTypeVar parseReifyTypeVar() { | |
845 tokens.consumeStart(REIFY_TYPE_VAR); | |
846 | |
847 TypeVariableElement type = new DummyElement(tokens.read()); | |
848 | |
849 tokens.consumeEnd(); | |
850 return new ReifyTypeVar(type); | |
851 } | |
852 | |
853 /// (GetStatic field) | |
854 GetStatic parseGetStatic() { | |
855 tokens.consumeStart(GET_STATIC); | |
856 | |
857 Element field = new DummyElement(tokens.read()); | |
858 | |
859 tokens.consumeEnd(); | |
860 return new GetStatic(field, null); | |
861 } | |
862 | |
863 /// (GetField object field) | |
864 GetField parseGetField() { | |
865 tokens.consumeStart(GET_FIELD); | |
866 | |
867 Primitive object = name2variable[tokens.read()]; | |
868 Element field = new DummyElement(tokens.read()); | |
869 | |
870 tokens.consumeEnd(); | |
871 return new GetField(object, field); | |
872 } | |
873 | |
874 /// (SetField object field value) | |
875 SetField parseSetField() { | |
876 tokens.consumeStart(SET_FIELD); | |
877 | |
878 Primitive object = name2variable[tokens.read()]; | |
879 Element field = new DummyElement(tokens.read()); | |
880 Primitive value = name2variable[tokens.read()]; | |
881 | |
882 tokens.consumeEnd(); | |
883 return new SetField(object, field, value); | |
884 } | |
885 } | |
OLD | NEW |