| 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 fasta.parser.parser; | 5 library fasta.parser.parser; |
| 6 | 6 |
| 7 import '../scanner.dart' show |
| 8 ErrorToken; |
| 9 |
| 10 import '../scanner/recover.dart' show |
| 11 closeBraceFor, |
| 12 skipToEof; |
| 13 |
| 7 import 'package:front_end/src/fasta/scanner/keyword.dart' show | 14 import 'package:front_end/src/fasta/scanner/keyword.dart' show |
| 8 Keyword; | 15 Keyword; |
| 9 | 16 |
| 10 import 'package:front_end/src/fasta/scanner/precedence.dart' show | 17 import 'package:front_end/src/fasta/scanner/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:front_end/src/fasta/scanner/token.dart' show | 35 import 'package:front_end/src/fasta/scanner/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:front_end/src/fasta/scanner/token_constants.dart' show | 42 import 'package:front_end/src/fasta/scanner/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); |
| 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) { |
| 1870 // This happens for degenerate programs, for example, a lot of nested |
| 1871 // if-statements. The language test deep_nesting2_negative_test, for |
| 1872 // example, provokes this. |
| 1873 reportRecoverableError( |
| 1874 token, ErrorKind.Unspecified, {'text': 'Stack overflow'}); |
| 1875 return skipToEof(token); |
| 1876 } |
| 1877 Token result = parseStatementX(token); |
| 1878 statementDepth--; |
| 1879 return result; |
| 1880 } |
| 1881 |
| 1882 Token parseStatementX(Token token) { |
| 1860 final value = token.stringValue; | 1883 final value = token.stringValue; |
| 1861 if (identical(token.kind, IDENTIFIER_TOKEN)) { | 1884 if (identical(token.kind, IDENTIFIER_TOKEN)) { |
| 1862 return parseExpressionStatementOrDeclaration(token); | 1885 return parseExpressionStatementOrDeclaration(token); |
| 1863 } else if (identical(value, '{')) { | 1886 } else if (identical(value, '{')) { |
| 1864 return parseBlock(token); | 1887 return parseBlock(token); |
| 1865 } else if (identical(value, 'return')) { | 1888 } else if (identical(value, 'return')) { |
| 1866 return parseReturnStatement(token); | 1889 return parseReturnStatement(token); |
| 1867 } else if (identical(value, 'var') || identical(value, 'final')) { | 1890 } else if (identical(value, 'var') || identical(value, 'final')) { |
| 1868 return parseVariablesDeclaration(token); | 1891 return parseVariablesDeclaration(token); |
| 1869 } else if (identical(value, 'if')) { | 1892 } else if (identical(value, 'if')) { |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2154 BeginGroupToken begin = token; | 2177 BeginGroupToken begin = token; |
| 2155 token = (begin.endGroup != null) ? begin.endGroup : token; | 2178 token = (begin.endGroup != null) ? begin.endGroup : token; |
| 2156 } else if (token is ErrorToken) { | 2179 } else if (token is ErrorToken) { |
| 2157 reportErrorToken(token, false); | 2180 reportErrorToken(token, false); |
| 2158 } | 2181 } |
| 2159 token = token.next; | 2182 token = token.next; |
| 2160 } | 2183 } |
| 2161 return token; | 2184 return token; |
| 2162 } | 2185 } |
| 2163 | 2186 |
| 2187 int expressionDepth = 0; |
| 2164 Token parseExpression(Token token) { | 2188 Token parseExpression(Token token) { |
| 2189 if (expressionDepth++ > 500) { |
| 2190 // This happens in degenerate programs, for example, with a lot of nested |
| 2191 // list literals. This is provoked by, for examaple, the language test |
| 2192 // deep_nesting1_negative_test. |
| 2193 reportRecoverableError( |
| 2194 token, ErrorKind.Unspecified, {'text': 'Stack overflow'}); |
| 2195 return token.next; |
| 2196 } |
| 2165 listener.beginExpression(token); | 2197 listener.beginExpression(token); |
| 2166 return optional('throw', token) | 2198 Token result = optional('throw', token) |
| 2167 ? parseThrowExpression(token, true) | 2199 ? parseThrowExpression(token, true) |
| 2168 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true); | 2200 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true); |
| 2201 expressionDepth--; |
| 2202 return result; |
| 2169 } | 2203 } |
| 2170 | 2204 |
| 2171 Token parseExpressionWithoutCascade(Token token) { | 2205 Token parseExpressionWithoutCascade(Token token) { |
| 2172 listener.beginExpression(token); | 2206 listener.beginExpression(token); |
| 2173 return optional('throw', token) | 2207 return optional('throw', token) |
| 2174 ? parseThrowExpression(token, false) | 2208 ? parseThrowExpression(token, false) |
| 2175 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false); | 2209 : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false); |
| 2176 } | 2210 } |
| 2177 | 2211 |
| 2178 Token parseConditionalExpressionRest(Token token) { | 2212 Token parseConditionalExpressionRest(Token token) { |
| (...skipping 24 matching lines...) Expand all Loading... |
| 2203 token = parseCascadeExpression(token); | 2237 token = parseCascadeExpression(token); |
| 2204 } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) { | 2238 } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) { |
| 2205 // Right associative, so we recurse at the same precedence | 2239 // Right associative, so we recurse at the same precedence |
| 2206 // level. | 2240 // level. |
| 2207 listener.beginExpression(token.next); | 2241 listener.beginExpression(token.next); |
| 2208 token = parsePrecedenceExpression(token.next, level, allowCascades); | 2242 token = parsePrecedenceExpression(token.next, level, allowCascades); |
| 2209 listener.handleAssignmentExpression(operator); | 2243 listener.handleAssignmentExpression(operator); |
| 2210 } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) { | 2244 } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) { |
| 2211 if (identical(info, PERIOD_INFO) || | 2245 if (identical(info, PERIOD_INFO) || |
| 2212 identical(info, QUESTION_PERIOD_INFO)) { | 2246 identical(info, QUESTION_PERIOD_INFO)) { |
| 2213 // Left associative, so we recurse at the next higher | 2247 // Left associative, so we recurse at the next higher precedence |
| 2214 // precedence level. However, POSTFIX_PRECEDENCE is the | 2248 // level. However, POSTFIX_PRECEDENCE is the highest level, so we |
| 2215 // highest level, so we just call parseUnaryExpression | 2249 // should just call [parseUnaryExpression] directly. However, a |
| 2216 // directly. | 2250 // unary expression isn't legal after a period, so we call |
| 2217 token = parseUnaryExpression(token.next, allowCascades); | 2251 // [parsePrimary] instead. |
| 2252 token = parsePrimary(token.next); |
| 2218 listener.handleBinaryExpression(operator); | 2253 listener.handleBinaryExpression(operator); |
| 2219 } else if ((identical(info, OPEN_PAREN_INFO)) || | 2254 } else if ((identical(info, OPEN_PAREN_INFO)) || |
| 2220 (identical(info, OPEN_SQUARE_BRACKET_INFO))) { | 2255 (identical(info, OPEN_SQUARE_BRACKET_INFO))) { |
| 2221 token = parseArgumentOrIndexStar(token); | 2256 token = parseArgumentOrIndexStar(token); |
| 2222 } else if ((identical(info, PLUS_PLUS_INFO)) || | 2257 } else if ((identical(info, PLUS_PLUS_INFO)) || |
| 2223 (identical(info, MINUS_MINUS_INFO))) { | 2258 (identical(info, MINUS_MINUS_INFO))) { |
| 2224 listener.handleUnaryPostfixAssignmentExpression(token); | 2259 listener.handleUnaryPostfixAssignmentExpression(token); |
| 2225 token = token.next; | 2260 token = token.next; |
| 2226 } else { | 2261 } else { |
| 2227 token = reportUnrecoverableError(token, ErrorKind.UnexpectedToken); | 2262 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]) { | 3276 void reportRecoverableError(Token token, ErrorKind kind, [Map arguments]) { |
| 3242 if (token is ErrorToken) { | 3277 if (token is ErrorToken) { |
| 3243 reportErrorToken(token, true); | 3278 reportErrorToken(token, true); |
| 3244 } else { | 3279 } else { |
| 3245 arguments ??= {}; | 3280 arguments ??= {}; |
| 3246 listener.handleRecoverableError(token, kind, arguments); | 3281 listener.handleRecoverableError(token, kind, arguments); |
| 3247 } | 3282 } |
| 3248 } | 3283 } |
| 3249 | 3284 |
| 3250 Token reportErrorToken(ErrorToken token, bool isRecoverable) { | 3285 Token reportErrorToken(ErrorToken token, bool isRecoverable) { |
| 3251 ErrorKind kind; | 3286 ErrorKind kind = token.errorCode; |
| 3252 Map arguments = const {}; | 3287 Map arguments = const {}; |
| 3253 if (token is BadInputToken) { | 3288 switch (kind) { |
| 3254 String hex = token.character.toRadixString(16); | 3289 case ErrorKind.NonAsciiIdentifier: |
| 3255 if (hex.length < 4) { | 3290 String hex = token.character.toRadixString(16); |
| 3256 String padding = "0000".substring(hex.length); | 3291 if (hex.length < 4) { |
| 3257 hex = "$padding$hex"; | 3292 String padding = "0000".substring(hex.length); |
| 3258 } | 3293 hex = "$padding$hex"; |
| 3259 kind = ErrorKind.InvalidInputCharacter; | 3294 } |
| 3260 arguments = {'characterHex': hex}; | 3295 arguments = {'characterHex': hex}; |
| 3261 } else if (token is UnterminatedToken) { | 3296 break; |
| 3262 switch (token.start) { | 3297 |
| 3263 case '1e': | 3298 case ErrorKind.UnterminatedString: |
| 3264 kind = ErrorKind.MissingExponent; | 3299 arguments = {'quote': token.start}; |
| 3265 break; | 3300 break; |
| 3266 case '"': | 3301 |
| 3267 case "'": | 3302 case ErrorKind.UnmatchedToken: |
| 3268 case '"""': | 3303 String begin = token.begin.value; |
| 3269 case "'''": | 3304 String end = closeBraceFor(begin); |
| 3270 case 'r"': | 3305 arguments = {'begin': begin, 'end': end}; |
| 3271 case "r'": | 3306 break; |
| 3272 case 'r"""': | 3307 |
| 3273 case "r'''": | 3308 case ErrorKind.Unspecified: |
| 3274 kind = ErrorKind.UnterminatedString; | 3309 arguments = {"text": token.assertionMessage}; |
| 3275 arguments = {'quote': token.start}; | 3310 break; |
| 3276 break; | 3311 |
| 3277 case '0x': | 3312 default: |
| 3278 kind = ErrorKind.ExpectedHexDigit; | 3313 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 } | 3314 } |
| 3299 if (isRecoverable) { | 3315 if (isRecoverable) { |
| 3300 listener.handleRecoverableError(token, kind, arguments); | 3316 listener.handleRecoverableError(token, kind, arguments); |
| 3301 return null; | 3317 return null; |
| 3302 } else { | 3318 } else { |
| 3303 return listener.handleUnrecoverableError(token, kind, arguments); | 3319 return listener.handleUnrecoverableError(token, kind, arguments); |
| 3304 } | 3320 } |
| 3305 } | 3321 } |
| 3306 } | 3322 } |
| 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 |