| 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 | 10 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 57 still has one semicolon: | 57 still has one semicolon: |
| 58 | 58 |
| 59 js.statement('if (happy) #;', ret) | 59 js.statement('if (happy) #;', ret) |
| 60 --> | 60 --> |
| 61 if (happy) | 61 if (happy) |
| 62 return 123; | 62 return 123; |
| 63 | 63 |
| 64 If the placeholder is not followed by a semicolon, it is part of an expression. | 64 If the placeholder is not followed by a semicolon, it is part of an expression. |
| 65 Here the paceholder is in the position of the function in a function call: | 65 Here the paceholder is in the position of the function in a function call: |
| 66 | 66 |
| 67 var vFoo = new VariableUse('foo'); | 67 var vFoo = new Identifier('foo'); |
| 68 js.statement('if (happy) #("Happy!")', vFoo) | 68 js.statement('if (happy) #("Happy!")', vFoo) |
| 69 --> | 69 --> |
| 70 if (happy) | 70 if (happy) |
| 71 foo("Happy!"); | 71 foo("Happy!"); |
| 72 | 72 |
| 73 Generally, a placeholder in an expression position requires an Expression AST as | 73 Generally, a placeholder in an expression position requires an Expression AST as |
| 74 an argument and a placeholder in a statement position requires a Statement AST. | 74 an argument and a placeholder in a statement position requires a Statement AST. |
| 75 An expression will be converted to a Statement if needed by creating an | 75 An expression will be converted to a Statement if needed by creating an |
| 76 ExpessionStatement. A String argument will be converted into a VariableUse and | 76 ExpessionStatement. A String argument will be converted into a Identifier and |
| 77 requires that the string is a JavaScript identifier. | 77 requires that the string is a JavaScript identifier. |
| 78 | 78 |
| 79 js('# + 1', vFoo) --> foo + 1 | 79 js('# + 1', vFoo) --> foo + 1 |
| 80 js('# + 1', 'foo') --> foo + 1 | 80 js('# + 1', 'foo') --> foo + 1 |
| 81 js('# + 1', 'foo.bar') --> assertion failure | 81 js('# + 1', 'foo.bar') --> assertion failure |
| 82 | 82 |
| 83 Some placeholder positions are _splicing contexts_. A function argument list is | 83 Some placeholder positions are _splicing contexts_. A function argument list is |
| 84 a splicing expression context. A placeholder in a splicing expression context | 84 a splicing expression context. A placeholder in a splicing expression context |
| 85 can take a single Expression (or String, converted to VariableUse) or an | 85 can take a single Expression (or String, converted to Identifier) or an |
| 86 Iterable of Expressions (and/or Strings). | 86 Iterable of Expressions (and/or Strings). |
| 87 | 87 |
| 88 // non-splicing argument: | 88 // non-splicing argument: |
| 89 js('#(#)', ['say', s]) --> say("hello") | 89 js('#(#)', ['say', s]) --> say("hello") |
| 90 // splicing arguments: | 90 // splicing arguments: |
| 91 js('#(#)', ['say', []]) --> say() | 91 js('#(#)', ['say', []]) --> say() |
| 92 js('#(#)', ['say', [s]]) --> say("hello") | 92 js('#(#)', ['say', [s]]) --> say("hello") |
| 93 js('#(#)', ['say', [s, n]]) --> say("hello", 123) | 93 js('#(#)', ['say', [s, n]]) --> say("hello", 123) |
| 94 | 94 |
| 95 A splicing context can be used to append 'lists' and add extra elements: | 95 A splicing context can be used to append 'lists' and add extra elements: |
| (...skipping 634 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 730 return new LiteralNull(); | 730 return new LiteralNull(); |
| 731 } else if (last == "function") { | 731 } else if (last == "function") { |
| 732 return parseFunctionExpression(); | 732 return parseFunctionExpression(); |
| 733 } else if (last == "this") { | 733 } else if (last == "this") { |
| 734 return new This(); | 734 return new This(); |
| 735 } else if (last == "super") { | 735 } else if (last == "super") { |
| 736 return new Super(); | 736 return new Super(); |
| 737 } else if (last == "class") { | 737 } else if (last == "class") { |
| 738 return parseClass(); | 738 return parseClass(); |
| 739 } else { | 739 } else { |
| 740 return new VariableUse(last); | 740 return new Identifier(last); |
| 741 } | 741 } |
| 742 } else if (acceptCategory(LPAREN)) { | 742 } else if (acceptCategory(LPAREN)) { |
| 743 return parseExpressionOrArrowFunction(); | 743 return parseExpressionOrArrowFunction(); |
| 744 } else if (acceptCategory(STRING)) { | 744 } else if (acceptCategory(STRING)) { |
| 745 return new LiteralString(last); | 745 return new LiteralString(last); |
| 746 } else if (acceptCategory(NUMERIC)) { | 746 } else if (acceptCategory(NUMERIC)) { |
| 747 return new LiteralNumber(last); | 747 return new LiteralNumber(last); |
| 748 } else if (acceptCategory(LBRACE)) { | 748 } else if (acceptCategory(LBRACE)) { |
| 749 return parseObjectInitializer(); | 749 return parseObjectInitializer(); |
| 750 } else if (acceptCategory(LSQUARE)) { | 750 } else if (acceptCategory(LSQUARE)) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 785 /** | 785 /** |
| 786 * CoverParenthesizedExpressionAndArrowParameterList[Yield] : | 786 * CoverParenthesizedExpressionAndArrowParameterList[Yield] : |
| 787 * ( Expression ) | 787 * ( Expression ) |
| 788 * ( ) | 788 * ( ) |
| 789 * ( ... BindingIdentifier ) | 789 * ( ... BindingIdentifier ) |
| 790 * ( Expression , ... BindingIdentifier ) | 790 * ( Expression , ... BindingIdentifier ) |
| 791 */ | 791 */ |
| 792 Expression parseExpressionOrArrowFunction() { | 792 Expression parseExpressionOrArrowFunction() { |
| 793 if (acceptCategory(RPAREN)) { | 793 if (acceptCategory(RPAREN)) { |
| 794 expectCategory(ARROW); | 794 expectCategory(ARROW); |
| 795 return parseArrowFunctionBody(<Parameter>[]); | 795 return parseArrowFunctionBody(<Identifier>[]); |
| 796 } | 796 } |
| 797 Expression expression = parseExpression(); | 797 Expression expression = parseExpression(); |
| 798 expectCategory(RPAREN); | 798 expectCategory(RPAREN); |
| 799 if (acceptCategory(ARROW)) { | 799 if (acceptCategory(ARROW)) { |
| 800 var params = <Parameter>[]; | 800 var params = <Identifier>[]; |
| 801 _expressionToParameterList(expression, params); | 801 _expressionToParameterList(expression, params); |
| 802 return parseArrowFunctionBody(params); | 802 return parseArrowFunctionBody(params); |
| 803 } | 803 } |
| 804 return expression; | 804 return expression; |
| 805 | 805 |
| 806 } | 806 } |
| 807 | 807 |
| 808 /** | 808 /** |
| 809 * Converts a parenthesized expression into a list of parameters, issuing an | 809 * Converts a parenthesized expression into a list of parameters, issuing an |
| 810 * error if the conversion fails. | 810 * error if the conversion fails. |
| 811 */ | 811 */ |
| 812 void _expressionToParameterList(Expression node, List<Parameter> params) { | 812 void _expressionToParameterList(Expression node, List<Identifier> params) { |
| 813 if (node is VariableUse) { | 813 if (node is Identifier) { |
| 814 // TODO(jmesserly): support default/rest parameters | 814 // TODO(jmesserly): support default/rest parameters |
| 815 params.add(new Parameter(node.name)); | 815 params.add(node); |
| 816 } else if (node is Binary && node.op == ',') { | 816 } else if (node is Binary && node.op == ',') { |
| 817 // TODO(jmesserly): this will allow illegal parens, such as | 817 // TODO(jmesserly): this will allow illegal parens, such as |
| 818 // `((a, b), (c, d))`. Fixing it on the left side needs an explicit | 818 // `((a, b), (c, d))`. Fixing it on the left side needs an explicit |
| 819 // ParenthesizedExpression node, so we can distinguish | 819 // ParenthesizedExpression node, so we can distinguish |
| 820 // `((a, b), c)` from `(a, b, c)`. | 820 // `((a, b), c)` from `(a, b, c)`. |
| 821 _expressionToParameterList(node.left, params); | 821 _expressionToParameterList(node.left, params); |
| 822 _expressionToParameterList(node.right, params); | 822 _expressionToParameterList(node.right, params); |
| 823 } else if (node is InterpolatedExpression) { | 823 } else if (node is InterpolatedExpression) { |
| 824 params.add(new InterpolatedParameter(node.nameOrPosition)); | 824 params.add(new InterpolatedParameter(node.nameOrPosition)); |
| 825 } else { | 825 } else { |
| 826 error("Expected arrow function parameter list"); | 826 error("Expected arrow function parameter list"); |
| 827 } | 827 } |
| 828 } | 828 } |
| 829 | 829 |
| 830 Expression parseArrowFunctionBody(List<Parameter> params) { | 830 Expression parseArrowFunctionBody(List<Identifier> params) { |
| 831 Node body; | 831 Node body; |
| 832 if (acceptCategory(LBRACE)) { | 832 if (acceptCategory(LBRACE)) { |
| 833 body = parseBlock(); | 833 body = parseBlock(); |
| 834 } else { | 834 } else { |
| 835 body = parseAssignment(); | 835 body = parseAssignment(); |
| 836 } | 836 } |
| 837 return new ArrowFun(params, body); | 837 return new ArrowFun(params, body); |
| 838 } | 838 } |
| 839 | 839 |
| 840 Expression parseFunctionExpression() { | 840 Expression parseFunctionExpression() { |
| 841 String last = lastToken; | 841 String last = lastToken; |
| 842 if (acceptCategory(ALPHA)) { | 842 if (acceptCategory(ALPHA)) { |
| 843 String functionName = last; | 843 String functionName = last; |
| 844 return new NamedFunction(new VariableDeclaration(functionName), | 844 return new NamedFunction(new Identifier(functionName), |
| 845 parseFun()); | 845 parseFun()); |
| 846 } | 846 } |
| 847 return parseFun(); | 847 return parseFun(); |
| 848 } | 848 } |
| 849 | 849 |
| 850 Expression parseFun() { | 850 Expression parseFun() { |
| 851 List<Parameter> params = <Parameter>[]; | 851 List<Identifier> params = <Identifier>[]; |
| 852 | 852 |
| 853 expectCategory(LPAREN); | 853 expectCategory(LPAREN); |
| 854 if (!acceptCategory(RPAREN)) { | 854 if (!acceptCategory(RPAREN)) { |
| 855 for (;;) { | 855 for (;;) { |
| 856 if (acceptCategory(HASH)) { | 856 if (acceptCategory(HASH)) { |
| 857 var nameOrPosition = parseHash(); | 857 var nameOrPosition = parseHash(); |
| 858 InterpolatedParameter parameter = | 858 InterpolatedParameter parameter = |
| 859 new InterpolatedParameter(nameOrPosition); | 859 new InterpolatedParameter(nameOrPosition); |
| 860 interpolatedValues.add(parameter); | 860 interpolatedValues.add(parameter); |
| 861 params.add(parameter); | 861 params.add(parameter); |
| 862 } else { | 862 } else { |
| 863 String argumentName = lastToken; | 863 String argumentName = lastToken; |
| 864 expectCategory(ALPHA); | 864 expectCategory(ALPHA); |
| 865 params.add(new Parameter(argumentName)); | 865 params.add(new Identifier(argumentName)); |
| 866 } | 866 } |
| 867 if (acceptCategory(COMMA)) continue; | 867 if (acceptCategory(COMMA)) continue; |
| 868 expectCategory(RPAREN); | 868 expectCategory(RPAREN); |
| 869 break; | 869 break; |
| 870 } | 870 } |
| 871 } | 871 } |
| 872 AsyncModifier asyncModifier; | 872 AsyncModifier asyncModifier; |
| 873 if (acceptString('async')) { | 873 if (acceptString('async')) { |
| 874 if (acceptString('*')) { | 874 if (acceptString('*')) { |
| 875 asyncModifier = const AsyncModifier.asyncStar(); | 875 asyncModifier = const AsyncModifier.asyncStar(); |
| (...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1072 expression = new Binary(',', expression, right); | 1072 expression = new Binary(',', expression, right); |
| 1073 } | 1073 } |
| 1074 return expression; | 1074 return expression; |
| 1075 } | 1075 } |
| 1076 | 1076 |
| 1077 /** Parse a variable declaration list, with `var` or `let` [keyword] */ | 1077 /** Parse a variable declaration list, with `var` or `let` [keyword] */ |
| 1078 VariableDeclarationList parseVariableDeclarationList(String keyword) { | 1078 VariableDeclarationList parseVariableDeclarationList(String keyword) { |
| 1079 // Supports one form for interpolated variable declaration: | 1079 // Supports one form for interpolated variable declaration: |
| 1080 // let # = ... | 1080 // let # = ... |
| 1081 if (acceptCategory(HASH)) { | 1081 if (acceptCategory(HASH)) { |
| 1082 var name = new InterpolatedVariableDeclaration(parseHash()); | 1082 var name = new InterpolatedIdentifier(parseHash()); |
| 1083 interpolatedValues.add(name); | 1083 interpolatedValues.add(name); |
| 1084 | 1084 |
| 1085 Expression initializer = acceptString("=") ? parseAssignment() : null; | 1085 Expression initializer = acceptString("=") ? parseAssignment() : null; |
| 1086 return new VariableDeclarationList(keyword, | 1086 return new VariableDeclarationList(keyword, |
| 1087 [new VariableInitialization(name, initializer)]); | 1087 [new VariableInitialization(name, initializer)]); |
| 1088 } | 1088 } |
| 1089 | 1089 |
| 1090 String firstVariable = lastToken; | 1090 String firstVariable = lastToken; |
| 1091 expectCategory(ALPHA); | 1091 expectCategory(ALPHA); |
| 1092 return finishVariableDeclarationList(keyword, firstVariable); | 1092 return finishVariableDeclarationList(keyword, firstVariable); |
| 1093 } | 1093 } |
| 1094 | 1094 |
| 1095 VariableDeclarationList finishVariableDeclarationList( | 1095 VariableDeclarationList finishVariableDeclarationList( |
| 1096 String keyword, String firstVariable) { | 1096 String keyword, String firstVariable) { |
| 1097 var initialization = []; | 1097 var initialization = []; |
| 1098 | 1098 |
| 1099 void declare(String variable) { | 1099 void declare(String variable) { |
| 1100 Expression initializer = null; | 1100 Expression initializer = null; |
| 1101 if (acceptString("=")) { | 1101 if (acceptString("=")) { |
| 1102 initializer = parseAssignment(); | 1102 initializer = parseAssignment(); |
| 1103 } | 1103 } |
| 1104 var declaration = new VariableDeclaration(variable); | 1104 var declaration = new Identifier(variable); |
| 1105 initialization.add(new VariableInitialization(declaration, initializer)); | 1105 initialization.add(new VariableInitialization(declaration, initializer)); |
| 1106 } | 1106 } |
| 1107 | 1107 |
| 1108 declare(firstVariable); | 1108 declare(firstVariable); |
| 1109 while (acceptCategory(COMMA)) { | 1109 while (acceptCategory(COMMA)) { |
| 1110 String variable = lastToken; | 1110 String variable = lastToken; |
| 1111 expectCategory(ALPHA); | 1111 expectCategory(ALPHA); |
| 1112 declare(variable); | 1112 declare(variable); |
| 1113 } | 1113 } |
| 1114 return new VariableDeclarationList(keyword, initialization); | 1114 return new VariableDeclarationList(keyword, initialization); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1207 if (lastToken == 'with') { | 1207 if (lastToken == 'with') { |
| 1208 error('Not implemented in mini parser'); | 1208 error('Not implemented in mini parser'); |
| 1209 } | 1209 } |
| 1210 | 1210 |
| 1211 } | 1211 } |
| 1212 | 1212 |
| 1213 bool checkForInterpolatedStatement = lastCategory == HASH; | 1213 bool checkForInterpolatedStatement = lastCategory == HASH; |
| 1214 | 1214 |
| 1215 Expression expression = parseExpression(); | 1215 Expression expression = parseExpression(); |
| 1216 | 1216 |
| 1217 if (expression is VariableUse && acceptCategory(COLON)) { | 1217 if (expression is Identifier && acceptCategory(COLON)) { |
| 1218 return new LabeledStatement(expression.name, parseStatement()); | 1218 return new LabeledStatement(expression.name, parseStatement()); |
| 1219 } | 1219 } |
| 1220 | 1220 |
| 1221 expectSemicolon(); | 1221 expectSemicolon(); |
| 1222 | 1222 |
| 1223 if (checkForInterpolatedStatement) { | 1223 if (checkForInterpolatedStatement) { |
| 1224 // 'Promote' the interpolated expression `#;` to an interpolated | 1224 // 'Promote' the interpolated expression `#;` to an interpolated |
| 1225 // statement. | 1225 // statement. |
| 1226 if (expression is InterpolatedExpression) { | 1226 if (expression is InterpolatedExpression) { |
| 1227 assert(identical(interpolatedValues.last, expression)); | 1227 assert(identical(interpolatedValues.last, expression)); |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1340 | 1340 |
| 1341 Expression init = parseExpression(); | 1341 Expression init = parseExpression(); |
| 1342 expectCategory(SEMICOLON); | 1342 expectCategory(SEMICOLON); |
| 1343 return finishFor(init); | 1343 return finishFor(init); |
| 1344 } | 1344 } |
| 1345 | 1345 |
| 1346 static VariableDeclarationList _createVariableDeclarationList( | 1346 static VariableDeclarationList _createVariableDeclarationList( |
| 1347 String keyword, String identifier) { | 1347 String keyword, String identifier) { |
| 1348 return new VariableDeclarationList(keyword, [ | 1348 return new VariableDeclarationList(keyword, [ |
| 1349 new VariableInitialization( | 1349 new VariableInitialization( |
| 1350 new VariableDeclaration(identifier), null)]); | 1350 new Identifier(identifier), null)]); |
| 1351 } | 1351 } |
| 1352 | 1352 |
| 1353 Statement parseFunctionDeclaration() { | 1353 Statement parseFunctionDeclaration() { |
| 1354 String name = lastToken; | 1354 String name = lastToken; |
| 1355 expectCategory(ALPHA); | 1355 expectCategory(ALPHA); |
| 1356 Expression fun = parseFun(); | 1356 Expression fun = parseFun(); |
| 1357 return new FunctionDeclaration(new VariableDeclaration(name), fun); | 1357 return new FunctionDeclaration(new Identifier(name), fun); |
| 1358 } | 1358 } |
| 1359 | 1359 |
| 1360 Statement parseTry() { | 1360 Statement parseTry() { |
| 1361 expectCategory(LBRACE); | 1361 expectCategory(LBRACE); |
| 1362 Block body = parseBlock(); | 1362 Block body = parseBlock(); |
| 1363 Catch catchPart = null; | 1363 Catch catchPart = null; |
| 1364 if (acceptString('catch')) catchPart = parseCatch(); | 1364 if (acceptString('catch')) catchPart = parseCatch(); |
| 1365 Block finallyPart = null; | 1365 Block finallyPart = null; |
| 1366 if (acceptString('finally')) { | 1366 if (acceptString('finally')) { |
| 1367 expectCategory(LBRACE); | 1367 expectCategory(LBRACE); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1426 return new Switch(key, clauses); | 1426 return new Switch(key, clauses); |
| 1427 } | 1427 } |
| 1428 | 1428 |
| 1429 Catch parseCatch() { | 1429 Catch parseCatch() { |
| 1430 expectCategory(LPAREN); | 1430 expectCategory(LPAREN); |
| 1431 String identifier = lastToken; | 1431 String identifier = lastToken; |
| 1432 expectCategory(ALPHA); | 1432 expectCategory(ALPHA); |
| 1433 expectCategory(RPAREN); | 1433 expectCategory(RPAREN); |
| 1434 expectCategory(LBRACE); | 1434 expectCategory(LBRACE); |
| 1435 Block body = parseBlock(); | 1435 Block body = parseBlock(); |
| 1436 return new Catch(new VariableDeclaration(identifier), body); | 1436 return new Catch(new Identifier(identifier), body); |
| 1437 } | 1437 } |
| 1438 | 1438 |
| 1439 ClassExpression parseClass() { | 1439 ClassExpression parseClass() { |
| 1440 VariableDeclaration name; | 1440 Identifier name; |
| 1441 if (acceptCategory(HASH)) { | 1441 if (acceptCategory(HASH)) { |
| 1442 var interpolatedName = new InterpolatedVariableDeclaration(parseHash()); | 1442 var interpolatedName = new InterpolatedIdentifier(parseHash()); |
| 1443 interpolatedValues.add(interpolatedName); | 1443 interpolatedValues.add(interpolatedName); |
| 1444 name = interpolatedName; | 1444 name = interpolatedName; |
| 1445 } else { | 1445 } else { |
| 1446 name = new VariableDeclaration(lastToken); | 1446 name = new Identifier(lastToken); |
| 1447 expectCategory(ALPHA); | 1447 expectCategory(ALPHA); |
| 1448 } | 1448 } |
| 1449 Expression heritage = null; | 1449 Expression heritage = null; |
| 1450 if (acceptString('extends')) { | 1450 if (acceptString('extends')) { |
| 1451 heritage = parseLeftHandSide(); | 1451 heritage = parseLeftHandSide(); |
| 1452 } | 1452 } |
| 1453 expectCategory(LBRACE); | 1453 expectCategory(LBRACE); |
| 1454 var methods = new List<Method>(); | 1454 var methods = new List<Method>(); |
| 1455 while (lastCategory != RBRACE) { | 1455 while (lastCategory != RBRACE) { |
| 1456 methods.add(parseMethodOrProperty(onlyMethods: true)); | 1456 methods.add(parseMethodOrProperty(onlyMethods: true)); |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1522 expectCategory(RSQUARE); | 1522 expectCategory(RSQUARE); |
| 1523 return expr; | 1523 return expr; |
| 1524 } else if (acceptCategory(HASH)) { | 1524 } else if (acceptCategory(HASH)) { |
| 1525 return parseInterpolatedExpression(); | 1525 return parseInterpolatedExpression(); |
| 1526 } else { | 1526 } else { |
| 1527 error('Expected property name'); | 1527 error('Expected property name'); |
| 1528 return null; | 1528 return null; |
| 1529 } | 1529 } |
| 1530 } | 1530 } |
| 1531 } | 1531 } |
| OLD | NEW |