]>
Commit | Line | Data |
---|---|---|
9dae56ea A |
1 | /* |
2 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
93a37866 | 4 | * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. |
9dae56ea A |
5 | * |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Library General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Library General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Library General Public License | |
17 | * along with this library; see the file COPYING.LIB. If not, write to | |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
19 | * Boston, MA 02110-1301, USA. | |
20 | * | |
21 | */ | |
22 | ||
23 | #include "config.h" | |
24 | #include "Parser.h" | |
25 | ||
6fe7ccc8 A |
26 | #include "ASTBuilder.h" |
27 | #include "CodeBlock.h" | |
9dae56ea | 28 | #include "Debugger.h" |
93a37866 | 29 | #include "JSCJSValueInlines.h" |
9dae56ea | 30 | #include "Lexer.h" |
81345200 | 31 | #include "JSCInlines.h" |
6fe7ccc8 | 32 | #include "SourceProvider.h" |
93a37866 | 33 | #include "VM.h" |
6fe7ccc8 A |
34 | #include <utility> |
35 | #include <wtf/HashFunctions.h> | |
81345200 | 36 | #include <wtf/StringPrintStream.h> |
6fe7ccc8 A |
37 | #include <wtf/WTFThreadData.h> |
38 | ||
81345200 A |
39 | |
40 | #define updateErrorMessage(shouldPrintToken, ...) do {\ | |
41 | propagateError(); \ | |
42 | logError(shouldPrintToken, __VA_ARGS__); \ | |
43 | } while (0) | |
44 | ||
45 | #define propagateError() do { if (hasError()) return 0; } while (0) | |
46 | #define internalFailWithMessage(shouldPrintToken, ...) do { updateErrorMessage(shouldPrintToken, __VA_ARGS__); return 0; } while (0) | |
47 | #define handleErrorToken() do { if (m_token.m_type == EOFTOK || m_token.m_type & ErrorTokenFlag) { failDueToUnexpectedToken(); } } while (0) | |
48 | #define failWithMessage(...) do { { handleErrorToken(); updateErrorMessage(true, __VA_ARGS__); } return 0; } while (0) | |
49 | #define failWithStackOverflow() do { updateErrorMessage(false, "Stack exhausted"); m_hasStackOverflow = true; return 0; } while (0) | |
50 | #define failIfFalse(cond, ...) do { if (!(cond)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) | |
51 | #define failIfTrue(cond, ...) do { if (cond) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) | |
52 | #define failIfTrueIfStrict(cond, ...) do { if ((cond) && strictMode()) internalFailWithMessage(false, __VA_ARGS__); } while (0) | |
53 | #define failIfFalseIfStrict(cond, ...) do { if ((!(cond)) && strictMode()) internalFailWithMessage(false, __VA_ARGS__); } while (0) | |
54 | #define consumeOrFail(tokenType, ...) do { if (!consume(tokenType)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) | |
55 | #define consumeOrFailWithFlags(tokenType, flags, ...) do { if (!consume(tokenType, flags)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) | |
56 | #define matchOrFail(tokenType, ...) do { if (!match(tokenType)) { handleErrorToken(); internalFailWithMessage(true, __VA_ARGS__); } } while (0) | |
93a37866 | 57 | #define failIfStackOverflow() do { if (!canRecurse()) failWithStackOverflow(); } while (0) |
81345200 A |
58 | #define semanticFail(...) do { internalFailWithMessage(false, __VA_ARGS__); } while (0) |
59 | #define semanticFailIfTrue(cond, ...) do { if (cond) internalFailWithMessage(false, __VA_ARGS__); } while (0) | |
60 | #define semanticFailIfFalse(cond, ...) do { if (!(cond)) internalFailWithMessage(false, __VA_ARGS__); } while (0) | |
61 | #define regexFail(failure) do { setErrorMessage(failure); return 0; } while (0) | |
62 | #define failDueToUnexpectedToken() do {\ | |
63 | logError(true);\ | |
64 | return 0;\ | |
65 | } while (0) | |
66 | ||
67 | #define handleProductionOrFail(token, tokenString, operation, production) do {\ | |
68 | consumeOrFail(token, "Expected '", tokenString, "' to ", operation, " a ", production);\ | |
69 | } while (0) | |
70 | ||
71 | #define semanticFailureDueToKeyword(...) do { \ | |
72 | if (strictMode() && m_token.m_type == RESERVED_IF_STRICT) \ | |
73 | semanticFail("Cannot use the reserved word '", getToken(), "' as a ", __VA_ARGS__, " in strict mode"); \ | |
74 | if (m_token.m_type == RESERVED || m_token.m_type == RESERVED_IF_STRICT) \ | |
75 | semanticFail("Cannot use the reserved word '", getToken(), "' as a ", __VA_ARGS__); \ | |
76 | if (m_token.m_type & KeywordTokenFlag) \ | |
77 | semanticFail("Cannot use the keyword '", getToken(), "' as a ", __VA_ARGS__); \ | |
78 | } while (0) | |
93a37866 | 79 | |
6fe7ccc8 | 80 | using namespace std; |
9dae56ea A |
81 | |
82 | namespace JSC { | |
83 | ||
81345200 A |
84 | template <typename LexerType> |
85 | void Parser<LexerType>::logError(bool) | |
86 | { | |
87 | if (hasError()) | |
88 | return; | |
89 | StringPrintStream stream; | |
90 | printUnexpectedTokenText(stream); | |
91 | setErrorMessage(stream.toString()); | |
92 | } | |
93 | ||
94 | template <typename LexerType> template <typename A> | |
95 | void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1) | |
96 | { | |
97 | if (hasError()) | |
98 | return; | |
99 | StringPrintStream stream; | |
100 | if (shouldPrintToken) { | |
101 | printUnexpectedTokenText(stream); | |
102 | stream.print(". "); | |
103 | } | |
104 | stream.print(value1, "."); | |
105 | setErrorMessage(stream.toString()); | |
106 | } | |
107 | ||
108 | template <typename LexerType> template <typename A, typename B> | |
109 | void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2) | |
110 | { | |
111 | if (hasError()) | |
112 | return; | |
113 | StringPrintStream stream; | |
114 | if (shouldPrintToken) { | |
115 | printUnexpectedTokenText(stream); | |
116 | stream.print(". "); | |
117 | } | |
118 | stream.print(value1, value2, "."); | |
119 | setErrorMessage(stream.toString()); | |
120 | } | |
121 | ||
122 | template <typename LexerType> template <typename A, typename B, typename C> | |
123 | void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3) | |
124 | { | |
125 | if (hasError()) | |
126 | return; | |
127 | StringPrintStream stream; | |
128 | if (shouldPrintToken) { | |
129 | printUnexpectedTokenText(stream); | |
130 | stream.print(". "); | |
131 | } | |
132 | stream.print(value1, value2, value3, "."); | |
133 | setErrorMessage(stream.toString()); | |
134 | } | |
135 | ||
136 | template <typename LexerType> template <typename A, typename B, typename C, typename D> | |
137 | void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4) | |
138 | { | |
139 | if (hasError()) | |
140 | return; | |
141 | StringPrintStream stream; | |
142 | if (shouldPrintToken) { | |
143 | printUnexpectedTokenText(stream); | |
144 | stream.print(". "); | |
145 | } | |
146 | stream.print(value1, value2, value3, value4, "."); | |
147 | setErrorMessage(stream.toString()); | |
148 | } | |
149 | ||
150 | template <typename LexerType> template <typename A, typename B, typename C, typename D, typename E> | |
151 | void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4, const E& value5) | |
152 | { | |
153 | if (hasError()) | |
154 | return; | |
155 | StringPrintStream stream; | |
156 | if (shouldPrintToken) { | |
157 | printUnexpectedTokenText(stream); | |
158 | stream.print(". "); | |
159 | } | |
160 | stream.print(value1, value2, value3, value4, value5, "."); | |
161 | setErrorMessage(stream.toString()); | |
162 | } | |
163 | ||
164 | template <typename LexerType> template <typename A, typename B, typename C, typename D, typename E, typename F> | |
165 | void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4, const E& value5, const F& value6) | |
166 | { | |
167 | if (hasError()) | |
168 | return; | |
169 | StringPrintStream stream; | |
170 | if (shouldPrintToken) { | |
171 | printUnexpectedTokenText(stream); | |
172 | stream.print(". "); | |
173 | } | |
174 | stream.print(value1, value2, value3, value4, value5, value6, "."); | |
175 | setErrorMessage(stream.toString()); | |
176 | } | |
177 | ||
178 | template <typename LexerType> template <typename A, typename B, typename C, typename D, typename E, typename F, typename G> | |
179 | void Parser<LexerType>::logError(bool shouldPrintToken, const A& value1, const B& value2, const C& value3, const D& value4, const E& value5, const F& value6, const G& value7) | |
180 | { | |
181 | if (hasError()) | |
182 | return; | |
183 | StringPrintStream stream; | |
184 | if (shouldPrintToken) { | |
185 | printUnexpectedTokenText(stream); | |
186 | stream.print(". "); | |
187 | } | |
188 | stream.print(value1, value2, value3, value4, value5, value6, value7, "."); | |
189 | setErrorMessage(stream.toString()); | |
190 | } | |
191 | ||
6fe7ccc8 | 192 | template <typename LexerType> |
ed1e77d3 A |
193 | Parser<LexerType>::Parser( |
194 | VM* vm, const SourceCode& source, FunctionParameters* parameters, | |
195 | const Identifier& name, JSParserBuiltinMode builtinMode, | |
196 | JSParserStrictMode strictMode, JSParserCodeType codeType, | |
197 | ConstructorKind defaultConstructorKind, ThisTDZMode thisTDZMode) | |
93a37866 | 198 | : m_vm(vm) |
6fe7ccc8 | 199 | , m_source(&source) |
93a37866 | 200 | , m_hasStackOverflow(false) |
6fe7ccc8 | 201 | , m_allowsIn(true) |
6fe7ccc8 A |
202 | , m_assignmentCount(0) |
203 | , m_nonLHSCount(0) | |
204 | , m_syntaxAlreadyValidated(source.provider()->isValid()) | |
205 | , m_statementDepth(0) | |
206 | , m_nonTrivialExpressionCount(0) | |
207 | , m_lastIdentifier(0) | |
81345200 | 208 | , m_lastFunctionName(nullptr) |
6fe7ccc8 | 209 | , m_sourceElements(0) |
ed1e77d3 A |
210 | , m_parsingBuiltin(builtinMode == JSParserBuiltinMode::Builtin) |
211 | , m_defaultConstructorKind(defaultConstructorKind) | |
212 | , m_thisTDZMode(thisTDZMode) | |
9dae56ea | 213 | { |
ed1e77d3 A |
214 | m_lexer = std::make_unique<LexerType>(vm, builtinMode); |
215 | m_lexer->setCode(source, &m_parserArena); | |
81345200 A |
216 | m_token.m_location.line = source.firstLine(); |
217 | m_token.m_location.startOffset = source.startOffset(); | |
93a37866 A |
218 | m_token.m_location.endOffset = source.startOffset(); |
219 | m_token.m_location.lineStartOffset = source.startOffset(); | |
93a37866 | 220 | m_functionCache = vm->addSourceProviderCache(source.provider()); |
6fe7ccc8 | 221 | ScopeRef scope = pushScope(); |
ed1e77d3 | 222 | if (codeType == JSParserCodeType::Function) |
6fe7ccc8 | 223 | scope->setIsFunction(); |
ed1e77d3 | 224 | if (strictMode == JSParserStrictMode::Strict) |
6fe7ccc8 A |
225 | scope->setStrictMode(); |
226 | if (parameters) { | |
81345200 A |
227 | bool hadBindingParameters = false; |
228 | for (unsigned i = 0; i < parameters->size(); i++) { | |
229 | auto parameter = parameters->at(i); | |
230 | if (!parameter->isBindingNode()) { | |
231 | hadBindingParameters = true; | |
232 | continue; | |
233 | } | |
234 | scope->declareParameter(&static_cast<BindingNode*>(parameter)->boundProperty()); | |
235 | } | |
236 | if (hadBindingParameters) { | |
237 | Vector<Identifier> boundParameterNames; | |
238 | for (unsigned i = 0; i < parameters->size(); i++) { | |
239 | auto parameter = parameters->at(i); | |
240 | if (parameter->isBindingNode()) | |
241 | continue; | |
242 | parameter->collectBoundIdentifiers(boundParameterNames); | |
243 | } | |
244 | for (auto& boundParameterName : boundParameterNames) | |
245 | scope->declareVariable(&boundParameterName); | |
246 | } | |
6fe7ccc8 | 247 | } |
93a37866 A |
248 | if (!name.isNull()) |
249 | scope->declareCallee(&name); | |
6fe7ccc8 | 250 | next(); |
6fe7ccc8 | 251 | } |
9dae56ea | 252 | |
6fe7ccc8 A |
253 | template <typename LexerType> |
254 | Parser<LexerType>::~Parser() | |
255 | { | |
256 | } | |
9dae56ea | 257 | |
6fe7ccc8 | 258 | template <typename LexerType> |
93a37866 | 259 | String Parser<LexerType>::parseInner() |
6fe7ccc8 | 260 | { |
93a37866 | 261 | String parseError = String(); |
6fe7ccc8 | 262 | |
ed1e77d3 | 263 | ASTBuilder context(const_cast<VM*>(m_vm), m_parserArena, const_cast<SourceCode*>(m_source)); |
6fe7ccc8 A |
264 | if (m_lexer->isReparsing()) |
265 | m_statementDepth--; | |
266 | ScopeRef scope = currentScope(); | |
ed1e77d3 | 267 | SourceElements* sourceElements = parseSourceElements(context, CheckForStrictMode, StandardFunctionParseType); |
93a37866 A |
268 | if (!sourceElements || !consume(EOFTOK)) { |
269 | if (hasError()) | |
270 | parseError = m_errorMessage; | |
271 | else | |
272 | parseError = ASCIILiteral("Parser error"); | |
273 | } | |
9dae56ea | 274 | |
6fe7ccc8 | 275 | IdentifierSet capturedVariables; |
81345200 | 276 | bool modifiedParameter = false; |
ed1e77d3 A |
277 | bool modifiedArguments = false; |
278 | scope->getCapturedVariables(capturedVariables, modifiedParameter, modifiedArguments); | |
81345200 | 279 | |
6fe7ccc8 A |
280 | CodeFeatures features = context.features(); |
281 | if (scope->strictMode()) | |
282 | features |= StrictModeFeature; | |
283 | if (scope->shadowsArguments()) | |
284 | features |= ShadowsArgumentsFeature; | |
81345200 A |
285 | if (modifiedParameter) |
286 | features |= ModifiedParameterFeature; | |
ed1e77d3 A |
287 | if (modifiedArguments) |
288 | features |= ModifiedArgumentsFeature; | |
289 | Vector<RefPtr<UniquedStringImpl>> closedVariables; | |
81345200 | 290 | if (m_parsingBuiltin) { |
81345200 A |
291 | IdentifierSet usedVariables; |
292 | scope->getUsedVariables(usedVariables); | |
293 | for (const auto& variable : usedVariables) { | |
ed1e77d3 A |
294 | Identifier identifier = Identifier::fromUid(m_vm, variable.get()); |
295 | if (scope->hasDeclaredVariable(identifier)) | |
81345200 A |
296 | continue; |
297 | ||
ed1e77d3 A |
298 | if (scope->hasDeclaredParameter(identifier)) |
299 | continue; | |
300 | ||
301 | if (variable == m_vm->propertyNames->arguments.impl()) | |
81345200 | 302 | continue; |
ed1e77d3 | 303 | |
81345200 A |
304 | closedVariables.append(variable); |
305 | } | |
ed1e77d3 A |
306 | |
307 | if (!capturedVariables.isEmpty()) { | |
308 | for (const auto& capturedVariable : capturedVariables) { | |
309 | Identifier identifier = Identifier::fromUid(m_vm, capturedVariable.get()); | |
310 | if (scope->hasDeclaredVariable(identifier)) | |
311 | continue; | |
312 | ||
313 | if (scope->hasDeclaredParameter(identifier)) | |
314 | continue; | |
315 | ||
316 | RELEASE_ASSERT_NOT_REACHED(); | |
317 | } | |
318 | } | |
81345200 | 319 | } |
6fe7ccc8 | 320 | didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features, |
81345200 | 321 | context.numConstants(), capturedVariables, WTF::move(closedVariables)); |
9dae56ea | 322 | |
6fe7ccc8 | 323 | return parseError; |
9dae56ea A |
324 | } |
325 | ||
6fe7ccc8 | 326 | template <typename LexerType> |
ed1e77d3 A |
327 | void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, DeclarationStacks::VarStack& varStack, |
328 | DeclarationStacks::FunctionStack& funcStack, CodeFeatures features, int numConstants, IdentifierSet& capturedVars, const Vector<RefPtr<UniquedStringImpl>>&& closedVariables) | |
9dae56ea A |
329 | { |
330 | m_sourceElements = sourceElements; | |
ed1e77d3 A |
331 | m_varDeclarations.swap(varStack); |
332 | m_funcDeclarations.swap(funcStack); | |
14957cd0 | 333 | m_capturedVariables.swap(capturedVars); |
81345200 | 334 | m_closedVariables = closedVariables; |
9dae56ea | 335 | m_features = features; |
9dae56ea A |
336 | m_numConstants = numConstants; |
337 | } | |
338 | ||
6fe7ccc8 A |
339 | template <typename LexerType> |
340 | bool Parser<LexerType>::allowAutomaticSemicolon() | |
341 | { | |
342 | return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator(); | |
343 | } | |
344 | ||
345 | template <typename LexerType> | |
ed1e77d3 | 346 | template <class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSourceElements(TreeBuilder& context, SourceElementsMode mode, FunctionParseType functionParseType) |
6fe7ccc8 A |
347 | { |
348 | const unsigned lengthOfUseStrictLiteral = 12; // "use strict".length | |
349 | TreeSourceElements sourceElements = context.createSourceElements(); | |
350 | bool seenNonDirective = false; | |
351 | const Identifier* directive = 0; | |
352 | unsigned directiveLiteralLength = 0; | |
81345200 | 353 | auto savePoint = createSavePoint(); |
6fe7ccc8 | 354 | bool hasSetStrict = false; |
ed1e77d3 A |
355 | |
356 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
357 | if (match(ARROWFUNCTION)) { | |
358 | TreeStatement arrowfunctionStatement = parseArrowFunctionSingleExpressionBody(context, functionParseType); | |
359 | ||
360 | if (arrowfunctionStatement) { | |
361 | context.setEndOffset(arrowfunctionStatement, m_lastTokenEndPosition.offset); | |
362 | context.appendStatement(sourceElements, arrowfunctionStatement); | |
363 | } | |
364 | ||
365 | propagateError(); | |
366 | return sourceElements; | |
367 | } | |
368 | #else | |
369 | UNUSED_PARAM(functionParseType); | |
370 | #endif | |
371 | ||
372 | while (TreeStatement statement = parseStatementListItem(context, directive, &directiveLiteralLength)) { | |
6fe7ccc8 A |
373 | if (mode == CheckForStrictMode && !seenNonDirective) { |
374 | if (directive) { | |
375 | // "use strict" must be the exact literal without escape sequences or line continuation. | |
93a37866 | 376 | if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) { |
6fe7ccc8 A |
377 | setStrictMode(); |
378 | hasSetStrict = true; | |
81345200 A |
379 | if (!isValidStrictMode()) { |
380 | if (m_lastFunctionName) { | |
381 | if (m_vm->propertyNames->arguments == *m_lastFunctionName) | |
382 | semanticFail("Cannot name a function 'arguments' in strict mode"); | |
383 | if (m_vm->propertyNames->eval == *m_lastFunctionName) | |
384 | semanticFail("Cannot name a function 'eval' in strict mode"); | |
385 | } | |
386 | if (hasDeclaredVariable(m_vm->propertyNames->arguments)) | |
387 | semanticFail("Cannot declare a variable named 'arguments' in strict mode"); | |
388 | if (hasDeclaredVariable(m_vm->propertyNames->eval)) | |
389 | semanticFail("Cannot declare a variable named 'eval' in strict mode"); | |
390 | semanticFailIfFalse(isValidStrictMode(), "Invalid parameters or function name in strict mode"); | |
391 | } | |
392 | restoreSavePoint(savePoint); | |
393 | propagateError(); | |
6fe7ccc8 A |
394 | continue; |
395 | } | |
396 | } else | |
397 | seenNonDirective = true; | |
398 | } | |
399 | context.appendStatement(sourceElements, statement); | |
400 | } | |
93a37866 | 401 | |
81345200 | 402 | propagateError(); |
6fe7ccc8 A |
403 | return sourceElements; |
404 | } | |
ed1e77d3 A |
405 | template <typename LexerType> |
406 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatementListItem(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength) | |
407 | { | |
408 | // The grammar is documented here: | |
409 | // http://www.ecma-international.org/ecma-262/6.0/index.html#sec-statements | |
410 | TreeStatement result = 0; | |
411 | switch (m_token.m_type) { | |
412 | case CONSTTOKEN: | |
413 | result = parseConstDeclaration(context); | |
414 | break; | |
415 | #if ENABLE(ES6_CLASS_SYNTAX) | |
416 | case CLASSTOKEN: | |
417 | result = parseClassDeclaration(context); | |
418 | break; | |
419 | #endif | |
420 | default: | |
421 | // FIXME: This needs to consider 'let' in bug: | |
422 | // https://bugs.webkit.org/show_bug.cgi?id=142944 | |
423 | result = parseStatement(context, directive, directiveLiteralLength); | |
424 | break; | |
425 | } | |
426 | ||
427 | return result; | |
428 | } | |
6fe7ccc8 A |
429 | |
430 | template <typename LexerType> | |
431 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVarDeclaration(TreeBuilder& context) | |
432 | { | |
433 | ASSERT(match(VAR)); | |
93a37866 | 434 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
435 | int start = tokenLine(); |
436 | int end = 0; | |
437 | int scratch; | |
ed1e77d3 | 438 | TreeDestructuringPattern scratch1 = 0; |
6fe7ccc8 | 439 | TreeExpression scratch2 = 0; |
81345200 | 440 | JSTextPosition scratch3; |
ed1e77d3 | 441 | TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3, VarDeclarationContext); |
81345200 A |
442 | propagateError(); |
443 | failIfFalse(autoSemiColon(), "Expected ';' after var declaration"); | |
6fe7ccc8 | 444 | |
93a37866 | 445 | return context.createVarStatement(location, varDecls, start, end); |
6fe7ccc8 A |
446 | } |
447 | ||
448 | template <typename LexerType> | |
449 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseConstDeclaration(TreeBuilder& context) | |
450 | { | |
451 | ASSERT(match(CONSTTOKEN)); | |
93a37866 | 452 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
453 | int start = tokenLine(); |
454 | int end = 0; | |
455 | TreeConstDeclList constDecls = parseConstDeclarationList(context); | |
81345200 A |
456 | propagateError(); |
457 | failIfFalse(autoSemiColon(), "Expected ';' after const declaration"); | |
6fe7ccc8 | 458 | |
93a37866 | 459 | return context.createConstStatement(location, constDecls, start, end); |
6fe7ccc8 A |
460 | } |
461 | ||
462 | template <typename LexerType> | |
463 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDoWhileStatement(TreeBuilder& context) | |
464 | { | |
465 | ASSERT(match(DO)); | |
466 | int startLine = tokenLine(); | |
467 | next(); | |
468 | const Identifier* unused = 0; | |
469 | startLoop(); | |
470 | TreeStatement statement = parseStatement(context, unused); | |
471 | endLoop(); | |
81345200 | 472 | failIfFalse(statement, "Expected a statement following 'do'"); |
6fe7ccc8 | 473 | int endLine = tokenLine(); |
93a37866 | 474 | JSTokenLocation location(tokenLocation()); |
81345200 A |
475 | handleProductionOrFail(WHILE, "while", "end", "do-while loop"); |
476 | handleProductionOrFail(OPENPAREN, "(", "start", "do-while loop condition"); | |
477 | semanticFailIfTrue(match(CLOSEPAREN), "Must provide an expression as a do-while loop condition"); | |
6fe7ccc8 | 478 | TreeExpression expr = parseExpression(context); |
81345200 A |
479 | failIfFalse(expr, "Unable to parse do-while loop condition"); |
480 | handleProductionOrFail(CLOSEPAREN, ")", "end", "do-while loop condition"); | |
6fe7ccc8 A |
481 | if (match(SEMICOLON)) |
482 | next(); // Always performs automatic semicolon insertion. | |
93a37866 | 483 | return context.createDoWhileStatement(location, statement, expr, startLine, endLine); |
6fe7ccc8 A |
484 | } |
485 | ||
486 | template <typename LexerType> | |
487 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWhileStatement(TreeBuilder& context) | |
488 | { | |
489 | ASSERT(match(WHILE)); | |
93a37866 | 490 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
491 | int startLine = tokenLine(); |
492 | next(); | |
81345200 A |
493 | |
494 | handleProductionOrFail(OPENPAREN, "(", "start", "while loop condition"); | |
495 | semanticFailIfTrue(match(CLOSEPAREN), "Must provide an expression as a while loop condition"); | |
6fe7ccc8 | 496 | TreeExpression expr = parseExpression(context); |
81345200 | 497 | failIfFalse(expr, "Unable to parse while loop condition"); |
6fe7ccc8 | 498 | int endLine = tokenLine(); |
81345200 A |
499 | handleProductionOrFail(CLOSEPAREN, ")", "end", "while loop condition"); |
500 | ||
6fe7ccc8 A |
501 | const Identifier* unused = 0; |
502 | startLoop(); | |
503 | TreeStatement statement = parseStatement(context, unused); | |
504 | endLoop(); | |
81345200 | 505 | failIfFalse(statement, "Expected a statement as the body of a while loop"); |
93a37866 | 506 | return context.createWhileStatement(location, expr, statement, startLine, endLine); |
6fe7ccc8 A |
507 | } |
508 | ||
509 | template <typename LexerType> | |
ed1e77d3 | 510 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, TreeDestructuringPattern& lastPattern, TreeExpression& lastInitializer, JSTextPosition& identStart, JSTextPosition& initStart, JSTextPosition& initEnd, VarDeclarationListContext declarationListContext) |
6fe7ccc8 | 511 | { |
ed1e77d3 A |
512 | TreeExpression head = 0; |
513 | TreeExpression tail = 0; | |
81345200 | 514 | const Identifier* lastIdent; |
ed1e77d3 | 515 | JSToken lastIdentToken; |
6fe7ccc8 | 516 | do { |
81345200 | 517 | lastIdent = 0; |
ed1e77d3 | 518 | lastPattern = TreeDestructuringPattern(0); |
93a37866 | 519 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 520 | next(); |
81345200 A |
521 | TreeExpression node = 0; |
522 | declarations++; | |
523 | bool hasInitializer = false; | |
524 | if (match(IDENT)) { | |
525 | JSTextPosition varStart = tokenStartPosition(); | |
ed1e77d3 | 526 | JSTokenLocation varStartLocation(tokenLocation()); |
81345200 A |
527 | identStart = varStart; |
528 | const Identifier* name = m_token.m_data.ident; | |
529 | lastIdent = name; | |
ed1e77d3 | 530 | lastIdentToken = m_token; |
81345200 A |
531 | next(); |
532 | hasInitializer = match(EQUAL); | |
533 | failIfFalseIfStrict(declareVariable(name), "Cannot declare a variable named ", name->impl(), " in strict mode"); | |
534 | context.addVar(name, (hasInitializer || (!m_allowsIn && (match(INTOKEN) || isofToken()))) ? DeclarationStacks::HasInitializer : 0); | |
535 | if (hasInitializer) { | |
536 | JSTextPosition varDivot = tokenStartPosition() + 1; | |
537 | initStart = tokenStartPosition(); | |
538 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
539 | TreeExpression initializer = parseAssignmentExpression(context); | |
540 | initEnd = lastTokenEndPosition(); | |
541 | lastInitializer = initializer; | |
542 | failIfFalse(initializer, "Expected expression as the intializer for the variable '", name->impl(), "'"); | |
543 | ||
544 | node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEndPosition()); | |
ed1e77d3 A |
545 | } else |
546 | node = context.createEmptyVarExpression(varStartLocation, *name); | |
81345200 A |
547 | } else { |
548 | lastIdent = 0; | |
ed1e77d3 A |
549 | auto pattern = parseDestructuringPattern(context, DestructureToVariables); |
550 | failIfFalse(pattern, "Cannot parse this destructuring pattern"); | |
81345200 | 551 | hasInitializer = match(EQUAL); |
ed1e77d3 | 552 | failIfTrue(declarationListContext == VarDeclarationContext && !hasInitializer, "Expected an initializer in destructuring variable declaration"); |
81345200 A |
553 | lastPattern = pattern; |
554 | if (hasInitializer) { | |
555 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
ed1e77d3 A |
556 | TreeExpression rhs = parseAssignmentExpression(context); |
557 | node = context.createDestructuringAssignment(location, pattern, rhs); | |
81345200 A |
558 | lastInitializer = rhs; |
559 | } | |
560 | } | |
6fe7ccc8 | 561 | |
ed1e77d3 A |
562 | if (!head) |
563 | head = node; | |
564 | else if (!tail) { | |
565 | head = context.createCommaExpr(location, head); | |
566 | tail = context.appendToCommaExpr(location, head, head, node); | |
567 | } else | |
568 | tail = context.appendToCommaExpr(location, head, tail, node); | |
6fe7ccc8 | 569 | } while (match(COMMA)); |
81345200 | 570 | if (lastIdent) |
ed1e77d3 A |
571 | lastPattern = createBindingPattern(context, DestructureToVariables, *lastIdent, 0, lastIdentToken); |
572 | return head; | |
6fe7ccc8 A |
573 | } |
574 | ||
81345200 | 575 | template <typename LexerType> |
ed1e77d3 | 576 | template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::createBindingPattern(TreeBuilder& context, DestructuringKind kind, const Identifier& name, int depth, JSToken token) |
81345200 | 577 | { |
81345200 A |
578 | ASSERT(!name.isNull()); |
579 | ||
ed1e77d3 | 580 | ASSERT(name.impl()->isAtomic() || name.impl()->isSymbol()); |
81345200 | 581 | if (depth) { |
ed1e77d3 A |
582 | if (kind == DestructureToVariables) |
583 | failIfFalseIfStrict(declareVariable(&name), "Cannot destructure to a variable named '", name.impl(), "' in strict mode"); | |
584 | if (kind == DestructureToParameters) { | |
81345200 A |
585 | auto bindingResult = declareBoundParameter(&name); |
586 | if (bindingResult == Scope::StrictBindingFailed && strictMode()) { | |
ed1e77d3 | 587 | semanticFailIfTrue(m_vm->propertyNames->arguments == name || m_vm->propertyNames->eval == name, "Cannot destructure to a parameter name '", name.impl(), "' in strict mode"); |
81345200 | 588 | if (m_lastFunctionName && name == *m_lastFunctionName) |
ed1e77d3 | 589 | semanticFail("Cannot destructure to '", name.impl(), "' as it shadows the name of a strict mode function"); |
81345200 A |
590 | semanticFailureDueToKeyword("bound parameter name"); |
591 | if (hasDeclaredParameter(name)) | |
ed1e77d3 | 592 | semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared"); |
81345200 A |
593 | semanticFail("Cannot bind to a parameter named '", name.impl(), "' in strict mode"); |
594 | } | |
595 | if (bindingResult == Scope::BindingFailed) { | |
596 | semanticFailureDueToKeyword("bound parameter name"); | |
597 | if (hasDeclaredParameter(name)) | |
ed1e77d3 A |
598 | semanticFail("Cannot destructure to '", name.impl(), "' as it has already been declared"); |
599 | semanticFail("Cannot destructure to a parameter named '", name.impl(), "'"); | |
81345200 A |
600 | } |
601 | } | |
ed1e77d3 | 602 | if (kind != DestructureToExpressions) |
81345200 A |
603 | context.addVar(&name, DeclarationStacks::HasInitializer); |
604 | ||
605 | } else { | |
ed1e77d3 | 606 | if (kind == DestructureToVariables) { |
81345200 A |
607 | failIfFalseIfStrict(declareVariable(&name), "Cannot declare a variable named '", name.impl(), "' in strict mode"); |
608 | context.addVar(&name, DeclarationStacks::HasInitializer); | |
609 | } | |
610 | ||
ed1e77d3 | 611 | if (kind == DestructureToParameters) { |
81345200 A |
612 | bool declarationResult = declareParameter(&name); |
613 | if (!declarationResult && strictMode()) { | |
ed1e77d3 | 614 | semanticFailIfTrue(m_vm->propertyNames->arguments == name || m_vm->propertyNames->eval == name, "Cannot destructure to a parameter name '", name.impl(), "' in strict mode"); |
81345200 A |
615 | if (m_lastFunctionName && name == *m_lastFunctionName) |
616 | semanticFail("Cannot declare a parameter named '", name.impl(), "' as it shadows the name of a strict mode function"); | |
617 | semanticFailureDueToKeyword("parameter name"); | |
618 | if (hasDeclaredParameter(name)) | |
619 | semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode as it has already been declared"); | |
620 | semanticFail("Cannot declare a parameter named '", name.impl(), "' in strict mode"); | |
621 | } | |
622 | } | |
623 | } | |
ed1e77d3 | 624 | return context.createBindingLocation(token.m_location, name, token.m_startPosition, token.m_endPosition); |
81345200 A |
625 | } |
626 | ||
ed1e77d3 | 627 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) |
81345200 | 628 | template <typename LexerType> |
ed1e77d3 | 629 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseArrowFunctionSingleExpressionBody(TreeBuilder& context, FunctionParseType parseType) |
81345200 | 630 | { |
ed1e77d3 A |
631 | ASSERT(match(ARROWFUNCTION)); |
632 | ||
633 | // When reparsing phase, parseType becomes StandardFunctionParseType even if the function is arrow function. | |
634 | // This condition considers the following situations. | |
635 | // (1): If we are in the reparsing phase, this arrow function is already parsed once, so there is no syntax error. | |
636 | // (2): But if we are not in the reparsing phase, we should check this function is called in the context of the arrow function. | |
637 | if (!m_lexer->isReparsing() && parseType != ArrowFunctionParseType) | |
638 | failDueToUnexpectedToken(); | |
639 | ||
640 | JSTokenLocation location(tokenLocation()); | |
641 | JSTextPosition start = tokenStartPosition(); | |
642 | JSTextPosition end = tokenEndPosition(); | |
643 | ||
644 | next(); | |
645 | ||
646 | failIfStackOverflow(); | |
647 | TreeExpression expr = parseAssignmentExpression(context); | |
648 | failIfFalse(expr, "Cannot parse the arrow function expression"); | |
649 | ||
650 | context.setEndOffset(expr, m_lastTokenEndPosition.offset); | |
651 | ||
652 | failIfFalse(isEndOfArrowFunction(), "Expected a ';', ']', '}', ')', ',', line terminator or EOF following a arrow function statement"); | |
653 | ||
654 | end = tokenEndPosition(); | |
655 | ||
656 | if (!m_lexer->prevTerminator()) | |
657 | setEndOfStatement(); | |
658 | ||
659 | return context.createReturnStatement(location, expr, start, end); | |
660 | } | |
661 | #endif | |
662 | ||
663 | template <typename LexerType> | |
664 | template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::tryParseDestructuringPatternExpression(TreeBuilder& context) | |
665 | { | |
666 | return parseDestructuringPattern(context, DestructureToExpressions); | |
81345200 A |
667 | } |
668 | ||
669 | template <typename LexerType> | |
ed1e77d3 | 670 | template <class TreeBuilder> TreeDestructuringPattern Parser<LexerType>::parseDestructuringPattern(TreeBuilder& context, DestructuringKind kind, int depth) |
81345200 A |
671 | { |
672 | failIfStackOverflow(); | |
673 | int nonLHSCount = m_nonLHSCount; | |
ed1e77d3 | 674 | TreeDestructuringPattern pattern; |
81345200 A |
675 | switch (m_token.m_type) { |
676 | case OPENBRACKET: { | |
ed1e77d3 | 677 | JSTextPosition divotStart = tokenStartPosition(); |
81345200 A |
678 | auto arrayPattern = context.createArrayPattern(m_token.m_location); |
679 | next(); | |
ed1e77d3 A |
680 | |
681 | bool restElementWasFound = false; | |
682 | ||
81345200 A |
683 | do { |
684 | while (match(COMMA)) { | |
685 | context.appendArrayPatternSkipEntry(arrayPattern, m_token.m_location); | |
686 | next(); | |
687 | } | |
688 | propagateError(); | |
ed1e77d3 A |
689 | |
690 | if (match(CLOSEBRACKET)) | |
691 | break; | |
692 | ||
693 | if (UNLIKELY(match(DOTDOTDOT))) { | |
694 | JSTokenLocation location = m_token.m_location; | |
695 | next(); | |
696 | auto innerPattern = parseDestructuringPattern(context, kind, depth + 1); | |
697 | if (kind == DestructureToExpressions && !innerPattern) | |
698 | return 0; | |
699 | failIfFalse(innerPattern, "Cannot parse this destructuring pattern"); | |
700 | ||
701 | failIfTrue(kind != DestructureToExpressions && !context.isBindingNode(innerPattern), "Expected identifier for a rest element destructuring pattern"); | |
702 | ||
703 | context.appendArrayPatternRestEntry(arrayPattern, location, innerPattern); | |
704 | restElementWasFound = true; | |
705 | break; | |
706 | } | |
707 | ||
81345200 | 708 | JSTokenLocation location = m_token.m_location; |
ed1e77d3 A |
709 | auto innerPattern = parseDestructuringPattern(context, kind, depth + 1); |
710 | if (kind == DestructureToExpressions && !innerPattern) | |
81345200 | 711 | return 0; |
ed1e77d3 A |
712 | failIfFalse(innerPattern, "Cannot parse this destructuring pattern"); |
713 | TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context); | |
714 | failIfTrue(kind == DestructureToParameters && defaultValue, "Default values in destructuring parameters are currently not supported"); | |
715 | context.appendArrayPatternEntry(arrayPattern, location, innerPattern, defaultValue); | |
81345200 | 716 | } while (consume(COMMA)); |
81345200 | 717 | |
ed1e77d3 A |
718 | if (kind == DestructureToExpressions && !match(CLOSEBRACKET)) |
719 | return 0; | |
720 | consumeOrFail(CLOSEBRACKET, restElementWasFound ? "Expected a closing ']' following a rest element destructuring pattern" : "Expected either a closing ']' or a ',' following an element destructuring pattern"); | |
721 | context.finishArrayPattern(arrayPattern, divotStart, divotStart, lastTokenEndPosition()); | |
81345200 A |
722 | pattern = arrayPattern; |
723 | break; | |
724 | } | |
725 | case OPENBRACE: { | |
ed1e77d3 | 726 | auto objectPattern = context.createObjectPattern(m_token.m_location); |
81345200 | 727 | next(); |
81345200 | 728 | |
81345200 | 729 | do { |
ed1e77d3 A |
730 | bool wasString = false; |
731 | ||
732 | if (match(CLOSEBRACE)) | |
733 | break; | |
734 | ||
81345200 | 735 | Identifier propertyName; |
ed1e77d3 | 736 | TreeDestructuringPattern innerPattern = 0; |
81345200 A |
737 | JSTokenLocation location = m_token.m_location; |
738 | if (match(IDENT)) { | |
739 | propertyName = *m_token.m_data.ident; | |
ed1e77d3 | 740 | JSToken identifierToken = m_token; |
81345200 A |
741 | next(); |
742 | if (consume(COLON)) | |
ed1e77d3 | 743 | innerPattern = parseDestructuringPattern(context, kind, depth + 1); |
81345200 | 744 | else |
ed1e77d3 | 745 | innerPattern = createBindingPattern(context, kind, propertyName, depth, identifierToken); |
81345200 A |
746 | } else { |
747 | JSTokenType tokenType = m_token.m_type; | |
748 | switch (m_token.m_type) { | |
ed1e77d3 A |
749 | case DOUBLE: |
750 | case INTEGER: | |
81345200 A |
751 | propertyName = Identifier::from(m_vm, m_token.m_data.doubleValue); |
752 | break; | |
753 | case STRING: | |
754 | propertyName = *m_token.m_data.ident; | |
755 | wasString = true; | |
756 | break; | |
757 | default: | |
758 | if (m_token.m_type != RESERVED && m_token.m_type != RESERVED_IF_STRICT && !(m_token.m_type & KeywordTokenFlag)) { | |
ed1e77d3 | 759 | if (kind == DestructureToExpressions) |
81345200 A |
760 | return 0; |
761 | failWithMessage("Expected a property name"); | |
762 | } | |
763 | propertyName = *m_token.m_data.ident; | |
764 | break; | |
765 | } | |
766 | next(); | |
767 | if (!consume(COLON)) { | |
ed1e77d3 | 768 | if (kind == DestructureToExpressions) |
81345200 | 769 | return 0; |
ed1e77d3 A |
770 | semanticFailIfTrue(tokenType == RESERVED, "Cannot use abbreviated destructuring syntax for reserved name '", propertyName.impl(), "'"); |
771 | semanticFailIfTrue(tokenType == RESERVED_IF_STRICT, "Cannot use abbreviated destructuring syntax for reserved name '", propertyName.impl(), "' in strict mode"); | |
772 | semanticFailIfTrue(tokenType & KeywordTokenFlag, "Cannot use abbreviated destructuring syntax for keyword '", propertyName.impl(), "'"); | |
81345200 | 773 | |
ed1e77d3 | 774 | failWithMessage("Expected a ':' prior to a named destructuring property"); |
81345200 | 775 | } |
ed1e77d3 | 776 | innerPattern = parseDestructuringPattern(context, kind, depth + 1); |
81345200 | 777 | } |
ed1e77d3 | 778 | if (kind == DestructureToExpressions && !innerPattern) |
81345200 | 779 | return 0; |
ed1e77d3 A |
780 | failIfFalse(innerPattern, "Cannot parse this destructuring pattern"); |
781 | TreeExpression defaultValue = parseDefaultValueForDestructuringPattern(context); | |
782 | failIfTrue(kind == DestructureToParameters && defaultValue, "Default values in destructuring parameters are currently not supported"); | |
783 | context.appendObjectPatternEntry(objectPattern, location, wasString, propertyName, innerPattern, defaultValue); | |
81345200 | 784 | } while (consume(COMMA)); |
ed1e77d3 A |
785 | |
786 | if (kind == DestructureToExpressions && !match(CLOSEBRACE)) | |
81345200 | 787 | return 0; |
ed1e77d3 | 788 | consumeOrFail(CLOSEBRACE, "Expected either a closing '}' or an ',' after a property destructuring pattern"); |
81345200 A |
789 | pattern = objectPattern; |
790 | break; | |
791 | } | |
792 | ||
793 | default: { | |
794 | if (!match(IDENT)) { | |
ed1e77d3 | 795 | if (kind == DestructureToExpressions) |
81345200 A |
796 | return 0; |
797 | semanticFailureDueToKeyword("variable name"); | |
798 | failWithMessage("Expected a parameter pattern or a ')' in parameter list"); | |
799 | } | |
ed1e77d3 | 800 | pattern = createBindingPattern(context, kind, *m_token.m_data.ident, depth, m_token); |
81345200 A |
801 | next(); |
802 | break; | |
803 | } | |
804 | } | |
805 | m_nonLHSCount = nonLHSCount; | |
806 | return pattern; | |
807 | } | |
808 | ||
ed1e77d3 A |
809 | template <typename LexerType> |
810 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseDefaultValueForDestructuringPattern(TreeBuilder& context) | |
811 | { | |
812 | if (!match(EQUAL)) | |
813 | return 0; | |
814 | ||
815 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
816 | return parseAssignmentExpression(context); | |
817 | } | |
818 | ||
6fe7ccc8 A |
819 | template <typename LexerType> |
820 | template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context) | |
821 | { | |
81345200 | 822 | failIfTrue(strictMode(), "Const declarations are not supported in strict mode"); |
6fe7ccc8 A |
823 | TreeConstDeclList constDecls = 0; |
824 | TreeConstDeclList tail = 0; | |
825 | do { | |
93a37866 | 826 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 827 | next(); |
81345200 | 828 | matchOrFail(IDENT, "Expected an identifier name in const declaration"); |
6fe7ccc8 A |
829 | const Identifier* name = m_token.m_data.ident; |
830 | next(); | |
831 | bool hasInitializer = match(EQUAL); | |
832 | declareVariable(name); | |
833 | context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0)); | |
93a37866 | 834 | |
6fe7ccc8 A |
835 | TreeExpression initializer = 0; |
836 | if (hasInitializer) { | |
837 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
838 | initializer = parseAssignmentExpression(context); | |
81345200 | 839 | failIfFalse(!!initializer, "Unable to parse initializer"); |
6fe7ccc8 | 840 | } |
93a37866 | 841 | tail = context.appendConstDecl(location, tail, name, initializer); |
6fe7ccc8 A |
842 | if (!constDecls) |
843 | constDecls = tail; | |
844 | } while (match(COMMA)); | |
845 | return constDecls; | |
846 | } | |
847 | ||
848 | template <typename LexerType> | |
849 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(TreeBuilder& context) | |
850 | { | |
851 | ASSERT(match(FOR)); | |
93a37866 | 852 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
853 | int startLine = tokenLine(); |
854 | next(); | |
81345200 | 855 | handleProductionOrFail(OPENPAREN, "(", "start", "for-loop header"); |
6fe7ccc8 A |
856 | int nonLHSCount = m_nonLHSCount; |
857 | int declarations = 0; | |
81345200 A |
858 | JSTextPosition declsStart; |
859 | JSTextPosition declsEnd; | |
6fe7ccc8 | 860 | TreeExpression decls = 0; |
ed1e77d3 | 861 | TreeDestructuringPattern pattern = 0; |
6fe7ccc8 A |
862 | if (match(VAR)) { |
863 | /* | |
864 | for (var IDENT in expression) statement | |
6fe7ccc8 A |
865 | for (var varDeclarationList; expressionOpt; expressionOpt) |
866 | */ | |
ed1e77d3 | 867 | TreeDestructuringPattern forInTarget = 0; |
6fe7ccc8 A |
868 | TreeExpression forInInitializer = 0; |
869 | m_allowsIn = false; | |
81345200 A |
870 | JSTextPosition initStart; |
871 | JSTextPosition initEnd; | |
ed1e77d3 | 872 | decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd, ForLoopContext); |
6fe7ccc8 | 873 | m_allowsIn = true; |
81345200 | 874 | propagateError(); |
93a37866 | 875 | |
6fe7ccc8 A |
876 | // Remainder of a standard for loop is handled identically |
877 | if (match(SEMICOLON)) | |
878 | goto standardForLoop; | |
879 | ||
81345200 A |
880 | failIfFalse(declarations == 1, "can only declare a single variable in an enumeration"); |
881 | failIfTrueIfStrict(forInInitializer, "Cannot use initialiser syntax in a strict mode enumeration"); | |
882 | ||
883 | if (forInInitializer) | |
884 | failIfFalse(context.isBindingNode(forInTarget), "Cannot use initialiser syntax when binding to a pattern during enumeration"); | |
885 | ||
6fe7ccc8 | 886 | // Handle for-in with var declaration |
81345200 A |
887 | JSTextPosition inLocation = tokenStartPosition(); |
888 | bool isOfEnumeration = false; | |
889 | if (!consume(INTOKEN)) { | |
890 | failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax"); | |
891 | isOfEnumeration = true; | |
892 | failIfTrue(forInInitializer, "Cannot use initialiser syntax in a for-of enumeration"); | |
893 | next(); | |
894 | } | |
6fe7ccc8 | 895 | TreeExpression expr = parseExpression(context); |
81345200 A |
896 | failIfFalse(expr, "Expected expression to enumerate"); |
897 | JSTextPosition exprEnd = lastTokenEndPosition(); | |
6fe7ccc8 A |
898 | |
899 | int endLine = tokenLine(); | |
81345200 A |
900 | |
901 | handleProductionOrFail(CLOSEPAREN, ")", "end", (isOfEnumeration ? "for-of header" : "for-in header")); | |
6fe7ccc8 A |
902 | |
903 | const Identifier* unused = 0; | |
904 | startLoop(); | |
905 | TreeStatement statement = parseStatement(context, unused); | |
906 | endLoop(); | |
81345200 A |
907 | failIfFalse(statement, "Expected statement as body of for-", isOfEnumeration ? "of" : "in", " statement"); |
908 | if (isOfEnumeration) | |
909 | return context.createForOfLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine); | |
910 | return context.createForInLoop(location, forInTarget, expr, statement, declsStart, inLocation, exprEnd, startLine, endLine); | |
6fe7ccc8 A |
911 | } |
912 | ||
913 | if (!match(SEMICOLON)) { | |
81345200 A |
914 | if (match(OPENBRACE) || match(OPENBRACKET)) { |
915 | SavePoint savePoint = createSavePoint(); | |
916 | declsStart = tokenStartPosition(); | |
ed1e77d3 | 917 | pattern = tryParseDestructuringPatternExpression(context); |
81345200 A |
918 | declsEnd = lastTokenEndPosition(); |
919 | if (pattern && (match(INTOKEN) || (match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of))) | |
920 | goto enumerationLoop; | |
ed1e77d3 | 921 | pattern = TreeDestructuringPattern(0); |
81345200 A |
922 | restoreSavePoint(savePoint); |
923 | } | |
6fe7ccc8 | 924 | m_allowsIn = false; |
81345200 | 925 | declsStart = tokenStartPosition(); |
6fe7ccc8 | 926 | decls = parseExpression(context); |
81345200 | 927 | declsEnd = lastTokenEndPosition(); |
6fe7ccc8 | 928 | m_allowsIn = true; |
81345200 | 929 | failIfFalse(decls, "Cannot parse for loop declarations"); |
6fe7ccc8 A |
930 | } |
931 | ||
932 | if (match(SEMICOLON)) { | |
933 | standardForLoop: | |
934 | // Standard for loop | |
935 | next(); | |
936 | TreeExpression condition = 0; | |
937 | ||
938 | if (!match(SEMICOLON)) { | |
939 | condition = parseExpression(context); | |
81345200 | 940 | failIfFalse(condition, "Cannot parse for loop condition expression"); |
6fe7ccc8 | 941 | } |
81345200 | 942 | consumeOrFail(SEMICOLON, "Expected a ';' after the for loop condition expression"); |
6fe7ccc8 A |
943 | |
944 | TreeExpression increment = 0; | |
945 | if (!match(CLOSEPAREN)) { | |
946 | increment = parseExpression(context); | |
81345200 | 947 | failIfFalse(increment, "Cannot parse for loop iteration expression"); |
6fe7ccc8 A |
948 | } |
949 | int endLine = tokenLine(); | |
81345200 | 950 | handleProductionOrFail(CLOSEPAREN, ")", "end", "for-loop header"); |
6fe7ccc8 A |
951 | const Identifier* unused = 0; |
952 | startLoop(); | |
953 | TreeStatement statement = parseStatement(context, unused); | |
954 | endLoop(); | |
81345200 | 955 | failIfFalse(statement, "Expected a statement as the body of a for loop"); |
93a37866 | 956 | return context.createForLoop(location, decls, condition, increment, statement, startLine, endLine); |
6fe7ccc8 A |
957 | } |
958 | ||
959 | // For-in loop | |
81345200 A |
960 | enumerationLoop: |
961 | failIfFalse(nonLHSCount == m_nonLHSCount, "Expected a reference on the left hand side of an enumeration statement"); | |
962 | bool isOfEnumeration = false; | |
963 | if (!consume(INTOKEN)) { | |
964 | failIfFalse(match(IDENT) && *m_token.m_data.ident == m_vm->propertyNames->of, "Expected either 'in' or 'of' in enumeration syntax"); | |
965 | isOfEnumeration = true; | |
966 | next(); | |
967 | } | |
6fe7ccc8 | 968 | TreeExpression expr = parseExpression(context); |
81345200 A |
969 | failIfFalse(expr, "Cannot parse subject for-", isOfEnumeration ? "of" : "in", " statement"); |
970 | JSTextPosition exprEnd = lastTokenEndPosition(); | |
6fe7ccc8 | 971 | int endLine = tokenLine(); |
81345200 A |
972 | |
973 | handleProductionOrFail(CLOSEPAREN, ")", "end", (isOfEnumeration ? "for-of header" : "for-in header")); | |
6fe7ccc8 A |
974 | const Identifier* unused = 0; |
975 | startLoop(); | |
976 | TreeStatement statement = parseStatement(context, unused); | |
977 | endLoop(); | |
81345200 A |
978 | failIfFalse(statement, "Expected a statement as the body of a for-", isOfEnumeration ? "of" : "in", "loop"); |
979 | if (pattern) { | |
980 | ASSERT(!decls); | |
981 | if (isOfEnumeration) | |
982 | return context.createForOfLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine); | |
983 | return context.createForInLoop(location, pattern, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine); | |
984 | } | |
985 | if (isOfEnumeration) | |
986 | return context.createForOfLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine); | |
987 | return context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine); | |
6fe7ccc8 A |
988 | } |
989 | ||
990 | template <typename LexerType> | |
991 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBreakStatement(TreeBuilder& context) | |
992 | { | |
993 | ASSERT(match(BREAK)); | |
93a37866 | 994 | JSTokenLocation location(tokenLocation()); |
81345200 A |
995 | JSTextPosition start = tokenStartPosition(); |
996 | JSTextPosition end = tokenEndPosition(); | |
6fe7ccc8 A |
997 | next(); |
998 | ||
999 | if (autoSemiColon()) { | |
81345200 | 1000 | semanticFailIfFalse(breakIsValid(), "'break' is only valid inside a switch or loop statement"); |
ed1e77d3 | 1001 | return context.createBreakStatement(location, &m_vm->propertyNames->nullIdentifier, start, end); |
6fe7ccc8 | 1002 | } |
81345200 | 1003 | matchOrFail(IDENT, "Expected an identifier as the target for a break statement"); |
6fe7ccc8 | 1004 | const Identifier* ident = m_token.m_data.ident; |
81345200 A |
1005 | semanticFailIfFalse(getLabel(ident), "Cannot use the undeclared label '", ident->impl(), "'"); |
1006 | end = tokenEndPosition(); | |
6fe7ccc8 | 1007 | next(); |
81345200 A |
1008 | failIfFalse(autoSemiColon(), "Expected a ';' following a targeted break statement"); |
1009 | return context.createBreakStatement(location, ident, start, end); | |
6fe7ccc8 A |
1010 | } |
1011 | ||
1012 | template <typename LexerType> | |
1013 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseContinueStatement(TreeBuilder& context) | |
1014 | { | |
1015 | ASSERT(match(CONTINUE)); | |
93a37866 | 1016 | JSTokenLocation location(tokenLocation()); |
81345200 A |
1017 | JSTextPosition start = tokenStartPosition(); |
1018 | JSTextPosition end = tokenEndPosition(); | |
6fe7ccc8 A |
1019 | next(); |
1020 | ||
1021 | if (autoSemiColon()) { | |
81345200 | 1022 | semanticFailIfFalse(continueIsValid(), "'continue' is only valid inside a loop statement"); |
ed1e77d3 | 1023 | return context.createContinueStatement(location, &m_vm->propertyNames->nullIdentifier, start, end); |
6fe7ccc8 | 1024 | } |
81345200 | 1025 | matchOrFail(IDENT, "Expected an identifier as the target for a continue statement"); |
6fe7ccc8 A |
1026 | const Identifier* ident = m_token.m_data.ident; |
1027 | ScopeLabelInfo* label = getLabel(ident); | |
81345200 | 1028 | semanticFailIfFalse(label, "Cannot use the undeclared label '", ident->impl(), "'"); |
ed1e77d3 | 1029 | semanticFailIfFalse(label->isLoop, "Cannot continue to the label '", ident->impl(), "' as it is not targeting a loop"); |
81345200 | 1030 | end = tokenEndPosition(); |
6fe7ccc8 | 1031 | next(); |
81345200 A |
1032 | failIfFalse(autoSemiColon(), "Expected a ';' following a targeted continue statement"); |
1033 | return context.createContinueStatement(location, ident, start, end); | |
6fe7ccc8 A |
1034 | } |
1035 | ||
1036 | template <typename LexerType> | |
1037 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseReturnStatement(TreeBuilder& context) | |
1038 | { | |
1039 | ASSERT(match(RETURN)); | |
93a37866 | 1040 | JSTokenLocation location(tokenLocation()); |
81345200 A |
1041 | semanticFailIfFalse(currentScope()->isFunction(), "Return statements are only valid inside functions"); |
1042 | JSTextPosition start = tokenStartPosition(); | |
1043 | JSTextPosition end = tokenEndPosition(); | |
6fe7ccc8 | 1044 | next(); |
81345200 | 1045 | // We do the auto semicolon check before attempting to parse expression |
6fe7ccc8 A |
1046 | // as we need to ensure the a line break after the return correctly terminates |
1047 | // the statement | |
1048 | if (match(SEMICOLON)) | |
81345200 A |
1049 | end = tokenEndPosition(); |
1050 | ||
6fe7ccc8 | 1051 | if (autoSemiColon()) |
81345200 | 1052 | return context.createReturnStatement(location, 0, start, end); |
6fe7ccc8 | 1053 | TreeExpression expr = parseExpression(context); |
81345200 A |
1054 | failIfFalse(expr, "Cannot parse the return expression"); |
1055 | end = lastTokenEndPosition(); | |
6fe7ccc8 | 1056 | if (match(SEMICOLON)) |
81345200 A |
1057 | end = tokenEndPosition(); |
1058 | if (!autoSemiColon()) | |
1059 | failWithMessage("Expected a ';' following a return statement"); | |
1060 | return context.createReturnStatement(location, expr, start, end); | |
6fe7ccc8 A |
1061 | } |
1062 | ||
1063 | template <typename LexerType> | |
1064 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseThrowStatement(TreeBuilder& context) | |
1065 | { | |
1066 | ASSERT(match(THROW)); | |
93a37866 | 1067 | JSTokenLocation location(tokenLocation()); |
81345200 | 1068 | JSTextPosition start = tokenStartPosition(); |
6fe7ccc8 | 1069 | next(); |
81345200 A |
1070 | failIfTrue(match(SEMICOLON), "Expected expression after 'throw'"); |
1071 | semanticFailIfTrue(autoSemiColon(), "Cannot have a newline after 'throw'"); | |
6fe7ccc8 A |
1072 | |
1073 | TreeExpression expr = parseExpression(context); | |
81345200 A |
1074 | failIfFalse(expr, "Cannot parse expression for throw statement"); |
1075 | JSTextPosition end = lastTokenEndPosition(); | |
1076 | failIfFalse(autoSemiColon(), "Expected a ';' after a throw statement"); | |
6fe7ccc8 | 1077 | |
81345200 | 1078 | return context.createThrowStatement(location, expr, start, end); |
6fe7ccc8 A |
1079 | } |
1080 | ||
1081 | template <typename LexerType> | |
1082 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWithStatement(TreeBuilder& context) | |
1083 | { | |
1084 | ASSERT(match(WITH)); | |
93a37866 | 1085 | JSTokenLocation location(tokenLocation()); |
81345200 | 1086 | semanticFailIfTrue(strictMode(), "'with' statements are not valid in strict mode"); |
6fe7ccc8 A |
1087 | currentScope()->setNeedsFullActivation(); |
1088 | int startLine = tokenLine(); | |
1089 | next(); | |
81345200 A |
1090 | |
1091 | handleProductionOrFail(OPENPAREN, "(", "start", "subject of a 'with' statement"); | |
6fe7ccc8 A |
1092 | int start = tokenStart(); |
1093 | TreeExpression expr = parseExpression(context); | |
81345200 A |
1094 | failIfFalse(expr, "Cannot parse 'with' subject expression"); |
1095 | JSTextPosition end = lastTokenEndPosition(); | |
6fe7ccc8 | 1096 | int endLine = tokenLine(); |
81345200 | 1097 | handleProductionOrFail(CLOSEPAREN, ")", "start", "subject of a 'with' statement"); |
6fe7ccc8 A |
1098 | const Identifier* unused = 0; |
1099 | TreeStatement statement = parseStatement(context, unused); | |
81345200 | 1100 | failIfFalse(statement, "A 'with' statement must have a body"); |
6fe7ccc8 | 1101 | |
81345200 | 1102 | return context.createWithStatement(location, expr, statement, start, end, startLine, endLine); |
6fe7ccc8 A |
1103 | } |
1104 | ||
1105 | template <typename LexerType> | |
1106 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseSwitchStatement(TreeBuilder& context) | |
1107 | { | |
1108 | ASSERT(match(SWITCH)); | |
93a37866 | 1109 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1110 | int startLine = tokenLine(); |
1111 | next(); | |
81345200 | 1112 | handleProductionOrFail(OPENPAREN, "(", "start", "subject of a 'switch'"); |
6fe7ccc8 | 1113 | TreeExpression expr = parseExpression(context); |
81345200 | 1114 | failIfFalse(expr, "Cannot parse switch subject expression"); |
6fe7ccc8 | 1115 | int endLine = tokenLine(); |
81345200 A |
1116 | |
1117 | handleProductionOrFail(CLOSEPAREN, ")", "end", "subject of a 'switch'"); | |
1118 | handleProductionOrFail(OPENBRACE, "{", "start", "body of a 'switch'"); | |
6fe7ccc8 A |
1119 | startSwitch(); |
1120 | TreeClauseList firstClauses = parseSwitchClauses(context); | |
81345200 | 1121 | propagateError(); |
6fe7ccc8 A |
1122 | |
1123 | TreeClause defaultClause = parseSwitchDefaultClause(context); | |
81345200 | 1124 | propagateError(); |
6fe7ccc8 A |
1125 | |
1126 | TreeClauseList secondClauses = parseSwitchClauses(context); | |
81345200 | 1127 | propagateError(); |
6fe7ccc8 | 1128 | endSwitch(); |
81345200 | 1129 | handleProductionOrFail(CLOSEBRACE, "}", "end", "body of a 'switch'"); |
6fe7ccc8 | 1130 | |
93a37866 | 1131 | return context.createSwitchStatement(location, expr, firstClauses, defaultClause, secondClauses, startLine, endLine); |
6fe7ccc8 A |
1132 | |
1133 | } | |
1134 | ||
1135 | template <typename LexerType> | |
1136 | template <class TreeBuilder> TreeClauseList Parser<LexerType>::parseSwitchClauses(TreeBuilder& context) | |
1137 | { | |
1138 | if (!match(CASE)) | |
1139 | return 0; | |
ed1e77d3 | 1140 | unsigned startOffset = tokenStart(); |
6fe7ccc8 A |
1141 | next(); |
1142 | TreeExpression condition = parseExpression(context); | |
81345200 A |
1143 | failIfFalse(condition, "Cannot parse switch clause"); |
1144 | consumeOrFail(COLON, "Expected a ':' after switch clause expression"); | |
ed1e77d3 | 1145 | TreeSourceElements statements = parseSourceElements(context, DontCheckForStrictMode, StandardFunctionParseType); |
81345200 | 1146 | failIfFalse(statements, "Cannot parse the body of a switch clause"); |
6fe7ccc8 | 1147 | TreeClause clause = context.createClause(condition, statements); |
ed1e77d3 | 1148 | context.setStartOffset(clause, startOffset); |
6fe7ccc8 A |
1149 | TreeClauseList clauseList = context.createClauseList(clause); |
1150 | TreeClauseList tail = clauseList; | |
1151 | ||
1152 | while (match(CASE)) { | |
ed1e77d3 | 1153 | startOffset = tokenStart(); |
6fe7ccc8 A |
1154 | next(); |
1155 | TreeExpression condition = parseExpression(context); | |
81345200 A |
1156 | failIfFalse(condition, "Cannot parse switch case expression"); |
1157 | consumeOrFail(COLON, "Expected a ':' after switch clause expression"); | |
ed1e77d3 | 1158 | TreeSourceElements statements = parseSourceElements(context, DontCheckForStrictMode, StandardFunctionParseType); |
81345200 | 1159 | failIfFalse(statements, "Cannot parse the body of a switch clause"); |
6fe7ccc8 | 1160 | clause = context.createClause(condition, statements); |
ed1e77d3 | 1161 | context.setStartOffset(clause, startOffset); |
6fe7ccc8 A |
1162 | tail = context.createClauseList(tail, clause); |
1163 | } | |
1164 | return clauseList; | |
1165 | } | |
1166 | ||
1167 | template <typename LexerType> | |
1168 | template <class TreeBuilder> TreeClause Parser<LexerType>::parseSwitchDefaultClause(TreeBuilder& context) | |
1169 | { | |
1170 | if (!match(DEFAULT)) | |
1171 | return 0; | |
ed1e77d3 | 1172 | unsigned startOffset = tokenStart(); |
6fe7ccc8 | 1173 | next(); |
81345200 | 1174 | consumeOrFail(COLON, "Expected a ':' after switch default clause"); |
ed1e77d3 | 1175 | TreeSourceElements statements = parseSourceElements(context, DontCheckForStrictMode, StandardFunctionParseType); |
81345200 | 1176 | failIfFalse(statements, "Cannot parse the body of a switch default clause"); |
ed1e77d3 A |
1177 | TreeClause result = context.createClause(0, statements); |
1178 | context.setStartOffset(result, startOffset); | |
1179 | return result; | |
6fe7ccc8 A |
1180 | } |
1181 | ||
1182 | template <typename LexerType> | |
1183 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement(TreeBuilder& context) | |
1184 | { | |
1185 | ASSERT(match(TRY)); | |
93a37866 | 1186 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1187 | TreeStatement tryBlock = 0; |
93a37866 | 1188 | const Identifier* ident = &m_vm->propertyNames->nullIdentifier; |
6fe7ccc8 A |
1189 | TreeStatement catchBlock = 0; |
1190 | TreeStatement finallyBlock = 0; | |
1191 | int firstLine = tokenLine(); | |
1192 | next(); | |
81345200 | 1193 | matchOrFail(OPENBRACE, "Expected a block statement as body of a try statement"); |
6fe7ccc8 A |
1194 | |
1195 | tryBlock = parseBlockStatement(context); | |
81345200 A |
1196 | failIfFalse(tryBlock, "Cannot parse the body of try block"); |
1197 | int lastLine = m_lastTokenEndPosition.line; | |
6fe7ccc8 A |
1198 | |
1199 | if (match(CATCH)) { | |
1200 | currentScope()->setNeedsFullActivation(); | |
1201 | next(); | |
81345200 A |
1202 | |
1203 | handleProductionOrFail(OPENPAREN, "(", "start", "'catch' target"); | |
1204 | if (!match(IDENT)) { | |
1205 | semanticFailureDueToKeyword("catch variable name"); | |
1206 | failWithMessage("Expected identifier name as catch target"); | |
1207 | } | |
6fe7ccc8 A |
1208 | ident = m_token.m_data.ident; |
1209 | next(); | |
1210 | AutoPopScopeRef catchScope(this, pushScope()); | |
81345200 | 1211 | failIfFalseIfStrict(declareVariable(ident), "Cannot declare a catch variable named '", ident->impl(), "' in strict mode"); |
6fe7ccc8 | 1212 | catchScope->preventNewDecls(); |
81345200 A |
1213 | handleProductionOrFail(CLOSEPAREN, ")", "end", "'catch' target"); |
1214 | matchOrFail(OPENBRACE, "Expected exception handler to be a block statement"); | |
6fe7ccc8 | 1215 | catchBlock = parseBlockStatement(context); |
81345200 A |
1216 | failIfFalse(catchBlock, "Unable to parse 'catch' block"); |
1217 | failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo), "Parse error"); | |
6fe7ccc8 A |
1218 | } |
1219 | ||
1220 | if (match(FINALLY)) { | |
1221 | next(); | |
81345200 | 1222 | matchOrFail(OPENBRACE, "Expected block statement for finally body"); |
6fe7ccc8 | 1223 | finallyBlock = parseBlockStatement(context); |
81345200 | 1224 | failIfFalse(finallyBlock, "Cannot parse finally body"); |
6fe7ccc8 | 1225 | } |
81345200 | 1226 | failIfFalse(catchBlock || finallyBlock, "Try statements must have at least a catch or finally block"); |
93a37866 | 1227 | return context.createTryStatement(location, tryBlock, ident, catchBlock, finallyBlock, firstLine, lastLine); |
6fe7ccc8 A |
1228 | } |
1229 | ||
1230 | template <typename LexerType> | |
1231 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDebuggerStatement(TreeBuilder& context) | |
1232 | { | |
1233 | ASSERT(match(DEBUGGER)); | |
93a37866 | 1234 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1235 | int startLine = tokenLine(); |
1236 | int endLine = startLine; | |
1237 | next(); | |
1238 | if (match(SEMICOLON)) | |
1239 | startLine = tokenLine(); | |
81345200 | 1240 | failIfFalse(autoSemiColon(), "Debugger keyword must be followed by a ';'"); |
93a37866 | 1241 | return context.createDebugger(location, startLine, endLine); |
6fe7ccc8 A |
1242 | } |
1243 | ||
1244 | template <typename LexerType> | |
1245 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatement(TreeBuilder& context) | |
1246 | { | |
1247 | ASSERT(match(OPENBRACE)); | |
93a37866 | 1248 | JSTokenLocation location(tokenLocation()); |
ed1e77d3 | 1249 | int startOffset = m_token.m_data.offset; |
6fe7ccc8 A |
1250 | int start = tokenLine(); |
1251 | next(); | |
1252 | if (match(CLOSEBRACE)) { | |
ed1e77d3 | 1253 | int endOffset = m_token.m_data.offset; |
6fe7ccc8 | 1254 | next(); |
ed1e77d3 A |
1255 | TreeStatement result = context.createBlockStatement(location, 0, start, m_lastTokenEndPosition.line); |
1256 | context.setStartOffset(result, startOffset); | |
1257 | context.setEndOffset(result, endOffset); | |
1258 | return result; | |
6fe7ccc8 | 1259 | } |
ed1e77d3 | 1260 | TreeSourceElements subtree = parseSourceElements(context, DontCheckForStrictMode, StandardFunctionParseType); |
81345200 A |
1261 | failIfFalse(subtree, "Cannot parse the body of the block statement"); |
1262 | matchOrFail(CLOSEBRACE, "Expected a closing '}' at the end of a block statement"); | |
ed1e77d3 | 1263 | int endOffset = m_token.m_data.offset; |
6fe7ccc8 | 1264 | next(); |
ed1e77d3 A |
1265 | TreeStatement result = context.createBlockStatement(location, subtree, start, m_lastTokenEndPosition.line); |
1266 | context.setStartOffset(result, startOffset); | |
1267 | context.setEndOffset(result, endOffset); | |
1268 | return result; | |
6fe7ccc8 A |
1269 | } |
1270 | ||
1271 | template <typename LexerType> | |
1272 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength) | |
1273 | { | |
1274 | DepthManager statementDepth(&m_statementDepth); | |
1275 | m_statementDepth++; | |
1276 | directive = 0; | |
1277 | int nonTrivialExpressionCount = 0; | |
1278 | failIfStackOverflow(); | |
ed1e77d3 A |
1279 | TreeStatement result = 0; |
1280 | bool shouldSetEndOffset = true; | |
1281 | ||
6fe7ccc8 A |
1282 | switch (m_token.m_type) { |
1283 | case OPENBRACE: | |
ed1e77d3 A |
1284 | result = parseBlockStatement(context); |
1285 | shouldSetEndOffset = false; | |
1286 | break; | |
6fe7ccc8 | 1287 | case VAR: |
ed1e77d3 A |
1288 | result = parseVarDeclaration(context); |
1289 | break; | |
6fe7ccc8 | 1290 | case FUNCTION: |
81345200 | 1291 | failIfFalseIfStrict(m_statementDepth == 1, "Strict mode does not allow function declarations in a lexically nested statement"); |
ed1e77d3 A |
1292 | result = parseFunctionDeclaration(context); |
1293 | break; | |
93a37866 A |
1294 | case SEMICOLON: { |
1295 | JSTokenLocation location(tokenLocation()); | |
6fe7ccc8 | 1296 | next(); |
ed1e77d3 A |
1297 | result = context.createEmptyStatement(location); |
1298 | break; | |
93a37866 | 1299 | } |
6fe7ccc8 | 1300 | case IF: |
ed1e77d3 A |
1301 | result = parseIfStatement(context); |
1302 | break; | |
6fe7ccc8 | 1303 | case DO: |
ed1e77d3 A |
1304 | result = parseDoWhileStatement(context); |
1305 | break; | |
6fe7ccc8 | 1306 | case WHILE: |
ed1e77d3 A |
1307 | result = parseWhileStatement(context); |
1308 | break; | |
6fe7ccc8 | 1309 | case FOR: |
ed1e77d3 A |
1310 | result = parseForStatement(context); |
1311 | break; | |
6fe7ccc8 | 1312 | case CONTINUE: |
ed1e77d3 A |
1313 | result = parseContinueStatement(context); |
1314 | break; | |
6fe7ccc8 | 1315 | case BREAK: |
ed1e77d3 A |
1316 | result = parseBreakStatement(context); |
1317 | break; | |
6fe7ccc8 | 1318 | case RETURN: |
ed1e77d3 A |
1319 | result = parseReturnStatement(context); |
1320 | break; | |
6fe7ccc8 | 1321 | case WITH: |
ed1e77d3 A |
1322 | result = parseWithStatement(context); |
1323 | break; | |
6fe7ccc8 | 1324 | case SWITCH: |
ed1e77d3 A |
1325 | result = parseSwitchStatement(context); |
1326 | break; | |
6fe7ccc8 | 1327 | case THROW: |
ed1e77d3 A |
1328 | result = parseThrowStatement(context); |
1329 | break; | |
6fe7ccc8 | 1330 | case TRY: |
ed1e77d3 A |
1331 | result = parseTryStatement(context); |
1332 | break; | |
6fe7ccc8 | 1333 | case DEBUGGER: |
ed1e77d3 A |
1334 | result = parseDebuggerStatement(context); |
1335 | break; | |
6fe7ccc8 A |
1336 | case EOFTOK: |
1337 | case CASE: | |
1338 | case CLOSEBRACE: | |
1339 | case DEFAULT: | |
1340 | // These tokens imply the end of a set of source elements | |
1341 | return 0; | |
1342 | case IDENT: | |
ed1e77d3 A |
1343 | result = parseExpressionOrLabelStatement(context); |
1344 | break; | |
6fe7ccc8 A |
1345 | case STRING: |
1346 | directive = m_token.m_data.ident; | |
1347 | if (directiveLiteralLength) | |
93a37866 | 1348 | *directiveLiteralLength = m_token.m_location.endOffset - m_token.m_location.startOffset; |
6fe7ccc8 | 1349 | nonTrivialExpressionCount = m_nonTrivialExpressionCount; |
81345200 | 1350 | FALLTHROUGH; |
6fe7ccc8 A |
1351 | default: |
1352 | TreeStatement exprStatement = parseExpressionStatement(context); | |
1353 | if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount) | |
1354 | directive = 0; | |
ed1e77d3 A |
1355 | result = exprStatement; |
1356 | break; | |
6fe7ccc8 | 1357 | } |
ed1e77d3 A |
1358 | |
1359 | if (result && shouldSetEndOffset) | |
1360 | context.setEndOffset(result, m_lastTokenEndPosition.offset); | |
1361 | return result; | |
6fe7ccc8 A |
1362 | } |
1363 | ||
1364 | template <typename LexerType> | |
1365 | template <class TreeBuilder> TreeFormalParameterList Parser<LexerType>::parseFormalParameters(TreeBuilder& context) | |
1366 | { | |
ed1e77d3 | 1367 | auto parameter = parseDestructuringPattern(context, DestructureToParameters); |
81345200 A |
1368 | failIfFalse(parameter, "Cannot parse parameter pattern"); |
1369 | TreeFormalParameterList list = context.createFormalParameterList(parameter); | |
6fe7ccc8 | 1370 | TreeFormalParameterList tail = list; |
81345200 | 1371 | while (consume(COMMA)) { |
ed1e77d3 | 1372 | parameter = parseDestructuringPattern(context, DestructureToParameters); |
81345200 A |
1373 | failIfFalse(parameter, "Cannot parse parameter pattern"); |
1374 | tail = context.createFormalParameterList(tail, parameter); | |
6fe7ccc8 A |
1375 | } |
1376 | return list; | |
1377 | } | |
1378 | ||
1379 | template <typename LexerType> | |
ed1e77d3 A |
1380 | template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody( |
1381 | TreeBuilder& context, int functionKeywordStart, int functionNameStart, | |
1382 | int parametersStart, ConstructorKind constructorKind, FunctionParseType parseType) | |
6fe7ccc8 | 1383 | { |
93a37866 A |
1384 | JSTokenLocation startLocation(tokenLocation()); |
1385 | unsigned startColumn = tokenColumn(); | |
93a37866 | 1386 | |
ed1e77d3 A |
1387 | if (parseType == StandardFunctionParseType) { |
1388 | next(); | |
1389 | if (match(CLOSEBRACE)) { | |
1390 | unsigned endColumn = tokenColumn(); | |
1391 | return context.createFunctionBody(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind); | |
1392 | } | |
81345200 | 1393 | } |
ed1e77d3 | 1394 | |
6fe7ccc8 A |
1395 | DepthManager statementDepth(&m_statementDepth); |
1396 | m_statementDepth = 0; | |
93a37866 | 1397 | typename TreeBuilder::FunctionBodyBuilder bodyBuilder(const_cast<VM*>(m_vm), m_lexer.get()); |
ed1e77d3 A |
1398 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) |
1399 | failIfFalse(parseSourceElements(bodyBuilder, CheckForStrictMode, parseType), parseType == StandardFunctionParseType ? "Cannot parse body of this function" : "Cannot parse body of this arrow function"); | |
1400 | #else | |
1401 | failIfFalse(parseSourceElements(bodyBuilder, CheckForStrictMode, StandardFunctionParseType), "Cannot parse body of this function"); | |
1402 | #endif | |
81345200 | 1403 | unsigned endColumn = tokenColumn(); |
ed1e77d3 | 1404 | return context.createFunctionBody(startLocation, tokenLocation(), startColumn, endColumn, functionKeywordStart, functionNameStart, parametersStart, strictMode(), constructorKind); |
81345200 A |
1405 | } |
1406 | ||
1407 | static const char* stringForFunctionMode(FunctionParseMode mode) | |
1408 | { | |
1409 | switch (mode) { | |
1410 | case GetterMode: | |
1411 | return "getter"; | |
1412 | case SetterMode: | |
1413 | return "setter"; | |
1414 | case FunctionMode: | |
1415 | return "function"; | |
ed1e77d3 A |
1416 | case MethodMode: |
1417 | return "method"; | |
1418 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
1419 | case ArrowFunctionMode: | |
1420 | return "arrow function"; | |
1421 | #endif | |
81345200 A |
1422 | } |
1423 | RELEASE_ASSERT_NOT_REACHED(); | |
1424 | return nullptr; | |
6fe7ccc8 A |
1425 | } |
1426 | ||
ed1e77d3 A |
1427 | template <typename LexerType> template <class TreeBuilder> int Parser<LexerType>::parseFunctionParameters(TreeBuilder& context, FunctionParseMode mode, ParserFunctionInfo<TreeBuilder>& info) |
1428 | { | |
1429 | int parametersStart = m_token.m_location.startOffset; | |
1430 | ||
1431 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
1432 | if (mode == ArrowFunctionMode) { | |
1433 | if (!match(IDENT) && !match(OPENPAREN)) { | |
1434 | semanticFailureDueToKeyword(stringForFunctionMode(mode), " name"); | |
1435 | failWithMessage("Expected an arrow function input parameter"); | |
1436 | } else { | |
1437 | if (match(OPENPAREN)) { | |
1438 | next(); | |
1439 | ||
1440 | if (!match(CLOSEPAREN)) { | |
1441 | info.parameters = parseFormalParameters(context); | |
1442 | failIfFalse(info.parameters, "Cannot parse parameters for this ", stringForFunctionMode(mode)); | |
1443 | } | |
1444 | ||
1445 | consumeOrFail(CLOSEPAREN, "Expected a ')' or a ',' after a parameter declaration"); | |
1446 | } else { | |
1447 | auto parameter = parseDestructuringPattern(context, DestructureToParameters); | |
1448 | failIfFalse(parameter, "Cannot parse parameter pattern"); | |
1449 | info.parameters = context.createFormalParameterList(parameter); | |
1450 | failIfFalse(info.parameters, "Cannot parse parameters for this ", stringForFunctionMode(mode)); | |
1451 | } | |
1452 | } | |
1453 | ||
1454 | return parametersStart; | |
1455 | } | |
1456 | #endif | |
1457 | ||
1458 | if (!consume(OPENPAREN)) { | |
1459 | semanticFailureDueToKeyword(stringForFunctionMode(mode), " name"); | |
1460 | failWithMessage("Expected an opening '(' before a ", stringForFunctionMode(mode), "'s parameter list"); | |
1461 | } | |
1462 | ||
1463 | if (mode == GetterMode) | |
1464 | consumeOrFail(CLOSEPAREN, "getter functions must have no parameters"); | |
1465 | else if (mode == SetterMode) { | |
1466 | failIfTrue(match(CLOSEPAREN), "setter functions must have one parameter"); | |
1467 | auto parameter = parseDestructuringPattern(context, DestructureToParameters); | |
1468 | failIfFalse(parameter, "setter functions must have one parameter"); | |
1469 | info.parameters = context.createFormalParameterList(parameter); | |
1470 | failIfTrue(match(COMMA), "setter functions must have one parameter"); | |
1471 | consumeOrFail(CLOSEPAREN, "Expected a ')' after a parameter declaration"); | |
1472 | } else { | |
1473 | if (!match(CLOSEPAREN)) { | |
1474 | info.parameters = parseFormalParameters(context); | |
1475 | failIfFalse(info.parameters, "Cannot parse parameters for this ", stringForFunctionMode(mode)); | |
1476 | } | |
1477 | consumeOrFail(CLOSEPAREN, "Expected a ')' or a ',' after a parameter declaration"); | |
1478 | } | |
1479 | ||
1480 | return parametersStart; | |
1481 | } | |
1482 | ||
6fe7ccc8 | 1483 | template <typename LexerType> |
ed1e77d3 | 1484 | template <class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, FunctionRequirements requirements, FunctionParseMode mode, bool nameIsInContainingScope, ConstructorKind constructorKind, SuperBinding expectedSuperBinding, int functionKeywordStart, ParserFunctionInfo<TreeBuilder>& info, FunctionParseType parseType) |
6fe7ccc8 A |
1485 | { |
1486 | AutoPopScopeRef functionScope(this, pushScope()); | |
1487 | functionScope->setIsFunction(); | |
81345200 A |
1488 | int functionNameStart = m_token.m_location.startOffset; |
1489 | const Identifier* lastFunctionName = m_lastFunctionName; | |
1490 | m_lastFunctionName = nullptr; | |
ed1e77d3 A |
1491 | int parametersStart; |
1492 | ||
1493 | switch (parseType) { | |
1494 | case StandardFunctionParseType: { | |
1495 | if (match(IDENT)) { | |
1496 | info.name = m_token.m_data.ident; | |
1497 | m_lastFunctionName = info.name; | |
1498 | next(); | |
1499 | if (!nameIsInContainingScope) | |
1500 | failIfFalseIfStrict(functionScope->declareVariable(info.name), "'", info.name->impl(), "' is not a valid ", stringForFunctionMode(mode), " name in strict mode"); | |
1501 | } else if (requirements == FunctionNeedsName) { | |
1502 | if (match(OPENPAREN) && mode == FunctionMode) | |
1503 | semanticFail("Function statements must have a name"); | |
1504 | semanticFailureDueToKeyword(stringForFunctionMode(mode), " name"); | |
1505 | failDueToUnexpectedToken(); | |
1506 | return false; | |
1507 | } | |
1508 | ||
1509 | parametersStart = parseFunctionParameters(context, mode, info); | |
1510 | propagateError(); | |
1511 | ||
1512 | matchOrFail(OPENBRACE, "Expected an opening '{' at the start of a ", stringForFunctionMode(mode), " body"); | |
1513 | ||
1514 | // BytecodeGenerator emits code to throw TypeError when a class constructor is "call"ed. | |
1515 | // Set ConstructorKind to None for non-constructor methods of classes. | |
1516 | ||
1517 | if (m_defaultConstructorKind != ConstructorKind::None) { | |
1518 | constructorKind = m_defaultConstructorKind; | |
1519 | expectedSuperBinding = m_defaultConstructorKind == ConstructorKind::Derived ? SuperBinding::Needed : SuperBinding::NotNeeded; | |
1520 | } | |
1521 | ||
1522 | info.startFunctionOffset = m_token.m_data.offset; | |
1523 | ||
1524 | break; | |
81345200 | 1525 | } |
ed1e77d3 A |
1526 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) |
1527 | case ArrowFunctionParseType: { | |
1528 | parametersStart = parseFunctionParameters(context, ArrowFunctionMode, info); | |
1529 | propagateError(); | |
1530 | ||
1531 | matchOrFail(ARROWFUNCTION, "Expected a '=>' after arrow function parameter declaration"); | |
1532 | ||
1533 | if (m_lexer->prevTerminator()) | |
1534 | failDueToUnexpectedToken(); | |
1535 | ||
1536 | ASSERT(constructorKind == ConstructorKind::None); | |
1537 | ||
1538 | info.arrowFunctionOffset = m_token.m_data.offset; | |
1539 | // Check if arrow body start with {. If it true it mean that arrow function is Fat arrow function | |
1540 | // and we need use common approach to parse function body | |
1541 | SavePoint savePoint = createSavePoint(); | |
1542 | ||
1543 | next(); | |
1544 | info.functionBodyType = match(OPENBRACE) ? ArrowFunctionBodyBlock : ArrowFunctionBodyExpression; | |
1545 | info.startFunctionOffset = (info.functionBodyType == ArrowFunctionBodyBlock) ? m_token.m_data.offset : info.arrowFunctionOffset; | |
1546 | ||
1547 | restoreSavePoint(savePoint); | |
1548 | ||
1549 | break; | |
81345200 | 1550 | } |
ed1e77d3 | 1551 | #endif |
6fe7ccc8 | 1552 | } |
6fe7ccc8 | 1553 | |
ed1e77d3 A |
1554 | bool isClassConstructor = constructorKind != ConstructorKind::None; |
1555 | ||
1556 | info.bodyStartLine = tokenLine(); | |
1557 | info.bodyStartColumn = m_token.m_data.offset - m_token.m_data.lineStartOffset; | |
93a37866 | 1558 | JSTokenLocation startLocation(tokenLocation()); |
6fe7ccc8 A |
1559 | |
1560 | // If we know about this function already, we can use the cached info and skip the parser to the end of the function. | |
ed1e77d3 | 1561 | if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(info.startFunctionOffset) : 0) { |
6fe7ccc8 A |
1562 | // If we're in a strict context, the cached function info must say it was strict too. |
1563 | ASSERT(!strictMode() || cachedInfo->strictMode); | |
93a37866 A |
1564 | JSTokenLocation endLocation; |
1565 | ||
ed1e77d3 A |
1566 | endLocation.line = cachedInfo->lastTockenLine; |
1567 | endLocation.startOffset = cachedInfo->lastTockenStartOffset; | |
1568 | endLocation.lineStartOffset = cachedInfo->lastTockenLineStartOffset; | |
81345200 | 1569 | |
ed1e77d3 | 1570 | bool endColumnIsOnStartLine = (endLocation.line == info.bodyStartLine); |
93a37866 | 1571 | ASSERT(endLocation.startOffset >= endLocation.lineStartOffset); |
81345200 A |
1572 | unsigned bodyEndColumn = endColumnIsOnStartLine ? |
1573 | endLocation.startOffset - m_token.m_data.lineStartOffset : | |
1574 | endLocation.startOffset - endLocation.lineStartOffset; | |
ed1e77d3 | 1575 | unsigned currentLineStartOffset = m_token.m_location.lineStartOffset; |
93a37866 | 1576 | |
ed1e77d3 A |
1577 | info.body = context.createFunctionBody( |
1578 | startLocation, endLocation, info.bodyStartColumn, bodyEndColumn, | |
1579 | functionKeywordStart, functionNameStart, parametersStart, | |
1580 | cachedInfo->strictMode, constructorKind); | |
6fe7ccc8 | 1581 | |
93a37866 | 1582 | functionScope->restoreFromSourceProviderCache(cachedInfo); |
81345200 | 1583 | failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo), "Parser error"); |
6fe7ccc8 | 1584 | |
ed1e77d3 A |
1585 | m_token = cachedInfo->endFunctionToken(); |
1586 | ||
1587 | if (endColumnIsOnStartLine) | |
1588 | m_token.m_location.lineStartOffset = currentLineStartOffset; | |
93a37866 A |
1589 | |
1590 | m_lexer->setOffset(m_token.m_location.endOffset, m_token.m_location.lineStartOffset); | |
1591 | m_lexer->setLineNumber(m_token.m_location.line); | |
ed1e77d3 A |
1592 | info.endFunctionOffset = cachedInfo->endFunctionOffset; |
1593 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
1594 | if (parseType == ArrowFunctionParseType) | |
1595 | info.functionBodyType = cachedInfo->isBodyArrowExpression ? ArrowFunctionBodyExpression : ArrowFunctionBodyBlock; | |
1596 | else | |
1597 | info.functionBodyType = StandardFunctionBodyBlock; | |
6fe7ccc8 | 1598 | |
ed1e77d3 A |
1599 | switch (info.functionBodyType) { |
1600 | case ArrowFunctionBodyExpression: | |
1601 | next(); | |
1602 | context.setEndOffset(info.body, m_lexer->currentOffset()); | |
1603 | break; | |
1604 | case ArrowFunctionBodyBlock: | |
1605 | case StandardFunctionBodyBlock: | |
1606 | context.setEndOffset(info.body, m_lexer->currentOffset()); | |
1607 | next(); | |
1608 | break; | |
1609 | } | |
1610 | #else | |
1611 | context.setEndOffset(info.body, m_lexer->currentOffset()); | |
6fe7ccc8 | 1612 | next(); |
ed1e77d3 A |
1613 | #endif |
1614 | info.bodyEndLine = m_lastTokenEndPosition.line; | |
6fe7ccc8 A |
1615 | return true; |
1616 | } | |
ed1e77d3 | 1617 | |
81345200 A |
1618 | m_lastFunctionName = lastFunctionName; |
1619 | ParserState oldState = saveState(); | |
ed1e77d3 A |
1620 | |
1621 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
1622 | switch (info.functionBodyType) { | |
1623 | case ArrowFunctionBodyBlock: { | |
1624 | // Consume => in case of arrow function block e.g. x => { return x; } | |
1625 | next(); | |
1626 | ||
1627 | info.bodyStartLine = tokenLine(); | |
1628 | info.bodyStartColumn = m_token.m_data.offset - m_token.m_data.lineStartOffset; | |
1629 | ||
1630 | info.body = parseFunctionBody(context, functionKeywordStart, functionNameStart, parametersStart, constructorKind, StandardFunctionParseType); | |
1631 | break; | |
1632 | } | |
1633 | case StandardFunctionBodyBlock: | |
1634 | case ArrowFunctionBodyExpression : { | |
1635 | info.body = parseFunctionBody(context, functionKeywordStart, functionNameStart, parametersStart, constructorKind, parseType); | |
1636 | break; | |
1637 | } | |
1638 | } | |
1639 | #else | |
1640 | info.body = parseFunctionBody(context, functionKeywordStart, functionNameStart, parametersStart, constructorKind, StandardFunctionParseType); | |
1641 | #endif | |
1642 | ||
81345200 | 1643 | restoreState(oldState); |
ed1e77d3 A |
1644 | failIfFalse(info.body, "Cannot parse the body of this ", stringForFunctionMode(mode)); |
1645 | context.setEndOffset(info.body, m_lexer->currentOffset()); | |
1646 | if (functionScope->strictMode() && info.name) { | |
1647 | RELEASE_ASSERT(mode == FunctionMode || mode == MethodMode); | |
1648 | semanticFailIfTrue(m_vm->propertyNames->arguments == *info.name, "'", info.name->impl(), "' is not a valid function name in strict mode"); | |
1649 | semanticFailIfTrue(m_vm->propertyNames->eval == *info.name, "'", info.name->impl(), "' is not a valid function name in strict mode"); | |
1650 | } | |
1651 | if (functionScope->hasDirectSuper()) { | |
1652 | semanticFailIfTrue(!isClassConstructor, "Cannot call super() outside of a class constructor"); | |
1653 | semanticFailIfTrue(constructorKind != ConstructorKind::Derived, "Cannot call super() in a base class constructor"); | |
1654 | } | |
1655 | if (functionScope->needsSuperBinding()) | |
1656 | semanticFailIfTrue(expectedSuperBinding == SuperBinding::NotNeeded, "super can only be used in a method of a derived class"); | |
1657 | ||
1658 | JSTokenLocation location = JSTokenLocation(m_token.m_location); | |
1659 | info.endFunctionOffset = m_token.m_data.offset; | |
1660 | ||
1661 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
1662 | if (info.functionBodyType == ArrowFunctionBodyExpression) { | |
1663 | location = locationBeforeLastToken(); | |
1664 | info.endFunctionOffset = location.endOffset; | |
6fe7ccc8 | 1665 | } |
ed1e77d3 | 1666 | #endif |
6fe7ccc8 A |
1667 | |
1668 | // Cache the tokenizer state and the function scope the first time the function is parsed. | |
1669 | // Any future reparsing can then skip the function. | |
93a37866 | 1670 | static const int minimumFunctionLengthToCache = 16; |
81345200 | 1671 | std::unique_ptr<SourceProviderCacheItem> newInfo; |
ed1e77d3 | 1672 | int functionLength = info.endFunctionOffset - info.startFunctionOffset; |
6fe7ccc8 | 1673 | if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) { |
93a37866 | 1674 | SourceProviderCacheItemCreationParameters parameters; |
ed1e77d3 | 1675 | parameters.endFunctionOffset = info.endFunctionOffset; |
81345200 | 1676 | parameters.functionNameStart = functionNameStart; |
ed1e77d3 A |
1677 | parameters.lastTockenLine = location.line; |
1678 | parameters.lastTockenStartOffset = location.startOffset; | |
1679 | parameters.lastTockenEndOffset = location.endOffset; | |
1680 | parameters.lastTockenLineStartOffset = location.lineStartOffset; | |
1681 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
1682 | if (info.functionBodyType == ArrowFunctionBodyExpression) { | |
1683 | parameters.isBodyArrowExpression = true; | |
1684 | parameters.tokenType = m_token.m_type; | |
1685 | } | |
1686 | #endif | |
93a37866 A |
1687 | functionScope->fillParametersForSourceProviderCache(parameters); |
1688 | newInfo = SourceProviderCacheItem::create(parameters); | |
6fe7ccc8 A |
1689 | } |
1690 | ||
81345200 | 1691 | failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo), "Parser error"); |
ed1e77d3 A |
1692 | |
1693 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
1694 | if (info.functionBodyType == ArrowFunctionBodyExpression) | |
1695 | failIfFalse(isEndOfArrowFunction(), "Expected the closing ';' ',' ']' ')' '}', line terminator or EOF after arrow function"); | |
1696 | else { | |
1697 | matchOrFail(CLOSEBRACE, "Expected a closing '}' after a ", stringForFunctionMode(mode), " body"); | |
1698 | next(); | |
1699 | } | |
1700 | #else | |
81345200 | 1701 | matchOrFail(CLOSEBRACE, "Expected a closing '}' after a ", stringForFunctionMode(mode), " body"); |
ed1e77d3 A |
1702 | next(); |
1703 | #endif | |
6fe7ccc8 | 1704 | |
93a37866 | 1705 | if (newInfo) |
ed1e77d3 | 1706 | m_functionCache->add(info.startFunctionOffset, WTF::move(newInfo)); |
6fe7ccc8 | 1707 | |
ed1e77d3 | 1708 | info.bodyEndLine = m_lastTokenEndPosition.line; |
6fe7ccc8 A |
1709 | return true; |
1710 | } | |
1711 | ||
1712 | template <typename LexerType> | |
1713 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context) | |
1714 | { | |
1715 | ASSERT(match(FUNCTION)); | |
93a37866 | 1716 | JSTokenLocation location(tokenLocation()); |
ed1e77d3 | 1717 | unsigned functionKeywordStart = tokenStart(); |
6fe7ccc8 | 1718 | next(); |
ed1e77d3 A |
1719 | ParserFunctionInfo<TreeBuilder> info; |
1720 | failIfFalse((parseFunctionInfo(context, FunctionNeedsName, FunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded, | |
1721 | functionKeywordStart, info, StandardFunctionParseType)), "Cannot parse this function"); | |
1722 | failIfFalse(info.name, "Function statements must have a name"); | |
1723 | failIfFalseIfStrict(declareVariable(info.name), "Cannot declare a function named '", info.name->impl(), "' in strict mode"); | |
1724 | return context.createFuncDeclStatement(location, info); | |
1725 | } | |
1726 | ||
1727 | #if ENABLE(ES6_CLASS_SYNTAX) | |
1728 | template <typename LexerType> | |
1729 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseClassDeclaration(TreeBuilder& context) | |
1730 | { | |
1731 | ASSERT(match(CLASSTOKEN)); | |
1732 | JSTokenLocation location(tokenLocation()); | |
1733 | JSTextPosition classStart = tokenStartPosition(); | |
1734 | unsigned classStartLine = tokenLine(); | |
1735 | ||
1736 | ParserClassInfo<TreeBuilder> info; | |
1737 | TreeClassExpression classExpr = parseClass(context, FunctionNeedsName, info); | |
1738 | failIfFalse(classExpr, "Failed to parse class"); | |
1739 | declareVariable(info.className); | |
1740 | ||
1741 | // FIXME: This should be like `let`, not `var`. | |
1742 | context.addVar(info.className, DeclarationStacks::HasInitializer); | |
1743 | ||
1744 | JSTextPosition classEnd = lastTokenEndPosition(); | |
1745 | unsigned classEndLine = tokenLine(); | |
1746 | ||
1747 | return context.createClassDeclStatement(location, classExpr, classStart, classEnd, classStartLine, classEndLine); | |
6fe7ccc8 A |
1748 | } |
1749 | ||
ed1e77d3 A |
1750 | template <typename LexerType> |
1751 | template <class TreeBuilder> TreeClassExpression Parser<LexerType>::parseClass(TreeBuilder& context, FunctionRequirements requirements, ParserClassInfo<TreeBuilder>& info) | |
1752 | { | |
1753 | ASSERT(match(CLASSTOKEN)); | |
1754 | JSTokenLocation location(tokenLocation()); | |
1755 | next(); | |
1756 | ||
1757 | AutoPopScopeRef classScope(this, pushScope()); | |
1758 | classScope->setStrictMode(); | |
1759 | ||
1760 | const Identifier* className = nullptr; | |
1761 | if (match(IDENT)) { | |
1762 | className = m_token.m_data.ident; | |
1763 | info.className = className; | |
1764 | next(); | |
1765 | failIfFalse(classScope->declareVariable(className), "'", className->impl(), "' is not a valid class name"); | |
1766 | } else if (requirements == FunctionNeedsName) { | |
1767 | if (match(OPENBRACE)) | |
1768 | semanticFail("Class statements must have a name"); | |
1769 | semanticFailureDueToKeyword("class name"); | |
1770 | failDueToUnexpectedToken(); | |
1771 | } else | |
1772 | className = &m_vm->propertyNames->nullIdentifier; | |
1773 | ASSERT(className); | |
1774 | ||
1775 | TreeExpression parentClass = 0; | |
1776 | if (consume(EXTENDS)) { | |
1777 | parentClass = parseMemberExpression(context); | |
1778 | failIfFalse(parentClass, "Cannot parse the parent class name"); | |
1779 | } | |
1780 | const ConstructorKind constructorKind = parentClass ? ConstructorKind::Derived : ConstructorKind::Base; | |
1781 | ||
1782 | consumeOrFail(OPENBRACE, "Expected opening '{' at the start of a class body"); | |
1783 | ||
1784 | TreeExpression constructor = 0; | |
1785 | TreePropertyList staticMethods = 0; | |
1786 | TreePropertyList instanceMethods = 0; | |
1787 | TreePropertyList instanceMethodsTail = 0; | |
1788 | TreePropertyList staticMethodsTail = 0; | |
1789 | while (!match(CLOSEBRACE)) { | |
1790 | if (match(SEMICOLON)) { | |
1791 | next(); | |
1792 | continue; | |
1793 | } | |
1794 | ||
1795 | JSTokenLocation methodLocation(tokenLocation()); | |
1796 | unsigned methodStart = tokenStart(); | |
1797 | ||
1798 | // For backwards compatibility, "static" is a non-reserved keyword in non-strict mode. | |
1799 | bool isStaticMethod = match(RESERVED_IF_STRICT) && *m_token.m_data.ident == m_vm->propertyNames->staticKeyword; | |
1800 | if (isStaticMethod) | |
1801 | next(); | |
1802 | ||
1803 | // FIXME: Figure out a way to share more code with parseProperty. | |
1804 | const CommonIdentifiers& propertyNames = *m_vm->propertyNames; | |
1805 | const Identifier* ident = nullptr; | |
1806 | bool isGetter = false; | |
1807 | bool isSetter = false; | |
1808 | switch (m_token.m_type) { | |
1809 | case STRING: | |
1810 | ident = m_token.m_data.ident; | |
1811 | ASSERT(ident); | |
1812 | next(); | |
1813 | break; | |
1814 | case IDENT: | |
1815 | ident = m_token.m_data.ident; | |
1816 | isGetter = *ident == propertyNames.get; | |
1817 | isSetter = *ident == propertyNames.set; | |
1818 | ASSERT(ident); | |
1819 | break; | |
1820 | case DOUBLE: | |
1821 | case INTEGER: | |
1822 | ident = &m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM*>(m_vm), m_token.m_data.doubleValue); | |
1823 | ASSERT(ident); | |
1824 | next(); | |
1825 | break; | |
1826 | default: | |
1827 | failDueToUnexpectedToken(); | |
1828 | } | |
1829 | ||
1830 | TreeProperty property; | |
1831 | const bool alwaysStrictInsideClass = true; | |
1832 | if (isGetter || isSetter) { | |
1833 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords); | |
1834 | property = parseGetterSetter(context, alwaysStrictInsideClass, isGetter ? PropertyNode::Getter : PropertyNode::Setter, methodStart, | |
1835 | ConstructorKind::None, SuperBinding::Needed); | |
1836 | failIfFalse(property, "Cannot parse this method"); | |
1837 | } else { | |
1838 | ParserFunctionInfo<TreeBuilder> methodInfo; | |
1839 | bool isConstructor = !isStaticMethod && *ident == propertyNames.constructor; | |
1840 | failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, isStaticMethod ? FunctionMode : MethodMode, false, isConstructor ? constructorKind : ConstructorKind::None, SuperBinding::Needed, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method"); | |
1841 | failIfFalse(ident && declareVariable(ident), "Cannot declare a method named '", methodInfo.name->impl(), "'"); | |
1842 | methodInfo.name = isConstructor ? className : ident; | |
1843 | ||
1844 | TreeExpression method = context.createFunctionExpr(methodLocation, methodInfo); | |
1845 | if (isConstructor) { | |
1846 | semanticFailIfTrue(constructor, "Cannot declare multiple constructors in a single class"); | |
1847 | constructor = method; | |
1848 | continue; | |
1849 | } | |
1850 | ||
1851 | // FIXME: Syntax error when super() is called | |
1852 | semanticFailIfTrue(isStaticMethod && methodInfo.name && *methodInfo.name == propertyNames.prototype, | |
1853 | "Cannot declare a static method named 'prototype'"); | |
1854 | property = context.createProperty(methodInfo.name, method, PropertyNode::Constant, PropertyNode::Unknown, alwaysStrictInsideClass, SuperBinding::Needed); | |
1855 | } | |
1856 | ||
1857 | TreePropertyList& tail = isStaticMethod ? staticMethodsTail : instanceMethodsTail; | |
1858 | if (tail) | |
1859 | tail = context.createPropertyList(methodLocation, property, tail); | |
1860 | else { | |
1861 | tail = context.createPropertyList(methodLocation, property); | |
1862 | if (isStaticMethod) | |
1863 | staticMethods = tail; | |
1864 | else | |
1865 | instanceMethods = tail; | |
1866 | } | |
1867 | } | |
1868 | ||
1869 | failIfFalse(popScope(classScope, TreeBuilder::NeedsFreeVariableInfo), "Parser error"); | |
1870 | consumeOrFail(CLOSEBRACE, "Expected a closing '}' after a class body"); | |
1871 | ||
1872 | return context.createClassExpr(location, *className, constructor, parentClass, instanceMethods, staticMethods); | |
1873 | } | |
1874 | #endif | |
1875 | ||
6fe7ccc8 | 1876 | struct LabelInfo { |
81345200 | 1877 | LabelInfo(const Identifier* ident, const JSTextPosition& start, const JSTextPosition& end) |
6fe7ccc8 A |
1878 | : m_ident(ident) |
1879 | , m_start(start) | |
1880 | , m_end(end) | |
1881 | { | |
1882 | } | |
1883 | ||
1884 | const Identifier* m_ident; | |
81345200 A |
1885 | JSTextPosition m_start; |
1886 | JSTextPosition m_end; | |
6fe7ccc8 A |
1887 | }; |
1888 | ||
1889 | template <typename LexerType> | |
1890 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionOrLabelStatement(TreeBuilder& context) | |
1891 | { | |
1892 | ||
1893 | /* Expression and Label statements are ambiguous at LL(1), so we have a | |
1894 | * special case that looks for a colon as the next character in the input. | |
1895 | */ | |
1896 | Vector<LabelInfo> labels; | |
93a37866 | 1897 | JSTokenLocation location; |
6fe7ccc8 | 1898 | do { |
81345200 | 1899 | JSTextPosition start = tokenStartPosition(); |
93a37866 | 1900 | location = tokenLocation(); |
6fe7ccc8 A |
1901 | if (!nextTokenIsColon()) { |
1902 | // If we hit this path we're making a expression statement, which | |
1903 | // by definition can't make use of continue/break so we can just | |
1904 | // ignore any labels we might have accumulated. | |
1905 | TreeExpression expression = parseExpression(context); | |
81345200 A |
1906 | failIfFalse(expression, "Cannot parse expression statement"); |
1907 | if (!autoSemiColon()) | |
1908 | failDueToUnexpectedToken(); | |
1909 | return context.createExprStatement(location, expression, start, m_lastTokenEndPosition.line); | |
6fe7ccc8 A |
1910 | } |
1911 | const Identifier* ident = m_token.m_data.ident; | |
81345200 | 1912 | JSTextPosition end = tokenEndPosition(); |
6fe7ccc8 | 1913 | next(); |
81345200 | 1914 | consumeOrFail(COLON, "Labels must be followed by a ':'"); |
6fe7ccc8 A |
1915 | if (!m_syntaxAlreadyValidated) { |
1916 | // This is O(N^2) over the current list of consecutive labels, but I | |
1917 | // have never seen more than one label in a row in the real world. | |
1918 | for (size_t i = 0; i < labels.size(); i++) | |
81345200 A |
1919 | failIfTrue(ident->impl() == labels[i].m_ident->impl(), "Attempted to redeclare the label '", ident->impl(), "'"); |
1920 | failIfTrue(getLabel(ident), "Cannot find scope for the label '", ident->impl(), "'"); | |
1921 | labels.append(LabelInfo(ident, start, end)); | |
6fe7ccc8 A |
1922 | } |
1923 | } while (match(IDENT)); | |
1924 | bool isLoop = false; | |
1925 | switch (m_token.m_type) { | |
1926 | case FOR: | |
1927 | case WHILE: | |
1928 | case DO: | |
1929 | isLoop = true; | |
1930 | break; | |
1931 | ||
1932 | default: | |
1933 | break; | |
1934 | } | |
1935 | const Identifier* unused = 0; | |
1936 | if (!m_syntaxAlreadyValidated) { | |
1937 | for (size_t i = 0; i < labels.size(); i++) | |
1938 | pushLabel(labels[i].m_ident, isLoop); | |
1939 | } | |
1940 | TreeStatement statement = parseStatement(context, unused); | |
1941 | if (!m_syntaxAlreadyValidated) { | |
1942 | for (size_t i = 0; i < labels.size(); i++) | |
1943 | popLabel(); | |
1944 | } | |
81345200 | 1945 | failIfFalse(statement, "Cannot parse statement"); |
6fe7ccc8 A |
1946 | for (size_t i = 0; i < labels.size(); i++) { |
1947 | const LabelInfo& info = labels[labels.size() - i - 1]; | |
81345200 | 1948 | statement = context.createLabelStatement(location, info.m_ident, statement, info.m_start, info.m_end); |
6fe7ccc8 A |
1949 | } |
1950 | return statement; | |
1951 | } | |
1952 | ||
1953 | template <typename LexerType> | |
1954 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionStatement(TreeBuilder& context) | |
1955 | { | |
ed1e77d3 A |
1956 | switch (m_token.m_type) { |
1957 | // Consult: http://www.ecma-international.org/ecma-262/6.0/index.html#sec-expression-statement | |
1958 | // The ES6 spec mandates that we should fail from FUNCTION token here. We handle this case | |
1959 | // in parseStatement() which is the only caller of parseExpressionStatement(). | |
1960 | // We actually allow FUNCTION in situations where it should not be allowed unless we're in strict mode. | |
1961 | case CLASSTOKEN: | |
1962 | failWithMessage("'class' declaration is not directly within a block statement"); | |
1963 | break; | |
1964 | default: | |
1965 | // FIXME: when implementing 'let' we should fail when we see the token sequence "let [". | |
1966 | // https://bugs.webkit.org/show_bug.cgi?id=142944 | |
1967 | break; | |
1968 | } | |
81345200 | 1969 | JSTextPosition start = tokenStartPosition(); |
93a37866 | 1970 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1971 | TreeExpression expression = parseExpression(context); |
81345200 A |
1972 | failIfFalse(expression, "Cannot parse expression statement"); |
1973 | failIfFalse(autoSemiColon(), "Parse error"); | |
1974 | return context.createExprStatement(location, expression, start, m_lastTokenEndPosition.line); | |
6fe7ccc8 A |
1975 | } |
1976 | ||
1977 | template <typename LexerType> | |
1978 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseIfStatement(TreeBuilder& context) | |
1979 | { | |
1980 | ASSERT(match(IF)); | |
93a37866 | 1981 | JSTokenLocation ifLocation(tokenLocation()); |
6fe7ccc8 A |
1982 | int start = tokenLine(); |
1983 | next(); | |
81345200 | 1984 | handleProductionOrFail(OPENPAREN, "(", "start", "'if' condition"); |
93a37866 | 1985 | |
6fe7ccc8 | 1986 | TreeExpression condition = parseExpression(context); |
81345200 | 1987 | failIfFalse(condition, "Expected a expression as the condition for an if statement"); |
6fe7ccc8 | 1988 | int end = tokenLine(); |
81345200 | 1989 | handleProductionOrFail(CLOSEPAREN, ")", "end", "'if' condition"); |
93a37866 | 1990 | |
6fe7ccc8 A |
1991 | const Identifier* unused = 0; |
1992 | TreeStatement trueBlock = parseStatement(context, unused); | |
81345200 | 1993 | failIfFalse(trueBlock, "Expected a statement as the body of an if block"); |
93a37866 | 1994 | |
6fe7ccc8 | 1995 | if (!match(ELSE)) |
93a37866 A |
1996 | return context.createIfStatement(ifLocation, condition, trueBlock, 0, start, end); |
1997 | ||
6fe7ccc8 | 1998 | Vector<TreeExpression> exprStack; |
81345200 | 1999 | Vector<std::pair<int, int>> posStack; |
93a37866 | 2000 | Vector<JSTokenLocation> tokenLocationStack; |
6fe7ccc8 A |
2001 | Vector<TreeStatement> statementStack; |
2002 | bool trailingElse = false; | |
2003 | do { | |
93a37866 | 2004 | JSTokenLocation tempLocation = tokenLocation(); |
6fe7ccc8 A |
2005 | next(); |
2006 | if (!match(IF)) { | |
2007 | const Identifier* unused = 0; | |
2008 | TreeStatement block = parseStatement(context, unused); | |
81345200 | 2009 | failIfFalse(block, "Expected a statement as the body of an else block"); |
6fe7ccc8 A |
2010 | statementStack.append(block); |
2011 | trailingElse = true; | |
2012 | break; | |
2013 | } | |
2014 | int innerStart = tokenLine(); | |
2015 | next(); | |
81345200 A |
2016 | |
2017 | handleProductionOrFail(OPENPAREN, "(", "start", "'if' condition"); | |
93a37866 | 2018 | |
6fe7ccc8 | 2019 | TreeExpression innerCondition = parseExpression(context); |
81345200 | 2020 | failIfFalse(innerCondition, "Expected a expression as the condition for an if statement"); |
6fe7ccc8 | 2021 | int innerEnd = tokenLine(); |
81345200 | 2022 | handleProductionOrFail(CLOSEPAREN, ")", "end", "'if' condition"); |
6fe7ccc8 A |
2023 | const Identifier* unused = 0; |
2024 | TreeStatement innerTrueBlock = parseStatement(context, unused); | |
81345200 | 2025 | failIfFalse(innerTrueBlock, "Expected a statement as the body of an if block"); |
93a37866 | 2026 | tokenLocationStack.append(tempLocation); |
6fe7ccc8 | 2027 | exprStack.append(innerCondition); |
81345200 | 2028 | posStack.append(std::make_pair(innerStart, innerEnd)); |
6fe7ccc8 A |
2029 | statementStack.append(innerTrueBlock); |
2030 | } while (match(ELSE)); | |
93a37866 | 2031 | |
6fe7ccc8 A |
2032 | if (!trailingElse) { |
2033 | TreeExpression condition = exprStack.last(); | |
2034 | exprStack.removeLast(); | |
2035 | TreeStatement trueBlock = statementStack.last(); | |
2036 | statementStack.removeLast(); | |
81345200 | 2037 | std::pair<int, int> pos = posStack.last(); |
6fe7ccc8 | 2038 | posStack.removeLast(); |
93a37866 A |
2039 | JSTokenLocation elseLocation = tokenLocationStack.last(); |
2040 | tokenLocationStack.removeLast(); | |
ed1e77d3 A |
2041 | TreeStatement ifStatement = context.createIfStatement(elseLocation, condition, trueBlock, 0, pos.first, pos.second); |
2042 | context.setEndOffset(ifStatement, context.endOffset(trueBlock)); | |
2043 | statementStack.append(ifStatement); | |
6fe7ccc8 | 2044 | } |
93a37866 | 2045 | |
6fe7ccc8 A |
2046 | while (!exprStack.isEmpty()) { |
2047 | TreeExpression condition = exprStack.last(); | |
2048 | exprStack.removeLast(); | |
2049 | TreeStatement falseBlock = statementStack.last(); | |
2050 | statementStack.removeLast(); | |
2051 | TreeStatement trueBlock = statementStack.last(); | |
2052 | statementStack.removeLast(); | |
81345200 | 2053 | std::pair<int, int> pos = posStack.last(); |
6fe7ccc8 | 2054 | posStack.removeLast(); |
93a37866 A |
2055 | JSTokenLocation elseLocation = tokenLocationStack.last(); |
2056 | tokenLocationStack.removeLast(); | |
ed1e77d3 A |
2057 | TreeStatement ifStatement = context.createIfStatement(elseLocation, condition, trueBlock, falseBlock, pos.first, pos.second); |
2058 | context.setEndOffset(ifStatement, context.endOffset(falseBlock)); | |
2059 | statementStack.append(ifStatement); | |
6fe7ccc8 | 2060 | } |
93a37866 A |
2061 | |
2062 | return context.createIfStatement(ifLocation, condition, trueBlock, statementStack.last(), start, end); | |
6fe7ccc8 A |
2063 | } |
2064 | ||
2065 | template <typename LexerType> | |
2066 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseExpression(TreeBuilder& context) | |
2067 | { | |
2068 | failIfStackOverflow(); | |
93a37866 | 2069 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2070 | TreeExpression node = parseAssignmentExpression(context); |
81345200 | 2071 | failIfFalse(node, "Cannot parse expression"); |
ed1e77d3 | 2072 | context.setEndOffset(node, m_lastTokenEndPosition.offset); |
6fe7ccc8 A |
2073 | if (!match(COMMA)) |
2074 | return node; | |
2075 | next(); | |
2076 | m_nonTrivialExpressionCount++; | |
2077 | m_nonLHSCount++; | |
2078 | TreeExpression right = parseAssignmentExpression(context); | |
81345200 | 2079 | failIfFalse(right, "Cannot parse expression in a comma expression"); |
ed1e77d3 A |
2080 | context.setEndOffset(right, m_lastTokenEndPosition.offset); |
2081 | typename TreeBuilder::Comma head = context.createCommaExpr(location, node); | |
2082 | typename TreeBuilder::Comma tail = context.appendToCommaExpr(location, head, head, right); | |
6fe7ccc8 A |
2083 | while (match(COMMA)) { |
2084 | next(TreeBuilder::DontBuildStrings); | |
2085 | right = parseAssignmentExpression(context); | |
81345200 | 2086 | failIfFalse(right, "Cannot parse expression in a comma expression"); |
ed1e77d3 A |
2087 | context.setEndOffset(right, m_lastTokenEndPosition.offset); |
2088 | tail = context.appendToCommaExpr(location, head, tail, right); | |
6fe7ccc8 | 2089 | } |
ed1e77d3 A |
2090 | context.setEndOffset(head, m_lastTokenEndPosition.offset); |
2091 | return head; | |
6fe7ccc8 A |
2092 | } |
2093 | ||
ed1e77d3 | 2094 | |
6fe7ccc8 A |
2095 | template <typename LexerType> |
2096 | template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmentExpression(TreeBuilder& context) | |
2097 | { | |
2098 | failIfStackOverflow(); | |
81345200 | 2099 | JSTextPosition start = tokenStartPosition(); |
93a37866 | 2100 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
2101 | int initialAssignmentCount = m_assignmentCount; |
2102 | int initialNonLHSCount = m_nonLHSCount; | |
81345200 A |
2103 | if (match(OPENBRACE) || match(OPENBRACKET)) { |
2104 | SavePoint savePoint = createSavePoint(); | |
ed1e77d3 | 2105 | auto pattern = tryParseDestructuringPatternExpression(context); |
81345200 A |
2106 | if (pattern && consume(EQUAL)) { |
2107 | auto rhs = parseAssignmentExpression(context); | |
2108 | if (rhs) | |
ed1e77d3 | 2109 | return context.createDestructuringAssignment(location, pattern, rhs); |
81345200 A |
2110 | } |
2111 | restoreSavePoint(savePoint); | |
2112 | } | |
ed1e77d3 A |
2113 | |
2114 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) | |
2115 | if (isArrowFunctionParamters()) | |
2116 | return parseArrowFunctionExpression(context); | |
2117 | #endif | |
2118 | ||
6fe7ccc8 | 2119 | TreeExpression lhs = parseConditionalExpression(context); |
81345200 A |
2120 | failIfFalse(lhs, "Cannot parse expression"); |
2121 | if (initialNonLHSCount != m_nonLHSCount) { | |
2122 | if (m_token.m_type >= EQUAL && m_token.m_type <= OREQUAL) | |
2123 | semanticFail("Left hand side of operator '", getToken(), "' must be a reference"); | |
2124 | ||
6fe7ccc8 | 2125 | return lhs; |
81345200 | 2126 | } |
6fe7ccc8 A |
2127 | |
2128 | int assignmentStack = 0; | |
2129 | Operator op; | |
2130 | bool hadAssignment = false; | |
2131 | while (true) { | |
2132 | switch (m_token.m_type) { | |
2133 | case EQUAL: op = OpEqual; break; | |
2134 | case PLUSEQUAL: op = OpPlusEq; break; | |
2135 | case MINUSEQUAL: op = OpMinusEq; break; | |
2136 | case MULTEQUAL: op = OpMultEq; break; | |
2137 | case DIVEQUAL: op = OpDivEq; break; | |
2138 | case LSHIFTEQUAL: op = OpLShift; break; | |
2139 | case RSHIFTEQUAL: op = OpRShift; break; | |
2140 | case URSHIFTEQUAL: op = OpURShift; break; | |
2141 | case ANDEQUAL: op = OpAndEq; break; | |
2142 | case XOREQUAL: op = OpXOrEq; break; | |
2143 | case OREQUAL: op = OpOrEq; break; | |
2144 | case MODEQUAL: op = OpModEq; break; | |
2145 | default: | |
2146 | goto end; | |
2147 | } | |
2148 | m_nonTrivialExpressionCount++; | |
2149 | hadAssignment = true; | |
81345200 A |
2150 | context.assignmentStackAppend(assignmentStack, lhs, start, tokenStartPosition(), m_assignmentCount, op); |
2151 | start = tokenStartPosition(); | |
6fe7ccc8 A |
2152 | m_assignmentCount++; |
2153 | next(TreeBuilder::DontBuildStrings); | |
2154 | if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) { | |
81345200 A |
2155 | failIfTrueIfStrict(m_vm->propertyNames->eval == *m_lastIdentifier, "Cannot modify 'eval' in strict mode"); |
2156 | failIfTrueIfStrict(m_vm->propertyNames->arguments == *m_lastIdentifier, "Cannot modify 'arguments' in strict mode"); | |
6fe7ccc8 A |
2157 | declareWrite(m_lastIdentifier); |
2158 | m_lastIdentifier = 0; | |
2159 | } | |
81345200 A |
2160 | lhs = parseAssignmentExpression(context); |
2161 | failIfFalse(lhs, "Cannot parse the right hand side of an assignment expression"); | |
2162 | if (initialNonLHSCount != m_nonLHSCount) { | |
2163 | if (m_token.m_type >= EQUAL && m_token.m_type <= OREQUAL) | |
2164 | semanticFail("Left hand side of operator '", getToken(), "' must be a reference"); | |
6fe7ccc8 | 2165 | break; |
81345200 | 2166 | } |
6fe7ccc8 A |
2167 | } |
2168 | end: | |
2169 | if (hadAssignment) | |
2170 | m_nonLHSCount++; | |
2171 | ||
2172 | if (!TreeBuilder::CreatesAST) | |
2173 | return lhs; | |
2174 | ||
2175 | while (assignmentStack) | |
81345200 | 2176 | lhs = context.createAssignment(location, assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEndPosition()); |
6fe7ccc8 A |
2177 | |
2178 | return lhs; | |
2179 | } | |
2180 | ||
2181 | template <typename LexerType> | |
2182 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseConditionalExpression(TreeBuilder& context) | |
2183 | { | |
93a37866 | 2184 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2185 | TreeExpression cond = parseBinaryExpression(context); |
81345200 | 2186 | failIfFalse(cond, "Cannot parse expression"); |
6fe7ccc8 A |
2187 | if (!match(QUESTION)) |
2188 | return cond; | |
2189 | m_nonTrivialExpressionCount++; | |
2190 | m_nonLHSCount++; | |
2191 | next(TreeBuilder::DontBuildStrings); | |
2192 | TreeExpression lhs = parseAssignmentExpression(context); | |
81345200 | 2193 | failIfFalse(lhs, "Cannot parse left hand side of ternary operator"); |
ed1e77d3 | 2194 | context.setEndOffset(lhs, m_lastTokenEndPosition.offset); |
81345200 | 2195 | consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings, "Expected ':' in ternary operator"); |
6fe7ccc8 A |
2196 | |
2197 | TreeExpression rhs = parseAssignmentExpression(context); | |
81345200 | 2198 | failIfFalse(rhs, "Cannot parse right hand side of ternary operator"); |
ed1e77d3 | 2199 | context.setEndOffset(rhs, m_lastTokenEndPosition.offset); |
93a37866 | 2200 | return context.createConditionalExpr(location, cond, lhs, rhs); |
6fe7ccc8 A |
2201 | } |
2202 | ||
2203 | ALWAYS_INLINE static bool isUnaryOp(JSTokenType token) | |
2204 | { | |
2205 | return token & UnaryOpTokenFlag; | |
2206 | } | |
2207 | ||
2208 | template <typename LexerType> | |
2209 | int Parser<LexerType>::isBinaryOperator(JSTokenType token) | |
2210 | { | |
2211 | if (m_allowsIn) | |
2212 | return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift); | |
2213 | return token & BinaryOpTokenPrecedenceMask; | |
2214 | } | |
2215 | ||
2216 | template <typename LexerType> | |
2217 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseBinaryExpression(TreeBuilder& context) | |
2218 | { | |
6fe7ccc8 A |
2219 | int operandStackDepth = 0; |
2220 | int operatorStackDepth = 0; | |
2221 | typename TreeBuilder::BinaryExprContext binaryExprContext(context); | |
93a37866 | 2222 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2223 | while (true) { |
81345200 | 2224 | JSTextPosition exprStart = tokenStartPosition(); |
6fe7ccc8 A |
2225 | int initialAssignments = m_assignmentCount; |
2226 | TreeExpression current = parseUnaryExpression(context); | |
81345200 | 2227 | failIfFalse(current, "Cannot parse expression"); |
6fe7ccc8 | 2228 | |
81345200 | 2229 | context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEndPosition(), lastTokenEndPosition(), initialAssignments != m_assignmentCount); |
6fe7ccc8 A |
2230 | int precedence = isBinaryOperator(m_token.m_type); |
2231 | if (!precedence) | |
2232 | break; | |
2233 | m_nonTrivialExpressionCount++; | |
2234 | m_nonLHSCount++; | |
2235 | int operatorToken = m_token.m_type; | |
2236 | next(TreeBuilder::DontBuildStrings); | |
2237 | ||
2238 | while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) { | |
2239 | ASSERT(operandStackDepth > 1); | |
2240 | ||
2241 | typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1); | |
2242 | typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2); | |
2243 | context.shrinkOperandStackBy(operandStackDepth, 2); | |
93a37866 | 2244 | context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs); |
6fe7ccc8 A |
2245 | context.operatorStackPop(operatorStackDepth); |
2246 | } | |
2247 | context.operatorStackAppend(operatorStackDepth, operatorToken, precedence); | |
2248 | } | |
2249 | while (operatorStackDepth) { | |
2250 | ASSERT(operandStackDepth > 1); | |
2251 | ||
2252 | typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1); | |
2253 | typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2); | |
2254 | context.shrinkOperandStackBy(operandStackDepth, 2); | |
93a37866 | 2255 | context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs); |
6fe7ccc8 A |
2256 | context.operatorStackPop(operatorStackDepth); |
2257 | } | |
2258 | return context.popOperandStack(operandStackDepth); | |
2259 | } | |
2260 | ||
2261 | template <typename LexerType> | |
81345200 | 2262 | template <class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeBuilder& context, bool complete) |
6fe7ccc8 A |
2263 | { |
2264 | bool wasIdent = false; | |
2265 | switch (m_token.m_type) { | |
2266 | namedProperty: | |
2267 | case IDENT: | |
2268 | wasIdent = true; | |
81345200 | 2269 | FALLTHROUGH; |
6fe7ccc8 A |
2270 | case STRING: { |
2271 | const Identifier* ident = m_token.m_data.ident; | |
ed1e77d3 | 2272 | unsigned getterOrSetterStartOffset = tokenStart(); |
93a37866 | 2273 | if (complete || (wasIdent && (*ident == m_vm->propertyNames->get || *ident == m_vm->propertyNames->set))) |
6fe7ccc8 A |
2274 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords); |
2275 | else | |
2276 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords); | |
ed1e77d3 | 2277 | |
6fe7ccc8 A |
2278 | if (match(COLON)) { |
2279 | next(); | |
2280 | TreeExpression node = parseAssignmentExpression(context); | |
81345200 | 2281 | failIfFalse(node, "Cannot parse expression for property declaration"); |
ed1e77d3 A |
2282 | context.setEndOffset(node, m_lexer->currentOffset()); |
2283 | return context.createProperty(ident, node, PropertyNode::Constant, PropertyNode::Unknown, complete); | |
6fe7ccc8 | 2284 | } |
ed1e77d3 A |
2285 | |
2286 | if (match(OPENPAREN)) { | |
2287 | auto method = parsePropertyMethod(context, ident); | |
2288 | propagateError(); | |
2289 | return context.createProperty(ident, method, PropertyNode::Constant, PropertyNode::KnownDirect, complete); | |
2290 | } | |
2291 | ||
81345200 | 2292 | failIfFalse(wasIdent, "Expected an identifier as property name"); |
ed1e77d3 A |
2293 | |
2294 | if (match(COMMA) || match(CLOSEBRACE)) { | |
2295 | JSTextPosition start = tokenStartPosition(); | |
2296 | JSTokenLocation location(tokenLocation()); | |
2297 | currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident); | |
2298 | TreeExpression node = context.createResolve(location, ident, start); | |
2299 | return context.createProperty(ident, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Shorthand), PropertyNode::KnownDirect, complete); | |
2300 | } | |
2301 | ||
6fe7ccc8 | 2302 | PropertyNode::Type type; |
93a37866 | 2303 | if (*ident == m_vm->propertyNames->get) |
6fe7ccc8 | 2304 | type = PropertyNode::Getter; |
93a37866 | 2305 | else if (*ident == m_vm->propertyNames->set) |
6fe7ccc8 A |
2306 | type = PropertyNode::Setter; |
2307 | else | |
81345200 | 2308 | failWithMessage("Expected a ':' following the property name '", ident->impl(), "'"); |
ed1e77d3 | 2309 | return parseGetterSetter(context, complete, type, getterOrSetterStartOffset); |
6fe7ccc8 | 2310 | } |
ed1e77d3 A |
2311 | case DOUBLE: |
2312 | case INTEGER: { | |
6fe7ccc8 A |
2313 | double propertyName = m_token.m_data.doubleValue; |
2314 | next(); | |
ed1e77d3 A |
2315 | |
2316 | if (match(OPENPAREN)) { | |
2317 | const Identifier& ident = m_parserArena.identifierArena().makeNumericIdentifier(const_cast<VM*>(m_vm), propertyName); | |
2318 | auto method = parsePropertyMethod(context, &ident); | |
2319 | propagateError(); | |
2320 | return context.createProperty(&ident, method, PropertyNode::Constant, PropertyNode::Unknown, complete); | |
2321 | } | |
2322 | ||
81345200 | 2323 | consumeOrFail(COLON, "Expected ':' after property name"); |
6fe7ccc8 | 2324 | TreeExpression node = parseAssignmentExpression(context); |
81345200 | 2325 | failIfFalse(node, "Cannot parse expression for property declaration"); |
ed1e77d3 A |
2326 | context.setEndOffset(node, m_lexer->currentOffset()); |
2327 | return context.createProperty(const_cast<VM*>(m_vm), m_parserArena, propertyName, node, PropertyNode::Constant, PropertyNode::Unknown, complete); | |
81345200 A |
2328 | } |
2329 | case OPENBRACKET: { | |
2330 | next(); | |
ed1e77d3 | 2331 | auto propertyName = parseAssignmentExpression(context); |
81345200 | 2332 | failIfFalse(propertyName, "Cannot parse computed property name"); |
81345200 | 2333 | handleProductionOrFail(CLOSEBRACKET, "]", "end", "computed property name"); |
ed1e77d3 A |
2334 | |
2335 | if (match(OPENPAREN)) { | |
2336 | auto method = parsePropertyMethod(context, &m_vm->propertyNames->nullIdentifier); | |
2337 | propagateError(); | |
2338 | return context.createProperty(propertyName, method, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::KnownDirect, complete); | |
2339 | } | |
2340 | ||
81345200 A |
2341 | consumeOrFail(COLON, "Expected ':' after property name"); |
2342 | TreeExpression node = parseAssignmentExpression(context); | |
2343 | failIfFalse(node, "Cannot parse expression for property declaration"); | |
ed1e77d3 A |
2344 | context.setEndOffset(node, m_lexer->currentOffset()); |
2345 | return context.createProperty(propertyName, node, static_cast<PropertyNode::Type>(PropertyNode::Constant | PropertyNode::Computed), PropertyNode::Unknown, complete); | |
6fe7ccc8 A |
2346 | } |
2347 | default: | |
81345200 | 2348 | failIfFalse(m_token.m_type & KeywordTokenFlag, "Expected a property name"); |
6fe7ccc8 A |
2349 | goto namedProperty; |
2350 | } | |
2351 | } | |
2352 | ||
ed1e77d3 A |
2353 | template <typename LexerType> |
2354 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePropertyMethod(TreeBuilder& context, const Identifier* methodName) | |
2355 | { | |
2356 | JSTokenLocation methodLocation(tokenLocation()); | |
2357 | unsigned methodStart = tokenStart(); | |
2358 | ParserFunctionInfo<TreeBuilder> methodInfo; | |
2359 | failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, MethodMode, false, ConstructorKind::None, SuperBinding::NotNeeded, methodStart, methodInfo, StandardFunctionParseType)), "Cannot parse this method"); | |
2360 | methodInfo.name = methodName; | |
2361 | return context.createFunctionExpr(methodLocation, methodInfo); | |
2362 | } | |
2363 | ||
2364 | template <typename LexerType> | |
2365 | template <class TreeBuilder> TreeProperty Parser<LexerType>::parseGetterSetter(TreeBuilder& context, bool strict, PropertyNode::Type type, unsigned getterOrSetterStartOffset, | |
2366 | ConstructorKind constructorKind, SuperBinding superBinding) | |
2367 | { | |
2368 | const Identifier* stringPropertyName = 0; | |
2369 | double numericPropertyName = 0; | |
2370 | if (m_token.m_type == IDENT || m_token.m_type == STRING) { | |
2371 | stringPropertyName = m_token.m_data.ident; | |
2372 | semanticFailIfTrue(superBinding == SuperBinding::Needed && *stringPropertyName == m_vm->propertyNames->prototype, | |
2373 | "Cannot declare a static method named 'prototype'"); | |
2374 | semanticFailIfTrue(superBinding == SuperBinding::Needed && *stringPropertyName == m_vm->propertyNames->constructor, | |
2375 | "Cannot declare a getter or setter named 'constructor'"); | |
2376 | } else if (m_token.m_type == DOUBLE || m_token.m_type == INTEGER) | |
2377 | numericPropertyName = m_token.m_data.doubleValue; | |
2378 | else | |
2379 | failDueToUnexpectedToken(); | |
2380 | JSTokenLocation location(tokenLocation()); | |
2381 | next(); | |
2382 | ParserFunctionInfo<TreeBuilder> info; | |
2383 | if (type & PropertyNode::Getter) { | |
2384 | failIfFalse(match(OPENPAREN), "Expected a parameter list for getter definition"); | |
2385 | failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, GetterMode, false, constructorKind, superBinding, | |
2386 | getterOrSetterStartOffset, info, StandardFunctionParseType)), "Cannot parse getter definition"); | |
2387 | } else { | |
2388 | failIfFalse(match(OPENPAREN), "Expected a parameter list for setter definition"); | |
2389 | failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, SetterMode, false, constructorKind, superBinding, | |
2390 | getterOrSetterStartOffset, info, StandardFunctionParseType)), "Cannot parse setter definition"); | |
2391 | } | |
2392 | if (stringPropertyName) | |
2393 | return context.createGetterOrSetterProperty(location, type, strict, stringPropertyName, info, superBinding); | |
2394 | return context.createGetterOrSetterProperty(const_cast<VM*>(m_vm), m_parserArena, location, type, strict, numericPropertyName, info, superBinding); | |
2395 | } | |
2396 | ||
2397 | template <typename LexerType> | |
2398 | template <class TreeBuilder> bool Parser<LexerType>::shouldCheckPropertyForUnderscoreProtoDuplicate(TreeBuilder& context, const TreeProperty& property) | |
2399 | { | |
2400 | if (m_syntaxAlreadyValidated) | |
2401 | return false; | |
2402 | ||
2403 | if (!context.getName(property)) | |
2404 | return false; | |
2405 | ||
2406 | // A Constant property that is not a Computed or Shorthand Constant property. | |
2407 | return context.getType(property) == PropertyNode::Constant; | |
2408 | } | |
2409 | ||
6fe7ccc8 A |
2410 | template <typename LexerType> |
2411 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseObjectLiteral(TreeBuilder& context) | |
2412 | { | |
81345200 A |
2413 | auto savePoint = createSavePoint(); |
2414 | consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings, "Expected opening '{' at the start of an object literal"); | |
93a37866 | 2415 | |
6fe7ccc8 | 2416 | int oldNonLHSCount = m_nonLHSCount; |
ed1e77d3 A |
2417 | |
2418 | JSTokenLocation location(tokenLocation()); | |
6fe7ccc8 A |
2419 | if (match(CLOSEBRACE)) { |
2420 | next(); | |
93a37866 | 2421 | return context.createObjectLiteral(location); |
6fe7ccc8 A |
2422 | } |
2423 | ||
81345200 A |
2424 | TreeProperty property = parseProperty(context, false); |
2425 | failIfFalse(property, "Cannot parse object literal property"); | |
ed1e77d3 A |
2426 | |
2427 | if (!m_syntaxAlreadyValidated && context.getType(property) & (PropertyNode::Getter | PropertyNode::Setter)) { | |
81345200 | 2428 | restoreSavePoint(savePoint); |
6fe7ccc8 A |
2429 | return parseStrictObjectLiteral(context); |
2430 | } | |
ed1e77d3 A |
2431 | |
2432 | bool seenUnderscoreProto = false; | |
2433 | if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property)) | |
2434 | seenUnderscoreProto = *context.getName(property) == m_vm->propertyNames->underscoreProto; | |
2435 | ||
93a37866 | 2436 | TreePropertyList propertyList = context.createPropertyList(location, property); |
6fe7ccc8 A |
2437 | TreePropertyList tail = propertyList; |
2438 | while (match(COMMA)) { | |
2439 | next(TreeBuilder::DontBuildStrings); | |
6fe7ccc8 A |
2440 | if (match(CLOSEBRACE)) |
2441 | break; | |
93a37866 | 2442 | JSTokenLocation propertyLocation(tokenLocation()); |
81345200 A |
2443 | property = parseProperty(context, false); |
2444 | failIfFalse(property, "Cannot parse object literal property"); | |
ed1e77d3 | 2445 | if (!m_syntaxAlreadyValidated && context.getType(property) & (PropertyNode::Getter | PropertyNode::Setter)) { |
81345200 | 2446 | restoreSavePoint(savePoint); |
6fe7ccc8 A |
2447 | return parseStrictObjectLiteral(context); |
2448 | } | |
ed1e77d3 A |
2449 | if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property)) { |
2450 | if (*context.getName(property) == m_vm->propertyNames->underscoreProto) { | |
2451 | semanticFailIfTrue(seenUnderscoreProto, "Attempted to redefine __proto__ property"); | |
2452 | seenUnderscoreProto = true; | |
2453 | } | |
2454 | } | |
93a37866 | 2455 | tail = context.createPropertyList(propertyLocation, property, tail); |
6fe7ccc8 | 2456 | } |
93a37866 A |
2457 | |
2458 | location = tokenLocation(); | |
81345200 | 2459 | handleProductionOrFail(CLOSEBRACE, "}", "end", "object literal"); |
6fe7ccc8 A |
2460 | |
2461 | m_nonLHSCount = oldNonLHSCount; | |
2462 | ||
93a37866 | 2463 | return context.createObjectLiteral(location, propertyList); |
6fe7ccc8 A |
2464 | } |
2465 | ||
2466 | template <typename LexerType> | |
2467 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseStrictObjectLiteral(TreeBuilder& context) | |
2468 | { | |
81345200 | 2469 | consumeOrFail(OPENBRACE, "Expected opening '{' at the start of an object literal"); |
6fe7ccc8 A |
2470 | |
2471 | int oldNonLHSCount = m_nonLHSCount; | |
2472 | ||
93a37866 | 2473 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
2474 | if (match(CLOSEBRACE)) { |
2475 | next(); | |
93a37866 | 2476 | return context.createObjectLiteral(location); |
6fe7ccc8 A |
2477 | } |
2478 | ||
81345200 A |
2479 | TreeProperty property = parseProperty(context, true); |
2480 | failIfFalse(property, "Cannot parse object literal property"); | |
ed1e77d3 A |
2481 | |
2482 | bool seenUnderscoreProto = false; | |
2483 | if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property)) | |
2484 | seenUnderscoreProto = *context.getName(property) == m_vm->propertyNames->underscoreProto; | |
2485 | ||
93a37866 | 2486 | TreePropertyList propertyList = context.createPropertyList(location, property); |
6fe7ccc8 A |
2487 | TreePropertyList tail = propertyList; |
2488 | while (match(COMMA)) { | |
2489 | next(); | |
6fe7ccc8 A |
2490 | if (match(CLOSEBRACE)) |
2491 | break; | |
93a37866 | 2492 | JSTokenLocation propertyLocation(tokenLocation()); |
81345200 A |
2493 | property = parseProperty(context, true); |
2494 | failIfFalse(property, "Cannot parse object literal property"); | |
ed1e77d3 A |
2495 | if (shouldCheckPropertyForUnderscoreProtoDuplicate(context, property)) { |
2496 | if (*context.getName(property) == m_vm->propertyNames->underscoreProto) { | |
2497 | semanticFailIfTrue(seenUnderscoreProto, "Attempted to redefine __proto__ property"); | |
2498 | seenUnderscoreProto = true; | |
6fe7ccc8 A |
2499 | } |
2500 | } | |
93a37866 | 2501 | tail = context.createPropertyList(propertyLocation, property, tail); |
6fe7ccc8 | 2502 | } |
93a37866 A |
2503 | |
2504 | location = tokenLocation(); | |
81345200 | 2505 | handleProductionOrFail(CLOSEBRACE, "}", "end", "object literal"); |
6fe7ccc8 A |
2506 | |
2507 | m_nonLHSCount = oldNonLHSCount; | |
2508 | ||
93a37866 | 2509 | return context.createObjectLiteral(location, propertyList); |
6fe7ccc8 A |
2510 | } |
2511 | ||
2512 | template <typename LexerType> | |
2513 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrayLiteral(TreeBuilder& context) | |
2514 | { | |
81345200 | 2515 | consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings, "Expected an opening '[' at the beginning of an array literal"); |
6fe7ccc8 A |
2516 | |
2517 | int oldNonLHSCount = m_nonLHSCount; | |
2518 | ||
2519 | int elisions = 0; | |
2520 | while (match(COMMA)) { | |
2521 | next(TreeBuilder::DontBuildStrings); | |
2522 | elisions++; | |
2523 | } | |
2524 | if (match(CLOSEBRACKET)) { | |
93a37866 | 2525 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2526 | next(TreeBuilder::DontBuildStrings); |
93a37866 | 2527 | return context.createArray(location, elisions); |
6fe7ccc8 A |
2528 | } |
2529 | ||
81345200 A |
2530 | TreeExpression elem; |
2531 | if (UNLIKELY(match(DOTDOTDOT))) { | |
2532 | auto spreadLocation = m_token.m_location; | |
2533 | auto start = m_token.m_startPosition; | |
2534 | auto divot = m_token.m_endPosition; | |
2535 | next(); | |
2536 | auto spreadExpr = parseAssignmentExpression(context); | |
2537 | failIfFalse(spreadExpr, "Cannot parse subject of a spread operation"); | |
2538 | elem = context.createSpreadExpression(spreadLocation, spreadExpr, start, divot, m_lastTokenEndPosition); | |
2539 | } else | |
2540 | elem = parseAssignmentExpression(context); | |
2541 | failIfFalse(elem, "Cannot parse array literal element"); | |
6fe7ccc8 A |
2542 | typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem); |
2543 | typename TreeBuilder::ElementList tail = elementList; | |
2544 | elisions = 0; | |
2545 | while (match(COMMA)) { | |
2546 | next(TreeBuilder::DontBuildStrings); | |
2547 | elisions = 0; | |
2548 | ||
2549 | while (match(COMMA)) { | |
2550 | next(); | |
2551 | elisions++; | |
2552 | } | |
2553 | ||
2554 | if (match(CLOSEBRACKET)) { | |
93a37866 | 2555 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2556 | next(TreeBuilder::DontBuildStrings); |
93a37866 | 2557 | return context.createArray(location, elisions, elementList); |
6fe7ccc8 | 2558 | } |
81345200 A |
2559 | if (UNLIKELY(match(DOTDOTDOT))) { |
2560 | auto spreadLocation = m_token.m_location; | |
2561 | auto start = m_token.m_startPosition; | |
2562 | auto divot = m_token.m_endPosition; | |
2563 | next(); | |
2564 | TreeExpression elem = parseAssignmentExpression(context); | |
2565 | failIfFalse(elem, "Cannot parse subject of a spread operation"); | |
2566 | auto spread = context.createSpreadExpression(spreadLocation, elem, start, divot, m_lastTokenEndPosition); | |
2567 | tail = context.createElementList(tail, elisions, spread); | |
2568 | continue; | |
2569 | } | |
6fe7ccc8 | 2570 | TreeExpression elem = parseAssignmentExpression(context); |
81345200 | 2571 | failIfFalse(elem, "Cannot parse array literal element"); |
6fe7ccc8 A |
2572 | tail = context.createElementList(tail, elisions, elem); |
2573 | } | |
93a37866 A |
2574 | |
2575 | JSTokenLocation location(tokenLocation()); | |
81345200 A |
2576 | if (!consume(CLOSEBRACKET)) { |
2577 | failIfFalse(match(DOTDOTDOT), "Expected either a closing ']' or a ',' following an array element"); | |
2578 | semanticFail("The '...' operator should come before a target expression"); | |
2579 | } | |
6fe7ccc8 A |
2580 | |
2581 | m_nonLHSCount = oldNonLHSCount; | |
2582 | ||
93a37866 | 2583 | return context.createArray(location, elementList); |
6fe7ccc8 A |
2584 | } |
2585 | ||
ed1e77d3 A |
2586 | #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) |
2587 | template <typename LexerType> | |
2588 | template <class TreeBuilder> typename TreeBuilder::TemplateString Parser<LexerType>::parseTemplateString(TreeBuilder& context, bool isTemplateHead, typename LexerType::RawStringsBuildMode rawStringsBuildMode, bool& elementIsTail) | |
2589 | { | |
2590 | if (!isTemplateHead) { | |
2591 | matchOrFail(CLOSEBRACE, "Expected a closing '}' following an expression in template literal"); | |
2592 | // Re-scan the token to recognize it as Template Element. | |
2593 | m_token.m_type = m_lexer->scanTrailingTemplateString(&m_token, rawStringsBuildMode); | |
2594 | } | |
2595 | matchOrFail(TEMPLATE, "Expected an template element"); | |
2596 | const Identifier* cooked = m_token.m_data.cooked; | |
2597 | const Identifier* raw = m_token.m_data.raw; | |
2598 | elementIsTail = m_token.m_data.isTail; | |
2599 | JSTokenLocation location(tokenLocation()); | |
2600 | next(); | |
2601 | return context.createTemplateString(location, *cooked, *raw); | |
2602 | } | |
2603 | ||
2604 | template <typename LexerType> | |
2605 | template <class TreeBuilder> typename TreeBuilder::TemplateLiteral Parser<LexerType>::parseTemplateLiteral(TreeBuilder& context, typename LexerType::RawStringsBuildMode rawStringsBuildMode) | |
2606 | { | |
2607 | JSTokenLocation location(tokenLocation()); | |
2608 | bool elementIsTail = false; | |
2609 | ||
2610 | auto headTemplateString = parseTemplateString(context, true, rawStringsBuildMode, elementIsTail); | |
2611 | failIfFalse(headTemplateString, "Cannot parse head template element"); | |
2612 | ||
2613 | typename TreeBuilder::TemplateStringList templateStringList = context.createTemplateStringList(headTemplateString); | |
2614 | typename TreeBuilder::TemplateStringList templateStringTail = templateStringList; | |
2615 | ||
2616 | if (elementIsTail) | |
2617 | return context.createTemplateLiteral(location, templateStringList); | |
2618 | ||
2619 | failIfTrue(match(CLOSEBRACE), "Template literal expression cannot be empty"); | |
2620 | TreeExpression expression = parseExpression(context); | |
2621 | failIfFalse(expression, "Cannot parse expression in template literal"); | |
2622 | ||
2623 | typename TreeBuilder::TemplateExpressionList templateExpressionList = context.createTemplateExpressionList(expression); | |
2624 | typename TreeBuilder::TemplateExpressionList templateExpressionTail = templateExpressionList; | |
2625 | ||
2626 | auto templateString = parseTemplateString(context, false, rawStringsBuildMode, elementIsTail); | |
2627 | failIfFalse(templateString, "Cannot parse template element"); | |
2628 | templateStringTail = context.createTemplateStringList(templateStringTail, templateString); | |
2629 | ||
2630 | while (!elementIsTail) { | |
2631 | failIfTrue(match(CLOSEBRACE), "Template literal expression cannot be empty"); | |
2632 | TreeExpression expression = parseExpression(context); | |
2633 | failIfFalse(expression, "Cannot parse expression in template literal"); | |
2634 | ||
2635 | templateExpressionTail = context.createTemplateExpressionList(templateExpressionTail, expression); | |
2636 | ||
2637 | auto templateString = parseTemplateString(context, false, rawStringsBuildMode, elementIsTail); | |
2638 | failIfFalse(templateString, "Cannot parse template element"); | |
2639 | templateStringTail = context.createTemplateStringList(templateStringTail, templateString); | |
2640 | } | |
2641 | ||
2642 | return context.createTemplateLiteral(location, templateStringList, templateExpressionList); | |
2643 | } | |
2644 | #endif | |
2645 | ||
6fe7ccc8 A |
2646 | template <typename LexerType> |
2647 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpression(TreeBuilder& context) | |
2648 | { | |
2649 | failIfStackOverflow(); | |
2650 | switch (m_token.m_type) { | |
ed1e77d3 A |
2651 | case FUNCTION: { |
2652 | JSTokenLocation location(tokenLocation()); | |
2653 | unsigned functionKeywordStart = tokenStart(); | |
2654 | next(); | |
2655 | ParserFunctionInfo<TreeBuilder> info; | |
2656 | info.name = &m_vm->propertyNames->nullIdentifier; | |
2657 | failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, false, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, StandardFunctionParseType)), "Cannot parse function expression"); | |
2658 | return context.createFunctionExpr(location, info); | |
2659 | } | |
2660 | #if ENABLE(ES6_CLASS_SYNTAX) | |
2661 | case CLASSTOKEN: { | |
2662 | ParserClassInfo<TreeBuilder> info; | |
2663 | return parseClass(context, FunctionNoRequirements, info); | |
2664 | } | |
2665 | #endif | |
6fe7ccc8 A |
2666 | case OPENBRACE: |
2667 | if (strictMode()) | |
2668 | return parseStrictObjectLiteral(context); | |
2669 | return parseObjectLiteral(context); | |
2670 | case OPENBRACKET: | |
2671 | return parseArrayLiteral(context); | |
2672 | case OPENPAREN: { | |
2673 | next(); | |
2674 | int oldNonLHSCount = m_nonLHSCount; | |
2675 | TreeExpression result = parseExpression(context); | |
2676 | m_nonLHSCount = oldNonLHSCount; | |
81345200 | 2677 | handleProductionOrFail(CLOSEPAREN, ")", "end", "compound expression"); |
6fe7ccc8 A |
2678 | return result; |
2679 | } | |
2680 | case THISTOKEN: { | |
93a37866 | 2681 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2682 | next(); |
ed1e77d3 | 2683 | return context.thisExpr(location, m_thisTDZMode); |
6fe7ccc8 A |
2684 | } |
2685 | case IDENT: { | |
81345200 | 2686 | JSTextPosition start = tokenStartPosition(); |
6fe7ccc8 | 2687 | const Identifier* ident = m_token.m_data.ident; |
93a37866 | 2688 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2689 | next(); |
93a37866 | 2690 | currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident); |
6fe7ccc8 | 2691 | m_lastIdentifier = ident; |
81345200 | 2692 | return context.createResolve(location, ident, start); |
6fe7ccc8 A |
2693 | } |
2694 | case STRING: { | |
2695 | const Identifier* ident = m_token.m_data.ident; | |
93a37866 | 2696 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2697 | next(); |
93a37866 | 2698 | return context.createString(location, ident); |
6fe7ccc8 | 2699 | } |
ed1e77d3 | 2700 | case DOUBLE: { |
6fe7ccc8 | 2701 | double d = m_token.m_data.doubleValue; |
93a37866 | 2702 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2703 | next(); |
ed1e77d3 A |
2704 | return context.createDoubleExpr(location, d); |
2705 | } | |
2706 | case INTEGER: { | |
2707 | double d = m_token.m_data.doubleValue; | |
2708 | JSTokenLocation location(tokenLocation()); | |
2709 | next(); | |
2710 | return context.createIntegerExpr(location, d); | |
6fe7ccc8 A |
2711 | } |
2712 | case NULLTOKEN: { | |
93a37866 | 2713 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2714 | next(); |
93a37866 | 2715 | return context.createNull(location); |
6fe7ccc8 A |
2716 | } |
2717 | case TRUETOKEN: { | |
93a37866 | 2718 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2719 | next(); |
93a37866 | 2720 | return context.createBoolean(location, true); |
6fe7ccc8 A |
2721 | } |
2722 | case FALSETOKEN: { | |
93a37866 | 2723 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2724 | next(); |
93a37866 | 2725 | return context.createBoolean(location, false); |
6fe7ccc8 A |
2726 | } |
2727 | case DIVEQUAL: | |
2728 | case DIVIDE: { | |
2729 | /* regexp */ | |
2730 | const Identifier* pattern; | |
2731 | const Identifier* flags; | |
2732 | if (match(DIVEQUAL)) | |
81345200 | 2733 | failIfFalse(m_lexer->scanRegExp(pattern, flags, '='), "Invalid regular expression"); |
6fe7ccc8 | 2734 | else |
81345200 | 2735 | failIfFalse(m_lexer->scanRegExp(pattern, flags), "Invalid regular expression"); |
6fe7ccc8 | 2736 | |
81345200 | 2737 | JSTextPosition start = tokenStartPosition(); |
93a37866 | 2738 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2739 | next(); |
81345200 | 2740 | TreeExpression re = context.createRegExp(location, *pattern, *flags, start); |
6fe7ccc8 | 2741 | if (!re) { |
93a37866 | 2742 | const char* yarrErrorMsg = Yarr::checkSyntax(pattern->string()); |
81345200 | 2743 | regexFail(yarrErrorMsg); |
6fe7ccc8 A |
2744 | } |
2745 | return re; | |
2746 | } | |
ed1e77d3 A |
2747 | #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) |
2748 | case TEMPLATE: | |
2749 | return parseTemplateLiteral(context, LexerType::RawStringsBuildMode::DontBuildRawStrings); | |
2750 | #endif | |
6fe7ccc8 | 2751 | default: |
81345200 | 2752 | failDueToUnexpectedToken(); |
6fe7ccc8 A |
2753 | } |
2754 | } | |
2755 | ||
2756 | template <typename LexerType> | |
81345200 | 2757 | template <class TreeBuilder> TreeArguments Parser<LexerType>::parseArguments(TreeBuilder& context, SpreadMode mode) |
6fe7ccc8 | 2758 | { |
81345200 | 2759 | consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings, "Expected opening '(' at start of argument list"); |
93a37866 | 2760 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
2761 | if (match(CLOSEPAREN)) { |
2762 | next(TreeBuilder::DontBuildStrings); | |
2763 | return context.createArguments(); | |
2764 | } | |
81345200 A |
2765 | if (match(DOTDOTDOT) && mode == AllowSpread) { |
2766 | JSTokenLocation spreadLocation(tokenLocation()); | |
2767 | auto start = m_token.m_startPosition; | |
2768 | auto divot = m_token.m_endPosition; | |
2769 | next(); | |
2770 | auto spreadExpr = parseAssignmentExpression(context); | |
2771 | auto end = m_lastTokenEndPosition; | |
2772 | if (!spreadExpr) | |
2773 | failWithMessage("Cannot parse spread expression"); | |
2774 | if (!consume(CLOSEPAREN)) { | |
2775 | if (match(COMMA)) | |
2776 | semanticFail("Spread operator may only be applied to the last argument passed to a function"); | |
2777 | handleProductionOrFail(CLOSEPAREN, ")", "end", "argument list"); | |
2778 | } | |
2779 | auto spread = context.createSpreadExpression(spreadLocation, spreadExpr, start, divot, end); | |
2780 | TreeArgumentsList argList = context.createArgumentsList(location, spread); | |
2781 | return context.createArguments(argList); | |
2782 | } | |
6fe7ccc8 | 2783 | TreeExpression firstArg = parseAssignmentExpression(context); |
81345200 | 2784 | failIfFalse(firstArg, "Cannot parse function argument"); |
6fe7ccc8 | 2785 | |
93a37866 | 2786 | TreeArgumentsList argList = context.createArgumentsList(location, firstArg); |
6fe7ccc8 A |
2787 | TreeArgumentsList tail = argList; |
2788 | while (match(COMMA)) { | |
93a37866 | 2789 | JSTokenLocation argumentLocation(tokenLocation()); |
6fe7ccc8 A |
2790 | next(TreeBuilder::DontBuildStrings); |
2791 | TreeExpression arg = parseAssignmentExpression(context); | |
81345200 | 2792 | failIfFalse(arg, "Cannot parse function argument"); |
93a37866 | 2793 | tail = context.createArgumentsList(argumentLocation, tail, arg); |
6fe7ccc8 | 2794 | } |
81345200 A |
2795 | semanticFailIfTrue(match(DOTDOTDOT), "The '...' operator should come before the target expression"); |
2796 | handleProductionOrFail(CLOSEPAREN, ")", "end", "argument list"); | |
6fe7ccc8 A |
2797 | return context.createArguments(argList); |
2798 | } | |
2799 | ||
2800 | template <typename LexerType> | |
2801 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpression(TreeBuilder& context) | |
2802 | { | |
2803 | TreeExpression base = 0; | |
81345200 | 2804 | JSTextPosition expressionStart = tokenStartPosition(); |
6fe7ccc8 | 2805 | int newCount = 0; |
ed1e77d3 | 2806 | JSTokenLocation startLocation = tokenLocation(); |
93a37866 | 2807 | JSTokenLocation location; |
6fe7ccc8 A |
2808 | while (match(NEW)) { |
2809 | next(); | |
2810 | newCount++; | |
2811 | } | |
ed1e77d3 A |
2812 | |
2813 | #if ENABLE(ES6_CLASS_SYNTAX) | |
2814 | bool baseIsSuper = match(SUPER); | |
2815 | semanticFailIfTrue(baseIsSuper && newCount, "Cannot use new with super"); | |
2816 | #else | |
2817 | bool baseIsSuper = false; | |
2818 | #endif | |
2819 | ||
2820 | if (baseIsSuper) { | |
2821 | base = context.superExpr(location); | |
6fe7ccc8 | 2822 | next(); |
ed1e77d3 | 2823 | currentScope()->setNeedsSuperBinding(); |
6fe7ccc8 A |
2824 | } else |
2825 | base = parsePrimaryExpression(context); | |
ed1e77d3 | 2826 | |
81345200 | 2827 | failIfFalse(base, "Cannot parse base expression"); |
6fe7ccc8 | 2828 | while (true) { |
93a37866 | 2829 | location = tokenLocation(); |
6fe7ccc8 A |
2830 | switch (m_token.m_type) { |
2831 | case OPENBRACKET: { | |
2832 | m_nonTrivialExpressionCount++; | |
81345200 | 2833 | JSTextPosition expressionEnd = lastTokenEndPosition(); |
6fe7ccc8 A |
2834 | next(); |
2835 | int nonLHSCount = m_nonLHSCount; | |
2836 | int initialAssignments = m_assignmentCount; | |
2837 | TreeExpression property = parseExpression(context); | |
81345200 A |
2838 | failIfFalse(property, "Cannot parse subscript expression"); |
2839 | base = context.createBracketAccess(location, base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEndPosition()); | |
2840 | handleProductionOrFail(CLOSEBRACKET, "]", "end", "subscript expression"); | |
6fe7ccc8 A |
2841 | m_nonLHSCount = nonLHSCount; |
2842 | break; | |
2843 | } | |
2844 | case OPENPAREN: { | |
2845 | m_nonTrivialExpressionCount++; | |
2846 | int nonLHSCount = m_nonLHSCount; | |
2847 | if (newCount) { | |
2848 | newCount--; | |
81345200 A |
2849 | JSTextPosition expressionEnd = lastTokenEndPosition(); |
2850 | TreeArguments arguments = parseArguments(context, AllowSpread); | |
2851 | failIfFalse(arguments, "Cannot parse call arguments"); | |
2852 | base = context.createNewExpr(location, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition()); | |
6fe7ccc8 | 2853 | } else { |
81345200 A |
2854 | JSTextPosition expressionEnd = lastTokenEndPosition(); |
2855 | TreeArguments arguments = parseArguments(context, AllowSpread); | |
2856 | failIfFalse(arguments, "Cannot parse call arguments"); | |
ed1e77d3 A |
2857 | if (baseIsSuper) |
2858 | currentScope()->setHasDirectSuper(); | |
2859 | base = context.makeFunctionCallNode(startLocation, base, arguments, expressionStart, expressionEnd, lastTokenEndPosition()); | |
6fe7ccc8 A |
2860 | } |
2861 | m_nonLHSCount = nonLHSCount; | |
2862 | break; | |
2863 | } | |
2864 | case DOT: { | |
2865 | m_nonTrivialExpressionCount++; | |
81345200 | 2866 | JSTextPosition expressionEnd = lastTokenEndPosition(); |
6fe7ccc8 | 2867 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords); |
81345200 A |
2868 | matchOrFail(IDENT, "Expected a property name after '.'"); |
2869 | base = context.createDotAccess(location, base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEndPosition()); | |
6fe7ccc8 A |
2870 | next(); |
2871 | break; | |
2872 | } | |
ed1e77d3 A |
2873 | #if ENABLE(ES6_TEMPLATE_LITERAL_SYNTAX) |
2874 | case TEMPLATE: { | |
2875 | semanticFailIfTrue(baseIsSuper, "Cannot use super as tag for tagged templates"); | |
2876 | JSTextPosition expressionEnd = lastTokenEndPosition(); | |
2877 | int nonLHSCount = m_nonLHSCount; | |
2878 | typename TreeBuilder::TemplateLiteral templateLiteral = parseTemplateLiteral(context, LexerType::RawStringsBuildMode::BuildRawStrings); | |
2879 | failIfFalse(templateLiteral, "Cannot parse template literal"); | |
2880 | base = context.createTaggedTemplate(location, base, templateLiteral, expressionStart, expressionEnd, lastTokenEndPosition()); | |
2881 | m_nonLHSCount = nonLHSCount; | |
2882 | break; | |
2883 | } | |
2884 | #endif | |
6fe7ccc8 A |
2885 | default: |
2886 | goto endMemberExpression; | |
2887 | } | |
ed1e77d3 | 2888 | baseIsSuper = false; |
6fe7ccc8 A |
2889 | } |
2890 | endMemberExpression: | |
ed1e77d3 | 2891 | semanticFailIfTrue(baseIsSuper, "Cannot reference super"); |
6fe7ccc8 | 2892 | while (newCount--) |
81345200 | 2893 | base = context.createNewExpr(location, base, expressionStart, lastTokenEndPosition()); |
6fe7ccc8 A |
2894 | return base; |
2895 | } | |
2896 | ||
ed1e77d3 A |
2897 | #if ENABLE(ES6_ARROWFUNCTION_SYNTAX) |
2898 | template <typename LexerType> | |
2899 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrowFunctionExpression(TreeBuilder& context) | |
2900 | { | |
2901 | JSTokenLocation location; | |
2902 | ||
2903 | unsigned functionKeywordStart = tokenStart(); | |
2904 | location = tokenLocation(); | |
2905 | ParserFunctionInfo<TreeBuilder> info; | |
2906 | info.name = &m_vm->propertyNames->nullIdentifier; | |
2907 | failIfFalse((parseFunctionInfo(context, FunctionNoRequirements, FunctionMode, true, ConstructorKind::None, SuperBinding::NotNeeded, functionKeywordStart, info, ArrowFunctionParseType)), "Cannot parse arrow function expression"); | |
2908 | ||
2909 | return context.createArrowFunctionExpr(location, info); | |
2910 | } | |
2911 | #endif | |
2912 | ||
81345200 A |
2913 | static const char* operatorString(bool prefix, unsigned tok) |
2914 | { | |
2915 | switch (tok) { | |
2916 | case MINUSMINUS: | |
2917 | case AUTOMINUSMINUS: | |
2918 | return prefix ? "prefix-decrement" : "decrement"; | |
2919 | ||
2920 | case PLUSPLUS: | |
2921 | case AUTOPLUSPLUS: | |
2922 | return prefix ? "prefix-increment" : "increment"; | |
2923 | ||
2924 | case EXCLAMATION: | |
2925 | return "logical-not"; | |
2926 | ||
2927 | case TILDE: | |
2928 | return "bitwise-not"; | |
2929 | ||
2930 | case TYPEOF: | |
2931 | return "typeof"; | |
2932 | ||
2933 | case VOIDTOKEN: | |
2934 | return "void"; | |
2935 | ||
2936 | case DELETETOKEN: | |
2937 | return "delete"; | |
2938 | } | |
2939 | RELEASE_ASSERT_NOT_REACHED(); | |
2940 | return "error"; | |
2941 | } | |
2942 | ||
6fe7ccc8 A |
2943 | template <typename LexerType> |
2944 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpression(TreeBuilder& context) | |
2945 | { | |
2946 | typename TreeBuilder::UnaryExprContext unaryExprContext(context); | |
2947 | AllowInOverride allowInOverride(this); | |
2948 | int tokenStackDepth = 0; | |
2949 | bool modifiesExpr = false; | |
2950 | bool requiresLExpr = false; | |
81345200 | 2951 | unsigned lastOperator = 0; |
6fe7ccc8 A |
2952 | while (isUnaryOp(m_token.m_type)) { |
2953 | if (strictMode()) { | |
2954 | switch (m_token.m_type) { | |
2955 | case PLUSPLUS: | |
2956 | case MINUSMINUS: | |
2957 | case AUTOPLUSPLUS: | |
2958 | case AUTOMINUSMINUS: | |
81345200 | 2959 | semanticFailIfTrue(requiresLExpr, "The ", operatorString(true, lastOperator), " operator requires a reference expression"); |
6fe7ccc8 A |
2960 | modifiesExpr = true; |
2961 | requiresLExpr = true; | |
2962 | break; | |
2963 | case DELETETOKEN: | |
81345200 | 2964 | semanticFailIfTrue(requiresLExpr, "The ", operatorString(true, lastOperator), " operator requires a reference expression"); |
6fe7ccc8 A |
2965 | requiresLExpr = true; |
2966 | break; | |
2967 | default: | |
81345200 | 2968 | semanticFailIfTrue(requiresLExpr, "The ", operatorString(true, lastOperator), " operator requires a reference expression"); |
6fe7ccc8 A |
2969 | break; |
2970 | } | |
2971 | } | |
81345200 | 2972 | lastOperator = m_token.m_type; |
6fe7ccc8 | 2973 | m_nonLHSCount++; |
81345200 | 2974 | context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStartPosition()); |
6fe7ccc8 A |
2975 | next(); |
2976 | m_nonTrivialExpressionCount++; | |
2977 | } | |
81345200 A |
2978 | JSTextPosition subExprStart = tokenStartPosition(); |
2979 | ASSERT(subExprStart.offset >= subExprStart.lineStartOffset); | |
93a37866 | 2980 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 2981 | TreeExpression expr = parseMemberExpression(context); |
81345200 A |
2982 | if (!expr) { |
2983 | if (lastOperator) | |
2984 | failWithMessage("Cannot parse subexpression of ", operatorString(true, lastOperator), "operator"); | |
2985 | failWithMessage("Cannot parse member expression"); | |
2986 | } | |
6fe7ccc8 A |
2987 | bool isEvalOrArguments = false; |
2988 | if (strictMode() && !m_syntaxAlreadyValidated) { | |
2989 | if (context.isResolve(expr)) | |
93a37866 | 2990 | isEvalOrArguments = *m_lastIdentifier == m_vm->propertyNames->eval || *m_lastIdentifier == m_vm->propertyNames->arguments; |
6fe7ccc8 | 2991 | } |
81345200 | 2992 | failIfTrueIfStrict(isEvalOrArguments && modifiesExpr, "Cannot modify '", m_lastIdentifier->impl(), "' in strict mode"); |
6fe7ccc8 A |
2993 | switch (m_token.m_type) { |
2994 | case PLUSPLUS: | |
2995 | m_nonTrivialExpressionCount++; | |
2996 | m_nonLHSCount++; | |
81345200 | 2997 | expr = context.makePostfixNode(location, expr, OpPlusPlus, subExprStart, lastTokenEndPosition(), tokenEndPosition()); |
6fe7ccc8 | 2998 | m_assignmentCount++; |
81345200 A |
2999 | failIfTrueIfStrict(isEvalOrArguments, "Cannot modify '", m_lastIdentifier->impl(), "' in strict mode"); |
3000 | semanticFailIfTrue(requiresLExpr, "The ", operatorString(false, lastOperator), " operator requires a reference expression"); | |
3001 | lastOperator = PLUSPLUS; | |
6fe7ccc8 A |
3002 | next(); |
3003 | break; | |
3004 | case MINUSMINUS: | |
3005 | m_nonTrivialExpressionCount++; | |
3006 | m_nonLHSCount++; | |
81345200 | 3007 | expr = context.makePostfixNode(location, expr, OpMinusMinus, subExprStart, lastTokenEndPosition(), tokenEndPosition()); |
6fe7ccc8 | 3008 | m_assignmentCount++; |
81345200 A |
3009 | failIfTrueIfStrict(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode"); |
3010 | semanticFailIfTrue(requiresLExpr, "The ", operatorString(false, lastOperator), " operator requires a reference expression"); | |
3011 | lastOperator = PLUSPLUS; | |
6fe7ccc8 A |
3012 | next(); |
3013 | break; | |
3014 | default: | |
3015 | break; | |
3016 | } | |
3017 | ||
81345200 | 3018 | JSTextPosition end = lastTokenEndPosition(); |
93a37866 | 3019 | |
6fe7ccc8 A |
3020 | if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode())) |
3021 | return expr; | |
93a37866 A |
3022 | |
3023 | location = tokenLocation(); | |
3024 | location.line = m_lexer->lastLineNumber(); | |
6fe7ccc8 A |
3025 | while (tokenStackDepth) { |
3026 | switch (context.unaryTokenStackLastType(tokenStackDepth)) { | |
3027 | case EXCLAMATION: | |
93a37866 | 3028 | expr = context.createLogicalNot(location, expr); |
6fe7ccc8 A |
3029 | break; |
3030 | case TILDE: | |
93a37866 | 3031 | expr = context.makeBitwiseNotNode(location, expr); |
6fe7ccc8 A |
3032 | break; |
3033 | case MINUS: | |
93a37866 | 3034 | expr = context.makeNegateNode(location, expr); |
6fe7ccc8 A |
3035 | break; |
3036 | case PLUS: | |
93a37866 | 3037 | expr = context.createUnaryPlus(location, expr); |
6fe7ccc8 A |
3038 | break; |
3039 | case PLUSPLUS: | |
3040 | case AUTOPLUSPLUS: | |
81345200 | 3041 | expr = context.makePrefixNode(location, expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end); |
6fe7ccc8 A |
3042 | m_assignmentCount++; |
3043 | break; | |
3044 | case MINUSMINUS: | |
3045 | case AUTOMINUSMINUS: | |
81345200 | 3046 | expr = context.makePrefixNode(location, expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end); |
6fe7ccc8 A |
3047 | m_assignmentCount++; |
3048 | break; | |
3049 | case TYPEOF: | |
93a37866 | 3050 | expr = context.makeTypeOfNode(location, expr); |
6fe7ccc8 A |
3051 | break; |
3052 | case VOIDTOKEN: | |
93a37866 | 3053 | expr = context.createVoid(location, expr); |
6fe7ccc8 A |
3054 | break; |
3055 | case DELETETOKEN: | |
81345200 A |
3056 | failIfTrueIfStrict(context.isResolve(expr), "Cannot delete unqualified property '", m_lastIdentifier->impl(), "' in strict mode"); |
3057 | expr = context.makeDeleteNode(location, expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end); | |
6fe7ccc8 A |
3058 | break; |
3059 | default: | |
3060 | // If we get here something has gone horribly horribly wrong | |
3061 | CRASH(); | |
3062 | } | |
3063 | subExprStart = context.unaryTokenStackLastStart(tokenStackDepth); | |
3064 | context.unaryTokenStackRemoveLast(tokenStackDepth); | |
3065 | } | |
3066 | return expr; | |
3067 | } | |
3068 | ||
6fe7ccc8 | 3069 | |
81345200 A |
3070 | template <typename LexerType> void Parser<LexerType>::printUnexpectedTokenText(WTF::PrintStream& out) |
3071 | { | |
3072 | switch (m_token.m_type) { | |
3073 | case EOFTOK: | |
3074 | out.print("Unexpected end of script"); | |
3075 | return; | |
3076 | case UNTERMINATED_IDENTIFIER_ESCAPE_ERRORTOK: | |
3077 | case UNTERMINATED_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK: | |
3078 | out.print("Incomplete unicode escape in identifier: '", getToken(), "'"); | |
3079 | return; | |
3080 | case UNTERMINATED_MULTILINE_COMMENT_ERRORTOK: | |
3081 | out.print("Unterminated multiline comment"); | |
3082 | return; | |
3083 | case UNTERMINATED_NUMERIC_LITERAL_ERRORTOK: | |
3084 | out.print("Unterminated numeric literal '", getToken(), "'"); | |
3085 | return; | |
3086 | case UNTERMINATED_STRING_LITERAL_ERRORTOK: | |
3087 | out.print("Unterminated string literal '", getToken(), "'"); | |
3088 | return; | |
3089 | case INVALID_IDENTIFIER_ESCAPE_ERRORTOK: | |
3090 | out.print("Invalid escape in identifier: '", getToken(), "'"); | |
3091 | return; | |
3092 | case INVALID_IDENTIFIER_UNICODE_ESCAPE_ERRORTOK: | |
3093 | out.print("Invalid unicode escape in identifier: '", getToken(), "'"); | |
3094 | return; | |
3095 | case INVALID_NUMERIC_LITERAL_ERRORTOK: | |
3096 | out.print("Invalid numeric literal: '", getToken(), "'"); | |
3097 | return; | |
3098 | case INVALID_OCTAL_NUMBER_ERRORTOK: | |
3099 | out.print("Invalid use of octal: '", getToken(), "'"); | |
3100 | return; | |
3101 | case INVALID_STRING_LITERAL_ERRORTOK: | |
3102 | out.print("Invalid string literal: '", getToken(), "'"); | |
3103 | return; | |
3104 | case ERRORTOK: | |
3105 | out.print("Unrecognized token '", getToken(), "'"); | |
3106 | return; | |
3107 | case STRING: | |
3108 | out.print("Unexpected string literal ", getToken()); | |
3109 | return; | |
ed1e77d3 A |
3110 | case INTEGER: |
3111 | case DOUBLE: | |
81345200 A |
3112 | out.print("Unexpected number '", getToken(), "'"); |
3113 | return; | |
3114 | ||
3115 | case RESERVED_IF_STRICT: | |
3116 | out.print("Unexpected use of reserved word '", getToken(), "' in strict mode"); | |
3117 | return; | |
3118 | ||
3119 | case RESERVED: | |
3120 | out.print("Unexpected use of reserved word '", getToken(), "'"); | |
3121 | return; | |
3122 | ||
3123 | case INVALID_PRIVATE_NAME_ERRORTOK: | |
3124 | out.print("Invalid private name '", getToken(), "'"); | |
3125 | return; | |
3126 | ||
3127 | case IDENT: | |
3128 | out.print("Unexpected identifier '", getToken(), "'"); | |
3129 | return; | |
3130 | ||
3131 | default: | |
3132 | break; | |
3133 | } | |
3134 | ||
3135 | if (m_token.m_type & KeywordTokenFlag) { | |
3136 | out.print("Unexpected keyword '", getToken(), "'"); | |
3137 | return; | |
3138 | } | |
3139 | ||
3140 | out.print("Unexpected token '", getToken(), "'"); | |
3141 | } | |
3142 | ||
3143 | // Instantiate the two flavors of Parser we need instead of putting most of this file in Parser.h | |
3144 | template class Parser<Lexer<LChar>>; | |
3145 | template class Parser<Lexer<UChar>>; | |
3146 | ||
9dae56ea | 3147 | } // namespace JSC |