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 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |