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

Side by Side Diff: sdk/lib/_internal/compiler/implementation/js/builder.dart

Issue 238633007: Redo "Add more MiniJsParser functionality." (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 8 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/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 class JsBuilder { 10 class JsBuilder {
11 const JsBuilder(); 11 const JsBuilder();
12 12
13 // Parse a bit of JavaScript, and return an expression. 13 /**
14 // See the MiniJsParser class. 14 * Parses a bit of JavaScript, and returns an expression.
15 // You can provide an expression or a list of expressions, which will be 15 *
16 // interpolated into the source at the '#' signs. 16 * See the MiniJsParser class.
17 *
18 * [expression] can be an [Expression] or a list of [Expression]s, which will
19 * be interpolated into the source at the '#' signs.
20 */
17 Expression call(String source, [var expression]) { 21 Expression call(String source, [var expression]) {
18 var result = new MiniJsParser(source).expression(); 22 var result = new MiniJsParser(source).expression();
19 if (expression == null) return result; 23 if (expression == null) return result;
20 24
21 List<Expression> expressions; 25 List<Node> nodes;
22 if (expression is List) { 26 if (expression is List) {
23 expressions = expression; 27 nodes = expression;
24 } else { 28 } else {
25 expressions = <Expression>[expression]; 29 nodes = <Node>[expression];
26 } 30 }
27 if (expressions.length != result.interpolatedExpressions.length) { 31 if (nodes.length != result.interpolatedNodes.length) {
28 throw "Unmatched number of interpolated expressions"; 32 throw 'Unmatched number of interpolated expressions given ${nodes.length}'
33 ' expected ${result.interpolatedNodes.length}';
29 } 34 }
30 for (int i = 0; i < expressions.length; i++) { 35 for (int i = 0; i < nodes.length; i++) {
31 result.interpolatedExpressions[i].value = expressions[i]; 36 result.interpolatedNodes[i].assign(nodes[i]);
32 } 37 }
33 38
34 return result.value; 39 return result.value;
35 } 40 }
36 41
42 Statement statement(String source) {
43 var result = new MiniJsParser(source).statement();
44 // TODO(sra): Interpolation.
45 return result;
46 }
47
37 // Parse JavaScript written in the JS foreign instruction. 48 // Parse JavaScript written in the JS foreign instruction.
38 Expression parseForeignJS(String source, [var expression]) { 49 Expression parseForeignJS(String source, [var expression]) {
39 // We can parse simple JS with the mini parser. At the moment we can't 50 // We can parse simple JS with the mini parser. At the moment we can't
40 // handle JSON literals and function literals, both of which contain "{". 51 // handle JSON literals and function literals, both of which contain "{".
41 if (source.contains("{") || source.startsWith("throw ")) { 52 if (source.contains("{") || source.startsWith("throw ")) {
42 assert(expression == null); 53 assert(expression == null);
43 return new LiteralExpression(source); 54 return new LiteralExpression(source);
44 } 55 }
45 return call(source, expression); 56 return call(source, expression);
46 } 57 }
(...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after
254 position = 0 { 265 position = 0 {
255 getToken(); 266 getToken();
256 } 267 }
257 268
258 int lastCategory = NONE; 269 int lastCategory = NONE;
259 String lastToken = null; 270 String lastToken = null;
260 int lastPosition = 0; 271 int lastPosition = 0;
261 int position = 0; 272 int position = 0;
262 bool skippedNewline = false; // skipped newline in last getToken? 273 bool skippedNewline = false; // skipped newline in last getToken?
263 final String src; 274 final String src;
264 final List<InterpolatedExpression> interpolatedValues = 275 final List<InterpolatedNode> interpolatedValues = <InterpolatedNode>[];
265 <InterpolatedExpression>[];
266 276
267 static const NONE = -1; 277 static const NONE = -1;
268 static const ALPHA = 0; 278 static const ALPHA = 0;
269 static const NUMERIC = 1; 279 static const NUMERIC = 1;
270 static const STRING = 2; 280 static const STRING = 2;
271 static const SYMBOL = 3; 281 static const SYMBOL = 3;
272 static const ASSIGNMENT = 4; 282 static const ASSIGNMENT = 4;
273 static const DOT = 5; 283 static const DOT = 5;
274 static const LPAREN = 6; 284 static const LPAREN = 6;
275 static const RPAREN = 7; 285 static const RPAREN = 7;
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after
365 } 375 }
366 376
367 String getDelimited(int startPosition) { 377 String getDelimited(int startPosition) {
368 position = startPosition; 378 position = startPosition;
369 int delimiter = src.codeUnitAt(startPosition); 379 int delimiter = src.codeUnitAt(startPosition);
370 int currentCode; 380 int currentCode;
371 do { 381 do {
372 position++; 382 position++;
373 if (position >= src.length) error("Unterminated literal"); 383 if (position >= src.length) error("Unterminated literal");
374 currentCode = src.codeUnitAt(position); 384 currentCode = src.codeUnitAt(position);
385 if (currentCode == charCodes.$LF) error("Unterminated literal");
375 if (currentCode == charCodes.$BACKSLASH) { 386 if (currentCode == charCodes.$BACKSLASH) {
376 if (++position >= src.length) error("Unterminated literal"); 387 if (++position >= src.length) error("Unterminated literal");
377 int escaped = src.codeUnitAt(position); 388 int escaped = src.codeUnitAt(position);
378 if (escaped == charCodes.$x || escaped == charCodes.$X || 389 if (escaped == charCodes.$x || escaped == charCodes.$X ||
379 escaped == charCodes.$u || escaped == charCodes.$U || 390 escaped == charCodes.$u || escaped == charCodes.$U ||
380 category(escaped) == NUMERIC) { 391 category(escaped) == NUMERIC) {
381 error('Numeric and hex escapes are not allowed in literals'); 392 error('Numeric and hex escapes are not allowed in literals');
382 } 393 }
383 } 394 }
384 } while (currentCode != delimiter); 395 } while (currentCode != delimiter);
385 position++; 396 position++;
386 return src.substring(lastPosition, position); 397 return src.substring(lastPosition, position);
387 } 398 }
388 399
389 void getToken() { 400 void getToken() {
390 skippedNewline = false; 401 skippedNewline = false;
391 for(;;) { 402 for (;;) {
392 if (position >= src.length) break; 403 if (position >= src.length) break;
393 int code = src.codeUnitAt(position); 404 int code = src.codeUnitAt(position);
394 if (category(code) != WHITESPACE) break; 405 // Skip '//' style comment.
395 if (code == charCodes.$LF) skippedNewline = true; 406 if (code == charCodes.$SLASH &&
396 ++position; 407 position + 1 < src.length &&
408 src.codeUnitAt(position + 1) == charCodes.$SLASH) {
409 int nextPosition = src.indexOf('\n', position);
410 if (nextPosition == -1) nextPosition = src.length;
411 position = nextPosition;
412 } else {
413 if (category(code) != WHITESPACE) break;
414 if (code == charCodes.$LF) skippedNewline = true;
415 ++position;
416 }
397 } 417 }
398 418
399 if (position == src.length) { 419 if (position == src.length) {
400 lastCategory = NONE; 420 lastCategory = NONE;
401 lastToken = null; 421 lastToken = null;
402 lastPosition = position; 422 lastPosition = position;
403 return; 423 return;
404 } 424 }
405 int code = src.codeUnitAt(position); 425 int code = src.codeUnitAt(position);
406 lastPosition = position; 426 lastPosition = position;
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
481 } 501 }
482 502
483 void expectSemicolon() { 503 void expectSemicolon() {
484 if (acceptSemicolon()) return; 504 if (acceptSemicolon()) return;
485 error('Expected SEMICOLON'); 505 error('Expected SEMICOLON');
486 } 506 }
487 507
488 bool acceptSemicolon() { 508 bool acceptSemicolon() {
489 // Accept semicolon or automatically inserted semicolon before close brace. 509 // Accept semicolon or automatically inserted semicolon before close brace.
490 // Miniparser forbids other kinds of semicolon insertion. 510 // Miniparser forbids other kinds of semicolon insertion.
511 if (RBRACE == lastCategory) return true;
491 if (skippedNewline) { 512 if (skippedNewline) {
492 error('No automatic semicolon insertion at preceding newline'); 513 error('No automatic semicolon insertion at preceding newline');
493 } 514 }
494 return acceptCategory(SEMICOLON) || RBRACE == lastCategory; 515 return acceptCategory(SEMICOLON);
495 } 516 }
496 517
497 bool acceptString(String string) { 518 bool acceptString(String string) {
498 if (lastToken == string) { 519 if (lastToken == string) {
499 getToken(); 520 getToken();
500 return true; 521 return true;
501 } 522 }
502 return false; 523 return false;
503 } 524 }
504 525
(...skipping 17 matching lines...) Expand all
522 } 543 }
523 } else if (acceptCategory(LPAREN)) { 544 } else if (acceptCategory(LPAREN)) {
524 Expression expression = parseExpression(); 545 Expression expression = parseExpression();
525 expectCategory(RPAREN); 546 expectCategory(RPAREN);
526 return expression; 547 return expression;
527 } else if (acceptCategory(STRING)) { 548 } else if (acceptCategory(STRING)) {
528 return new LiteralString(last); 549 return new LiteralString(last);
529 } else if (acceptCategory(NUMERIC)) { 550 } else if (acceptCategory(NUMERIC)) {
530 return new LiteralNumber(last); 551 return new LiteralNumber(last);
531 } else if (acceptCategory(LBRACE)) { 552 } else if (acceptCategory(LBRACE)) {
532 expectCategory(RBRACE); 553 return parseObjectInitializer();
533 return new ObjectInitializer([]);
534 } else if (acceptCategory(LSQUARE)) { 554 } else if (acceptCategory(LSQUARE)) {
535 var values = <ArrayElement>[]; 555 var values = <ArrayElement>[];
536 if (!acceptCategory(RSQUARE)) { 556 if (!acceptCategory(RSQUARE)) {
537 do { 557 do {
538 values.add(new ArrayElement(values.length, parseAssignment())); 558 values.add(new ArrayElement(values.length, parseAssignment()));
539 } while (acceptCategory(COMMA)); 559 } while (acceptCategory(COMMA));
540 expectCategory(RSQUARE); 560 expectCategory(RSQUARE);
541 } 561 }
542 return new ArrayInitializer(values.length, values); 562 return new ArrayInitializer(values.length, values);
543 } else if (last.startsWith("/")) { 563 } else if (last.startsWith("/")) {
544 String regexp = getDelimited(lastPosition); 564 String regexp = getDelimited(lastPosition);
545 getToken(); 565 getToken();
546 String flags = lastToken; 566 String flags = lastToken;
547 if (!acceptCategory(ALPHA)) flags = ""; 567 if (!acceptCategory(ALPHA)) flags = "";
548 Expression expression = new RegExpLiteral(regexp + flags); 568 Expression expression = new RegExpLiteral(regexp + flags);
549 return expression; 569 return expression;
550 } else if (acceptCategory(HASH)) { 570 } else if (acceptCategory(HASH)) {
551 InterpolatedExpression expression = new InterpolatedExpression(null); 571 InterpolatedExpression expression = new InterpolatedExpression(null);
552 interpolatedValues.add(expression); 572 interpolatedValues.add(expression);
553 return expression; 573 return expression;
554 } else { 574 } else {
555 error("Expected primary expression"); 575 error("Expected primary expression");
556 return null; 576 return null;
557 } 577 }
558 } 578 }
559 579
560 Expression parseFunctionExpression() { 580 Expression parseFunctionExpression() {
561 String functionName = null;
562 String last = lastToken; 581 String last = lastToken;
563 if (acceptCategory(ALPHA)) functionName = last; 582 if (acceptCategory(ALPHA)) {
583 String functionName = last;
584 return new NamedFunction(new VariableDeclaration(functionName),
585 parseFun());
586 }
587 return parseFun();
588 }
589
590 Expression parseFun() {
564 List<Parameter> params = <Parameter>[]; 591 List<Parameter> params = <Parameter>[];
565 expectCategory(LPAREN); 592 expectCategory(LPAREN);
566 String argumentName = lastToken; 593 String argumentName = lastToken;
567 if (acceptCategory(ALPHA)) { 594 if (acceptCategory(ALPHA)) {
568 params.add(new Parameter(argumentName)); 595 params.add(new Parameter(argumentName));
569 while (acceptCategory(COMMA)) { 596 while (acceptCategory(COMMA)) {
570 argumentName = lastToken; 597 argumentName = lastToken;
571 expectCategory(ALPHA); 598 expectCategory(ALPHA);
572 params.add(new Parameter(argumentName)); 599 params.add(new Parameter(argumentName));
573 } 600 }
574 } 601 }
575 expectCategory(RPAREN); 602 expectCategory(RPAREN);
576 expectCategory(LBRACE); 603 expectCategory(LBRACE);
577 Block block = parseBlock(); 604 Block block = parseBlock();
578 Fun fun = new Fun(params, block); 605 return new Fun(params, block);
579 if (functionName == null) { 606 }
580 return fun; 607
581 } else { 608 Expression parseObjectInitializer() {
582 return new NamedFunction(new VariableDeclaration(functionName), fun); 609 List<Property> properties = <Property>[];
610 for (;;) {
611 if (acceptCategory(RBRACE)) break;
612 // Limited subset: keys are identifiers, no 'get' or 'set' properties.
613 Literal propertyName;
614 String identifier = lastToken;
615 if (acceptCategory(ALPHA)) {
616 propertyName = new LiteralString('"$identifier"');
617 } else if (acceptCategory(STRING)) {
618 propertyName = new LiteralString(identifier);
619 } else {
620 error('Expected property name');
621 }
622 expectCategory(COLON);
623 Expression value = parseAssignment();
624 properties.add(new Property(propertyName, value));
625 if (acceptCategory(RBRACE)) break;
626 expectCategory(COMMA);
583 } 627 }
628 return new ObjectInitializer(properties);
584 } 629 }
585 630
586 Expression parseMember() { 631 Expression parseMember() {
587 Expression receiver = parsePrimary(); 632 Expression receiver = parsePrimary();
588 while (true) { 633 while (true) {
589 if (acceptCategory(DOT)) { 634 if (acceptCategory(DOT)) {
590 receiver = getDotRhs(receiver); 635 receiver = getDotRhs(receiver);
591 } else if (acceptCategory(LSQUARE)) { 636 } else if (acceptCategory(LSQUARE)) {
592 Expression inBraces = parseExpression(); 637 Expression inBraces = parseExpression();
593 expectCategory(RSQUARE); 638 expectCategory(RSQUARE);
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
783 Expression expression = parseVarDeclarationOrExpression(); 828 Expression expression = parseVarDeclarationOrExpression();
784 if (lastCategory != NONE || position != src.length) { 829 if (lastCategory != NONE || position != src.length) {
785 error("Unparsed junk: ${categoryToString(lastCategory)}"); 830 error("Unparsed junk: ${categoryToString(lastCategory)}");
786 } 831 }
787 if (!interpolatedValues.isEmpty) { 832 if (!interpolatedValues.isEmpty) {
788 return new JSExpression(expression, interpolatedValues); 833 return new JSExpression(expression, interpolatedValues);
789 } 834 }
790 return expression; 835 return expression;
791 } 836 }
792 837
838 Statement statement() {
839 Statement statement = parseStatement();
840 if (lastCategory != NONE || position != src.length) {
841 error("Unparsed junk: ${categoryToString(lastCategory)}");
842 }
843 // TODO(sra): interpolated capture here?
844 return statement;
845 }
846
793 Block parseBlock() { 847 Block parseBlock() {
794 List<Statement> statements = <Statement>[]; 848 List<Statement> statements = <Statement>[];
795 849
796 while (!acceptCategory(RBRACE)) { 850 while (!acceptCategory(RBRACE)) {
797 Statement statement = parseStatement(); 851 Statement statement = parseStatement();
798 statements.add(statement); 852 statements.add(statement);
799 } 853 }
800 return new Block(statements); 854 return new Block(statements);
801 } 855 }
802 856
803 Statement parseStatement() { 857 Statement parseStatement() {
804 if (acceptCategory(LBRACE)) return parseBlock(); 858 if (acceptCategory(LBRACE)) return parseBlock();
805 859
806 if (lastCategory == ALPHA) { 860 if (lastCategory == ALPHA) {
807 if (acceptString('return')) return parseReturn(); 861 if (acceptString('return')) return parseReturn();
808 862
863 if (acceptString('throw')) return parseThrow();
864
809 if (acceptString('break')) { 865 if (acceptString('break')) {
810 return parseBreakOrContinue((label) => new Break(label)); 866 return parseBreakOrContinue((label) => new Break(label));
811 } 867 }
812 868
813 if (acceptString('continue')) { 869 if (acceptString('continue')) {
814 return parseBreakOrContinue((label) => new Continue(label)); 870 return parseBreakOrContinue((label) => new Continue(label));
815 } 871 }
816 872
817 if (acceptString('if')) return parseIfThenElse(); 873 if (acceptString('if')) return parseIfThenElse();
818 874
819 if (acceptString('for')) return parseFor(); 875 if (acceptString('for')) return parseFor();
820 876
877 if (acceptString('function')) return parseFunctionDeclaration();
878
821 if (acceptString('var')) { 879 if (acceptString('var')) {
822 Expression declarations = parseVariableDeclarationList(); 880 Expression declarations = parseVariableDeclarationList();
823 expectSemicolon(); 881 expectSemicolon();
824 return new ExpressionStatement(declarations); 882 return new ExpressionStatement(declarations);
825 } 883 }
884
885 if (lastToken == 'case' ||
886 lastToken == 'do' ||
887 lastToken == 'while' ||
888 lastToken == 'switch' ||
889 lastToken == 'try' ||
890 lastToken == 'with') {
891 error('Not implemented in mini parser');
892 }
893 }
894
895 if (acceptCategory(HASH)) {
896 InterpolatedStatement statement = new InterpolatedStatement(null);
897 interpolatedValues.add(statement);
898 return statement;
826 } 899 }
827 900
828 // TODO: label: statement 901 // TODO: label: statement
829 902
830 Expression expression = parseExpression(); 903 Expression expression = parseExpression();
831 expectSemicolon(); 904 expectSemicolon();
832 return new ExpressionStatement(expression); 905 return new ExpressionStatement(expression);
833 } 906 }
834 907
835 Statement parseReturn() { 908 Statement parseReturn() {
836 if (acceptSemicolon()) return new Return(); 909 if (acceptSemicolon()) return new Return();
837 Expression expression = parseExpression(); 910 Expression expression = parseExpression();
838 expectSemicolon(); 911 expectSemicolon();
839 return new Return(expression); 912 return new Return(expression);
840 } 913 }
841 914
915 Statement parseThrow() {
916 if (skippedNewline) error('throw expression must be on same line');
917 Expression expression = parseExpression();
918 expectSemicolon();
919 return new Throw(expression);
920 }
921
842 Statement parseBreakOrContinue(constructor) { 922 Statement parseBreakOrContinue(constructor) {
843 var identifier = lastToken; 923 var identifier = lastToken;
844 if (!skippedNewline && acceptCategory(ALPHA)) { 924 if (!skippedNewline && acceptCategory(ALPHA)) {
845 expectSemicolon(); 925 expectSemicolon();
846 return constructor(identifier); 926 return constructor(identifier);
847 } 927 }
848 expectSemicolon(); 928 expectSemicolon();
849 return constructor(null); 929 return constructor(null);
850 } 930 }
851 931
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after
902 Expression declarations = finishVariableDeclarationList(identifier); 982 Expression declarations = finishVariableDeclarationList(identifier);
903 expectCategory(SEMICOLON); 983 expectCategory(SEMICOLON);
904 return finishFor(declarations); 984 return finishFor(declarations);
905 } 985 }
906 986
907 Expression init = parseExpression(); 987 Expression init = parseExpression();
908 expectCategory(SEMICOLON); 988 expectCategory(SEMICOLON);
909 return finishFor(init); 989 return finishFor(init);
910 } 990 }
911 991
992 Statement parseFunctionDeclaration() {
993 String name = lastToken;
994 expectCategory(ALPHA);
995 Expression fun = parseFun();
996 return new FunctionDeclaration(new VariableDeclaration(name), fun);
997 }
912 } 998 }
913 999
914 /** 1000 /**
915 * Clone a JSExpression node into an expression where all children 1001 * Clone a JSExpression node into an expression where all children
916 * have been cloned, and [InterpolatedExpression]s have been replaced 1002 * have been cloned, and [InterpolatedExpression]s have been replaced
917 * with real [Expression]. 1003 * with real [Expression].
918 */ 1004 */
919 class UninterpolateJSExpression extends BaseVisitor<Node> { 1005 class UninterpolateJSExpression extends BaseVisitor<Node> {
920 final List<Expression> arguments; 1006 final List<Expression> arguments;
921 int argumentIndex = 0; 1007 int argumentIndex = 0;
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
960 1046
961 Node visitCall(Call node) { 1047 Node visitCall(Call node) {
962 return copyPosition(node, 1048 return copyPosition(node,
963 new Call(visit(node.target), visitList(node.arguments))); 1049 new Call(visit(node.target), visitList(node.arguments)));
964 } 1050 }
965 1051
966 Node visitInterpolatedExpression(InterpolatedExpression expression) { 1052 Node visitInterpolatedExpression(InterpolatedExpression expression) {
967 return arguments[argumentIndex++]; 1053 return arguments[argumentIndex++];
968 } 1054 }
969 1055
1056 Node visitInterpolatedStatement(InterpolatedStatement statement) {
1057 return arguments[argumentIndex++];
1058 }
1059
970 Node visitJSExpression(JSExpression expression) { 1060 Node visitJSExpression(JSExpression expression) {
971 assert(argumentIndex == 0); 1061 assert(argumentIndex == 0);
972 Node result = visit(expression.value); 1062 Node result = visit(expression.value);
973 if (argumentIndex != arguments.length) { 1063 if (argumentIndex != arguments.length) {
974 error("Invalid number of arguments"); 1064 error("Invalid number of arguments");
975 } 1065 }
976 assert(result is! JSExpression); 1066 assert(result is! JSExpression);
977 return result; 1067 return result;
978 } 1068 }
979 1069
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
1036 } 1126 }
1037 1127
1038 Node visitLiteralNull(LiteralNull node) { 1128 Node visitLiteralNull(LiteralNull node) {
1039 return node; 1129 return node;
1040 } 1130 }
1041 1131
1042 Node visitLiteralBool(LiteralBool node) { 1132 Node visitLiteralBool(LiteralBool node) {
1043 return node; 1133 return node;
1044 } 1134 }
1045 } 1135 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/implementation/js/nodes.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698