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

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

Issue 1183033004: js_ast: implement rest/spread parsing (Closed) Base URL: git@github.com:dart-lang/dev_compiler.git@master
Patch Set: Created 5 years, 6 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
« no previous file with comments | « lib/runtime/dart_runtime.js ('k') | lib/src/js/nodes.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 432 matching lines...) Expand 10 before | Expand all | Expand 10 after
443 static const RPAREN = 7; 443 static const RPAREN = 7;
444 static const LBRACE = 8; 444 static const LBRACE = 8;
445 static const RBRACE = 9; 445 static const RBRACE = 9;
446 static const LSQUARE = 10; 446 static const LSQUARE = 10;
447 static const RSQUARE = 11; 447 static const RSQUARE = 11;
448 static const COMMA = 12; 448 static const COMMA = 12;
449 static const QUERY = 13; 449 static const QUERY = 13;
450 static const COLON = 14; 450 static const COLON = 14;
451 static const SEMICOLON = 15; 451 static const SEMICOLON = 15;
452 static const ARROW = 16; 452 static const ARROW = 16;
453 static const HASH = 17; 453 static const ELLIPSIS = 17;
454 static const WHITESPACE = 18; 454 static const HASH = 18;
455 static const OTHER = 19; 455 static const WHITESPACE = 19;
456 static const OTHER = 20;
456 457
457 // Make sure that ]] is two symbols. 458 // Make sure that ]] is two symbols.
458 bool singleCharCategory(int category) => category >= DOT; 459 // TODO(jmesserly): => and ... are not single char tokens, should we change
460 // their numbers? It shouldn't matter because this is only called on values
461 // from the [CATEGORIES] table.
462 bool singleCharCategory(int category) => category > DOT;
459 463
460 static String categoryToString(int cat) { 464 static String categoryToString(int cat) {
461 switch (cat) { 465 switch (cat) {
462 case NONE: return "NONE"; 466 case NONE: return "NONE";
463 case ALPHA: return "ALPHA"; 467 case ALPHA: return "ALPHA";
464 case NUMERIC: return "NUMERIC"; 468 case NUMERIC: return "NUMERIC";
465 case SYMBOL: return "SYMBOL"; 469 case SYMBOL: return "SYMBOL";
466 case ASSIGNMENT: return "ASSIGNMENT"; 470 case ASSIGNMENT: return "ASSIGNMENT";
467 case DOT: return "DOT"; 471 case DOT: return "DOT";
468 case LPAREN: return "LPAREN"; 472 case LPAREN: return "LPAREN";
469 case RPAREN: return "RPAREN"; 473 case RPAREN: return "RPAREN";
470 case LBRACE: return "LBRACE"; 474 case LBRACE: return "LBRACE";
471 case RBRACE: return "RBRACE"; 475 case RBRACE: return "RBRACE";
472 case LSQUARE: return "LSQUARE"; 476 case LSQUARE: return "LSQUARE";
473 case RSQUARE: return "RSQUARE"; 477 case RSQUARE: return "RSQUARE";
474 case STRING: return "STRING"; 478 case STRING: return "STRING";
475 case COMMA: return "COMMA"; 479 case COMMA: return "COMMA";
476 case QUERY: return "QUERY"; 480 case QUERY: return "QUERY";
477 case COLON: return "COLON"; 481 case COLON: return "COLON";
478 case SEMICOLON: return "SEMICOLON"; 482 case SEMICOLON: return "SEMICOLON";
479 case ARROW: return "ARROW"; 483 case ARROW: return "ARROW";
484 case ELLIPSIS: return "ELLIPSIS";
480 case HASH: return "HASH"; 485 case HASH: return "HASH";
481 case WHITESPACE: return "WHITESPACE"; 486 case WHITESPACE: return "WHITESPACE";
482 case OTHER: return "OTHER"; 487 case OTHER: return "OTHER";
483 } 488 }
484 return "Unknown: $cat"; 489 return "Unknown: $cat";
485 } 490 }
486 491
487 static const CATEGORIES = const <int>[ 492 static const CATEGORIES = const <int>[
488 OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 0-7 493 OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, OTHER, // 0-7
489 OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE, // 8-13 494 OTHER, WHITESPACE, WHITESPACE, OTHER, OTHER, WHITESPACE, // 8-13
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
521 '<': 8, '<=': 8, '>=': 8, '>': 8, 'in': 8, 'instanceof': 8, 526 '<': 8, '<=': 8, '>=': 8, '>': 8, 'in': 8, 'instanceof': 8,
522 '<<': 7, '>>': 7, '>>>': 7, 527 '<<': 7, '>>': 7, '>>>': 7,
523 '+': 6, '-': 6, 528 '+': 6, '-': 6,
524 '*': 5, '/': 5, '%': 5 529 '*': 5, '/': 5, '%': 5
525 }; 530 };
526 static final UNARY_OPERATORS = 531 static final UNARY_OPERATORS =
527 ['++', '--', '+', '-', '~', '!', 'typeof', 'void', 'delete', 'await'] 532 ['++', '--', '+', '-', '~', '!', 'typeof', 'void', 'delete', 'await']
528 .toSet(); 533 .toSet();
529 534
530 static final ARROW_TOKEN = '=>'; 535 static final ARROW_TOKEN = '=>';
536 static final ELLIPSIS_TOKEN = '...';
531 537
532 static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS = 538 static final OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS =
533 ['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet(); 539 ['typeof', 'void', 'delete', 'in', 'instanceof', 'await'].toSet();
534 540
535 static int category(int code) { 541 static int category(int code) {
536 if (code >= CATEGORIES.length) return OTHER; 542 if (code >= CATEGORIES.length) return OTHER;
537 return CATEGORIES[code]; 543 return CATEGORIES[code];
538 } 544 }
539 545
540 String getDelimited(int startPosition) { 546 String getDelimited(int startPosition) {
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
635 } while (!singleCharCategory(cat) && 641 } while (!singleCharCategory(cat) &&
636 (cat == newCat || 642 (cat == newCat ||
637 (cat == ALPHA && newCat == NUMERIC) || // eg. level42. 643 (cat == ALPHA && newCat == NUMERIC) || // eg. level42.
638 (cat == NUMERIC && newCat == DOT))); // eg. 3.1415 644 (cat == NUMERIC && newCat == DOT))); // eg. 3.1415
639 lastCategory = cat; 645 lastCategory = cat;
640 lastToken = src.substring(lastPosition, position); 646 lastToken = src.substring(lastPosition, position);
641 if (cat == NUMERIC) { 647 if (cat == NUMERIC) {
642 double.parse(lastToken, (_) { 648 double.parse(lastToken, (_) {
643 error("Unparseable number"); 649 error("Unparseable number");
644 }); 650 });
651 } else if (cat == DOT && lastToken.length > 1) {
652 if (lastToken == ELLIPSIS_TOKEN) {
653 lastCategory = ELLIPSIS;
654 } else {
655 error("Unknown operator");
656 }
645 } else if (cat == SYMBOL) { 657 } else if (cat == SYMBOL) {
646 if (lastToken == ARROW_TOKEN) { 658 if (lastToken == ARROW_TOKEN) {
647 lastCategory = ARROW; 659 lastCategory = ARROW;
648 } else { 660 } else {
649 int binaryPrecendence = BINARY_PRECEDENCE[lastToken]; 661 int binaryPrecendence = BINARY_PRECEDENCE[lastToken];
650 if (binaryPrecendence == null && !UNARY_OPERATORS.contains(lastToken)) { 662 if (binaryPrecendence == null && !UNARY_OPERATORS.contains(lastToken)) {
651 error("Unknown operator"); 663 error("Unknown operator");
652 } 664 }
653 if (isAssignment(lastToken)) lastCategory = ASSIGNMENT; 665 if (isAssignment(lastToken)) lastCategory = ASSIGNMENT;
654 } 666 }
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
785 /** 797 /**
786 * CoverParenthesizedExpressionAndArrowParameterList[Yield] : 798 * CoverParenthesizedExpressionAndArrowParameterList[Yield] :
787 * ( Expression ) 799 * ( Expression )
788 * ( ) 800 * ( )
789 * ( ... BindingIdentifier ) 801 * ( ... BindingIdentifier )
790 * ( Expression , ... BindingIdentifier ) 802 * ( Expression , ... BindingIdentifier )
791 */ 803 */
792 Expression parseExpressionOrArrowFunction() { 804 Expression parseExpressionOrArrowFunction() {
793 if (acceptCategory(RPAREN)) { 805 if (acceptCategory(RPAREN)) {
794 expectCategory(ARROW); 806 expectCategory(ARROW);
795 return parseArrowFunctionBody(<Identifier>[]); 807 return parseArrowFunctionBody(<Parameter>[]);
796 } 808 }
797 Expression expression = parseExpression(); 809 if (acceptCategory(ELLIPSIS)) {
810 var params = <Parameter>[new RestParameter(parseParameter())];
811 expectCategory(RPAREN);
812 expectCategory(ARROW);
813 return parseArrowFunctionBody(params);
814 }
815 Expression expression = parseAssignment();
816 while (acceptCategory(COMMA)) {
817 if (acceptCategory(ELLIPSIS)) {
818 var params = <Parameter>[];
819 _expressionToParameterList(expression, params);
820 params.add(new RestParameter(parseParameter()));
821 expectCategory(RPAREN);
822 expectCategory(ARROW);
823 return parseArrowFunctionBody(params);
824 }
825 Expression right = parseAssignment();
826 expression = new Binary(',', expression, right);
827 }
798 expectCategory(RPAREN); 828 expectCategory(RPAREN);
799 if (acceptCategory(ARROW)) { 829 if (acceptCategory(ARROW)) {
800 var params = <Identifier>[]; 830 var params = <Parameter>[];
801 _expressionToParameterList(expression, params); 831 _expressionToParameterList(expression, params);
802 return parseArrowFunctionBody(params); 832 return parseArrowFunctionBody(params);
803 } 833 }
804 return expression; 834 return expression;
805
806 } 835 }
807 836
808 /** 837 /**
809 * Converts a parenthesized expression into a list of parameters, issuing an 838 * Converts a parenthesized expression into a list of parameters, issuing an
810 * error if the conversion fails. 839 * error if the conversion fails.
811 */ 840 */
812 void _expressionToParameterList(Expression node, List<Identifier> params) { 841 void _expressionToParameterList(Expression node, List<Parameter> params) {
813 if (node is Identifier) { 842 if (node is Identifier) {
814 // TODO(jmesserly): support default/rest parameters
815 params.add(node); 843 params.add(node);
816 } else if (node is Binary && node.op == ',') { 844 } else if (node is Binary && node.op == ',') {
817 // TODO(jmesserly): this will allow illegal parens, such as 845 // TODO(jmesserly): this will allow illegal parens, such as
818 // `((a, b), (c, d))`. Fixing it on the left side needs an explicit 846 // `((a, b), (c, d))`. Fixing it on the left side needs an explicit
819 // ParenthesizedExpression node, so we can distinguish 847 // ParenthesizedExpression node, so we can distinguish
820 // `((a, b), c)` from `(a, b, c)`. 848 // `((a, b), c)` from `(a, b, c)`.
821 _expressionToParameterList(node.left, params); 849 _expressionToParameterList(node.left, params);
822 _expressionToParameterList(node.right, params); 850 _expressionToParameterList(node.right, params);
823 } else if (node is InterpolatedExpression) { 851 } else if (node is InterpolatedExpression) {
824 params.add(new InterpolatedParameter(node.nameOrPosition)); 852 params.add(new InterpolatedParameter(node.nameOrPosition));
825 } else { 853 } else {
826 error("Expected arrow function parameter list"); 854 error("Expected arrow function parameter list");
827 } 855 }
828 } 856 }
829 857
830 Expression parseArrowFunctionBody(List<Identifier> params) { 858 Expression parseArrowFunctionBody(List<Parameter> params) {
831 Node body; 859 Node body;
832 if (acceptCategory(LBRACE)) { 860 if (acceptCategory(LBRACE)) {
833 body = parseBlock(); 861 body = parseBlock();
834 } else { 862 } else {
835 body = parseAssignment(); 863 body = parseAssignment();
836 } 864 }
837 return new ArrowFun(params, body); 865 return new ArrowFun(params, body);
838 } 866 }
839 867
840 Expression parseFunctionExpression() { 868 Expression parseFunctionExpression() {
841 String last = lastToken; 869 String last = lastToken;
842 if (acceptCategory(ALPHA)) { 870 if (acceptCategory(ALPHA)) {
843 String functionName = last; 871 String functionName = last;
844 return new NamedFunction(new Identifier(functionName), 872 return new NamedFunction(new Identifier(functionName),
845 parseFun()); 873 parseFun());
846 } 874 }
847 return parseFun(); 875 return parseFun();
848 } 876 }
849 877
850 Expression parseFun() { 878 Expression parseFun() {
851 List<Identifier> params = <Identifier>[]; 879 List<Parameter> params = <Parameter>[];
852 880
853 expectCategory(LPAREN); 881 expectCategory(LPAREN);
854 if (!acceptCategory(RPAREN)) { 882 if (!acceptCategory(RPAREN)) {
855 for (;;) { 883 for (;;) {
856 if (acceptCategory(HASH)) { 884 if (acceptCategory(ELLIPSIS)) {
857 var nameOrPosition = parseHash(); 885 params.add(new RestParameter(parseParameter()));
858 InterpolatedParameter parameter = 886 expectCategory(RPAREN);
859 new InterpolatedParameter(nameOrPosition); 887 break;
860 interpolatedValues.add(parameter);
861 params.add(parameter);
862 } else {
863 String argumentName = lastToken;
864 expectCategory(ALPHA);
865 params.add(new Identifier(argumentName));
866 } 888 }
867 if (acceptCategory(COMMA)) continue; 889
868 expectCategory(RPAREN); 890 params.add(parseParameter());
869 break; 891 if (!acceptCategory(COMMA)) {
892 expectCategory(RPAREN);
893 break;
894 }
870 } 895 }
871 } 896 }
872 AsyncModifier asyncModifier; 897 AsyncModifier asyncModifier;
873 if (acceptString('async')) { 898 if (acceptString('async')) {
874 if (acceptString('*')) { 899 if (acceptString('*')) {
875 asyncModifier = const AsyncModifier.asyncStar(); 900 asyncModifier = const AsyncModifier.asyncStar();
876 } else { 901 } else {
877 asyncModifier = const AsyncModifier.async(); 902 asyncModifier = const AsyncModifier.async();
878 } 903 }
879 } else if (acceptString('sync')) { 904 } else if (acceptString('sync')) {
880 if (!acceptString('*')) error("Only sync* is valid - sync is implied"); 905 if (!acceptString('*')) error("Only sync* is valid - sync is implied");
881 asyncModifier = const AsyncModifier.syncStar(); 906 asyncModifier = const AsyncModifier.syncStar();
882 } else { 907 } else {
883 asyncModifier = const AsyncModifier.sync(); 908 asyncModifier = const AsyncModifier.sync();
884 } 909 }
885 expectCategory(LBRACE); 910 expectCategory(LBRACE);
886 Block block = parseBlock(); 911 Block block = parseBlock();
887 return new Fun(params, block, asyncModifier: asyncModifier); 912 return new Fun(params, block, asyncModifier: asyncModifier);
888 } 913 }
889 914
915 /** Parse parameter name or interpolated parameter. */
916 Identifier parseParameter() {
917 if (acceptCategory(HASH)) {
918 var nameOrPosition = parseHash();
919 var parameter = new InterpolatedParameter(nameOrPosition);
920 interpolatedValues.add(parameter);
921 return parameter;
922 } else {
923 // TODO(jmesserly): validate this is not a keyword
924 String argumentName = lastToken;
925 expectCategory(ALPHA);
926 return new Identifier(argumentName);
927 }
928 }
929
890 Expression parseObjectInitializer() { 930 Expression parseObjectInitializer() {
891 List<Property> properties = <Property>[]; 931 List<Property> properties = <Property>[];
892 for (;;) { 932 for (;;) {
893 if (acceptCategory(RBRACE)) break; 933 if (acceptCategory(RBRACE)) break;
894 // Limited subset of ES6 object initializers. 934 // Limited subset of ES6 object initializers.
895 // 935 //
896 // PropertyDefinition : 936 // PropertyDefinition :
897 // PropertyName : AssignmentExpression 937 // PropertyName : AssignmentExpression
898 // MethodDefinition 938 // MethodDefinition
899 properties.add(parseMethodOrProperty()); 939 properties.add(parseMethodOrProperty());
(...skipping 21 matching lines...) Expand all
921 } 961 }
922 962
923 Expression parseCall() { 963 Expression parseCall() {
924 bool constructor = acceptString("new"); 964 bool constructor = acceptString("new");
925 Expression receiver = parseMember(); 965 Expression receiver = parseMember();
926 while (true) { 966 while (true) {
927 if (acceptCategory(LPAREN)) { 967 if (acceptCategory(LPAREN)) {
928 final arguments = <Expression>[]; 968 final arguments = <Expression>[];
929 if (!acceptCategory(RPAREN)) { 969 if (!acceptCategory(RPAREN)) {
930 while (true) { 970 while (true) {
931 Expression argument = parseAssignment(); 971 if (acceptCategory(ELLIPSIS)) {
932 arguments.add(argument); 972 arguments.add(new Spread(parseAssignment()));
973 expectCategory(RPAREN);
974 break;
975 }
976 arguments.add(parseAssignment());
933 if (acceptCategory(RPAREN)) break; 977 if (acceptCategory(RPAREN)) break;
934 expectCategory(COMMA); 978 expectCategory(COMMA);
935 } 979 }
936 } 980 }
937 receiver = constructor ? 981 receiver = constructor ?
938 new New(receiver, arguments) : 982 new New(receiver, arguments) :
939 new Call(receiver, arguments); 983 new Call(receiver, arguments);
940 constructor = false; 984 constructor = false;
941 } else if (!constructor && acceptCategory(LSQUARE)) { 985 } else if (!constructor && acceptCategory(LSQUARE)) {
942 Expression inBraces = parseExpression(); 986 Expression inBraces = parseExpression();
(...skipping 579 matching lines...) Expand 10 before | Expand all | Expand 10 after
1522 expectCategory(RSQUARE); 1566 expectCategory(RSQUARE);
1523 return expr; 1567 return expr;
1524 } else if (acceptCategory(HASH)) { 1568 } else if (acceptCategory(HASH)) {
1525 return parseInterpolatedExpression(); 1569 return parseInterpolatedExpression();
1526 } else { 1570 } else {
1527 error('Expected property name'); 1571 error('Expected property name');
1528 return null; 1572 return null;
1529 } 1573 }
1530 } 1574 }
1531 } 1575 }
OLDNEW
« no previous file with comments | « lib/runtime/dart_runtime.js ('k') | lib/src/js/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698