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

Side by Side Diff: lib/src/js/builder.dart

Issue 949383003: use js_ast instead of strings to generate JS (Closed) Base URL: git@github.com:dart-lang/dart-dev-compiler.git@master
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 10
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 */ 288 */
289 Template expressionTemplateYielding(Node ast) { 289 Template expressionTemplateYielding(Node ast) {
290 return new Template.withExpressionResult(ast); 290 return new Template.withExpressionResult(ast);
291 } 291 }
292 292
293 Template statementTemplateYielding(Node ast) { 293 Template statementTemplateYielding(Node ast) {
294 return new Template.withStatementResult(ast); 294 return new Template.withStatementResult(ast);
295 } 295 }
296 296
297 /// Creates a literal js string from [value]. 297 /// Creates a literal js string from [value].
298 LiteralString escapedString(String value) { 298 LiteralString escapedString(String value, [String quote = '"']) {
299 // Start by escaping the backslashes. 299 // Start by escaping the backslashes.
300 String escaped = value.replaceAll('\\', '\\\\'); 300 String escaped = value.replaceAll('\\', '\\\\');
301 // Do not escape unicode characters and ' because they are allowed in the 301 // Do not escape unicode characters and ' because they are allowed in the
302 // string literal anyway. 302 // string literal anyway.
303 escaped = escaped.replaceAllMapped(new RegExp('\n|"|\b|\t|\v'), (match) { 303 escaped = escaped.replaceAllMapped(new RegExp('\n|$quote|\b|\t|\v'), (m) {
304 switch (match.group(0)) { 304 switch (m.group(0)) {
305 case "\n" : return r"\n"; 305 case "\n" : return r"\n";
306 case "\"" : return r'\"'; 306 // Quotes are only replaced if they conflict with the containing quote
307 case '"': return r'\"';
308 case "'": return r"\'";
309 case "`": return r"\`";
307 case "\b" : return r"\b"; 310 case "\b" : return r"\b";
308 case "\t" : return r"\t"; 311 case "\t" : return r"\t";
309 case "\f" : return r"\f"; 312 case "\f" : return r"\f";
310 case "\v" : return r"\v"; 313 case "\v" : return r"\v";
311 } 314 }
312 }); 315 });
313 LiteralString result = string(escaped); 316 LiteralString result = new LiteralString('$quote$escaped$quote');
314 // We don't escape ' under the assumption that the string is wrapped 317 // We don't escape quotes of a different style under the assumption that the
315 // into ". Verify that assumption. 318 // string is wrapped into quotes. Verify that assumption.
316 assert(result.value.codeUnitAt(0) == '"'.codeUnitAt(0)); 319 assert(result.value.codeUnitAt(0) == quote.codeUnitAt(0));
317 return result; 320 return result;
318 } 321 }
319 322
320 /// Creates a literal js string from [value]. 323 /// Creates a literal js string from [value].
321 /// 324 ///
322 /// Note that this function only puts quotes around [value]. It does not do 325 /// Note that this function only puts quotes around [value]. It does not do
323 /// any escaping, so use only when you can guarantee that [value] does not 326 /// any escaping, so use only when you can guarantee that [value] does not
324 /// contain newlines or backslashes. For escaping the string use 327 /// contain newlines or backslashes. For escaping the string use
325 /// [escapedString]. 328 /// [escapedString].
326 LiteralString string(String value) => new LiteralString('"$value"'); 329 LiteralString string(String value, [String quote = '"']) =>
330 new LiteralString('$quote$value$quote');
327 331
328 LiteralNumber number(num value) => new LiteralNumber('$value'); 332 LiteralNumber number(num value) => new LiteralNumber('$value');
329 333
330 LiteralBool boolean(bool value) => new LiteralBool(value); 334 LiteralBool boolean(bool value) => new LiteralBool(value);
331 335
332 ArrayInitializer numArray(Iterable<int> list) => 336 ArrayInitializer numArray(Iterable<int> list) =>
333 new ArrayInitializer(list.map(number).toList()); 337 new ArrayInitializer(list.map(number).toList());
334 338
335 ArrayInitializer stringArray(Iterable<String> list) => 339 ArrayInitializer stringArray(Iterable<String> list) =>
336 new ArrayInitializer(list.map(string).toList()); 340 new ArrayInitializer(list.map(string).toList());
337 341
338 Comment comment(String text) => new Comment(text); 342 Comment comment(String text) => new Comment(text);
343 CommentExpression commentExpression(String text, Expression expression) =>
344 new CommentExpression(text, expression);
339 345
340 Call propertyCall(Expression receiver, 346 Call propertyCall(Expression receiver,
341 String fieldName, 347 String fieldName,
342 List<Expression> arguments) { 348 List<Expression> arguments) {
343 return new Call(new PropertyAccess.field(receiver, fieldName), arguments); 349 return new Call(new PropertyAccess.field(receiver, fieldName), arguments);
344 } 350 }
345 } 351 }
346 352
347 LiteralString string(String value) => js.string(value); 353 LiteralString string(String value) => js.string(value);
348 LiteralNumber number(num value) => js.number(value); 354 LiteralNumber number(num value) => js.number(value);
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
436 static const LPAREN = 6; 442 static const LPAREN = 6;
437 static const RPAREN = 7; 443 static const RPAREN = 7;
438 static const LBRACE = 8; 444 static const LBRACE = 8;
439 static const RBRACE = 9; 445 static const RBRACE = 9;
440 static const LSQUARE = 10; 446 static const LSQUARE = 10;
441 static const RSQUARE = 11; 447 static const RSQUARE = 11;
442 static const COMMA = 12; 448 static const COMMA = 12;
443 static const QUERY = 13; 449 static const QUERY = 13;
444 static const COLON = 14; 450 static const COLON = 14;
445 static const SEMICOLON = 15; 451 static const SEMICOLON = 15;
446 static const HASH = 16; 452 static const ARROW = 16;
447 static const WHITESPACE = 17; 453 static const HASH = 17;
448 static const OTHER = 18; 454 static const WHITESPACE = 18;
455 static const OTHER = 19;
449 456
450 // Make sure that ]] is two symbols. 457 // Make sure that ]] is two symbols.
451 bool singleCharCategory(int category) => category >= DOT; 458 bool singleCharCategory(int category) => category >= DOT;
452 459
453 static String categoryToString(int cat) { 460 static String categoryToString(int cat) {
454 switch (cat) { 461 switch (cat) {
455 case NONE: return "NONE"; 462 case NONE: return "NONE";
456 case ALPHA: return "ALPHA"; 463 case ALPHA: return "ALPHA";
457 case NUMERIC: return "NUMERIC"; 464 case NUMERIC: return "NUMERIC";
458 case SYMBOL: return "SYMBOL"; 465 case SYMBOL: return "SYMBOL";
459 case ASSIGNMENT: return "ASSIGNMENT"; 466 case ASSIGNMENT: return "ASSIGNMENT";
460 case DOT: return "DOT"; 467 case DOT: return "DOT";
461 case LPAREN: return "LPAREN"; 468 case LPAREN: return "LPAREN";
462 case RPAREN: return "RPAREN"; 469 case RPAREN: return "RPAREN";
463 case LBRACE: return "LBRACE"; 470 case LBRACE: return "LBRACE";
464 case RBRACE: return "RBRACE"; 471 case RBRACE: return "RBRACE";
465 case LSQUARE: return "LSQUARE"; 472 case LSQUARE: return "LSQUARE";
466 case RSQUARE: return "RSQUARE"; 473 case RSQUARE: return "RSQUARE";
467 case STRING: return "STRING"; 474 case STRING: return "STRING";
468 case COMMA: return "COMMA"; 475 case COMMA: return "COMMA";
469 case QUERY: return "QUERY"; 476 case QUERY: return "QUERY";
470 case COLON: return "COLON"; 477 case COLON: return "COLON";
471 case SEMICOLON: return "SEMICOLON"; 478 case SEMICOLON: return "SEMICOLON";
479 case ARROW: return "ARROW";
472 case HASH: return "HASH"; 480 case HASH: return "HASH";
473 case WHITESPACE: return "WHITESPACE"; 481 case WHITESPACE: return "WHITESPACE";
474 case OTHER: return "OTHER"; 482 case OTHER: return "OTHER";
475 } 483 }
476 return "Unknown: $cat"; 484 return "Unknown: $cat";
477 } 485 }
478 486
479 static const CATEGORIES = const <int>[ 487 static const CATEGORIES = const <int>[
480 OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 0-7 488 OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 0-7
481 OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE, // 8-13 489 OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE, // 8-13
(...skipping 30 matching lines...) Expand all
512 '!=': 9, '==': 9, '!==': 9, '===': 9, 520 '!=': 9, '==': 9, '!==': 9, '===': 9,
513 '<': 8, '<=': 8, '>=': 8, '>': 8, 'in': 8, 'instanceof': 8, 521 '<': 8, '<=': 8, '>=': 8, '>': 8, 'in': 8, 'instanceof': 8,
514 '<<': 7, '>>': 7, '>>>': 7, 522 '<<': 7, '>>': 7, '>>>': 7,
515 '+': 6, '-': 6, 523 '+': 6, '-': 6,
516 '*': 5, '/': 5, '%': 5 524 '*': 5, '/': 5, '%': 5
517 }; 525 };
518 static final UNARY_OPERATORS = 526 static final UNARY_OPERATORS =
519 ['++', '--', '+', '-', '~', '!', 'typeof', 'void', 'delete', 'await'] 527 ['++', '--', '+', '-', '~', '!', 'typeof', 'void', 'delete', 'await']
520 .toSet(); 528 .toSet();
521 529
530 static final ARROW_TOKEN = '=>';
531
522 static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS = 532 static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS =
523 ['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet(); 533 ['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet();
524 534
525 static int category(int code) { 535 static int category(int code) {
526 if (code >= CATEGORIES.length) return OTHER; 536 if (code >= CATEGORIES.length) return OTHER;
527 return CATEGORIES[code]; 537 return CATEGORIES[code];
528 } 538 }
529 539
530 String getDelimited(int startPosition) { 540 String getDelimited(int startPosition) {
531 position = startPosition; 541 position = startPosition;
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
626 (cat == newCat || 636 (cat == newCat ||
627 (cat == ALPHA && newCat == NUMERIC) || // eg. level42. 637 (cat == ALPHA && newCat == NUMERIC) || // eg. level42.
628 (cat == NUMERIC && newCat == DOT))); // eg. 3.1415 638 (cat == NUMERIC && newCat == DOT))); // eg. 3.1415
629 lastCategory = cat; 639 lastCategory = cat;
630 lastToken = src.substring(lastPosition, position); 640 lastToken = src.substring(lastPosition, position);
631 if (cat == NUMERIC) { 641 if (cat == NUMERIC) {
632 double.parse(lastToken, (_) { 642 double.parse(lastToken, (_) {
633 error("Unparseable number"); 643 error("Unparseable number");
634 }); 644 });
635 } else if (cat == SYMBOL) { 645 } else if (cat == SYMBOL) {
636 int binaryPrecendence = BINARY_PRECEDENCE[lastToken]; 646 if (lastToken == ARROW_TOKEN) {
637 if (binaryPrecendence == null && !UNARY_OPERATORS.contains(lastToken)) { 647 lastCategory = ARROW;
638 error("Unknown operator"); 648 } else {
649 int binaryPrecendence = BINARY_PRECEDENCE[lastToken];
650 if (binaryPrecendence == null && !UNARY_OPERATORS.contains(lastToken)) {
651 error("Unknown operator");
652 }
653 if (isAssignment(lastToken)) lastCategory = ASSIGNMENT;
639 } 654 }
640 if (isAssignment(lastToken)) lastCategory = ASSIGNMENT;
641 } else if (cat == ALPHA) { 655 } else if (cat == ALPHA) {
642 if (OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS.contains(lastToken)) { 656 if (OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS.contains(lastToken)) {
643 lastCategory = SYMBOL; 657 lastCategory = SYMBOL;
644 } 658 }
645 } 659 }
646 } 660 }
647 } 661 }
648 662
649 void expectCategory(int cat) { 663 void expectCategory(int cat) {
650 if (cat != lastCategory) error("Expected ${categoryToString(cat)}"); 664 if (cat != lastCategory) error("Expected ${categoryToString(cat)}");
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
711 if (last == "true") { 725 if (last == "true") {
712 return new LiteralBool(true); 726 return new LiteralBool(true);
713 } else if (last == "false") { 727 } else if (last == "false") {
714 return new LiteralBool(false); 728 return new LiteralBool(false);
715 } else if (last == "null") { 729 } else if (last == "null") {
716 return new LiteralNull(); 730 return new LiteralNull();
717 } else if (last == "function") { 731 } else if (last == "function") {
718 return parseFunctionExpression(); 732 return parseFunctionExpression();
719 } else if (last == "this") { 733 } else if (last == "this") {
720 return new This(); 734 return new This();
735 } else if (last == "super") {
736 return new Super();
737 } else if (last == "class") {
738 return parseClass();
721 } else { 739 } else {
722 return new VariableUse(last); 740 return new VariableUse(last);
723 } 741 }
724 } else if (acceptCategory(LPAREN)) { 742 } else if (acceptCategory(LPAREN)) {
725 Expression expression = parseExpression(); 743 return parseExpressionOrArrowFunction();
726 expectCategory(RPAREN);
727 return expression;
728 } else if (acceptCategory(STRING)) { 744 } else if (acceptCategory(STRING)) {
729 return new LiteralString(last); 745 return new LiteralString(last);
730 } else if (acceptCategory(NUMERIC)) { 746 } else if (acceptCategory(NUMERIC)) {
731 return new LiteralNumber(last); 747 return new LiteralNumber(last);
732 } else if (acceptCategory(LBRACE)) { 748 } else if (acceptCategory(LBRACE)) {
733 return parseObjectInitializer(); 749 return parseObjectInitializer();
734 } else if (acceptCategory(LSQUARE)) { 750 } else if (acceptCategory(LSQUARE)) {
735 var values = <Expression>[]; 751 var values = <Expression>[];
736 752
737 while (true) { 753 while (true) {
(...skipping 19 matching lines...) Expand all
757 InterpolatedExpression expression = 773 InterpolatedExpression expression =
758 new InterpolatedExpression(nameOrPosition); 774 new InterpolatedExpression(nameOrPosition);
759 interpolatedValues.add(expression); 775 interpolatedValues.add(expression);
760 return expression; 776 return expression;
761 } else { 777 } else {
762 error("Expected primary expression"); 778 error("Expected primary expression");
763 return null; 779 return null;
764 } 780 }
765 } 781 }
766 782
783 /**
784 * CoverParenthesizedExpressionAndArrowParameterList[Yield] :
785 * ( Expression )
786 * ( )
787 * ( ... BindingIdentifier )
788 * ( Expression , ... BindingIdentifier )
789 */
790 Expression parseExpressionOrArrowFunction() {
791 if (acceptCategory(RPAREN)) {
792 expectCategory(ARROW);
793 return parseArrowFunctionBody(<Parameter>[]);
794 }
795 Expression expression = parseExpression();
796 expectCategory(RPAREN);
797 if (acceptCategory(ARROW)) {
798 var params = <Parameter>[];
799 _expressionToParameterList(expression, params);
800 return parseArrowFunctionBody(params);
801 }
802 return expression;
803
804 }
805
806 /**
807 * Converts a parenthesized expression into a list of parameters, issuing an
808 * error if the conversion fails.
809 */
810 void _expressionToParameterList(Expression node, List<Parameter> params) {
811 if (node is VariableUse) {
812 // TODO(jmesserly): support default/rest parameters
813 params.add(new Parameter(node.name));
814 } else if (node is Binary && node.op == ',') {
815 // TODO(jmesserly): this will allow illegal parens, such as
816 // `((a, b), (c, d))`. Fixing it on the left side needs an explicit
817 // ParenthesizedExpression node, so we can distinguish
818 // `((a, b), c)` from `(a, b, c)`.
819 _expressionToParameterList(node.left, params);
820 _expressionToParameterList(node.right, params);
821 } else if (node is InterpolatedExpression) {
822 params.add(new InterpolatedParameter(node.nameOrPosition));
823 } else {
824 error("Expected arrow function parameter list");
825 }
826 }
827
828 Expression parseArrowFunctionBody(List<Parameter> params) {
829 Node body;
830 if (acceptCategory(LBRACE)) {
831 body = parseBlock();
832 } else {
833 body = parseAssignment();
834 }
835 return new ArrowFun(params, body);
836 }
837
767 Expression parseFunctionExpression() { 838 Expression parseFunctionExpression() {
768 String last = lastToken; 839 String last = lastToken;
769 if (acceptCategory(ALPHA)) { 840 if (acceptCategory(ALPHA)) {
770 String functionName = last; 841 String functionName = last;
771 return new NamedFunction(new VariableDeclaration(functionName), 842 return new NamedFunction(new VariableDeclaration(functionName),
772 parseFun()); 843 parseFun());
773 } 844 }
774 return parseFun(); 845 return parseFun();
775 } 846 }
776 847
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
811 } 882 }
812 expectCategory(LBRACE); 883 expectCategory(LBRACE);
813 Block block = parseBlock(); 884 Block block = parseBlock();
814 return new Fun(params, block, asyncModifier: asyncModifier); 885 return new Fun(params, block, asyncModifier: asyncModifier);
815 } 886 }
816 887
817 Expression parseObjectInitializer() { 888 Expression parseObjectInitializer() {
818 List<Property> properties = <Property>[]; 889 List<Property> properties = <Property>[];
819 for (;;) { 890 for (;;) {
820 if (acceptCategory(RBRACE)) break; 891 if (acceptCategory(RBRACE)) break;
821 // Limited subset: keys are identifiers, no 'get' or 'set' properties. 892 // Limited subset of ES6 object initializers.
822 Literal propertyName; 893 //
823 String identifier = lastToken; 894 // PropertyDefinition :
824 if (acceptCategory(ALPHA)) { 895 // PropertyName : AssignmentExpression
825 propertyName = new LiteralString('"$identifier"'); 896 // MethodDefinition
826 } else if (acceptCategory(STRING)) { 897
827 propertyName = new LiteralString(identifier); 898 if (acceptCategory(HASH)) {
828 } else if (acceptCategory(SYMBOL)) { // e.g. void 899 properties.add(parseInterpolatedMember());
829 propertyName = new LiteralString('"$identifier"');
830 } else if (acceptCategory(HASH)) {
831 var nameOrPosition = parseHash();
832 InterpolatedLiteral interpolatedLiteral =
833 new InterpolatedLiteral(nameOrPosition);
834 interpolatedValues.add(interpolatedLiteral);
835 propertyName = interpolatedLiteral;
836 } else { 900 } else {
837 error('Expected property name'); 901 bool isGetter = acceptString('get');
902 bool isSetter = isGetter ? false : acceptString('set');
903 Expression name = parsePropertyName();
904
905 if (lastCategory == LPAREN) {
906 Fun fun = parseFun();
907 properties.add(
908 new Method(name, fun, isGetter: isGetter, isSetter: isSetter));
909 } else {
910 expectCategory(COLON);
911 Expression value = parseAssignment();
912 properties.add(new Property(name, value));
913 }
914 if (acceptCategory(RBRACE)) break;
915 expectCategory(COMMA);
838 } 916 }
839 expectCategory(COLON);
840 Expression value = parseAssignment();
841 properties.add(new Property(propertyName, value));
842 if (acceptCategory(RBRACE)) break;
843 expectCategory(COMMA);
844 } 917 }
845 return new ObjectInitializer(properties); 918 return new ObjectInitializer(properties);
846 } 919 }
847 920
848 Expression parseMember() { 921 Expression parseMember() {
849 Expression receiver = parsePrimary(); 922 Expression receiver = parsePrimary();
850 while (true) { 923 while (true) {
851 if (acceptCategory(DOT)) { 924 if (acceptCategory(DOT)) {
852 receiver = getDotRhs(receiver); 925 receiver = getDotRhs(receiver);
853 } else if (acceptCategory(LSQUARE)) { 926 } else if (acceptCategory(LSQUARE)) {
(...skipping 126 matching lines...) Expand 10 before | Expand all | Expand 10 after
980 1053
981 Expression parseConditional() { 1054 Expression parseConditional() {
982 Expression lhs = parseBinary(HIGHEST_PARSE_BINARY_PRECEDENCE); 1055 Expression lhs = parseBinary(HIGHEST_PARSE_BINARY_PRECEDENCE);
983 if (!acceptCategory(QUERY)) return lhs; 1056 if (!acceptCategory(QUERY)) return lhs;
984 Expression ifTrue = parseAssignment(); 1057 Expression ifTrue = parseAssignment();
985 expectCategory(COLON); 1058 expectCategory(COLON);
986 Expression ifFalse = parseAssignment(); 1059 Expression ifFalse = parseAssignment();
987 return new Conditional(lhs, ifTrue, ifFalse); 1060 return new Conditional(lhs, ifTrue, ifFalse);
988 } 1061 }
989 1062
1063 Expression parseLeftHandSide() => parseConditional();
990 1064
991 Expression parseAssignment() { 1065 Expression parseAssignment() {
992 Expression lhs = parseConditional(); 1066 Expression lhs = parseLeftHandSide();
993 String assignmentOperator = lastToken; 1067 String assignmentOperator = lastToken;
994 if (acceptCategory(ASSIGNMENT)) { 1068 if (acceptCategory(ASSIGNMENT)) {
995 Expression rhs = parseAssignment(); 1069 Expression rhs = parseAssignment();
996 if (assignmentOperator == "=") { 1070 if (assignmentOperator == "=") {
997 return new Assignment(lhs, rhs); 1071 return new Assignment(lhs, rhs);
998 } else { 1072 } else {
999 // Handle +=, -=, etc. 1073 // Handle +=, -=, etc.
1000 String operator = 1074 String operator =
1001 assignmentOperator.substring(0, assignmentOperator.length - 1); 1075 assignmentOperator.substring(0, assignmentOperator.length - 1);
1002 return new Assignment.compound(lhs, operator, rhs); 1076 return new Assignment.compound(lhs, operator, rhs);
1003 } 1077 }
1004 } 1078 }
1005 return lhs; 1079 return lhs;
1006 } 1080 }
1007 1081
1008 Expression parseExpression() { 1082 Expression parseExpression() {
1009 Expression expression = parseAssignment(); 1083 Expression expression = parseAssignment();
1010 while (acceptCategory(COMMA)) { 1084 while (acceptCategory(COMMA)) {
1011 Expression right = parseAssignment(); 1085 Expression right = parseAssignment();
1012 expression = new Binary(',', expression, right); 1086 expression = new Binary(',', expression, right);
1013 } 1087 }
1014 return expression; 1088 return expression;
1015 } 1089 }
1016 1090
1017 VariableDeclarationList parseVariableDeclarationList() { 1091 /** Parse a variable declaration list, with `var` or `let` [keyword] */
1092 VariableDeclarationList parseVariableDeclarationList(String keyword) {
1093 // Supports one form for interpolated variable declaration:
1094 // let # = ...
1095 if (acceptCategory(HASH)) {
1096 var name = new InterpolatedVariableDeclaration(parseHash());
1097 interpolatedValues.add(name);
1098
1099 Expression initializer = acceptString("=") ? parseAssignment() : null;
1100 return new VariableDeclarationList(keyword,
1101 [new VariableInitialization(name, initializer)]);
1102 }
1103
1018 String firstVariable = lastToken; 1104 String firstVariable = lastToken;
1019 expectCategory(ALPHA); 1105 expectCategory(ALPHA);
1020 return finishVariableDeclarationList(firstVariable); 1106 return finishVariableDeclarationList(keyword, firstVariable);
1021 } 1107 }
1022 1108
1023 VariableDeclarationList finishVariableDeclarationList(String firstVariable) { 1109 VariableDeclarationList finishVariableDeclarationList(
1110 String keyword, String firstVariable) {
1024 var initialization = []; 1111 var initialization = [];
1025 1112
1026 void declare(String variable) { 1113 void declare(String variable) {
1027 Expression initializer = null; 1114 Expression initializer = null;
1028 if (acceptString("=")) { 1115 if (acceptString("=")) {
1029 initializer = parseAssignment(); 1116 initializer = parseAssignment();
1030 } 1117 }
1031 var declaration = new VariableDeclaration(variable); 1118 var declaration = new VariableDeclaration(variable);
1032 initialization.add(new VariableInitialization(declaration, initializer)); 1119 initialization.add(new VariableInitialization(declaration, initializer));
1033 } 1120 }
1034 1121
1035 declare(firstVariable); 1122 declare(firstVariable);
1036 while (acceptCategory(COMMA)) { 1123 while (acceptCategory(COMMA)) {
1037 String variable = lastToken; 1124 String variable = lastToken;
1038 expectCategory(ALPHA); 1125 expectCategory(ALPHA);
1039 declare(variable); 1126 declare(variable);
1040 } 1127 }
1041 return new VariableDeclarationList(initialization); 1128 return new VariableDeclarationList(keyword, initialization);
1042 } 1129 }
1043 1130
1044 Expression parseVarDeclarationOrExpression() { 1131 Expression parseVarDeclarationOrExpression() {
1045 if (acceptString("var")) { 1132 var keyword = acceptVarOrLet();
1046 return parseVariableDeclarationList(); 1133 if (keyword != null) {
1134 return parseVariableDeclarationList(keyword);
1047 } else { 1135 } else {
1048 return parseExpression(); 1136 return parseExpression();
1049 } 1137 }
1050 } 1138 }
1051 1139
1140 /** Accepts a `var` or `let` keyword. If neither is found, returns null. */
1141 String acceptVarOrLet() {
1142 if (acceptString('var')) return 'var';
1143 if (acceptString('let')) return 'let';
1144 return null;
1145 }
1146
1052 Expression expression() { 1147 Expression expression() {
1053 Expression expression = parseVarDeclarationOrExpression(); 1148 Expression expression = parseVarDeclarationOrExpression();
1054 if (lastCategory != NONE || position != src.length) { 1149 if (lastCategory != NONE || position != src.length) {
1055 error("Unparsed junk: ${categoryToString(lastCategory)}"); 1150 error("Unparsed junk: ${categoryToString(lastCategory)}");
1056 } 1151 }
1057 return expression; 1152 return expression;
1058 } 1153 }
1059 1154
1060 Statement statement() { 1155 Statement statement() {
1061 Statement statement = parseStatement(); 1156 Statement statement = parseStatement();
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1093 if (acceptString('continue')) { 1188 if (acceptString('continue')) {
1094 return parseBreakOrContinue((label) => new Continue(label)); 1189 return parseBreakOrContinue((label) => new Continue(label));
1095 } 1190 }
1096 1191
1097 if (acceptString('if')) return parseIfThenElse(); 1192 if (acceptString('if')) return parseIfThenElse();
1098 1193
1099 if (acceptString('for')) return parseFor(); 1194 if (acceptString('for')) return parseFor();
1100 1195
1101 if (acceptString('function')) return parseFunctionDeclaration(); 1196 if (acceptString('function')) return parseFunctionDeclaration();
1102 1197
1198 if (acceptString('class')) return new ClassDeclaration(parseClass());
1199
1103 if (acceptString('try')) return parseTry(); 1200 if (acceptString('try')) return parseTry();
1104 1201
1105 if (acceptString('var')) { 1202 var keyword = acceptVarOrLet();
1106 Expression declarations = parseVariableDeclarationList(); 1203 if (keyword != null) {
1204 Expression declarations = parseVariableDeclarationList(keyword);
1107 expectSemicolon(); 1205 expectSemicolon();
1108 return new ExpressionStatement(declarations); 1206 return new ExpressionStatement(declarations);
1109 } 1207 }
1110 1208
1111 if (acceptString('while')) return parseWhile(); 1209 if (acceptString('while')) return parseWhile();
1112 1210
1113 if (acceptString('do')) return parseDo(); 1211 if (acceptString('do')) return parseDo();
1114 1212
1115 if (acceptString('switch')) return parseSwitch(); 1213 if (acceptString('switch')) return parseSwitch();
1116 1214
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after
1196 } 1294 }
1197 } 1295 }
1198 1296
1199 Statement parseFor() { 1297 Statement parseFor() {
1200 // For-init-condition-increment style loops are fully supported. 1298 // For-init-condition-increment style loops are fully supported.
1201 // 1299 //
1202 // Only one for-in variant is currently implemented: 1300 // Only one for-in variant is currently implemented:
1203 // 1301 //
1204 // for (var variable in Expression) Statement 1302 // for (var variable in Expression) Statement
1205 // 1303 //
1304 // One variant of ES6 for-of is also implemented:
1305 //
1306 // for (let variable of Expression) Statement
1307 //
1206 Statement finishFor(Expression init) { 1308 Statement finishFor(Expression init) {
1207 Expression condition = null; 1309 Expression condition = null;
1208 if (!acceptCategory(SEMICOLON)) { 1310 if (!acceptCategory(SEMICOLON)) {
1209 condition = parseExpression(); 1311 condition = parseExpression();
1210 expectCategory(SEMICOLON); 1312 expectCategory(SEMICOLON);
1211 } 1313 }
1212 Expression update = null; 1314 Expression update = null;
1213 if (!acceptCategory(RPAREN)) { 1315 if (!acceptCategory(RPAREN)) {
1214 update = parseExpression(); 1316 update = parseExpression();
1215 expectCategory(RPAREN); 1317 expectCategory(RPAREN);
1216 } 1318 }
1217 Statement body = parseStatement(); 1319 Statement body = parseStatement();
1218 return new For(init, condition, update, body); 1320 return new For(init, condition, update, body);
1219 } 1321 }
1220 1322
1221 expectCategory(LPAREN); 1323 expectCategory(LPAREN);
1222 if (acceptCategory(SEMICOLON)) { 1324 if (acceptCategory(SEMICOLON)) {
1223 return finishFor(null); 1325 return finishFor(null);
1224 } 1326 }
1225 1327
1226 if (acceptString('var')) { 1328 var keyword = acceptVarOrLet();
1329 if (keyword != null) {
1227 String identifier = lastToken; 1330 String identifier = lastToken;
1228 expectCategory(ALPHA); 1331 expectCategory(ALPHA);
1332
1229 if (acceptString('in')) { 1333 if (acceptString('in')) {
1230 Expression objectExpression = parseExpression(); 1334 Expression objectExpression = parseExpression();
1231 expectCategory(RPAREN); 1335 expectCategory(RPAREN);
1232 Statement body = parseStatement(); 1336 Statement body = parseStatement();
1233 return new ForIn( 1337 return new ForIn(
1234 new VariableDeclarationList([ 1338 _createVariableDeclarationList(keyword, identifier),
1235 new VariableInitialization(
1236 new VariableDeclaration(identifier), null)]),
1237 objectExpression, 1339 objectExpression,
1238 body); 1340 body);
1341 } else if (acceptString('of')) {
1342 Expression iterableExpression = parseAssignment();
1343 expectCategory(RPAREN);
1344 Statement body = parseStatement();
1345 return new ForOf(
1346 _createVariableDeclarationList(keyword, identifier),
1347 iterableExpression,
1348 body);
1239 } 1349 }
1240 Expression declarations = finishVariableDeclarationList(identifier); 1350 var declarations = finishVariableDeclarationList(keyword, identifier);
1241 expectCategory(SEMICOLON); 1351 expectCategory(SEMICOLON);
1242 return finishFor(declarations); 1352 return finishFor(declarations);
1243 } 1353 }
1244 1354
1245 Expression init = parseExpression(); 1355 Expression init = parseExpression();
1246 expectCategory(SEMICOLON); 1356 expectCategory(SEMICOLON);
1247 return finishFor(init); 1357 return finishFor(init);
1248 } 1358 }
1249 1359
1360 static VariableDeclarationList _createVariableDeclarationList(
1361 String keyword, String identifier) {
1362 return new VariableDeclarationList(keyword, [
1363 new VariableInitialization(
1364 new VariableDeclaration(identifier), null)]);
1365 }
1366
1250 Statement parseFunctionDeclaration() { 1367 Statement parseFunctionDeclaration() {
1251 String name = lastToken; 1368 String name = lastToken;
1252 expectCategory(ALPHA); 1369 expectCategory(ALPHA);
1253 Expression fun = parseFun(); 1370 Expression fun = parseFun();
1254 return new FunctionDeclaration(new VariableDeclaration(name), fun); 1371 return new FunctionDeclaration(new VariableDeclaration(name), fun);
1255 } 1372 }
1256 1373
1257 Statement parseTry() { 1374 Statement parseTry() {
1258 expectCategory(LBRACE); 1375 expectCategory(LBRACE);
1259 Block body = parseBlock(); 1376 Block body = parseBlock();
1260 String token = lastToken;
1261 Catch catchPart = null; 1377 Catch catchPart = null;
1262 if (acceptString('catch')) catchPart = parseCatch(); 1378 if (acceptString('catch')) catchPart = parseCatch();
1263 Block finallyPart = null; 1379 Block finallyPart = null;
1264 if (acceptString('finally')) { 1380 if (acceptString('finally')) {
1265 expectCategory(LBRACE); 1381 expectCategory(LBRACE);
1266 finallyPart = parseBlock(); 1382 finallyPart = parseBlock();
1267 } else { 1383 } else {
1268 if (catchPart == null) error("expected 'finally'"); 1384 if (catchPart == null) error("expected 'finally'");
1269 } 1385 }
1270 return new Try(body, catchPart, finallyPart); 1386 return new Try(body, catchPart, finallyPart);
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
1326 1442
1327 Catch parseCatch() { 1443 Catch parseCatch() {
1328 expectCategory(LPAREN); 1444 expectCategory(LPAREN);
1329 String identifier = lastToken; 1445 String identifier = lastToken;
1330 expectCategory(ALPHA); 1446 expectCategory(ALPHA);
1331 expectCategory(RPAREN); 1447 expectCategory(RPAREN);
1332 expectCategory(LBRACE); 1448 expectCategory(LBRACE);
1333 Block body = parseBlock(); 1449 Block body = parseBlock();
1334 return new Catch(new VariableDeclaration(identifier), body); 1450 return new Catch(new VariableDeclaration(identifier), body);
1335 } 1451 }
1452
1453 ClassExpression parseClass() {
1454 VariableDeclaration name;
1455 if (acceptCategory(HASH)) {
1456 var interpolatedName = new InterpolatedVariableDeclaration(parseHash());
1457 interpolatedValues.add(interpolatedName);
1458 name = interpolatedName;
1459 } else {
1460 name = new VariableDeclaration(lastToken);
1461 expectCategory(ALPHA);
1462 }
1463 Expression heritage = null;
1464 if (acceptString('extends')) {
1465 heritage = parseLeftHandSide();
1466 }
1467 expectCategory(LBRACE);
1468 var methods = new List<Method>();
1469 while (lastCategory != RBRACE) {
1470 methods.add(parseMethod());
1471 }
1472 expectCategory(RBRACE);
1473 return new ClassExpression(name, heritage, methods);
1474 }
1475
1476 Method parseMethod() {
1477 if (acceptCategory(HASH)) return parseInterpolatedMember();
1478
1479 bool isStatic = acceptString('static');
1480 bool isGetter = acceptString('get');
1481 bool isSetter = isGetter ? false : acceptString('set');
1482 var name = parsePropertyName();
1483 var fun = parseFun();
1484 return new Method(name, fun,
1485 isGetter: isGetter, isSetter: isSetter, isStatic: isStatic);
1486 }
1487
1488 InterpolatedMethod parseInterpolatedMember() {
1489 var member = new InterpolatedMethod(parseHash());
1490 interpolatedValues.add(member);
1491 return member;
1492 }
1493
1494 Expression parsePropertyName() {
1495 String identifier = lastToken;
1496 if (acceptCategory(ALPHA)) {
1497 return new PropertyName(identifier);
1498 } else if (acceptCategory(STRING)) {
1499 return new LiteralString(identifier);
1500 } else if (acceptCategory(SYMBOL)) {
1501 // e.g. void
1502 return new LiteralString('"$identifier"');
1503 } else if (acceptCategory(LSQUARE)) {
1504 var expr = parseAssignment();
1505 expectCategory(RSQUARE);
1506 return expr;
1507 } else if (acceptCategory(HASH)) {
1508 var nameOrPosition = parseHash();
1509 var interpolatedLiteral = new InterpolatedLiteral(nameOrPosition);
1510 interpolatedValues.add(interpolatedLiteral);
1511 return interpolatedLiteral;
1512 } else {
1513 error('Expected property name');
1514 return null;
1515 }
1516 }
1336 } 1517 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698