Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library dart_parser.parser; | 5 library dart_parser.parser; |
| 6 | 6 |
| 7 import 'package:dart_scanner/dart_scanner.dart' show | |
| 8 ErrorToken; | |
| 9 | |
| 10 import 'package:dart_scanner/src/recover.dart' show | |
| 11 closeBraceFor, | |
| 12 skipToEof; | |
| 13 | |
| 7 import 'package:dart_scanner/src/keyword.dart' show | 14 import 'package:dart_scanner/src/keyword.dart' show |
| 8 Keyword; | 15 Keyword; |
| 9 | 16 |
| 10 import 'package:dart_scanner/src/precedence.dart' show | 17 import 'package:dart_scanner/src/precedence.dart' show |
| 11 ASSIGNMENT_PRECEDENCE, | 18 ASSIGNMENT_PRECEDENCE, |
| 12 AS_INFO, | 19 AS_INFO, |
| 13 CASCADE_PRECEDENCE, | 20 CASCADE_PRECEDENCE, |
| 14 EOF_INFO, | |
| 15 EQUALITY_PRECEDENCE, | 21 EQUALITY_PRECEDENCE, |
| 16 GT_INFO, | 22 GT_INFO, |
| 17 IS_INFO, | 23 IS_INFO, |
| 18 MINUS_MINUS_INFO, | 24 MINUS_MINUS_INFO, |
| 19 OPEN_PAREN_INFO, | 25 OPEN_PAREN_INFO, |
| 20 OPEN_SQUARE_BRACKET_INFO, | 26 OPEN_SQUARE_BRACKET_INFO, |
| 21 PERIOD_INFO, | 27 PERIOD_INFO, |
| 22 PLUS_PLUS_INFO, | 28 PLUS_PLUS_INFO, |
| 23 POSTFIX_PRECEDENCE, | 29 POSTFIX_PRECEDENCE, |
| 24 PrecedenceInfo, | 30 PrecedenceInfo, |
| 25 QUESTION_INFO, | 31 QUESTION_INFO, |
| 26 QUESTION_PERIOD_INFO, | 32 QUESTION_PERIOD_INFO, |
| 27 RELATIONAL_PRECEDENCE; | 33 RELATIONAL_PRECEDENCE; |
| 28 | 34 |
| 29 import 'package:dart_scanner/src/token.dart' show | 35 import 'package:dart_scanner/src/token.dart' show |
| 30 BadInputToken, | |
| 31 BeginGroupToken, | 36 BeginGroupToken, |
| 32 ErrorToken, | |
| 33 KeywordToken, | 37 KeywordToken, |
| 34 SymbolToken, | 38 SymbolToken, |
| 35 Token, | 39 Token, |
| 36 UnmatchedToken, | |
| 37 UnterminatedToken, | |
| 38 isUserDefinableOperator; | 40 isUserDefinableOperator; |
| 39 | 41 |
| 40 import 'package:dart_scanner/src/token_constants.dart' show | 42 import 'package:dart_scanner/src/token_constants.dart' show |
| 41 BAD_INPUT_TOKEN, | |
| 42 COMMA_TOKEN, | 43 COMMA_TOKEN, |
| 43 DOUBLE_TOKEN, | 44 DOUBLE_TOKEN, |
| 44 EOF_TOKEN, | 45 EOF_TOKEN, |
| 45 EQ_TOKEN, | 46 EQ_TOKEN, |
| 46 FUNCTION_TOKEN, | 47 FUNCTION_TOKEN, |
| 47 GT_TOKEN, | 48 GT_TOKEN, |
| 48 GT_GT_TOKEN, | 49 GT_GT_TOKEN, |
| 49 HASH_TOKEN, | 50 HASH_TOKEN, |
| 50 HEXADECIMAL_TOKEN, | 51 HEXADECIMAL_TOKEN, |
| 51 IDENTIFIER_TOKEN, | 52 IDENTIFIER_TOKEN, |
| (...skipping 719 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 771 ++interfacesCount; | 772 ++interfacesCount; |
| 772 } while (optional(',', token)); | 773 } while (optional(',', token)); |
| 773 } | 774 } |
| 774 token = parseClassBody(token); | 775 token = parseClassBody(token); |
| 775 listener.endClassDeclaration( | 776 listener.endClassDeclaration( |
| 776 interfacesCount, begin, extendsKeyword, implementsKeyword, token); | 777 interfacesCount, begin, extendsKeyword, implementsKeyword, token); |
| 777 return token.next; | 778 return token.next; |
| 778 } | 779 } |
| 779 | 780 |
| 780 Token parseStringPart(Token token) { | 781 Token parseStringPart(Token token) { |
| 781 if (identical(token.kind, STRING_TOKEN)) { | 782 if (token.kind != STRING_TOKEN) { |
| 782 listener.handleStringPart(token); | 783 token = reportUnrecoverableError(token, ErrorKind.ExpectedString); |
| 783 return token.next; | |
| 784 } else { | |
| 785 return reportUnrecoverableError(token, ErrorKind.ExpectedString); | |
| 786 } | 784 } |
| 785 listener.handleStringPart(token); | |
| 786 return token.next; | |
| 787 } | 787 } |
| 788 | 788 |
| 789 Token parseIdentifier(Token token) { | 789 Token parseIdentifier(Token token) { |
| 790 if (!token.isIdentifier()) { | 790 if (!token.isIdentifier()) { |
| 791 token = reportUnrecoverableError(token, ErrorKind.ExpectedIdentifier); | 791 token = reportUnrecoverableError(token, ErrorKind.ExpectedIdentifier); |
| 792 } | 792 } |
| 793 listener.handleIdentifier(token); | 793 listener.handleIdentifier(token); |
| 794 return token.next; | 794 return token.next; |
| 795 } | 795 } |
| 796 | 796 |
| (...skipping 343 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1140 } else { | 1140 } else { |
| 1141 listener.handleNoTypeVariables(token); | 1141 listener.handleNoTypeVariables(token); |
| 1142 } | 1142 } |
| 1143 token = parseFormalParametersOpt(token); | 1143 token = parseFormalParametersOpt(token); |
| 1144 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1144 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| 1145 token = parseAsyncModifier(token); | 1145 token = parseAsyncModifier(token); |
| 1146 token = parseFunctionBody(token, false, externalModifier != null); | 1146 token = parseFunctionBody(token, false, externalModifier != null); |
| 1147 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1147 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
| 1148 Token endToken = token; | 1148 Token endToken = token; |
| 1149 token = token.next; | 1149 token = token.next; |
| 1150 if (token.kind == BAD_INPUT_TOKEN) { | |
| 1151 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken); | |
| 1152 } | |
| 1153 listener.endTopLevelMethod(start, getOrSet, endToken); | 1150 listener.endTopLevelMethod(start, getOrSet, endToken); |
| 1154 return token; | 1151 return token; |
| 1155 } | 1152 } |
| 1156 | 1153 |
| 1157 /// Looks ahead to find the name of a member. Returns a link of the modifiers, | 1154 /// Looks ahead to find the name of a member. Returns a link of the modifiers, |
| 1158 /// set/get, (operator) name, and either the start of the method body or the | 1155 /// set/get, (operator) name, and either the start of the method body or the |
| 1159 /// end of the declaration. | 1156 /// end of the declaration. |
| 1160 /// | 1157 /// |
| 1161 /// Examples: | 1158 /// Examples: |
| 1162 /// | 1159 /// |
| (...skipping 18 matching lines...) Expand all Loading... | |
| 1181 /// | 1178 /// |
| 1182 Link<Token> findMemberName(Token token) { | 1179 Link<Token> findMemberName(Token token) { |
| 1183 Link<Token> identifiers = const Link<Token>(); | 1180 Link<Token> identifiers = const Link<Token>(); |
| 1184 | 1181 |
| 1185 // `true` if 'get' has been seen. | 1182 // `true` if 'get' has been seen. |
| 1186 bool isGetter = false; | 1183 bool isGetter = false; |
| 1187 // `true` if an identifier has been seen after 'get'. | 1184 // `true` if an identifier has been seen after 'get'. |
| 1188 bool hasName = false; | 1185 bool hasName = false; |
| 1189 | 1186 |
| 1190 while (token.kind != EOF_TOKEN) { | 1187 while (token.kind != EOF_TOKEN) { |
| 1191 String value = token.stringValue; | 1188 if (optional('get', token)) { |
| 1192 if (value == 'get') { | |
| 1193 isGetter = true; | 1189 isGetter = true; |
| 1194 } else if (hasName && (value == 'sync' || value == 'async')) { | 1190 } else if (hasName && |
| 1191 (optional("sync", token) || optional("async", token))) { | |
| 1195 // Skip. | 1192 // Skip. |
| 1196 token = token.next; | 1193 token = token.next; |
| 1197 value = token.stringValue; | 1194 if (optional("*", token)) { |
| 1198 if (value == '*') { | |
| 1199 // Skip. | 1195 // Skip. |
| 1200 token = token.next; | 1196 token = token.next; |
| 1201 } | 1197 } |
| 1202 continue; | 1198 continue; |
| 1203 } else if (value == '(' || value == '{' || value == '=>') { | 1199 } else if (optional("(", token) || optional("{", token) || |
| 1200 optional("=>", token)) { | |
| 1204 // A method. | 1201 // A method. |
| 1205 identifiers = identifiers.prepend(token); | 1202 identifiers = identifiers.prepend(token); |
| 1206 return identifiers; | 1203 return identifiers; |
| 1207 } else if (value == '=' || value == ';' || value == ',') { | 1204 } else if (optional("=", token) || optional(";", token) || |
| 1205 optional(",", token)) { | |
| 1208 // A field or abstract getter. | 1206 // A field or abstract getter. |
| 1209 identifiers = identifiers.prepend(token); | 1207 identifiers = identifiers.prepend(token); |
| 1210 return identifiers; | 1208 return identifiers; |
| 1211 } else if (isGetter) { | 1209 } else if (isGetter) { |
| 1212 hasName = true; | 1210 hasName = true; |
| 1213 } | 1211 } |
| 1214 identifiers = identifiers.prepend(token); | 1212 identifiers = identifiers.prepend(token); |
| 1215 if (isValidTypeReference(token)) { | 1213 if (isValidTypeReference(token)) { |
| 1216 // type ... | 1214 // type ... |
| 1217 if (optional('.', token.next)) { | 1215 if (optional('.', token.next)) { |
| 1218 // type '.' ... | 1216 // type '.' ... |
| 1219 if (token.next.next.isIdentifier()) { | 1217 if (token.next.next.isIdentifier()) { |
| 1220 // type '.' identifier | 1218 // type '.' identifier |
| 1221 token = token.next.next; | 1219 token = token.next.next; |
| 1222 } | 1220 } |
| 1223 } | 1221 } |
| 1224 if (optional('<', token.next)) { | 1222 if (optional('<', token.next)) { |
| 1225 if (token.next is BeginGroupToken) { | 1223 if (token.next is BeginGroupToken) { |
| 1226 BeginGroupToken beginGroup = token.next; | 1224 BeginGroupToken beginGroup = token.next; |
| 1227 if (beginGroup.endGroup == null) { | 1225 if (beginGroup.endGroup == null) { |
| 1228 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); | 1226 reportUnrecoverableError(beginGroup, ErrorKind.UnmatchedToken); |
|
Johnni Winther
2017/01/30 09:04:38
Why not use the token returned from [reportUnrecov
ahe
2017/01/30 13:26:22
Because I'm not trying to change or improve error
| |
| 1227 } else { | |
| 1228 token = beginGroup.endGroup; | |
| 1229 } | 1229 } |
| 1230 token = beginGroup.endGroup; | |
| 1231 } | 1230 } |
| 1232 } | 1231 } |
| 1233 } | 1232 } |
| 1234 token = token.next; | 1233 token = token.next; |
| 1235 } | 1234 } |
| 1236 return const Link<Token>(); | 1235 return const Link<Token>(); |
| 1237 } | 1236 } |
| 1238 | 1237 |
| 1239 Token parseFieldInitializerOpt(Token token) { | 1238 Token parseFieldInitializerOpt(Token token) { |
| 1240 if (optional('=', token)) { | 1239 if (optional('=', token)) { |
| (...skipping 426 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1667 listener.endFunctionName(token); | 1666 listener.endFunctionName(token); |
| 1668 if (getOrSet == null) { | 1667 if (getOrSet == null) { |
| 1669 token = parseTypeVariablesOpt(token); | 1668 token = parseTypeVariablesOpt(token); |
| 1670 } else { | 1669 } else { |
| 1671 listener.handleNoTypeVariables(token); | 1670 listener.handleNoTypeVariables(token); |
| 1672 } | 1671 } |
| 1673 token = parseFormalParametersOpt(token); | 1672 token = parseFormalParametersOpt(token); |
| 1674 token = parseInitializersOpt(token); | 1673 token = parseInitializersOpt(token); |
| 1675 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1674 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| 1676 token = parseAsyncModifier(token); | 1675 token = parseAsyncModifier(token); |
| 1677 if (optional('=', token)) { | 1676 token = parseFunctionBody(token, false, true); |
| 1678 token = parseRedirectingFactoryBody(token); | |
| 1679 } else { | |
| 1680 token = parseFunctionBody(token, false, true); | |
| 1681 } | |
| 1682 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; | 1677 asyncAwaitKeywordsEnabled = previousAsyncAwaitKeywordsEnabled; |
| 1683 listener.endFunction(getOrSet, token); | 1678 listener.endFunction(getOrSet, token); |
| 1684 return token.next; | 1679 return token.next; |
| 1685 } | 1680 } |
| 1686 | 1681 |
| 1687 Token parseUnnamedFunction(Token token) { | 1682 Token parseUnnamedFunction(Token token) { |
| 1688 listener.beginUnnamedFunction(token); | 1683 listener.beginUnnamedFunction(token); |
| 1689 token = parseFormalParameters(token); | 1684 token = parseFormalParameters(token); |
| 1690 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; | 1685 bool previousAsyncAwaitKeywordsEnabled = asyncAwaitKeywordsEnabled; |
| 1691 token = parseAsyncModifier(token); | 1686 token = parseAsyncModifier(token); |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1754 String value = token.stringValue; | 1749 String value = token.stringValue; |
| 1755 if (identical(value, ';')) { | 1750 if (identical(value, ';')) { |
| 1756 if (!allowAbstract) { | 1751 if (!allowAbstract) { |
| 1757 reportRecoverableError(token, ErrorKind.ExpectedBody); | 1752 reportRecoverableError(token, ErrorKind.ExpectedBody); |
| 1758 } | 1753 } |
| 1759 listener.handleNoFunctionBody(token); | 1754 listener.handleNoFunctionBody(token); |
| 1760 } else { | 1755 } else { |
| 1761 if (identical(value, '=>')) { | 1756 if (identical(value, '=>')) { |
| 1762 token = parseExpression(token.next); | 1757 token = parseExpression(token.next); |
| 1763 expectSemicolon(token); | 1758 expectSemicolon(token); |
| 1764 } else if (value == '=') { | 1759 } else if (identical(value, '=')) { |
| 1765 token = parseRedirectingFactoryBody(token); | 1760 reportRecoverableError(token, ErrorKind.ExpectedBody); |
| 1761 token = parseExpression(token.next); | |
| 1766 expectSemicolon(token); | 1762 expectSemicolon(token); |
| 1767 } else { | 1763 } else { |
| 1768 token = skipBlock(token); | 1764 token = skipBlock(token); |
| 1769 } | 1765 } |
| 1770 listener.handleFunctionBodySkipped(token); | 1766 listener.handleFunctionBodySkipped(token); |
| 1771 } | 1767 } |
| 1772 return token; | 1768 return token; |
| 1773 } | 1769 } |
| 1774 | 1770 |
| 1775 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { | 1771 Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { |
| 1776 if (optional(';', token)) { | 1772 if (optional(';', token)) { |
| 1777 if (!allowAbstract) { | 1773 if (!allowAbstract) { |
| 1778 reportRecoverableError(token, ErrorKind.ExpectedBody); | 1774 reportRecoverableError(token, ErrorKind.ExpectedBody); |
| 1779 } | 1775 } |
| 1780 listener.endFunctionBody(0, null, token); | 1776 listener.endFunctionBody(0, null, token); |
| 1781 return token; | 1777 return token; |
| 1782 } else if (optional('=>', token)) { | 1778 } else if (optional('=>', token)) { |
| 1783 Token begin = token; | 1779 Token begin = token; |
| 1784 token = parseExpression(token.next); | 1780 token = parseExpression(token.next); |
| 1785 if (!isExpression) { | 1781 if (!isExpression) { |
| 1786 expectSemicolon(token); | 1782 expectSemicolon(token); |
| 1787 listener.endReturnStatement(true, begin, token); | 1783 listener.endReturnStatement(true, begin, token); |
| 1788 } else { | 1784 } else { |
| 1789 listener.endReturnStatement(true, begin, null); | 1785 listener.endReturnStatement(true, begin, null); |
| 1790 } | 1786 } |
| 1791 return token; | 1787 return token; |
| 1788 } else if (optional('=', token)) { | |
| 1789 Token begin = token; | |
| 1790 // Recover from a bad factory method. | |
| 1791 reportRecoverableError(token, ErrorKind.ExpectedBody); | |
| 1792 token = parseExpression(token.next); | |
| 1793 if (!isExpression) { | |
| 1794 expectSemicolon(token); | |
| 1795 listener.endReturnStatement(true, begin, token); | |
| 1796 } else { | |
| 1797 listener.endReturnStatement(true, begin, null); | |
| 1798 } | |
| 1799 return token; | |
| 1792 } | 1800 } |
| 1793 Token begin = token; | 1801 Token begin = token; |
| 1794 int statementCount = 0; | 1802 int statementCount = 0; |
| 1795 if (!optional('{', token)) { | 1803 if (!optional('{', token)) { |
| 1796 token = reportUnrecoverableError(token, ErrorKind.ExpectedFunctionBody); | 1804 token = reportUnrecoverableError(token, ErrorKind.ExpectedFunctionBody); |
| 1797 listener.handleInvalidFunctionBody(token); | 1805 listener.handleInvalidFunctionBody(token); |
| 1798 return token; | 1806 return token; |
| 1799 } | 1807 } |
| 1800 | 1808 |
| 1801 listener.beginFunctionBody(begin); | 1809 listener.beginFunctionBody(begin); |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1849 star = token; | 1857 star = token; |
| 1850 token = token.next; | 1858 token = token.next; |
| 1851 } else { | 1859 } else { |
| 1852 reportRecoverableError(async, ErrorKind.InvalidSyncModifier); | 1860 reportRecoverableError(async, ErrorKind.InvalidSyncModifier); |
| 1853 } | 1861 } |
| 1854 } | 1862 } |
| 1855 listener.handleAsyncModifier(async, star); | 1863 listener.handleAsyncModifier(async, star); |
| 1856 return token; | 1864 return token; |
| 1857 } | 1865 } |
| 1858 | 1866 |
| 1867 int statementDepth = 0; | |
| 1859 Token parseStatement(Token token) { | 1868 Token parseStatement(Token token) { |
| 1869 if (statementDepth++ > 500) { | |
|
Johnni Winther
2017/01/30 09:04:38
When does this occur?
ahe
2017/01/30 13:26:22
Deeply nested if statements. See tests/language/de
| |
| 1870 reportRecoverableError( | |
| 1871 token, ErrorKind.Unspecified, {'text': 'Stack overflow'}); | |
| 1872 return skipToEof(token); | |
| 1873 } | |
| 1874 Token result = parseStatementX(token); | |
| 1875 statementDepth--; | |
| 1876 return result; | |
| 1877 } | |
| 1878 | |
| 1879 Token parseStatementX(Token token) { | |
| 1860 final value = token.stringValue; | 1880 final value = token.stringValue; |
| 1861 if (identical(token.kind, IDENTIFIER_TOKEN)) { | 1881 if (identical(token.kind, IDENTIFIER_TOKEN)) { |
| 1862 return parseExpressionStatementOrDeclaration(token); | 1882 return parseExpressionStatementOrDeclaration(token); |
| 1863 } else if (identical(value, '{')) { | 1883 } else if (identical(value, '{')) { |
| 1864 return parseBlock(token); | 1884 return parseBlock(token); |
| 1865 } else if (identical(value, 'return')) { | 1885 } else if (identical(value, 'return')) { |
| 1866 return parseReturnStatement(token); | 1886 return parseReturnStatement(token); |
| 1867 } else if (identical(value, 'var') || identical(value, 'final')) { | 1887 } else if (identical(value, 'var') || identical(value, 'final')) { |
| 1868 return parseVariablesDeclaration(token); | 1888 return parseVariablesDeclaration(token); |
| 1869 } else if (identical(value, 'if')) { | 1889 } else if (identical(value, 'if')) { |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2154 BeginGroupToken begin = token; | 2174 BeginGroupToken begin = token; |
| 2155 token = (begin.endGroup != null) ? begin.endGroup : token; | 2175 token = (begin.endGroup != null) ? begin.endGroup : token; |
| 2156 } else if (token is ErrorToken) { | 2176 } else if (token is ErrorToken) { |
| 2157 reportErrorToken(token, false); | 2177 reportErrorToken(token, false); |
| 2158 } | 2178 } |
| 2159 token = token.next; | 2179 token = token.next; |
| 2160 } | 2180 } |
| 2161 return token; | 2181 return token; |
| 2162 } | 2182 } |
| 2163 | 2183 |
| 2184 int expressionDepth = 0; | |
| 2164 Token parseExpression(Token token) { | 2185 Token parseExpression(Token token) { |
| 2186 if (expressionDepth++ > 500) { | |
| 2187 reportRecoverableError( | |
|
Johnni Winther
2017/01/30 09:04:38
When does this occur?
ahe
2017/01/30 13:26:22
Deeply nested array literals, for example, see: te
| |
| 2188 token, ErrorKind.Unspecified, {'text': 'Stack overflow'}); | |
| 2189 return token.next; | |
| 2190 } | |
| 2165 listener.beginExpression(token); | 2191 listener.beginExpression(token); |
| 2166 return optional('throw', token) | 2192 Token result = optional('throw', token) |
| 2167 ? parseThrowExpression(token, true) | 2193 ? parseThrowExpression(token, true) |
| 2168 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true); | 2194 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true); |
| 2195 expressionDepth--; | |
| 2196 return result; | |
| 2169 } | 2197 } |
| 2170 | 2198 |
| 2171 Token parseExpressionWithoutCascade(Token token) { | 2199 Token parseExpressionWithoutCascade(Token token) { |
| 2172 listener.beginExpression(token); | 2200 listener.beginExpression(token); |
| 2173 return optional('throw', token) | 2201 return optional('throw', token) |
| 2174 ? parseThrowExpression(token, false) | 2202 ? parseThrowExpression(token, false) |
| 2175 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false); | 2203 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false); |
| 2176 } | 2204 } |
| 2177 | 2205 |
| 2178 Token parseConditionalExpressionRest(Token token) { | 2206 Token parseConditionalExpressionRest(Token token) { |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 2203 token = parseCascadeExpression(token); | 2231 token = parseCascadeExpression(token); |
| 2204 } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) { | 2232 } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) { |
| 2205 // Right associative, so we recurse at the same precedence | 2233 // Right associative, so we recurse at the same precedence |
| 2206 // level. | 2234 // level. |
| 2207 listener.beginExpression(token.next); | 2235 listener.beginExpression(token.next); |
| 2208 token = parsePrecedenceExpression(token.next, level, allowCascades); | 2236 token = parsePrecedenceExpression(token.next, level, allowCascades); |
| 2209 listener.handleAssignmentExpression(operator); | 2237 listener.handleAssignmentExpression(operator); |
| 2210 } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) { | 2238 } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) { |
| 2211 if (identical(info, PERIOD_INFO) || | 2239 if (identical(info, PERIOD_INFO) || |
| 2212 identical(info, QUESTION_PERIOD_INFO)) { | 2240 identical(info, QUESTION_PERIOD_INFO)) { |
| 2213 // Left associative, so we recurse at the next higher | 2241 // Left associative, so we recurse at the next higher precedence |
| 2214 // precedence level. However, POSTFIX_PRECEDENCE is the | 2242 // level. However, POSTFIX_PRECEDENCE is the highest level, so we |
| 2215 // highest level, so we just call parseUnaryExpression | 2243 // should just call [parseUnaryExpression] directly. However, a |
| 2216 // directly. | 2244 // unary expression isn't legal after a period, so we call |
| 2217 token = parseUnaryExpression(token.next, allowCascades); | 2245 // [parsePrimary] instead. |
| 2246 token = parsePrimary(token.next); | |
| 2218 listener.handleBinaryExpression(operator); | 2247 listener.handleBinaryExpression(operator); |
| 2219 } else if ((identical(info, OPEN_PAREN_INFO)) || | 2248 } else if ((identical(info, OPEN_PAREN_INFO)) || |
| 2220 (identical(info, OPEN_SQUARE_BRACKET_INFO))) { | 2249 (identical(info, OPEN_SQUARE_BRACKET_INFO))) { |
| 2221 token = parseArgumentOrIndexStar(token); | 2250 token = parseArgumentOrIndexStar(token); |
| 2222 } else if ((identical(info, PLUS_PLUS_INFO)) || | 2251 } else if ((identical(info, PLUS_PLUS_INFO)) || |
| 2223 (identical(info, MINUS_MINUS_INFO))) { | 2252 (identical(info, MINUS_MINUS_INFO))) { |
| 2224 listener.handleUnaryPostfixAssignmentExpression(token); | 2253 listener.handleUnaryPostfixAssignmentExpression(token); |
| 2225 token = token.next; | 2254 token = token.next; |
| 2226 } else { | 2255 } else { |
| 2227 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken); | 2256 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken); |
| (...skipping 1013 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 3241 void reportRecoverableError(Token token, ErrorKind kind, [Map arguments]) { | 3270 void reportRecoverableError(Token token, ErrorKind kind, [Map arguments]) { |
| 3242 if (token is ErrorToken) { | 3271 if (token is ErrorToken) { |
| 3243 reportErrorToken(token, true); | 3272 reportErrorToken(token, true); |
| 3244 } else { | 3273 } else { |
| 3245 arguments ??= {}; | 3274 arguments ??= {}; |
| 3246 listener.handleRecoverableError(token, kind, arguments); | 3275 listener.handleRecoverableError(token, kind, arguments); |
| 3247 } | 3276 } |
| 3248 } | 3277 } |
| 3249 | 3278 |
| 3250 Token reportErrorToken(ErrorToken token, bool isRecoverable) { | 3279 Token reportErrorToken(ErrorToken token, bool isRecoverable) { |
| 3251 ErrorKind kind; | 3280 ErrorKind kind = token.errorCode; |
| 3252 Map arguments = const {}; | 3281 Map arguments = const {}; |
| 3253 if (token is BadInputToken) { | 3282 switch (kind) { |
| 3254 String hex = token.character.toRadixString(16); | 3283 case ErrorKind.NonAsciiIdentifier: |
| 3255 if (hex.length < 4) { | 3284 String hex = token.character.toRadixString(16); |
| 3256 String padding = "0000".substring(hex.length); | 3285 if (hex.length < 4) { |
| 3257 hex = "$padding$hex"; | 3286 String padding = "0000".substring(hex.length); |
| 3258 } | 3287 hex = "$padding$hex"; |
| 3259 kind = ErrorKind.InvalidInputCharacter; | 3288 } |
| 3260 arguments = {'characterHex': hex}; | 3289 arguments = {'characterHex': hex}; |
| 3261 } else if (token is UnterminatedToken) { | 3290 break; |
| 3262 switch (token.start) { | 3291 |
| 3263 case '1e': | 3292 case ErrorKind.UnterminatedString: |
| 3264 kind = ErrorKind.MissingExponent; | 3293 arguments = {'quote': token.start}; |
| 3265 break; | 3294 break; |
| 3266 case '"': | 3295 |
| 3267 case "'": | 3296 case ErrorKind.UnmatchedToken: |
| 3268 case '"""': | 3297 String begin = token.begin.value; |
| 3269 case "'''": | 3298 String end = closeBraceFor(begin); |
| 3270 case 'r"': | 3299 arguments = {'begin': begin, 'end': end}; |
| 3271 case "r'": | 3300 break; |
| 3272 case 'r"""': | 3301 |
| 3273 case "r'''": | 3302 case ErrorKind.Unspecified: |
| 3274 kind = ErrorKind.UnterminatedString; | 3303 arguments = {"text": token.assertionMessage}; |
| 3275 arguments = {'quote': token.start}; | 3304 break; |
| 3276 break; | 3305 |
| 3277 case '0x': | 3306 default: |
| 3278 kind = ErrorKind.ExpectedHexDigit; | 3307 break; |
| 3279 break; | |
| 3280 case r'$': | |
| 3281 kind = ErrorKind.MalformedStringLiteral; | |
| 3282 break; | |
| 3283 case '/*': | |
| 3284 kind = ErrorKind.UnterminatedComment; | |
| 3285 break; | |
| 3286 default: | |
| 3287 kind = ErrorKind.UnterminatedToken; | |
| 3288 break; | |
| 3289 } | |
| 3290 } else if (token is UnmatchedToken) { | |
| 3291 String begin = token.begin.value; | |
| 3292 String end = closeBraceFor(begin); | |
| 3293 kind = ErrorKind.UnmatchedToken; | |
| 3294 arguments = {'begin': begin, 'end': end}; | |
| 3295 } else { | |
| 3296 return listener.handleUnrecoverableError( | |
| 3297 token, ErrorKind.Unspecified, {"text": token.assertionMessage}); | |
| 3298 } | 3308 } |
| 3299 if (isRecoverable) { | 3309 if (isRecoverable) { |
| 3300 listener.handleRecoverableError(token, kind, arguments); | 3310 listener.handleRecoverableError(token, kind, arguments); |
| 3301 return null; | 3311 return null; |
| 3302 } else { | 3312 } else { |
| 3303 return listener.handleUnrecoverableError(token, kind, arguments); | 3313 return listener.handleUnrecoverableError(token, kind, arguments); |
| 3304 } | 3314 } |
| 3305 } | 3315 } |
| 3306 } | 3316 } |
| 3307 | |
| 3308 String closeBraceFor(String openBrace) { | |
| 3309 return const { | |
| 3310 '(': ')', | |
| 3311 '[': ']', | |
| 3312 '{': '}', | |
| 3313 '<': '>', | |
| 3314 r'${': '}', | |
| 3315 }[openBrace]; | |
| 3316 } | |
| 3317 | |
| 3318 Token skipToEof(Token token) { | |
| 3319 while (!identical(token.info, EOF_INFO)) { | |
| 3320 token = token.next; | |
| 3321 } | |
| 3322 return token; | |
| 3323 } | |
| OLD | NEW |