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

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

Issue 671513013: dart2js: Accept named holes in js-templates. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebase, and move finishedClasses to buildFinishClass. Created 6 years, 1 month 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/compiler/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; 8 part of js;
9 9
10 10
(...skipping 190 matching lines...) Expand 10 before | Expand all | Expand 10 after
201 * 201 *
202 * See the MiniJsParser class. 202 * See the MiniJsParser class.
203 * 203 *
204 * [arguments] can be a single [Node] (e.g. an [Expression] or [Statement]) or 204 * [arguments] can be a single [Node] (e.g. an [Expression] or [Statement]) or
205 * a list of [Node]s, which will be interpolated into the source at the '#' 205 * a list of [Node]s, which will be interpolated into the source at the '#'
206 * signs. 206 * signs.
207 */ 207 */
208 Expression call(String source, [var arguments]) { 208 Expression call(String source, [var arguments]) {
209 Template template = _findExpressionTemplate(source); 209 Template template = _findExpressionTemplate(source);
210 if (arguments == null) return template.instantiate([]); 210 if (arguments == null) return template.instantiate([]);
211 return template.instantiate(arguments is List ? arguments : [arguments]); 211 // We allow a single argument to be given directly.
212 if (arguments is! List && arguments is! Map) arguments = [arguments];
213 return template.instantiate(arguments);
212 } 214 }
213 215
214 /** 216 /**
215 * Parses a JavaScript Statement, otherwise just like [call]. 217 * Parses a JavaScript Statement, otherwise just like [call].
216 */ 218 */
217 Statement statement(String source, [var arguments]) { 219 Statement statement(String source, [var arguments]) {
218 Template template = _findStatementTemplate(source); 220 Template template = _findStatementTemplate(source);
219 if (arguments == null) return template.instantiate([]); 221 if (arguments == null) return template.instantiate([]);
220 return template.instantiate(arguments is List ? arguments : [arguments]); 222 // We allow a single argument to be given directly.
223 if (arguments is! List && arguments is! Map) arguments = [arguments];
224 return template.instantiate(arguments);
221 } 225 }
222 226
223 /** 227 /**
224 * Parses JavaScript written in the `JS` foreign instruction. 228 * Parses JavaScript written in the `JS` foreign instruction.
225 * 229 *
226 * The [source] must be a JavaScript expression or a JavaScript throw 230 * The [source] must be a JavaScript expression or a JavaScript throw
227 * statement. 231 * statement.
228 */ 232 */
229 Template parseForeignJS(String source) { 233 Template parseForeignJS(String source) {
230 // TODO(sra): Parse with extra validation to forbid `#` interpolation in 234 // TODO(sra): Parse with extra validation to forbid `#` interpolation in
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after
395 position = 0 { 399 position = 0 {
396 getToken(); 400 getToken();
397 } 401 }
398 402
399 int lastCategory = NONE; 403 int lastCategory = NONE;
400 String lastToken = null; 404 String lastToken = null;
401 int lastPosition = 0; 405 int lastPosition = 0;
402 int position = 0; 406 int position = 0;
403 bool skippedNewline = false; // skipped newline in last getToken? 407 bool skippedNewline = false; // skipped newline in last getToken?
404 final String src; 408 final String src;
409
405 final List<InterpolatedNode> interpolatedValues = <InterpolatedNode>[]; 410 final List<InterpolatedNode> interpolatedValues = <InterpolatedNode>[];
411 bool get hasNamedHoles =>
412 interpolatedValues.isNotEmpty && interpolatedValues.first.isNamed;
413 bool get hasPositionalHoles =>
414 interpolatedValues.isNotEmpty && interpolatedValues.first.isPositional;
406 415
407 static const NONE = -1; 416 static const NONE = -1;
408 static const ALPHA = 0; 417 static const ALPHA = 0;
409 static const NUMERIC = 1; 418 static const NUMERIC = 1;
410 static const STRING = 2; 419 static const STRING = 2;
411 static const SYMBOL = 3; 420 static const SYMBOL = 3;
412 static const ASSIGNMENT = 4; 421 static const ASSIGNMENT = 4;
413 static const DOT = 5; 422 static const DOT = 5;
414 static const LPAREN = 6; 423 static const LPAREN = 6;
415 static const RPAREN = 7; 424 static const RPAREN = 7;
(...skipping 241 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 getToken(); 666 getToken();
658 return true; 667 return true;
659 } 668 }
660 return false; 669 return false;
661 } 670 }
662 671
663 void error(message) { 672 void error(message) {
664 throw new MiniJsParserError(this, message); 673 throw new MiniJsParserError(this, message);
665 } 674 }
666 675
676 /// Returns either the name for the hole, or its integer position.
677 parseHash() {
678 String holeName = lastToken;
679 if (acceptCategory(ALPHA)) {
680 // Named hole. Example: 'function #funName() { ... }'
681 if (hasPositionalHoles) {
682 error('Holes must all be positional or named. $holeName');
683 }
684 return holeName;
685 } else {
686 if (hasNamedHoles) {
687 error('Holes must all be positional or named. $holeName');
688 }
689 int position = interpolatedValues.length;
690 return position;
691 }
692 }
693
667 Expression parsePrimary() { 694 Expression parsePrimary() {
668 String last = lastToken; 695 String last = lastToken;
669 if (acceptCategory(ALPHA)) { 696 if (acceptCategory(ALPHA)) {
670 if (last == "true") { 697 if (last == "true") {
671 return new LiteralBool(true); 698 return new LiteralBool(true);
672 } else if (last == "false") { 699 } else if (last == "false") {
673 return new LiteralBool(false); 700 return new LiteralBool(false);
674 } else if (last == "null") { 701 } else if (last == "null") {
675 return new LiteralNull(); 702 return new LiteralNull();
676 } else if (last == "function") { 703 } else if (last == "function") {
(...skipping 21 matching lines...) Expand all
698 } 725 }
699 return new ArrayInitializer(values.length, values); 726 return new ArrayInitializer(values.length, values);
700 } else if (last != null && last.startsWith("/")) { 727 } else if (last != null && last.startsWith("/")) {
701 String regexp = getDelimited(lastPosition); 728 String regexp = getDelimited(lastPosition);
702 getToken(); 729 getToken();
703 String flags = lastToken; 730 String flags = lastToken;
704 if (!acceptCategory(ALPHA)) flags = ""; 731 if (!acceptCategory(ALPHA)) flags = "";
705 Expression expression = new RegExpLiteral(regexp + flags); 732 Expression expression = new RegExpLiteral(regexp + flags);
706 return expression; 733 return expression;
707 } else if (acceptCategory(HASH)) { 734 } else if (acceptCategory(HASH)) {
735 var nameOrPosition = parseHash();
708 InterpolatedExpression expression = 736 InterpolatedExpression expression =
709 new InterpolatedExpression(interpolatedValues.length); 737 new InterpolatedExpression(nameOrPosition);
710 interpolatedValues.add(expression); 738 interpolatedValues.add(expression);
711 return expression; 739 return expression;
712 } else { 740 } else {
713 error("Expected primary expression"); 741 error("Expected primary expression");
714 return null; 742 return null;
715 } 743 }
716 } 744 }
717 745
718 Expression parseFunctionExpression() { 746 Expression parseFunctionExpression() {
719 String last = lastToken; 747 String last = lastToken;
720 if (acceptCategory(ALPHA)) { 748 if (acceptCategory(ALPHA)) {
721 String functionName = last; 749 String functionName = last;
722 return new NamedFunction(new VariableDeclaration(functionName), 750 return new NamedFunction(new VariableDeclaration(functionName),
723 parseFun()); 751 parseFun());
724 } 752 }
725 return parseFun(); 753 return parseFun();
726 } 754 }
727 755
728 Expression parseFun() { 756 Expression parseFun() {
729 List<Parameter> params = <Parameter>[]; 757 List<Parameter> params = <Parameter>[];
730 758
731 expectCategory(LPAREN); 759 expectCategory(LPAREN);
732 if (!acceptCategory(RPAREN)) { 760 if (!acceptCategory(RPAREN)) {
733 for (;;) { 761 for (;;) {
734 if (acceptCategory(HASH)) { 762 if (acceptCategory(HASH)) {
763 var nameOrPosition = parseHash();
735 InterpolatedParameter parameter = 764 InterpolatedParameter parameter =
736 new InterpolatedParameter(interpolatedValues.length); 765 new InterpolatedParameter(nameOrPosition);
737 interpolatedValues.add(parameter); 766 interpolatedValues.add(parameter);
738 params.add(parameter); 767 params.add(parameter);
739 } else { 768 } else {
740 String argumentName = lastToken; 769 String argumentName = lastToken;
741 expectCategory(ALPHA); 770 expectCategory(ALPHA);
742 params.add(new Parameter(argumentName)); 771 params.add(new Parameter(argumentName));
743 } 772 }
744 if (acceptCategory(COMMA)) continue; 773 if (acceptCategory(COMMA)) continue;
745 expectCategory(RPAREN); 774 expectCategory(RPAREN);
746 break; 775 break;
(...skipping 12 matching lines...) Expand all
759 // Limited subset: keys are identifiers, no 'get' or 'set' properties. 788 // Limited subset: keys are identifiers, no 'get' or 'set' properties.
760 Literal propertyName; 789 Literal propertyName;
761 String identifier = lastToken; 790 String identifier = lastToken;
762 if (acceptCategory(ALPHA)) { 791 if (acceptCategory(ALPHA)) {
763 propertyName = new LiteralString('"$identifier"'); 792 propertyName = new LiteralString('"$identifier"');
764 } else if (acceptCategory(STRING)) { 793 } else if (acceptCategory(STRING)) {
765 propertyName = new LiteralString(identifier); 794 propertyName = new LiteralString(identifier);
766 } else if (acceptCategory(SYMBOL)) { // e.g. void 795 } else if (acceptCategory(SYMBOL)) { // e.g. void
767 propertyName = new LiteralString('"$identifier"'); 796 propertyName = new LiteralString('"$identifier"');
768 } else if (acceptCategory(HASH)) { 797 } else if (acceptCategory(HASH)) {
798 var nameOrPosition = parseHash();
769 InterpolatedLiteral interpolatedLiteral = 799 InterpolatedLiteral interpolatedLiteral =
770 new InterpolatedLiteral(interpolatedValues.length); 800 new InterpolatedLiteral(nameOrPosition);
771 interpolatedValues.add(interpolatedLiteral); 801 interpolatedValues.add(interpolatedLiteral);
772 propertyName = interpolatedLiteral; 802 propertyName = interpolatedLiteral;
773 } else { 803 } else {
774 error('Expected property name'); 804 error('Expected property name');
775 } 805 }
776 expectCategory(COLON); 806 expectCategory(COLON);
777 Expression value = parseAssignment(); 807 Expression value = parseAssignment();
778 properties.add(new Property(propertyName, value)); 808 properties.add(new Property(propertyName, value));
779 if (acceptCategory(RBRACE)) break; 809 if (acceptCategory(RBRACE)) break;
780 expectCategory(COMMA); 810 expectCategory(COMMA);
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
826 // JS allows new without (), but we don't. 856 // JS allows new without (), but we don't.
827 if (constructor) error("Parentheses are required for new"); 857 if (constructor) error("Parentheses are required for new");
828 break; 858 break;
829 } 859 }
830 } 860 }
831 return receiver; 861 return receiver;
832 } 862 }
833 863
834 Expression getDotRhs(Expression receiver) { 864 Expression getDotRhs(Expression receiver) {
835 if (acceptCategory(HASH)) { 865 if (acceptCategory(HASH)) {
836 InterpolatedSelector property = 866 var nameOrPosition = parseHash();
837 new InterpolatedSelector(interpolatedValues.length); 867 InterpolatedSelector property = new InterpolatedSelector(nameOrPosition);
838 interpolatedValues.add(property); 868 interpolatedValues.add(property);
839 return new PropertyAccess(receiver, property); 869 return new PropertyAccess(receiver, property);
840 } 870 }
841 String identifier = lastToken; 871 String identifier = lastToken;
842 // In ES5 keywords like delete and continue are allowed as property 872 // In ES5 keywords like delete and continue are allowed as property
843 // names, and the IndexedDB API uses that, so we need to allow it here. 873 // names, and the IndexedDB API uses that, so we need to allow it here.
844 if (acceptCategory(SYMBOL)) { 874 if (acceptCategory(SYMBOL)) {
845 if (!OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS.contains(identifier)) { 875 if (!OPERATORS_THAT_LOOK_LIKE_IDENTIFIERS.contains(identifier)) {
846 error("Expected alphanumeric identifier"); 876 error("Expected alphanumeric identifier");
847 } 877 }
(...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after
1059 1089
1060 Expression expression = parseExpression(); 1090 Expression expression = parseExpression();
1061 expectSemicolon(); 1091 expectSemicolon();
1062 1092
1063 if (checkForInterpolatedStatement) { 1093 if (checkForInterpolatedStatement) {
1064 // 'Promote' the interpolated expression `#;` to an interpolated 1094 // 'Promote' the interpolated expression `#;` to an interpolated
1065 // statement. 1095 // statement.
1066 if (expression is InterpolatedExpression) { 1096 if (expression is InterpolatedExpression) {
1067 assert(identical(interpolatedValues.last, expression)); 1097 assert(identical(interpolatedValues.last, expression));
1068 InterpolatedStatement statement = 1098 InterpolatedStatement statement =
1069 new InterpolatedStatement(expression.name); 1099 new InterpolatedStatement(expression.nameOrPosition);
1070 interpolatedValues[interpolatedValues.length - 1] = statement; 1100 interpolatedValues[interpolatedValues.length - 1] = statement;
1071 return statement; 1101 return statement;
1072 } 1102 }
1073 } 1103 }
1074 1104
1075 return new ExpressionStatement(expression); 1105 return new ExpressionStatement(expression);
1076 } 1106 }
1077 1107
1078 Statement parseReturn() { 1108 Statement parseReturn() {
1079 if (acceptSemicolon()) return new Return(); 1109 if (acceptSemicolon()) return new Return();
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after
1190 Catch parseCatch() { 1220 Catch parseCatch() {
1191 expectCategory(LPAREN); 1221 expectCategory(LPAREN);
1192 String identifier = lastToken; 1222 String identifier = lastToken;
1193 expectCategory(ALPHA); 1223 expectCategory(ALPHA);
1194 expectCategory(RPAREN); 1224 expectCategory(RPAREN);
1195 expectCategory(LBRACE); 1225 expectCategory(LBRACE);
1196 Block body = parseBlock(); 1226 Block body = parseBlock();
1197 return new Catch(new VariableDeclaration(identifier), body); 1227 return new Catch(new VariableDeclaration(identifier), body);
1198 } 1228 }
1199 } 1229 }
OLDNEW
« no previous file with comments | « no previous file | pkg/compiler/lib/src/js/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698