| 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 |