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

Side by Side Diff: frog/parser.dart

Issue 8545003: Parser fix for lambdas (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: merged Created 9 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 | « frog/member.dart ('k') | frog/tokenizer.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) 2011, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2011, 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 // TODO(jimhug): Error recovery needs major work! 5 // TODO(jimhug): Error recovery needs major work!
6 /** 6 /**
7 * A simple recursive descent parser for the dart language. 7 * A simple recursive descent parser for the dart language.
8 * 8 *
9 * This parser is designed to be more permissive than the official 9 * This parser is designed to be more permissive than the official
10 * Dart grammar. It is expected that many grammar errors would be 10 * Dart grammar. It is expected that many grammar errors would be
11 * reported by a later compiler phase. For example, a class is allowed 11 * reported by a later compiler phase. For example, a class is allowed
12 * to extend an arbitrary number of base classes - this can be 12 * to extend an arbitrary number of base classes - this can be
13 * very clearly detected and is reported in a later compiler phase. 13 * very clearly detected and is reported in a later compiler phase.
14 */ 14 */
15 class Parser { 15 class Parser {
16 Tokenizer tokenizer; 16 TokenSource tokenizer;
17 17
18 final SourceFile source; 18 final SourceFile source;
19 /** Enables diet parse, which skips function bodies. */ 19 /** Enables diet parse, which skips function bodies. */
20 final bool diet; 20 final bool diet;
21 /** 21 /**
22 * Throw an IncompleteSourceException if the parser encounters a premature end 22 * Throw an IncompleteSourceException if the parser encounters a premature end
23 * of file or an incomplete multiline string. 23 * of file or an incomplete multiline string.
24 */ 24 */
25 final bool throwOnIncomplete; 25 final bool throwOnIncomplete;
26 /** 26
27 * Allow semicolons to be omitted at the end of lines. 27 /** Allow semicolons to be omitted at the end of lines. */
28 * // TODO(nweiz): make this work for more than just end-of-file 28 // TODO(nweiz): make this work for more than just end-of-file
29 */
30 final bool optionalSemicolons; 29 final bool optionalSemicolons;
31 30
32 // TODO(jimhug): Is it possible to handle initializers cleanly? 31 /** To prevent conflicts in initializers */
33 bool _inInitializers; 32 bool _inInitializers;
34 33
35 Token _previousToken; 34 Token _previousToken;
36 Token _peekToken; 35 Token _peekToken;
37 36
37 // When we encounter '(' in a method body we need to find the ')' to know it
38 // we're parsing a lambda, paren-expr, or argument list. Closure formals are
39 // followed by '=>' or '{'. This list is used to cache the tokens after any
40 // nested parenthesis we find while peeking.
41 // TODO(jmesserly): it's simpler and faster to cache this on the Token itself,
42 // but that might add too much complexity for tools that need to invalidate.
43 List<Token> _afterParens;
44 int _afterParensIndex = 0;
45
38 Parser(this.source, [this.diet = false, this.throwOnIncomplete = false, 46 Parser(this.source, [this.diet = false, this.throwOnIncomplete = false,
39 this.optionalSemicolons = false, int startOffset = 0]) { 47 this.optionalSemicolons = false, int startOffset = 0]) {
40 tokenizer = new Tokenizer(source, true, startOffset); 48 tokenizer = new Tokenizer(source, true, startOffset);
41 _peekToken = tokenizer.next(); 49 _peekToken = tokenizer.next();
42 _previousToken = null; 50 _previousToken = null;
43 _inInitializers = false; 51 _inInitializers = false;
52 _afterParens = <Token>[];
44 } 53 }
45 54
46 /** Generate an error if [source] has not been completely consumed. */ 55 /** Generate an error if [source] has not been completely consumed. */
47 void checkEndOfFile() { 56 void checkEndOfFile() {
48 _eat(TokenKind.END_OF_FILE); 57 _eat(TokenKind.END_OF_FILE);
49 } 58 }
50 59
51 /** Guard to break out of parser when an unexpected end of file is found. */ 60 /** Guard to break out of parser when an unexpected end of file is found. */
52 // TODO(jimhug): Failure to call this method can lead to inifinite parser 61 // TODO(jimhug): Failure to call this method can lead to inifinite parser
53 // loops. Consider embracing exceptions for more errors to reduce 62 // loops. Consider embracing exceptions for more errors to reduce
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after
486 value = expression(); 495 value = expression();
487 } 496 }
488 return finishField(expr.span.start, null, gt, name, value); 497 return finishField(expr.span.start, null, gt, name, value);
489 } else { 498 } else {
490 _eatSemicolon(); 499 _eatSemicolon();
491 return new ExpressionStatement(expr, _makeSpan(expr.span.start)); 500 return new ExpressionStatement(expr, _makeSpan(expr.span.start));
492 } 501 }
493 } 502 }
494 503
495 Expression testCondition() { 504 Expression testCondition() {
496 _eat(TokenKind.LPAREN); 505 _eatLeftParen();
497 var ret = expression(); 506 var ret = expression();
498 _eat(TokenKind.RPAREN); 507 _eat(TokenKind.RPAREN);
499 return ret; 508 return ret;
500 } 509 }
501 510
502 BlockStatement block() { 511 BlockStatement block() {
503 int start = _peekToken.start; 512 int start = _peekToken.start;
504 _eat(TokenKind.LBRACE); 513 _eat(TokenKind.LBRACE);
505 var stmts = []; 514 var stmts = [];
506 while (!_maybeEat(TokenKind.RBRACE)) { 515 while (!_maybeEat(TokenKind.RBRACE)) {
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
543 var body = statement(); 552 var body = statement();
544 _eat(TokenKind.WHILE); 553 _eat(TokenKind.WHILE);
545 var test = testCondition(); 554 var test = testCondition();
546 _eatSemicolon(); 555 _eatSemicolon();
547 return new DoStatement(body, test, _makeSpan(start)); 556 return new DoStatement(body, test, _makeSpan(start));
548 } 557 }
549 558
550 forStatement() { 559 forStatement() {
551 int start = _peekToken.start; 560 int start = _peekToken.start;
552 _eat(TokenKind.FOR); 561 _eat(TokenKind.FOR);
553 _eat(TokenKind.LPAREN); 562 _eatLeftParen();
554 563
555 var init = forInitializerStatement(start); 564 var init = forInitializerStatement(start);
556 if (init is ForInStatement) { 565 if (init is ForInStatement) {
557 return init; 566 return init;
558 } 567 }
559 var test = null; 568 var test = null;
560 if (!_maybeEat(TokenKind.SEMICOLON)) { 569 if (!_maybeEat(TokenKind.SEMICOLON)) {
561 test = expression(); 570 test = expression();
562 _eatSemicolon(); 571 _eatSemicolon();
563 } 572 }
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after
620 var finallyBlock = null; 629 var finallyBlock = null;
621 if (_maybeEat(TokenKind.FINALLY)) { 630 if (_maybeEat(TokenKind.FINALLY)) {
622 finallyBlock = block(); 631 finallyBlock = block();
623 } 632 }
624 return new TryStatement(body, catches, finallyBlock, _makeSpan(start)); 633 return new TryStatement(body, catches, finallyBlock, _makeSpan(start));
625 } 634 }
626 635
627 catchNode() { 636 catchNode() {
628 int start = _peekToken.start; 637 int start = _peekToken.start;
629 _eat(TokenKind.CATCH); 638 _eat(TokenKind.CATCH);
630 _eat(TokenKind.LPAREN); 639 _eatLeftParen();
631 var exc = declaredIdentifier(); 640 var exc = declaredIdentifier();
632 var trace = null; 641 var trace = null;
633 if (_maybeEat(TokenKind.COMMA)) { 642 if (_maybeEat(TokenKind.COMMA)) {
634 trace = declaredIdentifier(); 643 trace = declaredIdentifier();
635 } 644 }
636 _eat(TokenKind.RPAREN); 645 _eat(TokenKind.RPAREN);
637 var body = block(); 646 var body = block();
638 return new CatchNode(exc, trace, body, _makeSpan(start)); 647 return new CatchNode(exc, trace, body, _makeSpan(start));
639 } 648 }
640 649
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
710 } else { 719 } else {
711 expr = expression(); 720 expr = expression();
712 _eatSemicolon(); 721 _eatSemicolon();
713 } 722 }
714 return new ThrowStatement(expr, _makeSpan(start)); 723 return new ThrowStatement(expr, _makeSpan(start));
715 } 724 }
716 725
717 assertStatement() { 726 assertStatement() {
718 int start = _peekToken.start; 727 int start = _peekToken.start;
719 _eat(TokenKind.ASSERT); 728 _eat(TokenKind.ASSERT);
720 _eat(TokenKind.LPAREN); 729 _eatLeftParen();
721 var expr = expression(); 730 var expr = expression();
722 _eat(TokenKind.RPAREN); 731 _eat(TokenKind.RPAREN);
723 _eatSemicolon(); 732 _eatSemicolon();
724 return new AssertStatement(expr, _makeSpan(start)); 733 return new AssertStatement(expr, _makeSpan(start));
725 } 734 }
726 735
727 breakStatement() { 736 breakStatement() {
728 int start = _peekToken.start; 737 int start = _peekToken.start;
729 _eat(TokenKind.BREAK); 738 _eat(TokenKind.BREAK);
730 var name = null; 739 var name = null;
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
898 expr = expression(); 907 expr = expression();
899 if (label === null && _maybeEat(TokenKind.COLON)) { 908 if (label === null && _maybeEat(TokenKind.COLON)) {
900 label = _makeLabel(expr); 909 label = _makeLabel(expr);
901 expr = expression(); 910 expr = expression();
902 } 911 }
903 return new ArgumentNode(label, expr, _makeSpan(start)); 912 return new ArgumentNode(label, expr, _makeSpan(start));
904 } 913 }
905 914
906 arguments() { 915 arguments() {
907 var args = []; 916 var args = [];
908 // TODO(jimhug): switch to forced formals when get a DeclaredId 917 _eatLeftParen();
909 _eat(TokenKind.LPAREN);
910 if (!_maybeEat(TokenKind.RPAREN)) { 918 if (!_maybeEat(TokenKind.RPAREN)) {
911 do { 919 do {
912 args.add(argument()); 920 args.add(argument());
913 } while (_maybeEat(TokenKind.COMMA)); 921 } while (_maybeEat(TokenKind.COMMA));
914 _eat(TokenKind.RPAREN); 922 _eat(TokenKind.RPAREN);
915 } 923 }
916 return args; 924 return args;
917 } 925 }
918 926
919 finishPostfixExpression(expr) { 927 finishPostfixExpression(expr) {
920 switch(_peek()) { 928 switch(_peek()) {
921 case TokenKind.LPAREN: 929 case TokenKind.LPAREN:
922 return finishPostfixExpression(new CallExpression(expr, arguments(), 930 return finishCallOrLambdaExpression(expr);
923 _makeSpan(expr.span.start)));
924 case TokenKind.LBRACK: 931 case TokenKind.LBRACK:
925 _eat(TokenKind.LBRACK); 932 _eat(TokenKind.LBRACK);
926 var index = expression(); 933 var index = expression();
927 _eat(TokenKind.RBRACK); 934 _eat(TokenKind.RBRACK);
928 return finishPostfixExpression(new IndexExpression(expr, index, 935 return finishPostfixExpression(new IndexExpression(expr, index,
929 _makeSpan(expr.span.start))); 936 _makeSpan(expr.span.start)));
930 case TokenKind.DOT: 937 case TokenKind.DOT:
931 _eat(TokenKind.DOT); 938 _eat(TokenKind.DOT);
932 var name = identifier(); 939 var name = identifier();
933 var ret = new DotExpression(expr, name, _makeSpan(expr.span.start)); 940 var ret = new DotExpression(expr, name, _makeSpan(expr.span.start));
934 return finishPostfixExpression(ret); 941 return finishPostfixExpression(ret);
935 942
936 case TokenKind.INCR: 943 case TokenKind.INCR:
937 case TokenKind.DECR: 944 case TokenKind.DECR:
938 var tok = _next(); 945 var tok = _next();
939 return new PostfixExpression(expr, tok, _makeSpan(expr.span.start)); 946 return new PostfixExpression(expr, tok, _makeSpan(expr.span.start));
940 947
941 // These are pseudo-expressions supported for cover grammar 948 // These are pseudo-expressions supported for cover grammar
942 // must be forbidden when parsing initializers. 949 // must be forbidden when parsing initializers.
950 // TODO(jmesserly): is this still needed?
943 case TokenKind.ARROW: 951 case TokenKind.ARROW:
944 case TokenKind.LBRACE: 952 case TokenKind.LBRACE:
945 if (_inInitializers) return expr; 953 return expr;
946 var body = functionBody(true);
947 return _makeFunction(expr, body);
948 954
949 default: 955 default:
950 if (_peekIdentifier()) { 956 if (_peekIdentifier()) {
951 return finishPostfixExpression( 957 return finishPostfixExpression(
952 new DeclaredIdentifier(_makeType(expr), identifier(), 958 new DeclaredIdentifier(_makeType(expr), identifier(),
953 _makeSpan(expr.span.start))); 959 _makeSpan(expr.span.start)));
954 } else { 960 } else {
955 return expr; 961 return expr;
956 } 962 }
957 } 963 }
958 } 964 }
959 965
966 finishCallOrLambdaExpression(expr) {
967 if (_atClosureParameters()) {
968 var formals = formalParameterList();
969 var body = functionBody(true);
970 return _makeFunction(expr, formals, body);
971 } else {
972 var args = arguments();
973 return finishPostfixExpression(
974 new CallExpression(expr, args, _makeSpan(expr.span.start)));
975 }
976 }
977
960 /** Checks if the given expression is a binary op of the given kind. */ 978 /** Checks if the given expression is a binary op of the given kind. */
961 _isBin(expr, kind) { 979 _isBin(expr, kind) {
962 return expr is BinaryExpression && expr.op.kind == kind; 980 return expr is BinaryExpression && expr.op.kind == kind;
963 } 981 }
964 982
965 _boolTypeRef(SourceSpan span) { 983 _boolTypeRef(SourceSpan span) {
966 return new TypeReference(span, world.nonNullBool); 984 return new TypeReference(span, world.nonNullBool);
967 } 985 }
968 986
969 _intTypeRef(SourceSpan span) { 987 _intTypeRef(SourceSpan span) {
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
1129 _errorExpected('string literal, but found interpolated string start'); 1147 _errorExpected('string literal, but found interpolated string start');
1130 } else if (kind == TokenKind.INCOMPLETE_STRING) { 1148 } else if (kind == TokenKind.INCOMPLETE_STRING) {
1131 _next(); 1149 _next();
1132 _errorExpected('string literal, but found incomplete string'); 1150 _errorExpected('string literal, but found incomplete string');
1133 } 1151 }
1134 return null; 1152 return null;
1135 } 1153 }
1136 1154
1137 _parenOrLambda() { 1155 _parenOrLambda() {
1138 int start = _peekToken.start; 1156 int start = _peekToken.start;
1139 var args = arguments(); 1157 if (_atClosureParameters()) {
1140 if (!_inInitializers && 1158 var formals = formalParameterList();
1141 (_peekKind(TokenKind.ARROW) || _peekKind(TokenKind.LBRACE))) {
1142 var body = functionBody(true); 1159 var body = functionBody(true);
1143 var formals = _makeFormals(args);
1144 var func = new FunctionDefinition(null, null, null, formals, null, 1160 var func = new FunctionDefinition(null, null, null, formals, null,
1145 body, _makeSpan(start)); 1161 body, _makeSpan(start));
1146 return new LambdaExpression(func, func.span); 1162 return new LambdaExpression(func, func.span);
1147 } else { 1163 } else {
1164 var saved = _inInitializers;
1165 _inInitializers = false;
1166 var args = arguments();
1167 _inInitializers = saved;
1148 if (args.length == 1) { 1168 if (args.length == 1) {
1149 return new ParenExpression(args[0].value, _makeSpan(start)); 1169 return new ParenExpression(args[0].value, _makeSpan(start));
1150 } else { 1170 } else {
1151 _error('unexpected comma expression'); 1171 _error('unexpected comma expression');
1152 return args[0].value; 1172 return args[0].value;
1153 } 1173 }
1154 } 1174 }
1155 } 1175 }
1156 1176
1177 bool _atClosureParameters() {
1178 if (_inInitializers) return false;
1179 Token after = _peekAfterCloseParen();
1180 return after.kind == TokenKind.ARROW || after.kind == TokenKind.LBRACE;
1181 }
1182
1183 /** Eats an LPAREN, and advances our after-RPAREN lookahead. */
1184 _eatLeftParen() {
1185 _eat(TokenKind.LPAREN);
1186 _afterParensIndex++;
1187 }
1188
1189 Token _peekAfterCloseParen() {
1190 if (_afterParensIndex < _afterParens.length) {
1191 return _afterParens[_afterParensIndex];
1192 }
1193
1194 // Reset the queue
1195 _afterParensIndex = 0;
1196 _afterParens.clear();
1197
1198 // Start copying tokens as we lookahead
1199 var tokens = <Token>[_next()]; // LPAREN
1200 _lookaheadAfterParens(tokens);
1201
1202 // Put all the lookahead tokens back into the parser's token stream.
1203 var after = _peekToken;
1204 tokens.add(after);
1205 tokenizer = new DivertedTokenSource(tokens, this, tokenizer);
1206 _next(); // Re-synchronize parser lookahead state.
1207 return after;
1208 }
1209
1210 /**
1211 * This scan for the matching RPAREN to the current LPAREN and saves this
1212 * result for all nested parentheses so we don't need to look-head again.
1213 */
1214 _lookaheadAfterParens(List<Token> tokens) {
1215 // Save a slot in the array. This will hold the token after the parens.
1216 int saved = _afterParens.length;
1217 _afterParens.add(null); // save a slot
1218 while (true) {
1219 Token token = _next();
1220 tokens.add(token);
1221 int kind = token.kind;
1222 if (kind == TokenKind.RPAREN || kind == TokenKind.END_OF_FILE) {
1223 _afterParens[saved] = _peekToken;
1224 return;
1225 } else if (kind == TokenKind.LPAREN) {
1226 // Scan anything inside these nested parenthesis
1227 _lookaheadAfterParens(tokens);
1228 }
1229 }
1230 }
1157 1231
1158 _typeAsIdentifier(type) { 1232 _typeAsIdentifier(type) {
1159 // TODO(jimhug): lots of errors to check for 1233 // TODO(jimhug): lots of errors to check for
1160 return type.name; 1234 return type.name;
1161 } 1235 }
1162 1236
1163 _specialIdentifier(bool includeOperators) { 1237 _specialIdentifier(bool includeOperators) {
1164 int start = _peekToken.start; 1238 int start = _peekToken.start;
1165 String name; 1239 String name;
1166 1240
(...skipping 320 matching lines...) Expand 10 before | Expand all | Expand 10 after
1487 type = new FunctionTypeReference(false, func, func.span); 1561 type = new FunctionTypeReference(false, func, func.span);
1488 } 1562 }
1489 if (inOptionalBlock && value == null) { 1563 if (inOptionalBlock && value == null) {
1490 value = new NullExpression(_makeSpan(start)); 1564 value = new NullExpression(_makeSpan(start));
1491 } 1565 }
1492 1566
1493 return new FormalNode(isThis, isRest, type, name, value, _makeSpan(start)); 1567 return new FormalNode(isThis, isRest, type, name, value, _makeSpan(start));
1494 } 1568 }
1495 1569
1496 formalParameterList() { 1570 formalParameterList() {
1497 _eat(TokenKind.LPAREN); 1571 _eatLeftParen();
1498 var formals = []; 1572 var formals = [];
1499 var inOptionalBlock = false; 1573 var inOptionalBlock = false;
1500 if (!_maybeEat(TokenKind.RPAREN)) { 1574 if (!_maybeEat(TokenKind.RPAREN)) {
1501 if (_maybeEat(TokenKind.LBRACK)) { 1575 if (_maybeEat(TokenKind.LBRACK)) {
1502 inOptionalBlock = true; 1576 inOptionalBlock = true;
1503 } 1577 }
1504 formals.add(formalParameter(inOptionalBlock)); 1578 formals.add(formalParameter(inOptionalBlock));
1505 while (_maybeEat(TokenKind.COMMA)) { 1579 while (_maybeEat(TokenKind.COMMA)) {
1506 if (_maybeEat(TokenKind.LBRACK)) { 1580 if (_maybeEat(TokenKind.LBRACK)) {
1507 if (inOptionalBlock) { 1581 if (inOptionalBlock) {
(...skipping 19 matching lines...) Expand all
1527 1601
1528 return new Identifier(tok.text, _makeSpan(tok.start)); 1602 return new Identifier(tok.text, _makeSpan(tok.start));
1529 } 1603 }
1530 1604
1531 /////////////////////////////////////////////////////////////////// 1605 ///////////////////////////////////////////////////////////////////
1532 // These last productions handle most ambiguities in grammar 1606 // These last productions handle most ambiguities in grammar
1533 // They will convert expressions into other types. 1607 // They will convert expressions into other types.
1534 /////////////////////////////////////////////////////////////////// 1608 ///////////////////////////////////////////////////////////////////
1535 1609
1536 /** 1610 /**
1537 * Converts an [Expression] and a [Statment] body into a 1611 * Converts an [Expression], [Formals] and a [Statment] body into a
1538 * [FunctionDefinition]. 1612 * [FunctionDefinition].
1539 */ 1613 */
1540 _makeFunction(expr, body) { 1614 _makeFunction(expr, formals, body) {
1541 var name, type; 1615 var name, type;
1542 if (expr is CallExpression) { 1616 if (expr is VarExpression) {
1543 if (expr.target is VarExpression) { 1617 name = expr.name;
1544 name = expr.target.name; 1618 type = null;
1545 type = null; 1619 } else if (expr is DeclaredIdentifier) {
1546 } else if (expr.target is DeclaredIdentifier) { 1620 name = expr.name;
1547 name = expr.target.name; 1621 type = expr.type;
1548 type = expr.target.type; 1622 } else {
1549 } else { 1623 _error('bad function body', expr.span);
1550 _error('bad function'); 1624 }
1551 } 1625 var span = new SourceSpan(expr.span.file, expr.span.start, body.span.end);
1552 var formals = _makeFormals(expr.arguments); 1626 var func =
1553 var span =
1554 new SourceSpan(expr.span.file, expr.span.start, body.span.end);
1555 var func =
1556 new FunctionDefinition(null, type, name, formals, null, body, span); 1627 new FunctionDefinition(null, type, name, formals, null, body, span);
1557 return new LambdaExpression(func, func.span); 1628 return new LambdaExpression(func, func.span);
1558 } else {
1559 _error('expected function');
1560 }
1561 }
1562
1563 /** Converts a single expression into a formal or list of formals. */
1564 _makeFormal(expr) {
1565 if (expr is VarExpression) {
1566 return new FormalNode(false, false, null, expr.name, null, expr.span);
1567 } else if (expr is DeclaredIdentifier) {
1568 return new FormalNode(false, false, expr.type, expr.name, null,
1569 expr.span);
1570 } else if (_isBin(expr, TokenKind.ASSIGN) &&
1571 (expr.x is DeclaredIdentifier)) {
1572 DeclaredIdentifier di = expr.x; // TODO(jimhug): inference should handle!
1573 return new FormalNode(false, false, di.type, di.name, expr.y,
1574 expr.span);
1575 } else if (_isBin(expr, TokenKind.LT)) {
1576 // special signaling value to merge with next arg.
1577 return null;
1578 } else if (expr is ListExpression) {
1579 return _makeFormalsFromList(expr);
1580 } else {
1581 _error('expected formal', expr.span);
1582 }
1583 }
1584
1585 _makeFormalsFromList(expr) {
1586 if (expr.isConst) {
1587 _error('expected formal, but found "const"', expr.span);
1588 } else if (expr.type != null) {
1589 _error('expected formal, but found generic type arguments',
1590 expr.type.span);
1591 }
1592
1593 return _makeFormalsFromExpressions(expr.values, allowOptional:false);
1594 }
1595
1596 /** Converts a list of arguments into a list of formals. */
1597 _makeFormals(arguments) {
1598 var expressions = [];
1599 for (int i = 0; i < arguments.length; i++) {
1600 final arg = arguments[i];
1601 if (arg.label != null) {
1602 _error('expected formal, but found ":"');
1603 }
1604 expressions.add(arg.value);
1605 }
1606 return _makeFormalsFromExpressions(expressions, allowOptional:true);
1607 }
1608
1609 /** Converts a list of expressions into a list of formals. */
1610 _makeFormalsFromExpressions(expressions, [bool allowOptional]) {
1611 var formals = [];
1612 for (int i = 0; i < expressions.length; i++) {
1613 var formal = _makeFormal(expressions[i]);
1614 if (formal == null) {
1615 // special signal that we have the A<C case
1616 var baseType = _makeType(expressions[i].x);
1617 var typeParams = [_makeType(expressions[i].y)];
1618 i++;
1619 while (i < expressions.length) {
1620 var expr = expressions[i++];
1621 // Looking for D > m closer
1622 if (_isBin(expr, TokenKind.GT)) {
1623 typeParams.add(_makeType(expr.x));
1624 var type = new GenericTypeReference(baseType, typeParams, 0,
1625 _makeSpan(baseType.span.start));
1626 var name = null;
1627 if (expr.y is VarExpression) {
1628 // TODO(jimhug): Should be handled by inference!
1629 VarExpression ve = expr.y;
1630 name = ve.name;
1631 } else {
1632 _error('expected formal', expr.span);
1633 }
1634 formal = new FormalNode(false, false, type, name, null,
1635 _makeSpan(expressions[0].span.start));
1636 break;
1637 } else {
1638 typeParams.add(_makeType(expr));
1639 }
1640 }
1641 formals.add(formal);
1642
1643 } else if (formal is List) {
1644 formals.addAll(formal);
1645 if (!allowOptional) {
1646 _error('unexpected nested optional formal', expressions[i].span);
1647 }
1648
1649 } else {
1650 formals.add(formal);
1651 }
1652 }
1653 return formals;
1654 } 1629 }
1655 1630
1656 /** Converts an expression to a [DeclaredIdentifier]. */ 1631 /** Converts an expression to a [DeclaredIdentifier]. */
1657 _makeDeclaredIdentifier(e) { 1632 _makeDeclaredIdentifier(e) {
1658 if (e is VarExpression) { 1633 if (e is VarExpression) {
1659 return new DeclaredIdentifier(null, e.name, e.span); 1634 return new DeclaredIdentifier(null, e.name, e.span);
1660 } else if (e is DeclaredIdentifier) { 1635 } else if (e is DeclaredIdentifier) {
1661 return e; 1636 return e;
1662 } else { 1637 } else {
1663 _error('expected declared identifier'); 1638 _error('expected declared identifier');
(...skipping 15 matching lines...) Expand all
1679 class IncompleteSourceException implements Exception { 1654 class IncompleteSourceException implements Exception {
1680 final Token token; 1655 final Token token;
1681 1656
1682 IncompleteSourceException(this.token); 1657 IncompleteSourceException(this.token);
1683 1658
1684 String toString() { 1659 String toString() {
1685 if (token.span == null) return 'Unexpected $token'; 1660 if (token.span == null) return 'Unexpected $token';
1686 return token.span.toMessageString('Unexpected $token'); 1661 return token.span.toMessageString('Unexpected $token');
1687 } 1662 }
1688 } 1663 }
1664
1665 /**
1666 * Stores a token stream that will be used by the parser. Once the parser has
1667 * reached the end of this [TokenSource], it switches back to the
1668 * [previousTokenizer]
1669 */
1670 class DivertedTokenSource implements TokenSource {
1671 final List<Token> tokens;
1672 final Parser parser;
1673 final TokenSource previousTokenizer;
1674 DivertedTokenSource(this.tokens, this.parser, this.previousTokenizer);
1675
1676 int _pos = 0;
1677 next() {
1678 var token = tokens[_pos];
1679 ++_pos;
1680 if (_pos == tokens.length) {
1681 parser.tokenizer = previousTokenizer;
1682 }
1683 return token;
1684 }
1685 }
OLDNEW
« no previous file with comments | « frog/member.dart ('k') | frog/tokenizer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698