Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 61 _afterParens = <Token>[]; | 61 _afterParens = <Token>[]; |
| 62 } | 62 } |
| 63 | 63 |
| 64 /** Generate an error if [source] has not been completely consumed. */ | 64 /** Generate an error if [source] has not been completely consumed. */ |
| 65 void checkEndOfFile() { | 65 void checkEndOfFile() { |
| 66 _eat(TokenKind.END_OF_FILE); | 66 _eat(TokenKind.END_OF_FILE); |
| 67 } | 67 } |
| 68 | 68 |
| 69 /** Guard to break out of parser when an unexpected end of file is found. */ | 69 /** Guard to break out of parser when an unexpected end of file is found. */ |
| 70 bool isPrematureEndOfFile() { | 70 bool isPrematureEndOfFile() { |
| 71 if (throwOnIncomplete && _maybeEat(TokenKind.END_OF_FILE) || | 71 if (throwOnIncomplete && _maybeEat(TokenKind.END_OF_FILE)) { |
| 72 _maybeEat(TokenKind.INCOMPLETE_MULTILINE_STRING_DQ) || | |
|
Jennifer Messerly
2012/01/09 20:16:26
I think this was REPL support code that had found
jimhug
2012/01/09 21:19:05
This was originally my code intended to handle sin
| |
| 73 _maybeEat(TokenKind.INCOMPLETE_MULTILINE_STRING_SQ)) { | |
| 74 throw new IncompleteSourceException(_previousToken); | 72 throw new IncompleteSourceException(_previousToken); |
| 75 } else if (_maybeEat(TokenKind.END_OF_FILE)) { | 73 } else if (_maybeEat(TokenKind.END_OF_FILE)) { |
| 76 _error('unexpected end of file', _peekToken.span); | 74 _error('unexpected end of file', _peekToken.span); |
| 77 return true; | 75 return true; |
| 78 } else { | 76 } else { |
| 79 return false; | 77 return false; |
| 80 } | 78 } |
| 81 } | 79 } |
| 82 | 80 |
| 83 /** | 81 /** |
| (...skipping 957 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1041 return finishPostfixExpression( | 1039 return finishPostfixExpression( |
| 1042 new CallExpression(expr, args, _makeSpan(expr.span.start))); | 1040 new CallExpression(expr, args, _makeSpan(expr.span.start))); |
| 1043 } | 1041 } |
| 1044 } | 1042 } |
| 1045 | 1043 |
| 1046 /** Checks if the given expression is a binary op of the given kind. */ | 1044 /** Checks if the given expression is a binary op of the given kind. */ |
| 1047 _isBin(expr, kind) { | 1045 _isBin(expr, kind) { |
| 1048 return expr is BinaryExpression && expr.op.kind == kind; | 1046 return expr is BinaryExpression && expr.op.kind == kind; |
| 1049 } | 1047 } |
| 1050 | 1048 |
| 1051 _boolTypeRef(SourceSpan span) { | 1049 _makeLiteral(Value value) { |
| 1052 return new TypeReference(span, world.nonNullBool); | 1050 return new LiteralExpression(value, value.span); |
| 1053 } | |
| 1054 | |
| 1055 _intTypeRef(SourceSpan span) { | |
| 1056 return new TypeReference(span, world.intType); | |
| 1057 } | |
| 1058 | |
| 1059 _doubleTypeRef(SourceSpan span) { | |
| 1060 return new TypeReference(span, world.doubleType); | |
| 1061 } | |
| 1062 | |
| 1063 _stringTypeRef(SourceSpan span) { | |
| 1064 return new TypeReference(span, world.stringType); | |
| 1065 } | 1051 } |
| 1066 | 1052 |
| 1067 primary() { | 1053 primary() { |
| 1068 int start = _peekToken.start; | 1054 int start = _peekToken.start; |
| 1069 switch (_peek()) { | 1055 switch (_peek()) { |
| 1070 case TokenKind.THIS: | 1056 case TokenKind.THIS: |
| 1071 _eat(TokenKind.THIS); | 1057 _eat(TokenKind.THIS); |
| 1072 return new ThisExpression(_makeSpan(start)); | 1058 return new ThisExpression(_makeSpan(start)); |
| 1073 | 1059 |
| 1074 case TokenKind.SUPER: | 1060 case TokenKind.SUPER: |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 1096 | 1082 |
| 1097 case TokenKind.LBRACK: | 1083 case TokenKind.LBRACK: |
| 1098 case TokenKind.INDEX: | 1084 case TokenKind.INDEX: |
| 1099 return finishListLiteral(start, false, null); | 1085 return finishListLiteral(start, false, null); |
| 1100 case TokenKind.LBRACE: | 1086 case TokenKind.LBRACE: |
| 1101 return finishMapLiteral(start, false, null); | 1087 return finishMapLiteral(start, false, null); |
| 1102 | 1088 |
| 1103 // Literals | 1089 // Literals |
| 1104 case TokenKind.NULL: | 1090 case TokenKind.NULL: |
| 1105 _eat(TokenKind.NULL); | 1091 _eat(TokenKind.NULL); |
| 1106 return new NullExpression(_makeSpan(start)); | 1092 return _makeLiteral(Value.fromNull(_makeSpan(start))); |
| 1107 | 1093 |
| 1108 // TODO(jimhug): Make Literal creation less wasteful - no dup span/text. | 1094 // TODO(jimhug): Make Literal creation less wasteful - no dup span/text. |
| 1109 case TokenKind.TRUE: | 1095 case TokenKind.TRUE: |
| 1110 _eat(TokenKind.TRUE); | 1096 _eat(TokenKind.TRUE); |
| 1111 return new LiteralExpression(true, _boolTypeRef(_makeSpan(start)), | 1097 return _makeLiteral(Value.fromBool(true, _makeSpan(start))); |
| 1112 'true', _makeSpan(start)); | |
| 1113 | 1098 |
| 1114 case TokenKind.FALSE: | 1099 case TokenKind.FALSE: |
| 1115 _eat(TokenKind.FALSE); | 1100 _eat(TokenKind.FALSE); |
| 1116 return new LiteralExpression(false,_boolTypeRef(_makeSpan(start)), | 1101 return _makeLiteral(Value.fromBool(false, _makeSpan(start))); |
| 1117 'false', _makeSpan(start)); | |
| 1118 | 1102 |
| 1119 case TokenKind.HEX_INTEGER: | 1103 case TokenKind.HEX_INTEGER: |
| 1120 var t = _next(); | 1104 var t = _next(); |
| 1121 // Remove the 0x or 0X before parsing the hex number. | 1105 return _makeLiteral(Value.fromInt(t.value, t.span)); |
| 1122 return new LiteralExpression(parseHex(t.text.substring(2)), | |
| 1123 _intTypeRef(_makeSpan(start)), t.text, _makeSpan(start)); | |
| 1124 | 1106 |
| 1125 case TokenKind.INTEGER: | 1107 case TokenKind.INTEGER: |
| 1126 var t = _next(); | 1108 var t = _next(); |
| 1127 return new LiteralExpression(Math.parseInt(t.text), | 1109 return _makeLiteral(Value.fromInt(Math.parseInt(t.text), t.span)); |
| 1128 _intTypeRef(_makeSpan(start)), t.text, _makeSpan(start)); | |
| 1129 | 1110 |
| 1130 case TokenKind.DOUBLE: | 1111 case TokenKind.DOUBLE: |
| 1131 var t = _next(); | 1112 var t = _next(); |
| 1132 return new LiteralExpression(Math.parseDouble(t.text), | 1113 return _makeLiteral( |
| 1133 _doubleTypeRef(_makeSpan(start)), t.text, _makeSpan(start)); | 1114 Value.fromDouble(Math.parseDouble(t.text), t.span)); |
| 1134 | 1115 |
| 1135 case TokenKind.STRING: | 1116 case TokenKind.STRING: |
| 1136 return stringLiteralExpr(); | 1117 var t = _next(); |
| 1118 return _makeLiteral(Value.fromString(t.value, t.span)); | |
| 1137 | 1119 |
| 1138 case TokenKind.INCOMPLETE_STRING: | 1120 case TokenKind.STRING_PART: |
| 1139 return stringInterpolation(); | 1121 return stringInterpolation(); |
| 1140 | 1122 |
| 1141 case TokenKind.LT: | 1123 case TokenKind.LT: |
| 1142 return finishTypedLiteral(start, false); | 1124 return finishTypedLiteral(start, false); |
| 1143 | 1125 |
| 1144 case TokenKind.VOID: | 1126 case TokenKind.VOID: |
| 1145 case TokenKind.VAR: | 1127 case TokenKind.VAR: |
| 1146 case TokenKind.FINAL: | 1128 case TokenKind.FINAL: |
| 1147 return declaredIdentifier(false); | 1129 return declaredIdentifier(false); |
| 1148 | 1130 |
| 1149 default: | 1131 default: |
| 1150 if (!_peekIdentifier()) { | 1132 if (!_peekIdentifier()) { |
| 1151 // TODO(jimhug): Better error message. | 1133 // TODO(jimhug): Better error message. |
| 1152 _errorExpected('expression'); | 1134 _errorExpected('expression'); |
| 1153 } | 1135 } |
| 1154 return new VarExpression(identifier(), _makeSpan(start)); | 1136 return new VarExpression(identifier(), _makeSpan(start)); |
| 1155 } | 1137 } |
| 1156 } | 1138 } |
| 1157 | 1139 |
| 1158 stringInterpolation() { | 1140 stringInterpolation() { |
| 1159 int start = _peekToken.start; | 1141 int start = _peekToken.start; |
| 1160 var lits = []; | 1142 var pieces = new List<Expression>(); |
| 1161 var startQuote = null, endQuote = null; | 1143 var startQuote = null, endQuote = null; |
| 1162 while(_peekKind(TokenKind.INCOMPLETE_STRING)) { | 1144 while(_peekKind(TokenKind.STRING_PART)) { |
| 1163 var token = _next(); | 1145 var token = _next(); |
| 1164 var text = token.text; | 1146 pieces.add(_makeLiteral(Value.fromString(token.value, token.span))); |
| 1165 if (startQuote == null) { | |
| 1166 if (isMultilineString(text)) { | |
| 1167 endQuote = text.substring(0, 3); | |
| 1168 // TODO(jmesserly): HACK add a newline to everything that's not | |
|
Jennifer Messerly
2012/01/09 20:16:26
--hack;
| |
| 1169 // the first multiline string, so we don't incorrectly strip off any | |
| 1170 // real newlines later in the interpolated string. | |
| 1171 startQuote = endQuote + '\n'; | |
| 1172 } else { | |
| 1173 startQuote = endQuote = text[0]; | |
| 1174 } | |
| 1175 text = text.substring(0, text.length-1) + endQuote; // fix trailing $ | |
| 1176 } else { | |
| 1177 text = startQuote + text.substring(0, text.length-1) + endQuote; | |
| 1178 } | |
| 1179 lits.add(makeStringLiteral(text, token.span)); | |
| 1180 if (_maybeEat(TokenKind.LBRACE)) { | 1147 if (_maybeEat(TokenKind.LBRACE)) { |
| 1181 lits.add(expression()); | 1148 pieces.add(expression()); |
| 1182 _eat(TokenKind.RBRACE); | 1149 _eat(TokenKind.RBRACE); |
| 1183 } else if (_maybeEat(TokenKind.THIS)) { | 1150 } else if (_maybeEat(TokenKind.THIS)) { |
| 1184 lits.add(new ThisExpression(_previousToken.span)); | 1151 pieces.add(new ThisExpression(_previousToken.span)); |
| 1185 } else { | 1152 } else { |
| 1186 var id = identifier(); | 1153 var id = identifier(); |
| 1187 lits.add(new VarExpression(id, id.span)); | 1154 pieces.add(new VarExpression(id, id.span)); |
| 1188 } | 1155 } |
| 1189 } | 1156 } |
| 1190 var tok = _next(); | 1157 var tok = _next(); |
| 1191 if (tok.kind != TokenKind.STRING) { | 1158 if (tok.kind != TokenKind.STRING) { |
| 1192 _errorExpected('interpolated string'); | 1159 _errorExpected('interpolated string'); |
| 1193 } | 1160 } |
| 1194 var text = startQuote + tok.text; | 1161 pieces.add(_makeLiteral(Value.fromString(tok.value, tok.span))); |
| 1195 lits.add(makeStringLiteral(text, tok.span)); | |
| 1196 var span = _makeSpan(start); | 1162 var span = _makeSpan(start); |
| 1197 return new LiteralExpression(lits, _stringTypeRef(span), '\$\$\$', span); | 1163 return new StringInterpExpression(pieces, span); |
| 1198 } | |
| 1199 | |
| 1200 makeStringLiteral(String text, SourceSpan span) { | |
| 1201 return new LiteralExpression(text, _stringTypeRef(span), text, span); | |
| 1202 } | |
| 1203 | |
| 1204 stringLiteralExpr() { | |
| 1205 var token = _next(); | |
| 1206 return makeStringLiteral(token.text, token.span); | |
| 1207 } | 1164 } |
| 1208 | 1165 |
| 1209 String maybeStringLiteral() { | 1166 String maybeStringLiteral() { |
| 1210 var kind = _peek(); | 1167 var kind = _peek(); |
| 1211 if (kind == TokenKind.STRING) { | 1168 if (kind == TokenKind.STRING) { |
| 1212 return parseStringLiteral(_next().text); | 1169 var t = _next(); |
| 1170 return t.value; | |
| 1213 } else if (kind == TokenKind.STRING_PART) { | 1171 } else if (kind == TokenKind.STRING_PART) { |
| 1214 _next(); | 1172 _next(); |
| 1215 _errorExpected('string literal, but found interpolated string start'); | 1173 _errorExpected('string literal, but found interpolated string start'); |
| 1216 } else if (kind == TokenKind.INCOMPLETE_STRING) { | |
| 1217 _next(); | |
| 1218 _errorExpected('string literal, but found incomplete string'); | |
| 1219 } | 1174 } |
| 1220 return null; | 1175 return null; |
| 1221 } | 1176 } |
| 1222 | 1177 |
| 1223 _parenOrLambda() { | 1178 _parenOrLambda() { |
| 1224 int start = _peekToken.start; | 1179 int start = _peekToken.start; |
| 1225 if (_atClosureParameters()) { | 1180 if (_atClosureParameters()) { |
| 1226 var formals = formalParameterList(); | 1181 var formals = formalParameterList(); |
| 1227 var body = functionBody(true); | 1182 var body = functionBody(true); |
| 1228 var func = new FunctionDefinition(null, null, null, formals, null, null, | 1183 var func = new FunctionDefinition(null, null, null, formals, null, null, |
| (...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1372 name = _typeAsIdentifier(myType); | 1327 name = _typeAsIdentifier(myType); |
| 1373 myType = null; | 1328 myType = null; |
| 1374 } else { | 1329 } else { |
| 1375 // TODO(jimhug): Where do these errors get handled? | 1330 // TODO(jimhug): Where do these errors get handled? |
| 1376 } | 1331 } |
| 1377 } | 1332 } |
| 1378 } | 1333 } |
| 1379 return new DeclaredIdentifier(myType, name, _makeSpan(start)); | 1334 return new DeclaredIdentifier(myType, name, _makeSpan(start)); |
| 1380 } | 1335 } |
| 1381 | 1336 |
| 1382 // TODO(jimhug): Move this to base <= 36 and into shared code. | |
| 1383 static int _hexDigit(int c) { | |
| 1384 if(c >= 48/*0*/ && c <= 57/*9*/) { | |
| 1385 return c - 48; | |
| 1386 } else if (c >= 97/*a*/ && c <= 102/*f*/) { | |
| 1387 return c - 87; | |
| 1388 } else if (c >= 65/*A*/ && c <= 70/*F*/) { | |
| 1389 return c - 55; | |
| 1390 } else { | |
| 1391 return -1; | |
| 1392 } | |
| 1393 } | |
| 1394 | |
| 1395 static int parseHex(String hex) { | |
| 1396 var result = 0; | |
| 1397 | |
| 1398 for (int i = 0; i < hex.length; i++) { | |
| 1399 var digit = _hexDigit(hex.charCodeAt(i)); | |
| 1400 assert(digit != -1); | |
| 1401 // Multiply by 16 rather than shift by 4 since that will result in a | |
| 1402 // correct value for numbers that exceed the 32 bit precision of JS | |
| 1403 // 'integers'. | |
| 1404 // TODO: Figure out a better solution to integer truncation. Issue 638. | |
| 1405 result = (result * 16) + digit; | |
| 1406 } | |
| 1407 | |
| 1408 return result; | |
| 1409 } | |
| 1410 | |
| 1411 finishNewExpression(int start, bool isConst) { | 1337 finishNewExpression(int start, bool isConst) { |
| 1412 var type = type(); | 1338 var type = type(); |
| 1413 var name = null; | 1339 var name = null; |
| 1414 if (_maybeEat(TokenKind.DOT)) { | 1340 if (_maybeEat(TokenKind.DOT)) { |
| 1415 name = identifier(); | 1341 name = identifier(); |
| 1416 } | 1342 } |
| 1417 var args = arguments(); | 1343 var args = arguments(); |
| 1418 return new NewExpression(isConst, type, name, args, _makeSpan(start)); | 1344 return new NewExpression(isConst, type, name, args, _makeSpan(start)); |
| 1419 } | 1345 } |
| 1420 | 1346 |
| (...skipping 230 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1651 _error('default values only allowed inside [optional] section'); | 1577 _error('default values only allowed inside [optional] section'); |
| 1652 } | 1578 } |
| 1653 value = expression(); | 1579 value = expression(); |
| 1654 } else if (_peekKind(TokenKind.LPAREN)) { | 1580 } else if (_peekKind(TokenKind.LPAREN)) { |
| 1655 var formals = formalParameterList(); | 1581 var formals = formalParameterList(); |
| 1656 var func = new FunctionDefinition(null, type, name, formals, | 1582 var func = new FunctionDefinition(null, type, name, formals, |
| 1657 null, null, null, _makeSpan(start)); | 1583 null, null, null, _makeSpan(start)); |
| 1658 type = new FunctionTypeReference(false, func, func.span); | 1584 type = new FunctionTypeReference(false, func, func.span); |
| 1659 } | 1585 } |
| 1660 if (inOptionalBlock && value == null) { | 1586 if (inOptionalBlock && value == null) { |
| 1661 value = new NullExpression(_makeSpan(start)); | 1587 value = _makeLiteral(Value.fromNull(_makeSpan(start))); |
| 1662 } | 1588 } |
| 1663 | 1589 |
| 1664 return new FormalNode(isThis, isRest, type, name, value, _makeSpan(start)); | 1590 return new FormalNode(isThis, isRest, type, name, value, _makeSpan(start)); |
| 1665 } | 1591 } |
| 1666 | 1592 |
| 1667 formalParameterList() { | 1593 formalParameterList() { |
| 1668 _eatLeftParen(); | 1594 _eatLeftParen(); |
| 1669 var formals = []; | 1595 var formals = []; |
| 1670 var inOptionalBlock = false; | 1596 var inOptionalBlock = false; |
| 1671 if (!_maybeEat(TokenKind.RPAREN)) { | 1597 if (!_maybeEat(TokenKind.RPAREN)) { |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1773 int _pos = 0; | 1699 int _pos = 0; |
| 1774 next() { | 1700 next() { |
| 1775 var token = tokens[_pos]; | 1701 var token = tokens[_pos]; |
| 1776 ++_pos; | 1702 ++_pos; |
| 1777 if (_pos == tokens.length) { | 1703 if (_pos == tokens.length) { |
| 1778 parser.tokenizer = previousTokenizer; | 1704 parser.tokenizer = previousTokenizer; |
| 1779 } | 1705 } |
| 1780 return token; | 1706 return token; |
| 1781 } | 1707 } |
| 1782 } | 1708 } |
| OLD | NEW |