| OLD | NEW | 
|---|
| 1 // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file | 1 // Copyright (c) 2013, 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 // Utilities for building JS ASTs at runtime.  Contains a builder class | 5 // Utilities for building JS ASTs at runtime.  Contains a builder class | 
| 6 // and a parser that parses part of the language. | 6 // and a parser that parses part of the language. | 
| 7 | 7 | 
| 8 part of js_ast; | 8 part of js_ast; | 
| 9 | 9 | 
| 10 |  | 
| 11 /** | 10 /** | 
| 12  * Global template manager.  We should aim to have a fixed number of | 11  * Global template manager.  We should aim to have a fixed number of | 
| 13  * templates. This implies that we do not use js('xxx') to parse text that is | 12  * templates. This implies that we do not use js('xxx') to parse text that is | 
| 14  * constructed from values that depend on names in the Dart program. | 13  * constructed from values that depend on names in the Dart program. | 
| 15  * | 14  * | 
| 16  * TODO(sra): Find the remaining places where js('xxx') used to parse an | 15  * TODO(sra): Find the remaining places where js('xxx') used to parse an | 
| 17  * unbounded number of expression, or institute a cache policy. | 16  * unbounded number of expression, or institute a cache policy. | 
| 18  */ | 17  */ | 
| 19 TemplateManager templateManager = new TemplateManager(); | 18 TemplateManager templateManager = new TemplateManager(); | 
| 20 | 19 | 
| 21 |  | 
| 22 /** | 20 /** | 
| 23 | 21 | 
| 24 [js] is a singleton instace of JsBuilder.  JsBuilder is a set of conveniences | 22 [js] is a singleton instace of JsBuilder.  JsBuilder is a set of conveniences | 
| 25 for constructing JavaScript ASTs. | 23 for constructing JavaScript ASTs. | 
| 26 | 24 | 
| 27 [string] and [number] are used to create leaf AST nodes: | 25 [string] and [number] are used to create leaf AST nodes: | 
| 28 | 26 | 
| 29     var s = js.string('hello');    //  s = new LiteralString('"hello"') | 27     var s = js.string('hello');    //  s = new LiteralString('"hello"') | 
| 30     var n = js.number(123);        //  n = new LiteralNumber(123) | 28     var n = js.number(123);        //  n = new LiteralNumber(123) | 
| 31 | 29 | 
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 180 | 178 | 
| 181 What is not implemented: | 179 What is not implemented: | 
| 182 | 180 | 
| 183  -  Array initializers and object initializers could support splicing.  In the | 181  -  Array initializers and object initializers could support splicing.  In the | 
| 184     array case, we would need some way to know if an ArrayInitializer argument | 182     array case, we would need some way to know if an ArrayInitializer argument | 
| 185     should be splice or is intended as a single value. | 183     should be splice or is intended as a single value. | 
| 186 | 184 | 
| 187 */ | 185 */ | 
| 188 const JsBuilder js = const JsBuilder(); | 186 const JsBuilder js = const JsBuilder(); | 
| 189 | 187 | 
| 190 |  | 
| 191 class JsBuilder { | 188 class JsBuilder { | 
| 192   const JsBuilder(); | 189   const JsBuilder(); | 
| 193 | 190 | 
| 194   /** | 191   /** | 
| 195    * Parses a bit of JavaScript, and returns an expression. | 192    * Parses a bit of JavaScript, and returns an expression. | 
| 196    * | 193    * | 
| 197    * See the MiniJsParser class. | 194    * See the MiniJsParser class. | 
| 198    * | 195    * | 
| 199    * [arguments] can be a single [Node] (e.g. an [Expression] or [Statement]) or | 196    * [arguments] can be a single [Node] (e.g. an [Expression] or [Statement]) or | 
| 200    * a list of [Node]s, which will be interpolated into the source at the '#' | 197    * a list of [Node]s, which will be interpolated into the source at the '#' | 
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 264   Template expressionTemplateFor(String source) { | 261   Template expressionTemplateFor(String source) { | 
| 265     return _findExpressionTemplate(source); | 262     return _findExpressionTemplate(source); | 
| 266   } | 263   } | 
| 267 | 264 | 
| 268   /** | 265   /** | 
| 269    * Creates an Expression template without caching the result. | 266    * Creates an Expression template without caching the result. | 
| 270    */ | 267    */ | 
| 271   Template uncachedExpressionTemplate(String source) { | 268   Template uncachedExpressionTemplate(String source) { | 
| 272     MiniJsParser parser = new MiniJsParser(source); | 269     MiniJsParser parser = new MiniJsParser(source); | 
| 273     Expression expression = parser.expression(); | 270     Expression expression = parser.expression(); | 
| 274     return new Template( | 271     return new Template(source, expression, | 
| 275         source, expression, isExpression: true, forceCopy: false); | 272         isExpression: true, forceCopy: false); | 
| 276   } | 273   } | 
| 277 | 274 | 
| 278   /** | 275   /** | 
| 279    * Creates a Statement template without caching the result. | 276    * Creates a Statement template without caching the result. | 
| 280    */ | 277    */ | 
| 281   Template uncachedStatementTemplate(String source) { | 278   Template uncachedStatementTemplate(String source) { | 
| 282     MiniJsParser parser = new MiniJsParser(source); | 279     MiniJsParser parser = new MiniJsParser(source); | 
| 283     Statement statement = parser.statement(); | 280     Statement statement = parser.statement(); | 
| 284     return new Template( | 281     return new Template(source, statement, | 
| 285         source, statement, isExpression: false, forceCopy: false); | 282         isExpression: false, forceCopy: false); | 
| 286   } | 283   } | 
| 287 | 284 | 
| 288   /** | 285   /** | 
| 289    * Create an Expression template which has [ast] as the result.  This is used | 286    * Create an Expression template which has [ast] as the result.  This is used | 
| 290    * to wrap a generated AST in a zero-argument Template so it can be passed to | 287    * to wrap a generated AST in a zero-argument Template so it can be passed to | 
| 291    * context that expects a template. | 288    * context that expects a template. | 
| 292    */ | 289    */ | 
| 293   Template expressionTemplateYielding(Node ast) { | 290   Template expressionTemplateYielding(Node ast) { | 
| 294     return new Template.withExpressionResult(ast); | 291     return new Template.withExpressionResult(ast); | 
| 295   } | 292   } | 
| 296 | 293 | 
| 297   Template statementTemplateYielding(Node ast) { | 294   Template statementTemplateYielding(Node ast) { | 
| 298     return new Template.withStatementResult(ast); | 295     return new Template.withStatementResult(ast); | 
| 299   } | 296   } | 
| 300 | 297 | 
| 301   /// Creates a literal js string from [value]. | 298   /// Creates a literal js string from [value]. | 
| 302   LiteralString _legacyEscapedString(String value) { | 299   LiteralString _legacyEscapedString(String value) { | 
| 303    // Start by escaping the backslashes. | 300     // Start by escaping the backslashes. | 
| 304     String escaped = value.replaceAll('\\', '\\\\'); | 301     String escaped = value.replaceAll('\\', '\\\\'); | 
| 305     // Do not escape unicode characters and ' because they are allowed in the | 302     // Do not escape unicode characters and ' because they are allowed in the | 
| 306     // string literal anyway. | 303     // string literal anyway. | 
| 307     escaped = escaped.replaceAllMapped(new RegExp('\n|"|\b|\t|\v|\r'), (match) { | 304     escaped = escaped.replaceAllMapped(new RegExp('\n|"|\b|\t|\v|\r'), (match) { | 
| 308       switch (match.group(0)) { | 305       switch (match.group(0)) { | 
| 309         case "\n" : return r"\n"; | 306         case "\n": | 
| 310         case "\"" : return r'\"'; | 307           return r"\n"; | 
| 311         case "\b" : return r"\b"; | 308         case "\"": | 
| 312         case "\t" : return r"\t"; | 309           return r'\"'; | 
| 313         case "\f" : return r"\f"; | 310         case "\b": | 
| 314         case "\r" : return r"\r"; | 311           return r"\b"; | 
| 315         case "\v" : return r"\v"; | 312         case "\t": | 
|  | 313           return r"\t"; | 
|  | 314         case "\f": | 
|  | 315           return r"\f"; | 
|  | 316         case "\r": | 
|  | 317           return r"\r"; | 
|  | 318         case "\v": | 
|  | 319           return r"\v"; | 
| 316       } | 320       } | 
| 317     }); | 321     }); | 
| 318     LiteralString result = string(escaped); | 322     LiteralString result = string(escaped); | 
| 319     // We don't escape ' under the assumption that the string is wrapped | 323     // We don't escape ' under the assumption that the string is wrapped | 
| 320     // into ". Verify that assumption. | 324     // into ". Verify that assumption. | 
| 321     assert(result.value.codeUnitAt(0) == '"'.codeUnitAt(0)); | 325     assert(result.value.codeUnitAt(0) == '"'.codeUnitAt(0)); | 
| 322     return result; | 326     return result; | 
| 323   } | 327   } | 
| 324 | 328 | 
| 325   /// Creates a literal js string from [value]. | 329   /// Creates a literal js string from [value]. | 
| 326   LiteralString escapedString(String value, | 330   LiteralString escapedString(String value, | 
| 327        {bool utf8: false, bool ascii: false}) { | 331       {bool utf8: false, bool ascii: false}) { | 
| 328     if (utf8 == false && ascii == false) return _legacyEscapedString(value); | 332     if (utf8 == false && ascii == false) return _legacyEscapedString(value); | 
| 329     if (utf8 && ascii) throw new ArgumentError('Cannot be both UTF8 and ASCII'); | 333     if (utf8 && ascii) throw new ArgumentError('Cannot be both UTF8 and ASCII'); | 
| 330 | 334 | 
| 331     int singleQuotes = 0; | 335     int singleQuotes = 0; | 
| 332     int doubleQuotes = 0; | 336     int doubleQuotes = 0; | 
| 333     int otherEscapes = 0; | 337     int otherEscapes = 0; | 
| 334     int unpairedSurrogates = 0; | 338     int unpairedSurrogates = 0; | 
| 335 | 339 | 
| 336     for (int rune in value.runes) { | 340     for (int rune in value.runes) { | 
| 337       if (rune == charCodes.$BACKSLASH) { | 341       if (rune == charCodes.$BACKSLASH) { | 
| 338         ++otherEscapes; | 342         ++otherEscapes; | 
| 339       } else if (rune == charCodes.$SQ) { | 343       } else if (rune == charCodes.$SQ) { | 
| 340         ++singleQuotes; | 344         ++singleQuotes; | 
| 341       } else if (rune == charCodes.$DQ) { | 345       } else if (rune == charCodes.$DQ) { | 
| 342         ++doubleQuotes; | 346         ++doubleQuotes; | 
| 343       } else if (rune == charCodes.$LF || rune == charCodes.$CR || | 347       } else if (rune == charCodes.$LF || | 
| 344                  rune == charCodes.$LS || rune == charCodes.$PS) { | 348           rune == charCodes.$CR || | 
|  | 349           rune == charCodes.$LS || | 
|  | 350           rune == charCodes.$PS) { | 
| 345         // Line terminators. | 351         // Line terminators. | 
| 346         ++otherEscapes; | 352         ++otherEscapes; | 
| 347       } else if (rune == charCodes.$BS || rune == charCodes.$TAB || | 353       } else if (rune == charCodes.$BS || | 
| 348                  rune == charCodes.$VTAB || rune == charCodes.$FF) { | 354           rune == charCodes.$TAB || | 
|  | 355           rune == charCodes.$VTAB || | 
|  | 356           rune == charCodes.$FF) { | 
| 349         ++otherEscapes; | 357         ++otherEscapes; | 
| 350       } else if (_isUnpairedSurrogate(rune)) { | 358       } else if (_isUnpairedSurrogate(rune)) { | 
| 351         ++unpairedSurrogates; | 359         ++unpairedSurrogates; | 
| 352       } else { | 360       } else { | 
| 353         if (ascii && (rune < charCodes.$SPACE || rune >= charCodes.$DEL)) { | 361         if (ascii && (rune < charCodes.$SPACE || rune >= charCodes.$DEL)) { | 
| 354           ++otherEscapes; | 362           ++otherEscapes; | 
| 355         } | 363         } | 
| 356       } | 364       } | 
| 357     } | 365     } | 
| 358 | 366 | 
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 401       } | 409       } | 
| 402     } | 410     } | 
| 403 | 411 | 
| 404     return finish(useSingleQuotes ? "'" : '"', sb.toString()); | 412     return finish(useSingleQuotes ? "'" : '"', sb.toString()); | 
| 405   } | 413   } | 
| 406 | 414 | 
| 407   static bool _isUnpairedSurrogate(int code) => (code & 0xFFFFF800) == 0xD800; | 415   static bool _isUnpairedSurrogate(int code) => (code & 0xFFFFF800) == 0xD800; | 
| 408 | 416 | 
| 409   static String _irregularEscape(int code, bool useSingleQuotes) { | 417   static String _irregularEscape(int code, bool useSingleQuotes) { | 
| 410     switch (code) { | 418     switch (code) { | 
| 411       case charCodes.$SQ: return useSingleQuotes ? r"\'" : r"'"; | 419       case charCodes.$SQ: | 
| 412       case charCodes.$DQ: return useSingleQuotes ? r'"' : r'\"'; | 420         return useSingleQuotes ? r"\'" : r"'"; | 
| 413       case charCodes.$BACKSLASH: return r'\\'; | 421       case charCodes.$DQ: | 
| 414       case charCodes.$BS: return r'\b'; | 422         return useSingleQuotes ? r'"' : r'\"'; | 
| 415       case charCodes.$TAB: return r'\t'; | 423       case charCodes.$BACKSLASH: | 
| 416       case charCodes.$LF: return r'\n'; | 424         return r'\\'; | 
| 417       case charCodes.$VTAB: return r'\v'; | 425       case charCodes.$BS: | 
| 418       case charCodes.$FF: return r'\f'; | 426         return r'\b'; | 
| 419       case charCodes.$CR: return r'\r'; | 427       case charCodes.$TAB: | 
|  | 428         return r'\t'; | 
|  | 429       case charCodes.$LF: | 
|  | 430         return r'\n'; | 
|  | 431       case charCodes.$VTAB: | 
|  | 432         return r'\v'; | 
|  | 433       case charCodes.$FF: | 
|  | 434         return r'\f'; | 
|  | 435       case charCodes.$CR: | 
|  | 436         return r'\r'; | 
| 420     } | 437     } | 
| 421     return null; | 438     return null; | 
| 422   } | 439   } | 
| 423 | 440 | 
| 424   /// Creates a literal js string from [value]. | 441   /// Creates a literal js string from [value]. | 
| 425   /// | 442   /// | 
| 426   /// Note that this function only puts quotes around [value]. It does not do | 443   /// Note that this function only puts quotes around [value]. It does not do | 
| 427   /// any escaping, so use only when you can guarantee that [value] does not | 444   /// any escaping, so use only when you can guarantee that [value] does not | 
| 428   /// contain newlines or backslashes. For escaping the string use | 445   /// contain newlines or backslashes. For escaping the string use | 
| 429   /// [escapedString]. | 446   /// [escapedString]. | 
| 430   LiteralString string(String value) => new LiteralString('"$value"'); | 447   LiteralString string(String value) => new LiteralString('"$value"'); | 
| 431 | 448 | 
| 432   /// Creates an instance of [LiteralString] from [value]. | 449   /// Creates an instance of [LiteralString] from [value]. | 
| 433   /// | 450   /// | 
| 434   /// Does not add quotes or do any escaping. | 451   /// Does not add quotes or do any escaping. | 
| 435   LiteralString stringPart(String value) => new LiteralString(value); | 452   LiteralString stringPart(String value) => new LiteralString(value); | 
| 436 | 453 | 
| 437   StringConcatenation concatenateStrings(Iterable<Literal> parts, | 454   StringConcatenation concatenateStrings(Iterable<Literal> parts, | 
| 438                                          {addQuotes: false}) { | 455       {addQuotes: false}) { | 
| 439     List<Literal> _parts; | 456     List<Literal> _parts; | 
| 440     if (addQuotes) { | 457     if (addQuotes) { | 
| 441       Literal quote = stringPart('"'); | 458       Literal quote = stringPart('"'); | 
| 442       _parts = <Literal>[quote] | 459       _parts = <Literal>[quote] | 
| 443           ..addAll(parts) | 460         ..addAll(parts) | 
| 444           ..add(quote); | 461         ..add(quote); | 
| 445     } else { | 462     } else { | 
| 446       _parts = new List.from(parts, growable: false); | 463       _parts = new List.from(parts, growable: false); | 
| 447     } | 464     } | 
| 448     return new StringConcatenation(_parts); | 465     return new StringConcatenation(_parts); | 
| 449   } | 466   } | 
| 450 | 467 | 
| 451   Iterable<Literal> joinLiterals(Iterable<Literal> list, Literal separator) { | 468   Iterable<Literal> joinLiterals(Iterable<Literal> list, Literal separator) { | 
| 452     return new _InterleaveIterable(list, separator); | 469     return new _InterleaveIterable(list, separator); | 
| 453   } | 470   } | 
| 454 | 471 | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 465   LiteralBool boolean(bool value) => new LiteralBool(value); | 482   LiteralBool boolean(bool value) => new LiteralBool(value); | 
| 466 | 483 | 
| 467   ArrayInitializer numArray(Iterable<int> list) => | 484   ArrayInitializer numArray(Iterable<int> list) => | 
| 468       new ArrayInitializer(list.map(number).toList()); | 485       new ArrayInitializer(list.map(number).toList()); | 
| 469 | 486 | 
| 470   ArrayInitializer stringArray(Iterable<String> list) => | 487   ArrayInitializer stringArray(Iterable<String> list) => | 
| 471       new ArrayInitializer(list.map(string).toList()); | 488       new ArrayInitializer(list.map(string).toList()); | 
| 472 | 489 | 
| 473   Comment comment(String text) => new Comment(text); | 490   Comment comment(String text) => new Comment(text); | 
| 474 | 491 | 
| 475   Call propertyCall(Expression receiver, | 492   Call propertyCall( | 
| 476                     Expression fieldName, | 493       Expression receiver, Expression fieldName, List<Expression> arguments) { | 
| 477                     List<Expression> arguments) { |  | 
| 478     return new Call(new PropertyAccess(receiver, fieldName), arguments); | 494     return new Call(new PropertyAccess(receiver, fieldName), arguments); | 
| 479   } | 495   } | 
| 480 | 496 | 
| 481   ObjectInitializer objectLiteral(Map<String, Expression> map) { | 497   ObjectInitializer objectLiteral(Map<String, Expression> map) { | 
| 482     List<Property> properties = <Property>[]; | 498     List<Property> properties = <Property>[]; | 
| 483     map.forEach((name, value) { | 499     map.forEach((name, value) { | 
| 484       properties.add(new Property(string(name), value)); | 500       properties.add(new Property(string(name), value)); | 
| 485     }); | 501     }); | 
| 486     return new ObjectInitializer(properties); | 502     return new ObjectInitializer(properties); | 
| 487   } | 503   } | 
| 488 } | 504 } | 
| 489 | 505 | 
| 490 LiteralString string(String value) => js.string(value); | 506 LiteralString string(String value) => js.string(value); | 
| 491 LiteralString quoteName(Name name, {allowNull: false}) { | 507 LiteralString quoteName(Name name, {allowNull: false}) { | 
| 492   return js.quoteName(name, allowNull: allowNull); | 508   return js.quoteName(name, allowNull: allowNull); | 
| 493 } | 509 } | 
|  | 510 | 
| 494 LiteralString stringPart(String value) => js.stringPart(value); | 511 LiteralString stringPart(String value) => js.stringPart(value); | 
| 495 Iterable<Literal> joinLiterals(Iterable<Literal> list, Literal separator) { | 512 Iterable<Literal> joinLiterals(Iterable<Literal> list, Literal separator) { | 
| 496   return js.joinLiterals(list, separator); | 513   return js.joinLiterals(list, separator); | 
| 497 } | 514 } | 
|  | 515 | 
| 498 StringConcatenation concatenateStrings(Iterable<Literal> parts, | 516 StringConcatenation concatenateStrings(Iterable<Literal> parts, | 
| 499                                        {addQuotes: false}) { | 517     {addQuotes: false}) { | 
| 500   return js.concatenateStrings(parts, addQuotes: addQuotes); | 518   return js.concatenateStrings(parts, addQuotes: addQuotes); | 
| 501 } | 519 } | 
| 502 | 520 | 
| 503 LiteralNumber number(num value) => js.number(value); | 521 LiteralNumber number(num value) => js.number(value); | 
| 504 ArrayInitializer numArray(Iterable<int> list) => js.numArray(list); | 522 ArrayInitializer numArray(Iterable<int> list) => js.numArray(list); | 
| 505 ArrayInitializer stringArray(Iterable<String> list) => js.stringArray(list); | 523 ArrayInitializer stringArray(Iterable<String> list) => js.stringArray(list); | 
| 506 Call propertyCall(Expression receiver, | 524 Call propertyCall( | 
| 507                   Expression fieldName, | 525     Expression receiver, Expression fieldName, List<Expression> arguments) { | 
| 508                   List<Expression> arguments) { |  | 
| 509   return js.propertyCall(receiver, fieldName, arguments); | 526   return js.propertyCall(receiver, fieldName, arguments); | 
| 510 } | 527 } | 
|  | 528 | 
| 511 ObjectInitializer objectLiteral(Map<String, Expression> map) { | 529 ObjectInitializer objectLiteral(Map<String, Expression> map) { | 
| 512   return js.objectLiteral(map); | 530   return js.objectLiteral(map); | 
| 513 } | 531 } | 
| 514 | 532 | 
| 515 class MiniJsParserError { | 533 class MiniJsParserError { | 
| 516   MiniJsParserError(this.parser, this.message) { } | 534   MiniJsParserError(this.parser, this.message) {} | 
| 517 | 535 | 
| 518   final MiniJsParser parser; | 536   final MiniJsParser parser; | 
| 519   final String message; | 537   final String message; | 
| 520 | 538 | 
| 521   String toString() { | 539   String toString() { | 
| 522     int pos = parser.lastPosition; | 540     int pos = parser.lastPosition; | 
| 523 | 541 | 
| 524     // Discard lines following the line containing lastPosition. | 542     // Discard lines following the line containing lastPosition. | 
| 525     String src = parser.src; | 543     String src = parser.src; | 
| 526     int newlinePos = src.indexOf('\n', pos); | 544     int newlinePos = src.indexOf('\n', pos); | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 568         lastToken = null, | 586         lastToken = null, | 
| 569         lastPosition = 0, | 587         lastPosition = 0, | 
| 570         position = 0 { | 588         position = 0 { | 
| 571     getToken(); | 589     getToken(); | 
| 572   } | 590   } | 
| 573 | 591 | 
| 574   int lastCategory = NONE; | 592   int lastCategory = NONE; | 
| 575   String lastToken = null; | 593   String lastToken = null; | 
| 576   int lastPosition = 0; | 594   int lastPosition = 0; | 
| 577   int position = 0; | 595   int position = 0; | 
| 578   bool skippedNewline = false;  // skipped newline in last getToken? | 596   bool skippedNewline = false; // skipped newline in last getToken? | 
| 579   final String src; | 597   final String src; | 
| 580 | 598 | 
| 581   final List<InterpolatedNode> interpolatedValues = <InterpolatedNode>[]; | 599   final List<InterpolatedNode> interpolatedValues = <InterpolatedNode>[]; | 
| 582   bool get hasNamedHoles => | 600   bool get hasNamedHoles => | 
| 583       interpolatedValues.isNotEmpty && interpolatedValues.first.isNamed; | 601       interpolatedValues.isNotEmpty && interpolatedValues.first.isNamed; | 
| 584   bool get hasPositionalHoles => | 602   bool get hasPositionalHoles => | 
| 585       interpolatedValues.isNotEmpty && interpolatedValues.first.isPositional; | 603       interpolatedValues.isNotEmpty && interpolatedValues.first.isPositional; | 
| 586 | 604 | 
| 587   static const NONE = -1; | 605   static const NONE = -1; | 
| 588   static const ALPHA = 0; | 606   static const ALPHA = 0; | 
| (...skipping 14 matching lines...) Expand all  Loading... | 
| 603   static const SEMICOLON = 15; | 621   static const SEMICOLON = 15; | 
| 604   static const HASH = 16; | 622   static const HASH = 16; | 
| 605   static const WHITESPACE = 17; | 623   static const WHITESPACE = 17; | 
| 606   static const OTHER = 18; | 624   static const OTHER = 18; | 
| 607 | 625 | 
| 608   // Make sure that ]] is two symbols. | 626   // Make sure that ]] is two symbols. | 
| 609   bool singleCharCategory(int category) => category >= DOT; | 627   bool singleCharCategory(int category) => category >= DOT; | 
| 610 | 628 | 
| 611   static String categoryToString(int cat) { | 629   static String categoryToString(int cat) { | 
| 612     switch (cat) { | 630     switch (cat) { | 
| 613       case NONE: return "NONE"; | 631       case NONE: | 
| 614       case ALPHA: return "ALPHA"; | 632         return "NONE"; | 
| 615       case NUMERIC: return "NUMERIC"; | 633       case ALPHA: | 
| 616       case SYMBOL: return "SYMBOL"; | 634         return "ALPHA"; | 
| 617       case ASSIGNMENT: return "ASSIGNMENT"; | 635       case NUMERIC: | 
| 618       case DOT: return "DOT"; | 636         return "NUMERIC"; | 
| 619       case LPAREN: return "LPAREN"; | 637       case SYMBOL: | 
| 620       case RPAREN: return "RPAREN"; | 638         return "SYMBOL"; | 
| 621       case LBRACE: return "LBRACE"; | 639       case ASSIGNMENT: | 
| 622       case RBRACE: return "RBRACE"; | 640         return "ASSIGNMENT"; | 
| 623       case LSQUARE: return "LSQUARE"; | 641       case DOT: | 
| 624       case RSQUARE: return "RSQUARE"; | 642         return "DOT"; | 
| 625       case STRING: return "STRING"; | 643       case LPAREN: | 
| 626       case COMMA: return "COMMA"; | 644         return "LPAREN"; | 
| 627       case QUERY: return "QUERY"; | 645       case RPAREN: | 
| 628       case COLON: return "COLON"; | 646         return "RPAREN"; | 
| 629       case SEMICOLON: return "SEMICOLON"; | 647       case LBRACE: | 
| 630       case HASH: return "HASH"; | 648         return "LBRACE"; | 
| 631       case WHITESPACE: return "WHITESPACE"; | 649       case RBRACE: | 
| 632       case OTHER: return "OTHER"; | 650         return "RBRACE"; | 
|  | 651       case LSQUARE: | 
|  | 652         return "LSQUARE"; | 
|  | 653       case RSQUARE: | 
|  | 654         return "RSQUARE"; | 
|  | 655       case STRING: | 
|  | 656         return "STRING"; | 
|  | 657       case COMMA: | 
|  | 658         return "COMMA"; | 
|  | 659       case QUERY: | 
|  | 660         return "QUERY"; | 
|  | 661       case COLON: | 
|  | 662         return "COLON"; | 
|  | 663       case SEMICOLON: | 
|  | 664         return "SEMICOLON"; | 
|  | 665       case HASH: | 
|  | 666         return "HASH"; | 
|  | 667       case WHITESPACE: | 
|  | 668         return "WHITESPACE"; | 
|  | 669       case OTHER: | 
|  | 670         return "OTHER"; | 
| 633     } | 671     } | 
| 634     return "Unknown: $cat"; | 672     return "Unknown: $cat"; | 
| 635   } | 673   } | 
| 636 | 674 | 
| 637   static const CATEGORIES = const <int>[ | 675   static const CATEGORIES = const <int>[ | 
| 638       OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,       // 0-7 | 676     OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 0-7 | 
| 639       OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE,      // 8-13 | 677     OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE, // 8-13 | 
| 640       OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,       // 14-21 | 678     OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 14-21 | 
| 641       OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER,       // 22-29 | 679     OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 22-29 | 
| 642       OTHER, OTHER, WHITESPACE,                                     // 30-32 | 680     OTHER, OTHER, WHITESPACE, // 30-32 | 
| 643       SYMBOL, OTHER, HASH, ALPHA, SYMBOL, SYMBOL, OTHER,            // !"#$%&´ | 681     SYMBOL, OTHER, HASH, ALPHA, SYMBOL, SYMBOL, OTHER, // !"#$%&´ | 
| 644       LPAREN, RPAREN, SYMBOL, SYMBOL, COMMA, SYMBOL, DOT, SYMBOL,   // ()*+,-./ | 682     LPAREN, RPAREN, SYMBOL, SYMBOL, COMMA, SYMBOL, DOT, SYMBOL, // ()*+,-./ | 
| 645       NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC,                  // 01234 | 683     NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, // 01234 | 
| 646       NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC,                  // 56789 | 684     NUMERIC, NUMERIC, NUMERIC, NUMERIC, NUMERIC, // 56789 | 
| 647       COLON, SEMICOLON, SYMBOL, SYMBOL, SYMBOL, QUERY, OTHER,       // :;<=>?@ | 685     COLON, SEMICOLON, SYMBOL, SYMBOL, SYMBOL, QUERY, OTHER, // :;<=>?@ | 
| 648       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // ABCDEFGH | 686     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // ABCDEFGH | 
| 649       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // IJKLMNOP | 687     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // IJKLMNOP | 
| 650       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // QRSTUVWX | 688     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // QRSTUVWX | 
| 651       ALPHA, ALPHA, LSQUARE, OTHER, RSQUARE, SYMBOL, ALPHA, OTHER,  // YZ[\]^_' | 689     ALPHA, ALPHA, LSQUARE, OTHER, RSQUARE, SYMBOL, ALPHA, OTHER, // YZ[\]^_' | 
| 652       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // abcdefgh | 690     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // abcdefgh | 
| 653       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // ijklmnop | 691     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // ijklmnop | 
| 654       ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA,       // qrstuvwx | 692     ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, ALPHA, // qrstuvwx | 
| 655       ALPHA, ALPHA, LBRACE, SYMBOL, RBRACE, SYMBOL];                // yz{|}~ | 693     ALPHA, ALPHA, LBRACE, SYMBOL, RBRACE, SYMBOL | 
|  | 694   ]; // yz{|}~ | 
| 656 | 695 | 
| 657   // This must be a >= the highest precedence number handled by parseBinary. | 696   // This must be a >= the highest precedence number handled by parseBinary. | 
| 658   static var HIGHEST_PARSE_BINARY_PRECEDENCE = 16; | 697   static var HIGHEST_PARSE_BINARY_PRECEDENCE = 16; | 
| 659   static bool isAssignment(String symbol) => BINARY_PRECEDENCE[symbol] == 17; | 698   static bool isAssignment(String symbol) => BINARY_PRECEDENCE[symbol] == 17; | 
| 660 | 699 | 
| 661   // From https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operator
      s/Operator_Precedence | 700   // From https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operator
      s/Operator_Precedence | 
| 662   static final BINARY_PRECEDENCE = { | 701   static final BINARY_PRECEDENCE = { | 
| 663       '+=': 17, '-=': 17, '*=': 17, '/=': 17, '%=': 17, '^=': 17, '|=': 17, | 702     '+=': 17, | 
| 664       '&=': 17, '<<=': 17, '>>=': 17, '>>>=': 17, '=': 17, | 703     '-=': 17, | 
| 665       '||': 14, | 704     '*=': 17, | 
| 666       '&&': 13, | 705     '/=': 17, | 
| 667       '|': 12, | 706     '%=': 17, | 
| 668       '^': 11, | 707     '^=': 17, | 
| 669       '&': 10, | 708     '|=': 17, | 
| 670       '!=': 9, '==': 9, '!==': 9, '===': 9, | 709     '&=': 17, | 
| 671       '<': 8, '<=': 8, '>=': 8, '>': 8, 'in': 8, 'instanceof': 8, | 710     '<<=': 17, | 
| 672       '<<': 7, '>>': 7, '>>>': 7, | 711     '>>=': 17, | 
| 673       '+': 6, '-': 6, | 712     '>>>=': 17, | 
| 674       '*': 5, '/': 5, '%': 5 | 713     '=': 17, | 
|  | 714     '||': 14, | 
|  | 715     '&&': 13, | 
|  | 716     '|': 12, | 
|  | 717     '^': 11, | 
|  | 718     '&': 10, | 
|  | 719     '!=': 9, | 
|  | 720     '==': 9, | 
|  | 721     '!==': 9, | 
|  | 722     '===': 9, | 
|  | 723     '<': 8, | 
|  | 724     '<=': 8, | 
|  | 725     '>=': 8, | 
|  | 726     '>': 8, | 
|  | 727     'in': 8, | 
|  | 728     'instanceof': 8, | 
|  | 729     '<<': 7, | 
|  | 730     '>>': 7, | 
|  | 731     '>>>': 7, | 
|  | 732     '+': 6, | 
|  | 733     '-': 6, | 
|  | 734     '*': 5, | 
|  | 735     '/': 5, | 
|  | 736     '%': 5 | 
| 675   }; | 737   }; | 
| 676   static final UNARY_OPERATORS = | 738   static final UNARY_OPERATORS = [ | 
| 677       ['++', '--', '+', '-', '~', '!', 'typeof', 'void', 'delete', 'await'] | 739     '++', | 
| 678         .toSet(); | 740     '--', | 
|  | 741     '+', | 
|  | 742     '-', | 
|  | 743     '~', | 
|  | 744     '!', | 
|  | 745     'typeof', | 
|  | 746     'void', | 
|  | 747     'delete', | 
|  | 748     'await' | 
|  | 749   ].toSet(); | 
| 679 | 750 | 
| 680   static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS = | 751   static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS = | 
| 681       ['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet(); | 752       ['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet(); | 
| 682 | 753 | 
| 683   static int category(int code) { | 754   static int category(int code) { | 
| 684     if (code >= CATEGORIES.length) return OTHER; | 755     if (code >= CATEGORIES.length) return OTHER; | 
| 685     return CATEGORIES[code]; | 756     return CATEGORIES[code]; | 
| 686   } | 757   } | 
| 687 | 758 | 
| 688   String getDelimited(int startPosition) { | 759   String getDelimited(int startPosition) { | 
| 689     position = startPosition; | 760     position = startPosition; | 
| 690     int delimiter = src.codeUnitAt(startPosition); | 761     int delimiter = src.codeUnitAt(startPosition); | 
| 691     int currentCode; | 762     int currentCode; | 
| 692     do { | 763     do { | 
| 693       position++; | 764       position++; | 
| 694       if (position >= src.length) error("Unterminated literal"); | 765       if (position >= src.length) error("Unterminated literal"); | 
| 695       currentCode = src.codeUnitAt(position); | 766       currentCode = src.codeUnitAt(position); | 
| 696       if (currentCode == charCodes.$LF) error("Unterminated literal"); | 767       if (currentCode == charCodes.$LF) error("Unterminated literal"); | 
| 697       if (currentCode == charCodes.$BACKSLASH) { | 768       if (currentCode == charCodes.$BACKSLASH) { | 
| 698         if (++position >= src.length) error("Unterminated literal"); | 769         if (++position >= src.length) error("Unterminated literal"); | 
| 699         int escaped = src.codeUnitAt(position); | 770         int escaped = src.codeUnitAt(position); | 
| 700         if (escaped == charCodes.$x || escaped == charCodes.$X || | 771         if (escaped == charCodes.$x || | 
| 701             escaped == charCodes.$u || escaped == charCodes.$U || | 772             escaped == charCodes.$X || | 
|  | 773             escaped == charCodes.$u || | 
|  | 774             escaped == charCodes.$U || | 
| 702             category(escaped) == NUMERIC) { | 775             category(escaped) == NUMERIC) { | 
| 703           error('Numeric and hex escapes are not allowed in literals'); | 776           error('Numeric and hex escapes are not allowed in literals'); | 
| 704         } | 777         } | 
| 705       } | 778       } | 
| 706     } while (currentCode != delimiter); | 779     } while (currentCode != delimiter); | 
| 707     position++; | 780     position++; | 
| 708     return src.substring(lastPosition, position); | 781     return src.substring(lastPosition, position); | 
| 709   } | 782   } | 
| 710 | 783 | 
| 711   void getToken() { | 784   void getToken() { | 
| 712     skippedNewline = false; | 785     skippedNewline = false; | 
| 713     for (;;) { | 786     for (;;) { | 
| 714       if (position >= src.length) break; | 787       if (position >= src.length) break; | 
| 715       int code = src.codeUnitAt(position); | 788       int code = src.codeUnitAt(position); | 
| 716       //  Skip '//' and '/*' style comments. | 789       //  Skip '//' and '/*' style comments. | 
| 717       if (code == charCodes.$SLASH && | 790       if (code == charCodes.$SLASH && position + 1 < src.length) { | 
| 718           position + 1 < src.length) { |  | 
| 719         if (src.codeUnitAt(position + 1) == charCodes.$SLASH) { | 791         if (src.codeUnitAt(position + 1) == charCodes.$SLASH) { | 
| 720           int nextPosition = src.indexOf('\n', position); | 792           int nextPosition = src.indexOf('\n', position); | 
| 721           if (nextPosition == -1) nextPosition = src.length; | 793           if (nextPosition == -1) nextPosition = src.length; | 
| 722           position = nextPosition; | 794           position = nextPosition; | 
| 723           continue; | 795           continue; | 
| 724         } else if (src.codeUnitAt(position + 1) == charCodes.$STAR) { | 796         } else if (src.codeUnitAt(position + 1) == charCodes.$STAR) { | 
| 725           int nextPosition = src.indexOf('*/', position + 2); | 797           int nextPosition = src.indexOf('*/', position + 2); | 
| 726           if (nextPosition == -1) error('Unterminated comment'); | 798           if (nextPosition == -1) error('Unterminated comment'); | 
| 727           position = nextPosition + 2; | 799           position = nextPosition + 2; | 
| 728           continue; | 800           continue; | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 739       lastPosition = position; | 811       lastPosition = position; | 
| 740       return; | 812       return; | 
| 741     } | 813     } | 
| 742     int code = src.codeUnitAt(position); | 814     int code = src.codeUnitAt(position); | 
| 743     lastPosition = position; | 815     lastPosition = position; | 
| 744     if (code == charCodes.$SQ || code == charCodes.$DQ) { | 816     if (code == charCodes.$SQ || code == charCodes.$DQ) { | 
| 745       // String literal. | 817       // String literal. | 
| 746       lastCategory = STRING; | 818       lastCategory = STRING; | 
| 747       lastToken = getDelimited(position); | 819       lastToken = getDelimited(position); | 
| 748     } else if (code == charCodes.$0 && | 820     } else if (code == charCodes.$0 && | 
| 749                position + 2 < src.length && | 821         position + 2 < src.length && | 
| 750                src.codeUnitAt(position + 1) == charCodes.$x) { | 822         src.codeUnitAt(position + 1) == charCodes.$x) { | 
| 751       // Hex literal. | 823       // Hex literal. | 
| 752       for (position += 2; position < src.length; position++) { | 824       for (position += 2; position < src.length; position++) { | 
| 753         int cat = category(src.codeUnitAt(position)); | 825         int cat = category(src.codeUnitAt(position)); | 
| 754         if (cat != NUMERIC && cat != ALPHA) break; | 826         if (cat != NUMERIC && cat != ALPHA) break; | 
| 755       } | 827       } | 
| 756       lastCategory = NUMERIC; | 828       lastCategory = NUMERIC; | 
| 757       lastToken = src.substring(lastPosition, position); | 829       lastToken = src.substring(lastPosition, position); | 
| 758       int.parse(lastToken, onError: (_) { | 830       int.parse(lastToken, onError: (_) { | 
| 759         error("Unparseable number"); | 831         error("Unparseable number"); | 
| 760       }); | 832       }); | 
| 761     } else if (code == charCodes.$SLASH) { | 833     } else if (code == charCodes.$SLASH) { | 
| 762       // Tokens that start with / are special due to regexp literals. | 834       // Tokens that start with / are special due to regexp literals. | 
| 763       lastCategory = SYMBOL; | 835       lastCategory = SYMBOL; | 
| 764       position++; | 836       position++; | 
| 765       if (position < src.length && src.codeUnitAt(position) == charCodes.$EQ) { | 837       if (position < src.length && src.codeUnitAt(position) == charCodes.$EQ) { | 
| 766         position++; | 838         position++; | 
| 767       } | 839       } | 
| 768       lastToken = src.substring(lastPosition, position); | 840       lastToken = src.substring(lastPosition, position); | 
| 769     } else { | 841     } else { | 
| 770       // All other tokens handled here. | 842       // All other tokens handled here. | 
| 771       int cat = category(src.codeUnitAt(position)); | 843       int cat = category(src.codeUnitAt(position)); | 
| 772       int newCat; | 844       int newCat; | 
| 773       do { | 845       do { | 
| 774         position++; | 846         position++; | 
| 775         if (position == src.length) break; | 847         if (position == src.length) break; | 
| 776         int code = src.codeUnitAt(position); | 848         int code = src.codeUnitAt(position); | 
| 777         // Special code to disallow !, ~ and / in non-first position in token, | 849         // Special code to disallow !, ~ and / in non-first position in token, | 
| 778         // so that !! and ~~ parse as two tokens and != parses as one, while =/ | 850         // so that !! and ~~ parse as two tokens and != parses as one, while =/ | 
| 779         // parses as a an equals token followed by a regexp literal start. | 851         // parses as a an equals token followed by a regexp literal start. | 
| 780         newCat = | 852         newCat = (code == charCodes.$BANG || | 
| 781             (code == charCodes.$BANG || | 853                 code == charCodes.$SLASH || | 
| 782              code == charCodes.$SLASH || | 854                 code == charCodes.$TILDE) | 
| 783              code == charCodes.$TILDE) |  | 
| 784             ? NONE | 855             ? NONE | 
| 785             : category(code); | 856             : category(code); | 
| 786       } while (!singleCharCategory(cat) && | 857       } while (!singleCharCategory(cat) && | 
| 787                (cat == newCat || | 858           (cat == newCat || | 
| 788                 (cat == ALPHA && newCat == NUMERIC) ||    // eg. level42. | 859               (cat == ALPHA && newCat == NUMERIC) || // eg. level42. | 
| 789                 (cat == NUMERIC && newCat == DOT)));      // eg. 3.1415 | 860               (cat == NUMERIC && newCat == DOT))); // eg. 3.1415 | 
| 790       lastCategory = cat; | 861       lastCategory = cat; | 
| 791       lastToken = src.substring(lastPosition, position); | 862       lastToken = src.substring(lastPosition, position); | 
| 792       if (cat == NUMERIC) { | 863       if (cat == NUMERIC) { | 
| 793         double.parse(lastToken, (_) { | 864         double.parse(lastToken, (_) { | 
| 794           error("Unparseable number"); | 865           error("Unparseable number"); | 
| 795         }); | 866         }); | 
| 796       } else if (cat == SYMBOL) { | 867       } else if (cat == SYMBOL) { | 
| 797         int binaryPrecendence = BINARY_PRECEDENCE[lastToken]; | 868         int binaryPrecendence = BINARY_PRECEDENCE[lastToken]; | 
| 798         if (binaryPrecendence == null && !UNARY_OPERATORS.contains(lastToken)) { | 869         if (binaryPrecendence == null && !UNARY_OPERATORS.contains(lastToken)) { | 
| 799           error("Unknown operator"); | 870           error("Unknown operator"); | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
| 822 | 893 | 
| 823   void expectSemicolon() { | 894   void expectSemicolon() { | 
| 824     if (acceptSemicolon()) return; | 895     if (acceptSemicolon()) return; | 
| 825     error('Expected SEMICOLON'); | 896     error('Expected SEMICOLON'); | 
| 826   } | 897   } | 
| 827 | 898 | 
| 828   bool acceptSemicolon() { | 899   bool acceptSemicolon() { | 
| 829     // Accept semicolon or automatically inserted semicolon before close brace. | 900     // Accept semicolon or automatically inserted semicolon before close brace. | 
| 830     // Miniparser forbids other kinds of semicolon insertion. | 901     // Miniparser forbids other kinds of semicolon insertion. | 
| 831     if (RBRACE == lastCategory) return true; | 902     if (RBRACE == lastCategory) return true; | 
| 832     if (NONE == lastCategory) return true;  // end of input | 903     if (NONE == lastCategory) return true; // end of input | 
| 833     if (skippedNewline) { | 904     if (skippedNewline) { | 
| 834       error('No automatic semicolon insertion at preceding newline'); | 905       error('No automatic semicolon insertion at preceding newline'); | 
| 835     } | 906     } | 
| 836     return acceptCategory(SEMICOLON); | 907     return acceptCategory(SEMICOLON); | 
| 837   } | 908   } | 
| 838 | 909 | 
| 839   bool acceptString(String string) { | 910   bool acceptString(String string) { | 
| 840     if (lastToken == string) { | 911     if (lastToken == string) { | 
| 841       getToken(); | 912       getToken(); | 
| 842       return true; | 913       return true; | 
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 977     List<Property> properties = <Property>[]; | 1048     List<Property> properties = <Property>[]; | 
| 978     for (;;) { | 1049     for (;;) { | 
| 979       if (acceptCategory(RBRACE)) break; | 1050       if (acceptCategory(RBRACE)) break; | 
| 980       // Limited subset: keys are identifiers, no 'get' or 'set' properties. | 1051       // Limited subset: keys are identifiers, no 'get' or 'set' properties. | 
| 981       Literal propertyName; | 1052       Literal propertyName; | 
| 982       String identifier = lastToken; | 1053       String identifier = lastToken; | 
| 983       if (acceptCategory(ALPHA)) { | 1054       if (acceptCategory(ALPHA)) { | 
| 984         propertyName = new LiteralString('"$identifier"'); | 1055         propertyName = new LiteralString('"$identifier"'); | 
| 985       } else if (acceptCategory(STRING)) { | 1056       } else if (acceptCategory(STRING)) { | 
| 986         propertyName = new LiteralString(identifier); | 1057         propertyName = new LiteralString(identifier); | 
| 987       } else if (acceptCategory(SYMBOL)) {  // e.g. void | 1058       } else if (acceptCategory(SYMBOL)) { | 
|  | 1059         // e.g. void | 
| 988         propertyName = new LiteralString('"$identifier"'); | 1060         propertyName = new LiteralString('"$identifier"'); | 
| 989       } else if (acceptCategory(HASH)) { | 1061       } else if (acceptCategory(HASH)) { | 
| 990         var nameOrPosition = parseHash(); | 1062         var nameOrPosition = parseHash(); | 
| 991         InterpolatedLiteral interpolatedLiteral = | 1063         InterpolatedLiteral interpolatedLiteral = | 
| 992             new InterpolatedLiteral(nameOrPosition); | 1064             new InterpolatedLiteral(nameOrPosition); | 
| 993         interpolatedValues.add(interpolatedLiteral); | 1065         interpolatedValues.add(interpolatedLiteral); | 
| 994         propertyName = interpolatedLiteral; | 1066         propertyName = interpolatedLiteral; | 
| 995       } else { | 1067       } else { | 
| 996         error('Expected property name'); | 1068         error('Expected property name'); | 
| 997       } | 1069       } | 
| (...skipping 29 matching lines...) Expand all  Loading... | 
| 1027       if (acceptCategory(LPAREN)) { | 1099       if (acceptCategory(LPAREN)) { | 
| 1028         final arguments = <Expression>[]; | 1100         final arguments = <Expression>[]; | 
| 1029         if (!acceptCategory(RPAREN)) { | 1101         if (!acceptCategory(RPAREN)) { | 
| 1030           while (true) { | 1102           while (true) { | 
| 1031             Expression argument = parseAssignment(); | 1103             Expression argument = parseAssignment(); | 
| 1032             arguments.add(argument); | 1104             arguments.add(argument); | 
| 1033             if (acceptCategory(RPAREN)) break; | 1105             if (acceptCategory(RPAREN)) break; | 
| 1034             expectCategory(COMMA); | 1106             expectCategory(COMMA); | 
| 1035           } | 1107           } | 
| 1036         } | 1108         } | 
| 1037         receiver = constructor ? | 1109         receiver = constructor | 
| 1038                new New(receiver, arguments) : | 1110             ? new New(receiver, arguments) | 
| 1039                new Call(receiver, arguments); | 1111             : new Call(receiver, arguments); | 
| 1040         constructor = false; | 1112         constructor = false; | 
| 1041       } else if (!constructor && acceptCategory(LSQUARE)) { | 1113       } else if (!constructor && acceptCategory(LSQUARE)) { | 
| 1042         Expression inBraces = parseExpression(); | 1114         Expression inBraces = parseExpression(); | 
| 1043         expectCategory(RSQUARE); | 1115         expectCategory(RSQUARE); | 
| 1044         receiver = new PropertyAccess(receiver, inBraces); | 1116         receiver = new PropertyAccess(receiver, inBraces); | 
| 1045       } else if (!constructor && acceptCategory(DOT)) { | 1117       } else if (!constructor && acceptCategory(DOT)) { | 
| 1046         receiver = getDotRhs(receiver); | 1118         receiver = getDotRhs(receiver); | 
| 1047       } else { | 1119       } else { | 
| 1048         // JS allows new without (), but we don't. | 1120         // JS allows new without (), but we don't. | 
| 1049         if (constructor) error("Parentheses are required for new"); | 1121         if (constructor) error("Parentheses are required for new"); | 
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1084       return new Postfix(operator, expression); | 1156       return new Postfix(operator, expression); | 
| 1085     } | 1157     } | 
| 1086     // If we don't accept '++' or '--' due to skippedNewline a newline, no other | 1158     // If we don't accept '++' or '--' due to skippedNewline a newline, no other | 
| 1087     // part of the parser will accept the token and we will get an error at the | 1159     // part of the parser will accept the token and we will get an error at the | 
| 1088     // whole expression level. | 1160     // whole expression level. | 
| 1089     return expression; | 1161     return expression; | 
| 1090   } | 1162   } | 
| 1091 | 1163 | 
| 1092   Expression parseUnaryHigh() { | 1164   Expression parseUnaryHigh() { | 
| 1093     String operator = lastToken; | 1165     String operator = lastToken; | 
| 1094     if (lastCategory == SYMBOL && UNARY_OPERATORS.contains(operator) && | 1166     if (lastCategory == SYMBOL && | 
|  | 1167         UNARY_OPERATORS.contains(operator) && | 
| 1095         (acceptString("++") || acceptString("--") || acceptString('await'))) { | 1168         (acceptString("++") || acceptString("--") || acceptString('await'))) { | 
| 1096       if (operator == "await") return new Await(parsePostfix()); | 1169       if (operator == "await") return new Await(parsePostfix()); | 
| 1097       return new Prefix(operator, parsePostfix()); | 1170       return new Prefix(operator, parsePostfix()); | 
| 1098     } | 1171     } | 
| 1099     return parsePostfix(); | 1172     return parsePostfix(); | 
| 1100   } | 1173   } | 
| 1101 | 1174 | 
| 1102   Expression parseUnaryLow() { | 1175   Expression parseUnaryLow() { | 
| 1103     String operator = lastToken; | 1176     String operator = lastToken; | 
| 1104     if (lastCategory == SYMBOL && UNARY_OPERATORS.contains(operator) && | 1177     if (lastCategory == SYMBOL && | 
| 1105         operator != "++" && operator != "--") { | 1178         UNARY_OPERATORS.contains(operator) && | 
|  | 1179         operator != "++" && | 
|  | 1180         operator != "--") { | 
| 1106       expectCategory(SYMBOL); | 1181       expectCategory(SYMBOL); | 
| 1107       if (operator == "await") return new Await(parsePostfix()); | 1182       if (operator == "await") return new Await(parsePostfix()); | 
| 1108       return new Prefix(operator, parseUnaryLow()); | 1183       return new Prefix(operator, parseUnaryLow()); | 
| 1109     } | 1184     } | 
| 1110     return parseUnaryHigh(); | 1185     return parseUnaryHigh(); | 
| 1111   } | 1186   } | 
| 1112 | 1187 | 
| 1113   Expression parseBinary(int maxPrecedence) { | 1188   Expression parseBinary(int maxPrecedence) { | 
| 1114     Expression lhs = parseUnaryLow(); | 1189     Expression lhs = parseUnaryLow(); | 
| 1115     int minPrecedence; | 1190     int minPrecedence; | 
| 1116     String lastSymbol; | 1191     String lastSymbol; | 
| 1117     Expression rhs;  // This is null first time around. | 1192     Expression rhs; // This is null first time around. | 
| 1118     while (true) { | 1193     while (true) { | 
| 1119       String symbol = lastToken; | 1194       String symbol = lastToken; | 
| 1120       if (lastCategory != SYMBOL || | 1195       if (lastCategory != SYMBOL || | 
| 1121           !BINARY_PRECEDENCE.containsKey(symbol) || | 1196           !BINARY_PRECEDENCE.containsKey(symbol) || | 
| 1122           BINARY_PRECEDENCE[symbol] > maxPrecedence) { | 1197           BINARY_PRECEDENCE[symbol] > maxPrecedence) { | 
| 1123         break; | 1198         break; | 
| 1124       } | 1199       } | 
| 1125       expectCategory(SYMBOL); | 1200       expectCategory(SYMBOL); | 
| 1126       if (rhs == null || BINARY_PRECEDENCE[symbol] >= minPrecedence) { | 1201       if (rhs == null || BINARY_PRECEDENCE[symbol] >= minPrecedence) { | 
| 1127         if (rhs != null) lhs = new Binary(lastSymbol, lhs, rhs); | 1202         if (rhs != null) lhs = new Binary(lastSymbol, lhs, rhs); | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 1139 | 1214 | 
| 1140   Expression parseConditional() { | 1215   Expression parseConditional() { | 
| 1141     Expression lhs = parseBinary(HIGHEST_PARSE_BINARY_PRECEDENCE); | 1216     Expression lhs = parseBinary(HIGHEST_PARSE_BINARY_PRECEDENCE); | 
| 1142     if (!acceptCategory(QUERY)) return lhs; | 1217     if (!acceptCategory(QUERY)) return lhs; | 
| 1143     Expression ifTrue = parseAssignment(); | 1218     Expression ifTrue = parseAssignment(); | 
| 1144     expectCategory(COLON); | 1219     expectCategory(COLON); | 
| 1145     Expression ifFalse = parseAssignment(); | 1220     Expression ifFalse = parseAssignment(); | 
| 1146     return new Conditional(lhs, ifTrue, ifFalse); | 1221     return new Conditional(lhs, ifTrue, ifFalse); | 
| 1147   } | 1222   } | 
| 1148 | 1223 | 
| 1149 |  | 
| 1150   Expression parseAssignment() { | 1224   Expression parseAssignment() { | 
| 1151     Expression lhs = parseConditional(); | 1225     Expression lhs = parseConditional(); | 
| 1152     String assignmentOperator = lastToken; | 1226     String assignmentOperator = lastToken; | 
| 1153     if (acceptCategory(ASSIGNMENT)) { | 1227     if (acceptCategory(ASSIGNMENT)) { | 
| 1154       Expression rhs = parseAssignment(); | 1228       Expression rhs = parseAssignment(); | 
| 1155       if (assignmentOperator == "=") { | 1229       if (assignmentOperator == "=") { | 
| 1156         return new Assignment(lhs, rhs); | 1230         return new Assignment(lhs, rhs); | 
| 1157       } else  { | 1231       } else { | 
| 1158         // Handle +=, -=, etc. | 1232         // Handle +=, -=, etc. | 
| 1159         String operator = | 1233         String operator = | 
| 1160             assignmentOperator.substring(0, assignmentOperator.length - 1); | 1234             assignmentOperator.substring(0, assignmentOperator.length - 1); | 
| 1161         return new Assignment.compound(lhs, operator, rhs); | 1235         return new Assignment.compound(lhs, operator, rhs); | 
| 1162       } | 1236       } | 
| 1163     } | 1237     } | 
| 1164     return lhs; | 1238     return lhs; | 
| 1165   } | 1239   } | 
| 1166 | 1240 | 
| 1167   Expression parseExpression() { | 1241   Expression parseExpression() { | 
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1273 | 1347 | 
| 1274       if (lastToken == 'case') error("Case outside switch."); | 1348       if (lastToken == 'case') error("Case outside switch."); | 
| 1275 | 1349 | 
| 1276       if (lastToken == 'default') error("Default outside switch."); | 1350       if (lastToken == 'default') error("Default outside switch."); | 
| 1277 | 1351 | 
| 1278       if (lastToken == 'yield') return parseYield(); | 1352       if (lastToken == 'yield') return parseYield(); | 
| 1279 | 1353 | 
| 1280       if (lastToken == 'with') { | 1354       if (lastToken == 'with') { | 
| 1281         error('Not implemented in mini parser'); | 1355         error('Not implemented in mini parser'); | 
| 1282       } | 1356       } | 
| 1283 |  | 
| 1284     } | 1357     } | 
| 1285 | 1358 | 
| 1286     bool checkForInterpolatedStatement = lastCategory == HASH; | 1359     bool checkForInterpolatedStatement = lastCategory == HASH; | 
| 1287 | 1360 | 
| 1288     Expression expression = parseExpression(); | 1361     Expression expression = parseExpression(); | 
| 1289 | 1362 | 
| 1290     if (expression is VariableUse && acceptCategory(COLON)) { | 1363     if (expression is VariableUse && acceptCategory(COLON)) { | 
| 1291       return new LabeledStatement(expression.name, parseStatement()); | 1364       return new LabeledStatement(expression.name, parseStatement()); | 
| 1292     } | 1365     } | 
| 1293 | 1366 | 
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1380       return finishFor(null); | 1453       return finishFor(null); | 
| 1381     } | 1454     } | 
| 1382 | 1455 | 
| 1383     if (acceptString('var')) { | 1456     if (acceptString('var')) { | 
| 1384       Declaration declaration = parseVariableDeclaration(); | 1457       Declaration declaration = parseVariableDeclaration(); | 
| 1385       if (acceptString('in')) { | 1458       if (acceptString('in')) { | 
| 1386         Expression objectExpression = parseExpression(); | 1459         Expression objectExpression = parseExpression(); | 
| 1387         expectCategory(RPAREN); | 1460         expectCategory(RPAREN); | 
| 1388         Statement body = parseStatement(); | 1461         Statement body = parseStatement(); | 
| 1389         return new ForIn( | 1462         return new ForIn( | 
| 1390             new VariableDeclarationList([ | 1463             new VariableDeclarationList( | 
| 1391                 new VariableInitialization(declaration, null)]), | 1464                 [new VariableInitialization(declaration, null)]), | 
| 1392             objectExpression, | 1465             objectExpression, | 
| 1393             body); | 1466             body); | 
| 1394       } | 1467       } | 
| 1395       Expression declarations = finishVariableDeclarationList(declaration); | 1468       Expression declarations = finishVariableDeclarationList(declaration); | 
| 1396       expectCategory(SEMICOLON); | 1469       expectCategory(SEMICOLON); | 
| 1397       return finishFor(declarations); | 1470       return finishFor(declarations); | 
| 1398     } | 1471     } | 
| 1399 | 1472 | 
| 1400     Expression init = parseExpression(); | 1473     Expression init = parseExpression(); | 
| 1401     expectCategory(SEMICOLON); | 1474     expectCategory(SEMICOLON); | 
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1443       expression = parseExpression(); | 1516       expression = parseExpression(); | 
| 1444       expectCategory(COLON); | 1517       expectCategory(COLON); | 
| 1445     } else { | 1518     } else { | 
| 1446       if (!acceptString('default')) { | 1519       if (!acceptString('default')) { | 
| 1447         error('expected case or default'); | 1520         error('expected case or default'); | 
| 1448       } | 1521       } | 
| 1449       expectCategory(COLON); | 1522       expectCategory(COLON); | 
| 1450     } | 1523     } | 
| 1451     List statements = new List<Statement>(); | 1524     List statements = new List<Statement>(); | 
| 1452     while (lastCategory != RBRACE && | 1525     while (lastCategory != RBRACE && | 
| 1453            lastToken != 'case' && | 1526         lastToken != 'case' && | 
| 1454            lastToken != 'default') { | 1527         lastToken != 'default') { | 
| 1455       statements.add(parseStatement()); | 1528       statements.add(parseStatement()); | 
| 1456     } | 1529     } | 
| 1457     return expression == null | 1530     return expression == null | 
| 1458         ? new Default(new Block(statements)) | 1531         ? new Default(new Block(statements)) | 
| 1459         : new Case(expression, new Block(statements)); | 1532         : new Case(expression, new Block(statements)); | 
| 1460   } | 1533   } | 
| 1461 | 1534 | 
| 1462   Statement parseWhile() { | 1535   Statement parseWhile() { | 
| 1463     expectCategory(LPAREN); | 1536     expectCategory(LPAREN); | 
| 1464     Expression condition = parseExpression(); | 1537     Expression condition = parseExpression(); | 
| (...skipping 12 matching lines...) Expand all  Loading... | 
| 1477     expectSemicolon(); | 1550     expectSemicolon(); | 
| 1478     return new Do(body, condition); | 1551     return new Do(body, condition); | 
| 1479   } | 1552   } | 
| 1480 | 1553 | 
| 1481   Statement parseSwitch() { | 1554   Statement parseSwitch() { | 
| 1482     expectCategory(LPAREN); | 1555     expectCategory(LPAREN); | 
| 1483     Expression key = parseExpression(); | 1556     Expression key = parseExpression(); | 
| 1484     expectCategory(RPAREN); | 1557     expectCategory(RPAREN); | 
| 1485     expectCategory(LBRACE); | 1558     expectCategory(LBRACE); | 
| 1486     List<SwitchClause> clauses = new List<SwitchClause>(); | 1559     List<SwitchClause> clauses = new List<SwitchClause>(); | 
| 1487     while(lastCategory != RBRACE) { | 1560     while (lastCategory != RBRACE) { | 
| 1488       clauses.add(parseSwitchClause()); | 1561       clauses.add(parseSwitchClause()); | 
| 1489     } | 1562     } | 
| 1490     expectCategory(RBRACE); | 1563     expectCategory(RBRACE); | 
| 1491     return new Switch(key, clauses); | 1564     return new Switch(key, clauses); | 
| 1492   } | 1565   } | 
| 1493 | 1566 | 
| 1494   Catch parseCatch() { | 1567   Catch parseCatch() { | 
| 1495     expectCategory(LPAREN); | 1568     expectCategory(LPAREN); | 
| 1496     Declaration errorName = parseVariableDeclaration(); | 1569     Declaration errorName = parseVariableDeclaration(); | 
| 1497     expectCategory(RPAREN); | 1570     expectCategory(RPAREN); | 
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 1530 class _InterleaveIterable extends IterableBase { | 1603 class _InterleaveIterable extends IterableBase { | 
| 1531   Iterable<Node> source; | 1604   Iterable<Node> source; | 
| 1532   Node separator; | 1605   Node separator; | 
| 1533 | 1606 | 
| 1534   _InterleaveIterable(this.source, this.separator); | 1607   _InterleaveIterable(this.source, this.separator); | 
| 1535 | 1608 | 
| 1536   Iterator<Node> get iterator { | 1609   Iterator<Node> get iterator { | 
| 1537     return new _InterleaveIterator(source.iterator, separator); | 1610     return new _InterleaveIterator(source.iterator, separator); | 
| 1538   } | 1611   } | 
| 1539 } | 1612 } | 
| OLD | NEW | 
|---|