]>
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" |
6fe7ccc8 A |
31 | #include "NodeInfo.h" |
32 | #include "SourceProvider.h" | |
93a37866 | 33 | #include "VM.h" |
6fe7ccc8 A |
34 | #include <utility> |
35 | #include <wtf/HashFunctions.h> | |
36 | #include <wtf/OwnPtr.h> | |
37 | #include <wtf/WTFThreadData.h> | |
38 | ||
93a37866 A |
39 | #define fail() do { if (!hasError()) updateErrorMessage(); return 0; } while (0) |
40 | #define failWithToken(tok) do { if (!hasError()) updateErrorMessage(tok); return 0; } while (0) | |
41 | #define failWithMessage(msg) do { if (!hasError()) updateErrorMessage(msg); return 0; } while (0) | |
42 | #define failWithNameAndMessage(before, name, after) do { if (!hasError()) updateErrorWithNameAndMessage(before, name, after); return 0; } while (0) | |
43 | #define failWithStackOverflow() do { updateErrorMessage("Stack exhausted"); m_hasStackOverflow = true; return 0; } while (0) | |
44 | #define failIfFalse(cond) do { if (!(cond)) fail(); } while (0) | |
45 | #define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0) | |
46 | #define failIfFalseWithNameAndMessage(cond, before, name, msg) do { if (!(cond)) failWithNameAndMessage(before, name, msg); } while (0) | |
47 | #define failIfTrue(cond) do { if ((cond)) fail(); } while (0) | |
48 | #define failIfTrueWithMessage(cond, msg) do { if ((cond)) failWithMessage(msg); } while (0) | |
49 | #define failIfTrueWithNameAndMessage(cond, before, name, msg) do { if ((cond)) failWithNameAndMessage(before, name, msg); } while (0) | |
50 | #define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0) | |
51 | #define failIfTrueIfStrictWithMessage(cond, msg) do { if ((cond) && strictMode()) failWithMessage(msg); } while (0) | |
52 | #define failIfTrueIfStrictWithNameAndMessage(cond, before, name, after) do { if ((cond) && strictMode()) failWithNameAndMessage(before, name, after); } while (0) | |
53 | #define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0) | |
54 | #define failIfFalseIfStrictWithMessage(cond, msg) do { if ((!(cond)) && strictMode()) failWithMessage(msg); } while (0) | |
55 | #define failIfFalseIfStrictWithNameAndMessage(cond, before, name, after) do { if ((!(cond)) && strictMode()) failWithNameAndMessage(before, name, after); } while (0) | |
56 | #define consumeOrFail(tokenType) do { if (!consume(tokenType)) failWithToken(tokenType); } while (0) | |
57 | #define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0) | |
58 | #define matchOrFail(tokenType) do { if (!match(tokenType)) failWithToken(tokenType); } while (0) | |
59 | #define failIfStackOverflow() do { if (!canRecurse()) failWithStackOverflow(); } while (0) | |
60 | ||
6fe7ccc8 | 61 | using namespace std; |
9dae56ea A |
62 | |
63 | namespace JSC { | |
64 | ||
6fe7ccc8 | 65 | template <typename LexerType> |
93a37866 A |
66 | Parser<LexerType>::Parser(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode) |
67 | : m_vm(vm) | |
6fe7ccc8 A |
68 | , m_source(&source) |
69 | , m_stack(wtfThreadData().stack()) | |
93a37866 | 70 | , m_hasStackOverflow(false) |
6fe7ccc8 A |
71 | , m_allowsIn(true) |
72 | , m_lastLine(0) | |
73 | , m_lastTokenEnd(0) | |
74 | , m_assignmentCount(0) | |
75 | , m_nonLHSCount(0) | |
76 | , m_syntaxAlreadyValidated(source.provider()->isValid()) | |
77 | , m_statementDepth(0) | |
78 | , m_nonTrivialExpressionCount(0) | |
79 | , m_lastIdentifier(0) | |
80 | , m_sourceElements(0) | |
9dae56ea | 81 | { |
93a37866 A |
82 | m_lexer = adoptPtr(new LexerType(vm)); |
83 | m_arena = m_vm->parserArena.get(); | |
6fe7ccc8 | 84 | m_lexer->setCode(source, m_arena); |
93a37866 A |
85 | m_token.m_location.endOffset = source.startOffset(); |
86 | m_token.m_location.lineStartOffset = source.startOffset(); | |
9dae56ea | 87 | |
93a37866 | 88 | m_functionCache = vm->addSourceProviderCache(source.provider()); |
6fe7ccc8 A |
89 | ScopeRef scope = pushScope(); |
90 | if (parserMode == JSParseFunctionCode) | |
91 | scope->setIsFunction(); | |
92 | if (strictness == JSParseStrict) | |
93 | scope->setStrictMode(); | |
94 | if (parameters) { | |
95 | for (unsigned i = 0; i < parameters->size(); i++) | |
96 | scope->declareParameter(¶meters->at(i)); | |
97 | } | |
93a37866 A |
98 | if (!name.isNull()) |
99 | scope->declareCallee(&name); | |
6fe7ccc8 | 100 | next(); |
6fe7ccc8 | 101 | } |
9dae56ea | 102 | |
6fe7ccc8 A |
103 | template <typename LexerType> |
104 | Parser<LexerType>::~Parser() | |
105 | { | |
106 | } | |
9dae56ea | 107 | |
6fe7ccc8 | 108 | template <typename LexerType> |
93a37866 | 109 | String Parser<LexerType>::parseInner() |
6fe7ccc8 | 110 | { |
93a37866 | 111 | String parseError = String(); |
6fe7ccc8 | 112 | |
93a37866 | 113 | ASTBuilder context(const_cast<VM*>(m_vm), const_cast<SourceCode*>(m_source)); |
6fe7ccc8 A |
114 | if (m_lexer->isReparsing()) |
115 | m_statementDepth--; | |
116 | ScopeRef scope = currentScope(); | |
117 | SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context); | |
93a37866 A |
118 | if (!sourceElements || !consume(EOFTOK)) { |
119 | if (hasError()) | |
120 | parseError = m_errorMessage; | |
121 | else | |
122 | parseError = ASCIILiteral("Parser error"); | |
123 | } | |
9dae56ea | 124 | |
6fe7ccc8 A |
125 | IdentifierSet capturedVariables; |
126 | scope->getCapturedVariables(capturedVariables); | |
127 | CodeFeatures features = context.features(); | |
128 | if (scope->strictMode()) | |
129 | features |= StrictModeFeature; | |
130 | if (scope->shadowsArguments()) | |
131 | features |= ShadowsArgumentsFeature; | |
9dae56ea | 132 | |
6fe7ccc8 A |
133 | didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features, |
134 | m_lastLine, context.numConstants(), capturedVariables); | |
9dae56ea | 135 | |
6fe7ccc8 | 136 | return parseError; |
9dae56ea A |
137 | } |
138 | ||
6fe7ccc8 A |
139 | template <typename LexerType> |
140 | void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack, | |
14957cd0 | 141 | ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants, IdentifierSet& capturedVars) |
9dae56ea A |
142 | { |
143 | m_sourceElements = sourceElements; | |
144 | m_varDeclarations = varStack; | |
145 | m_funcDeclarations = funcStack; | |
14957cd0 | 146 | m_capturedVariables.swap(capturedVars); |
9dae56ea A |
147 | m_features = features; |
148 | m_lastLine = lastLine; | |
149 | m_numConstants = numConstants; | |
150 | } | |
151 | ||
6fe7ccc8 A |
152 | template <typename LexerType> |
153 | bool Parser<LexerType>::allowAutomaticSemicolon() | |
154 | { | |
155 | return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator(); | |
156 | } | |
157 | ||
158 | template <typename LexerType> | |
159 | template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSourceElements(TreeBuilder& context) | |
160 | { | |
161 | const unsigned lengthOfUseStrictLiteral = 12; // "use strict".length | |
162 | TreeSourceElements sourceElements = context.createSourceElements(); | |
163 | bool seenNonDirective = false; | |
164 | const Identifier* directive = 0; | |
165 | unsigned directiveLiteralLength = 0; | |
93a37866 A |
166 | unsigned startOffset = m_token.m_location.startOffset; |
167 | unsigned startLineStartOffset = m_token.m_location.lineStartOffset; | |
6fe7ccc8 A |
168 | unsigned oldLastLineNumber = m_lexer->lastLineNumber(); |
169 | unsigned oldLineNumber = m_lexer->lineNumber(); | |
170 | bool hasSetStrict = false; | |
171 | while (TreeStatement statement = parseStatement(context, directive, &directiveLiteralLength)) { | |
172 | if (mode == CheckForStrictMode && !seenNonDirective) { | |
173 | if (directive) { | |
174 | // "use strict" must be the exact literal without escape sequences or line continuation. | |
93a37866 | 175 | if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) { |
6fe7ccc8 A |
176 | setStrictMode(); |
177 | hasSetStrict = true; | |
178 | failIfFalse(isValidStrictMode()); | |
93a37866 | 179 | m_lexer->setOffset(startOffset, startLineStartOffset); |
6fe7ccc8 A |
180 | next(); |
181 | m_lexer->setLastLineNumber(oldLastLineNumber); | |
182 | m_lexer->setLineNumber(oldLineNumber); | |
93a37866 | 183 | failIfTrue(hasError()); |
6fe7ccc8 A |
184 | continue; |
185 | } | |
186 | } else | |
187 | seenNonDirective = true; | |
188 | } | |
189 | context.appendStatement(sourceElements, statement); | |
190 | } | |
93a37866 A |
191 | |
192 | failIfTrue(hasError()); | |
6fe7ccc8 A |
193 | return sourceElements; |
194 | } | |
195 | ||
196 | template <typename LexerType> | |
197 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVarDeclaration(TreeBuilder& context) | |
198 | { | |
199 | ASSERT(match(VAR)); | |
93a37866 | 200 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
201 | int start = tokenLine(); |
202 | int end = 0; | |
203 | int scratch; | |
204 | const Identifier* scratch1 = 0; | |
205 | TreeExpression scratch2 = 0; | |
206 | int scratch3 = 0; | |
207 | TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3); | |
93a37866 | 208 | failIfTrue(hasError()); |
6fe7ccc8 A |
209 | failIfFalse(autoSemiColon()); |
210 | ||
93a37866 | 211 | return context.createVarStatement(location, varDecls, start, end); |
6fe7ccc8 A |
212 | } |
213 | ||
214 | template <typename LexerType> | |
215 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseConstDeclaration(TreeBuilder& context) | |
216 | { | |
217 | ASSERT(match(CONSTTOKEN)); | |
93a37866 | 218 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
219 | int start = tokenLine(); |
220 | int end = 0; | |
221 | TreeConstDeclList constDecls = parseConstDeclarationList(context); | |
93a37866 | 222 | failIfTrue(hasError()); |
6fe7ccc8 A |
223 | failIfFalse(autoSemiColon()); |
224 | ||
93a37866 | 225 | return context.createConstStatement(location, constDecls, start, end); |
6fe7ccc8 A |
226 | } |
227 | ||
228 | template <typename LexerType> | |
229 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDoWhileStatement(TreeBuilder& context) | |
230 | { | |
231 | ASSERT(match(DO)); | |
232 | int startLine = tokenLine(); | |
233 | next(); | |
234 | const Identifier* unused = 0; | |
235 | startLoop(); | |
236 | TreeStatement statement = parseStatement(context, unused); | |
237 | endLoop(); | |
238 | failIfFalse(statement); | |
239 | int endLine = tokenLine(); | |
93a37866 | 240 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
241 | consumeOrFail(WHILE); |
242 | consumeOrFail(OPENPAREN); | |
243 | TreeExpression expr = parseExpression(context); | |
244 | failIfFalse(expr); | |
245 | consumeOrFail(CLOSEPAREN); | |
246 | if (match(SEMICOLON)) | |
247 | next(); // Always performs automatic semicolon insertion. | |
93a37866 | 248 | return context.createDoWhileStatement(location, statement, expr, startLine, endLine); |
6fe7ccc8 A |
249 | } |
250 | ||
251 | template <typename LexerType> | |
252 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWhileStatement(TreeBuilder& context) | |
253 | { | |
254 | ASSERT(match(WHILE)); | |
93a37866 | 255 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
256 | int startLine = tokenLine(); |
257 | next(); | |
258 | consumeOrFail(OPENPAREN); | |
259 | TreeExpression expr = parseExpression(context); | |
260 | failIfFalse(expr); | |
261 | int endLine = tokenLine(); | |
262 | consumeOrFail(CLOSEPAREN); | |
263 | const Identifier* unused = 0; | |
264 | startLoop(); | |
265 | TreeStatement statement = parseStatement(context, unused); | |
266 | endLoop(); | |
267 | failIfFalse(statement); | |
93a37866 | 268 | return context.createWhileStatement(location, expr, statement, startLine, endLine); |
6fe7ccc8 A |
269 | } |
270 | ||
271 | template <typename LexerType> | |
272 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd) | |
273 | { | |
274 | TreeExpression varDecls = 0; | |
275 | do { | |
276 | declarations++; | |
93a37866 | 277 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
278 | next(); |
279 | matchOrFail(IDENT); | |
280 | ||
281 | int varStart = tokenStart(); | |
282 | identStart = varStart; | |
283 | const Identifier* name = m_token.m_data.ident; | |
284 | lastIdent = name; | |
285 | next(); | |
286 | bool hasInitializer = match(EQUAL); | |
287 | failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode."); | |
288 | context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0); | |
289 | if (hasInitializer) { | |
290 | int varDivot = tokenStart() + 1; | |
93a37866 A |
291 | unsigned varLine = tokenLine(); |
292 | unsigned varLineStart = tokenLineStart(); | |
6fe7ccc8 A |
293 | initStart = tokenStart(); |
294 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
6fe7ccc8 A |
295 | TreeExpression initializer = parseAssignmentExpression(context); |
296 | initEnd = lastTokenEnd(); | |
297 | lastInitializer = initializer; | |
298 | failIfFalse(initializer); | |
299 | ||
93a37866 | 300 | TreeExpression node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEnd(), varLine, varLineStart); |
6fe7ccc8 A |
301 | if (!varDecls) |
302 | varDecls = node; | |
303 | else | |
93a37866 | 304 | varDecls = context.combineCommaNodes(location, varDecls, node); |
6fe7ccc8 A |
305 | } |
306 | } while (match(COMMA)); | |
307 | return varDecls; | |
308 | } | |
309 | ||
310 | template <typename LexerType> | |
311 | template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context) | |
312 | { | |
313 | failIfTrue(strictMode()); | |
314 | TreeConstDeclList constDecls = 0; | |
315 | TreeConstDeclList tail = 0; | |
316 | do { | |
93a37866 | 317 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
318 | next(); |
319 | matchOrFail(IDENT); | |
320 | const Identifier* name = m_token.m_data.ident; | |
321 | next(); | |
322 | bool hasInitializer = match(EQUAL); | |
323 | declareVariable(name); | |
324 | context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0)); | |
93a37866 | 325 | |
6fe7ccc8 A |
326 | TreeExpression initializer = 0; |
327 | if (hasInitializer) { | |
328 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
329 | initializer = parseAssignmentExpression(context); | |
330 | } | |
93a37866 | 331 | tail = context.appendConstDecl(location, tail, name, initializer); |
6fe7ccc8 A |
332 | if (!constDecls) |
333 | constDecls = tail; | |
334 | } while (match(COMMA)); | |
335 | return constDecls; | |
336 | } | |
337 | ||
338 | template <typename LexerType> | |
339 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(TreeBuilder& context) | |
340 | { | |
341 | ASSERT(match(FOR)); | |
93a37866 | 342 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
343 | int startLine = tokenLine(); |
344 | next(); | |
345 | consumeOrFail(OPENPAREN); | |
346 | int nonLHSCount = m_nonLHSCount; | |
347 | int declarations = 0; | |
348 | int declsStart = 0; | |
349 | int declsEnd = 0; | |
93a37866 A |
350 | unsigned declsLine = 0; |
351 | unsigned declsLineStart = 0; | |
6fe7ccc8 | 352 | TreeExpression decls = 0; |
6fe7ccc8 A |
353 | if (match(VAR)) { |
354 | /* | |
355 | for (var IDENT in expression) statement | |
356 | for (var IDENT = expression in expression) statement | |
357 | for (var varDeclarationList; expressionOpt; expressionOpt) | |
358 | */ | |
6fe7ccc8 A |
359 | const Identifier* forInTarget = 0; |
360 | TreeExpression forInInitializer = 0; | |
361 | m_allowsIn = false; | |
362 | int initStart = 0; | |
363 | int initEnd = 0; | |
364 | decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd); | |
365 | m_allowsIn = true; | |
93a37866 A |
366 | failIfTrue(hasError()); |
367 | ||
6fe7ccc8 A |
368 | // Remainder of a standard for loop is handled identically |
369 | if (match(SEMICOLON)) | |
370 | goto standardForLoop; | |
371 | ||
372 | failIfFalse(declarations == 1); | |
373 | ||
374 | // Handle for-in with var declaration | |
375 | int inLocation = tokenStart(); | |
93a37866 A |
376 | unsigned inLine = tokenLine(); |
377 | unsigned inLineStart = tokenLineStart(); | |
6fe7ccc8 A |
378 | consumeOrFail(INTOKEN); |
379 | ||
380 | TreeExpression expr = parseExpression(context); | |
381 | failIfFalse(expr); | |
382 | int exprEnd = lastTokenEnd(); | |
383 | ||
384 | int endLine = tokenLine(); | |
385 | consumeOrFail(CLOSEPAREN); | |
386 | ||
387 | const Identifier* unused = 0; | |
388 | startLoop(); | |
389 | TreeStatement statement = parseStatement(context, unused); | |
390 | endLoop(); | |
391 | failIfFalse(statement); | |
392 | ||
93a37866 | 393 | return context.createForInLoop(location, forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine, inLine, inLineStart); |
6fe7ccc8 A |
394 | } |
395 | ||
396 | if (!match(SEMICOLON)) { | |
397 | m_allowsIn = false; | |
398 | declsStart = tokenStart(); | |
399 | decls = parseExpression(context); | |
400 | declsEnd = lastTokenEnd(); | |
93a37866 A |
401 | declsLine = lastTokenLine(); |
402 | declsLineStart = lastTokenLineStart(); | |
6fe7ccc8 A |
403 | m_allowsIn = true; |
404 | failIfFalse(decls); | |
405 | } | |
406 | ||
407 | if (match(SEMICOLON)) { | |
408 | standardForLoop: | |
409 | // Standard for loop | |
410 | next(); | |
411 | TreeExpression condition = 0; | |
412 | ||
413 | if (!match(SEMICOLON)) { | |
414 | condition = parseExpression(context); | |
415 | failIfFalse(condition); | |
416 | } | |
417 | consumeOrFail(SEMICOLON); | |
418 | ||
419 | TreeExpression increment = 0; | |
420 | if (!match(CLOSEPAREN)) { | |
421 | increment = parseExpression(context); | |
422 | failIfFalse(increment); | |
423 | } | |
424 | int endLine = tokenLine(); | |
425 | consumeOrFail(CLOSEPAREN); | |
426 | const Identifier* unused = 0; | |
427 | startLoop(); | |
428 | TreeStatement statement = parseStatement(context, unused); | |
429 | endLoop(); | |
430 | failIfFalse(statement); | |
93a37866 | 431 | return context.createForLoop(location, decls, condition, increment, statement, startLine, endLine); |
6fe7ccc8 A |
432 | } |
433 | ||
434 | // For-in loop | |
435 | failIfFalse(nonLHSCount == m_nonLHSCount); | |
436 | consumeOrFail(INTOKEN); | |
437 | TreeExpression expr = parseExpression(context); | |
438 | failIfFalse(expr); | |
439 | int exprEnd = lastTokenEnd(); | |
440 | int endLine = tokenLine(); | |
441 | consumeOrFail(CLOSEPAREN); | |
442 | const Identifier* unused = 0; | |
443 | startLoop(); | |
444 | TreeStatement statement = parseStatement(context, unused); | |
445 | endLoop(); | |
446 | failIfFalse(statement); | |
447 | ||
93a37866 | 448 | return context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, declsLine, declsLineStart); |
6fe7ccc8 A |
449 | } |
450 | ||
451 | template <typename LexerType> | |
452 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBreakStatement(TreeBuilder& context) | |
453 | { | |
454 | ASSERT(match(BREAK)); | |
93a37866 | 455 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
456 | int startCol = tokenStart(); |
457 | int endCol = tokenEnd(); | |
458 | int startLine = tokenLine(); | |
459 | int endLine = tokenLine(); | |
93a37866 | 460 | unsigned endLineStart = tokenLineStart(); |
6fe7ccc8 A |
461 | next(); |
462 | ||
463 | if (autoSemiColon()) { | |
464 | failIfFalseWithMessage(breakIsValid(), "'break' is only valid inside a switch or loop statement"); | |
93a37866 | 465 | return context.createBreakStatement(location, startCol, endCol, startLine, endLine, endLineStart); |
6fe7ccc8 A |
466 | } |
467 | matchOrFail(IDENT); | |
468 | const Identifier* ident = m_token.m_data.ident; | |
469 | failIfFalseWithNameAndMessage(getLabel(ident), "Label", ident->impl(), "is not defined"); | |
470 | endCol = tokenEnd(); | |
471 | endLine = tokenLine(); | |
93a37866 | 472 | endLineStart = tokenLineStart(); |
6fe7ccc8 A |
473 | next(); |
474 | failIfFalse(autoSemiColon()); | |
93a37866 | 475 | return context.createBreakStatement(location, ident, startCol, endCol, startLine, endLine, endLineStart); |
6fe7ccc8 A |
476 | } |
477 | ||
478 | template <typename LexerType> | |
479 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseContinueStatement(TreeBuilder& context) | |
480 | { | |
481 | ASSERT(match(CONTINUE)); | |
93a37866 | 482 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
483 | int startCol = tokenStart(); |
484 | int endCol = tokenEnd(); | |
485 | int startLine = tokenLine(); | |
486 | int endLine = tokenLine(); | |
93a37866 | 487 | unsigned endLineStart = tokenLineStart(); |
6fe7ccc8 A |
488 | next(); |
489 | ||
490 | if (autoSemiColon()) { | |
491 | failIfFalseWithMessage(continueIsValid(), "'continue' is only valid inside a loop statement"); | |
93a37866 | 492 | return context.createContinueStatement(location, startCol, endCol, startLine, endLine, endLineStart); |
6fe7ccc8 A |
493 | } |
494 | matchOrFail(IDENT); | |
495 | const Identifier* ident = m_token.m_data.ident; | |
496 | ScopeLabelInfo* label = getLabel(ident); | |
497 | failIfFalseWithNameAndMessage(label, "Label", ident->impl(), "is not defined"); | |
498 | failIfFalseWithMessage(label->m_isLoop, "'continue' is only valid inside a loop statement"); | |
499 | endCol = tokenEnd(); | |
500 | endLine = tokenLine(); | |
93a37866 | 501 | endLineStart = tokenLineStart(); |
6fe7ccc8 A |
502 | next(); |
503 | failIfFalse(autoSemiColon()); | |
93a37866 | 504 | return context.createContinueStatement(location, ident, startCol, endCol, startLine, endLine, endLineStart); |
6fe7ccc8 A |
505 | } |
506 | ||
507 | template <typename LexerType> | |
508 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseReturnStatement(TreeBuilder& context) | |
509 | { | |
510 | ASSERT(match(RETURN)); | |
93a37866 | 511 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
512 | failIfFalse(currentScope()->isFunction()); |
513 | int startLine = tokenLine(); | |
514 | int endLine = startLine; | |
515 | int start = tokenStart(); | |
516 | int end = tokenEnd(); | |
93a37866 A |
517 | unsigned divotLine = tokenLine(); |
518 | unsigned divotLineStart = tokenLineStart(); | |
6fe7ccc8 A |
519 | next(); |
520 | // We do the auto semicolon check before attempting to parse an expression | |
521 | // as we need to ensure the a line break after the return correctly terminates | |
522 | // the statement | |
523 | if (match(SEMICOLON)) | |
524 | endLine = tokenLine(); | |
525 | if (autoSemiColon()) | |
93a37866 | 526 | return context.createReturnStatement(location, 0, start, end, startLine, endLine, divotLine, divotLineStart); |
6fe7ccc8 A |
527 | TreeExpression expr = parseExpression(context); |
528 | failIfFalse(expr); | |
529 | end = lastTokenEnd(); | |
93a37866 A |
530 | divotLine = lastTokenLine(); |
531 | divotLineStart = lastTokenLineStart(); | |
6fe7ccc8 A |
532 | if (match(SEMICOLON)) |
533 | endLine = tokenLine(); | |
534 | failIfFalse(autoSemiColon()); | |
93a37866 | 535 | return context.createReturnStatement(location, expr, start, end, startLine, endLine, divotLine, divotLineStart); |
6fe7ccc8 A |
536 | } |
537 | ||
538 | template <typename LexerType> | |
539 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseThrowStatement(TreeBuilder& context) | |
540 | { | |
541 | ASSERT(match(THROW)); | |
93a37866 | 542 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
543 | int eStart = tokenStart(); |
544 | int startLine = tokenLine(); | |
545 | next(); | |
546 | ||
547 | failIfTrue(autoSemiColon()); | |
548 | ||
549 | TreeExpression expr = parseExpression(context); | |
550 | failIfFalse(expr); | |
551 | int eEnd = lastTokenEnd(); | |
93a37866 A |
552 | unsigned divotLine = lastTokenLine(); |
553 | unsigned divotLineStart = lastTokenLineStart(); | |
6fe7ccc8 A |
554 | int endLine = tokenLine(); |
555 | failIfFalse(autoSemiColon()); | |
556 | ||
93a37866 | 557 | return context.createThrowStatement(location, expr, eStart, eEnd, startLine, endLine, divotLine, divotLineStart); |
6fe7ccc8 A |
558 | } |
559 | ||
560 | template <typename LexerType> | |
561 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWithStatement(TreeBuilder& context) | |
562 | { | |
563 | ASSERT(match(WITH)); | |
93a37866 | 564 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
565 | failIfTrueWithMessage(strictMode(), "'with' statements are not valid in strict mode"); |
566 | currentScope()->setNeedsFullActivation(); | |
567 | int startLine = tokenLine(); | |
568 | next(); | |
569 | consumeOrFail(OPENPAREN); | |
570 | int start = tokenStart(); | |
571 | TreeExpression expr = parseExpression(context); | |
572 | failIfFalse(expr); | |
573 | int end = lastTokenEnd(); | |
93a37866 A |
574 | unsigned divotLine = lastTokenLine(); |
575 | unsigned divotLineStart = lastTokenLineStart(); | |
6fe7ccc8 A |
576 | int endLine = tokenLine(); |
577 | consumeOrFail(CLOSEPAREN); | |
578 | const Identifier* unused = 0; | |
579 | TreeStatement statement = parseStatement(context, unused); | |
580 | failIfFalse(statement); | |
581 | ||
93a37866 | 582 | return context.createWithStatement(location, expr, statement, start, end, startLine, endLine, divotLine, divotLineStart); |
6fe7ccc8 A |
583 | } |
584 | ||
585 | template <typename LexerType> | |
586 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseSwitchStatement(TreeBuilder& context) | |
587 | { | |
588 | ASSERT(match(SWITCH)); | |
93a37866 | 589 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
590 | int startLine = tokenLine(); |
591 | next(); | |
592 | consumeOrFail(OPENPAREN); | |
593 | TreeExpression expr = parseExpression(context); | |
594 | failIfFalse(expr); | |
595 | int endLine = tokenLine(); | |
596 | consumeOrFail(CLOSEPAREN); | |
597 | consumeOrFail(OPENBRACE); | |
598 | startSwitch(); | |
599 | TreeClauseList firstClauses = parseSwitchClauses(context); | |
93a37866 | 600 | failIfTrue(hasError()); |
6fe7ccc8 A |
601 | |
602 | TreeClause defaultClause = parseSwitchDefaultClause(context); | |
93a37866 | 603 | failIfTrue(hasError()); |
6fe7ccc8 A |
604 | |
605 | TreeClauseList secondClauses = parseSwitchClauses(context); | |
93a37866 | 606 | failIfTrue(hasError()); |
6fe7ccc8 A |
607 | endSwitch(); |
608 | consumeOrFail(CLOSEBRACE); | |
609 | ||
93a37866 | 610 | return context.createSwitchStatement(location, expr, firstClauses, defaultClause, secondClauses, startLine, endLine); |
6fe7ccc8 A |
611 | |
612 | } | |
613 | ||
614 | template <typename LexerType> | |
615 | template <class TreeBuilder> TreeClauseList Parser<LexerType>::parseSwitchClauses(TreeBuilder& context) | |
616 | { | |
617 | if (!match(CASE)) | |
618 | return 0; | |
619 | next(); | |
620 | TreeExpression condition = parseExpression(context); | |
621 | failIfFalse(condition); | |
622 | consumeOrFail(COLON); | |
623 | TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context); | |
624 | failIfFalse(statements); | |
625 | TreeClause clause = context.createClause(condition, statements); | |
626 | TreeClauseList clauseList = context.createClauseList(clause); | |
627 | TreeClauseList tail = clauseList; | |
628 | ||
629 | while (match(CASE)) { | |
630 | next(); | |
631 | TreeExpression condition = parseExpression(context); | |
632 | failIfFalse(condition); | |
633 | consumeOrFail(COLON); | |
634 | TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context); | |
635 | failIfFalse(statements); | |
636 | clause = context.createClause(condition, statements); | |
637 | tail = context.createClauseList(tail, clause); | |
638 | } | |
639 | return clauseList; | |
640 | } | |
641 | ||
642 | template <typename LexerType> | |
643 | template <class TreeBuilder> TreeClause Parser<LexerType>::parseSwitchDefaultClause(TreeBuilder& context) | |
644 | { | |
645 | if (!match(DEFAULT)) | |
646 | return 0; | |
647 | next(); | |
648 | consumeOrFail(COLON); | |
649 | TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context); | |
650 | failIfFalse(statements); | |
651 | return context.createClause(0, statements); | |
652 | } | |
653 | ||
654 | template <typename LexerType> | |
655 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement(TreeBuilder& context) | |
656 | { | |
657 | ASSERT(match(TRY)); | |
93a37866 | 658 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 659 | TreeStatement tryBlock = 0; |
93a37866 | 660 | const Identifier* ident = &m_vm->propertyNames->nullIdentifier; |
6fe7ccc8 A |
661 | TreeStatement catchBlock = 0; |
662 | TreeStatement finallyBlock = 0; | |
663 | int firstLine = tokenLine(); | |
664 | next(); | |
665 | matchOrFail(OPENBRACE); | |
666 | ||
667 | tryBlock = parseBlockStatement(context); | |
668 | failIfFalse(tryBlock); | |
669 | int lastLine = m_lastLine; | |
670 | ||
671 | if (match(CATCH)) { | |
672 | currentScope()->setNeedsFullActivation(); | |
673 | next(); | |
674 | consumeOrFail(OPENPAREN); | |
675 | matchOrFail(IDENT); | |
676 | ident = m_token.m_data.ident; | |
677 | next(); | |
678 | AutoPopScopeRef catchScope(this, pushScope()); | |
679 | failIfFalseIfStrictWithNameAndMessage(declareVariable(ident), "Cannot declare a variable named", ident->impl(), "in strict mode"); | |
680 | catchScope->preventNewDecls(); | |
681 | consumeOrFail(CLOSEPAREN); | |
682 | matchOrFail(OPENBRACE); | |
683 | catchBlock = parseBlockStatement(context); | |
684 | failIfFalseWithMessage(catchBlock, "'try' must have a catch or finally block"); | |
685 | failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo)); | |
686 | } | |
687 | ||
688 | if (match(FINALLY)) { | |
689 | next(); | |
690 | matchOrFail(OPENBRACE); | |
691 | finallyBlock = parseBlockStatement(context); | |
692 | failIfFalse(finallyBlock); | |
693 | } | |
694 | failIfFalse(catchBlock || finallyBlock); | |
93a37866 | 695 | return context.createTryStatement(location, tryBlock, ident, catchBlock, finallyBlock, firstLine, lastLine); |
6fe7ccc8 A |
696 | } |
697 | ||
698 | template <typename LexerType> | |
699 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDebuggerStatement(TreeBuilder& context) | |
700 | { | |
701 | ASSERT(match(DEBUGGER)); | |
93a37866 | 702 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
703 | int startLine = tokenLine(); |
704 | int endLine = startLine; | |
705 | next(); | |
706 | if (match(SEMICOLON)) | |
707 | startLine = tokenLine(); | |
708 | failIfFalse(autoSemiColon()); | |
93a37866 | 709 | return context.createDebugger(location, startLine, endLine); |
6fe7ccc8 A |
710 | } |
711 | ||
712 | template <typename LexerType> | |
713 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatement(TreeBuilder& context) | |
714 | { | |
715 | ASSERT(match(OPENBRACE)); | |
93a37866 | 716 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
717 | int start = tokenLine(); |
718 | next(); | |
719 | if (match(CLOSEBRACE)) { | |
720 | next(); | |
93a37866 | 721 | return context.createBlockStatement(location, 0, start, m_lastLine); |
6fe7ccc8 A |
722 | } |
723 | TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context); | |
724 | failIfFalse(subtree); | |
725 | matchOrFail(CLOSEBRACE); | |
726 | next(); | |
93a37866 | 727 | return context.createBlockStatement(location, subtree, start, m_lastLine); |
6fe7ccc8 A |
728 | } |
729 | ||
730 | template <typename LexerType> | |
731 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength) | |
732 | { | |
733 | DepthManager statementDepth(&m_statementDepth); | |
734 | m_statementDepth++; | |
735 | directive = 0; | |
736 | int nonTrivialExpressionCount = 0; | |
737 | failIfStackOverflow(); | |
738 | switch (m_token.m_type) { | |
739 | case OPENBRACE: | |
740 | return parseBlockStatement(context); | |
741 | case VAR: | |
742 | return parseVarDeclaration(context); | |
743 | case CONSTTOKEN: | |
744 | return parseConstDeclaration(context); | |
745 | case FUNCTION: | |
746 | failIfFalseIfStrictWithMessage(m_statementDepth == 1, "Functions cannot be declared in a nested block in strict mode"); | |
747 | return parseFunctionDeclaration(context); | |
93a37866 A |
748 | case SEMICOLON: { |
749 | JSTokenLocation location(tokenLocation()); | |
6fe7ccc8 | 750 | next(); |
93a37866 A |
751 | return context.createEmptyStatement(location); |
752 | } | |
6fe7ccc8 A |
753 | case IF: |
754 | return parseIfStatement(context); | |
755 | case DO: | |
756 | return parseDoWhileStatement(context); | |
757 | case WHILE: | |
758 | return parseWhileStatement(context); | |
759 | case FOR: | |
760 | return parseForStatement(context); | |
761 | case CONTINUE: | |
762 | return parseContinueStatement(context); | |
763 | case BREAK: | |
764 | return parseBreakStatement(context); | |
765 | case RETURN: | |
766 | return parseReturnStatement(context); | |
767 | case WITH: | |
768 | return parseWithStatement(context); | |
769 | case SWITCH: | |
770 | return parseSwitchStatement(context); | |
771 | case THROW: | |
772 | return parseThrowStatement(context); | |
773 | case TRY: | |
774 | return parseTryStatement(context); | |
775 | case DEBUGGER: | |
776 | return parseDebuggerStatement(context); | |
777 | case EOFTOK: | |
778 | case CASE: | |
779 | case CLOSEBRACE: | |
780 | case DEFAULT: | |
781 | // These tokens imply the end of a set of source elements | |
782 | return 0; | |
783 | case IDENT: | |
784 | return parseExpressionOrLabelStatement(context); | |
785 | case STRING: | |
786 | directive = m_token.m_data.ident; | |
787 | if (directiveLiteralLength) | |
93a37866 | 788 | *directiveLiteralLength = m_token.m_location.endOffset - m_token.m_location.startOffset; |
6fe7ccc8 A |
789 | nonTrivialExpressionCount = m_nonTrivialExpressionCount; |
790 | default: | |
791 | TreeStatement exprStatement = parseExpressionStatement(context); | |
792 | if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount) | |
793 | directive = 0; | |
794 | return exprStatement; | |
795 | } | |
796 | } | |
797 | ||
798 | template <typename LexerType> | |
799 | template <class TreeBuilder> TreeFormalParameterList Parser<LexerType>::parseFormalParameters(TreeBuilder& context) | |
800 | { | |
801 | matchOrFail(IDENT); | |
802 | failIfFalseIfStrictWithNameAndMessage(declareParameter(m_token.m_data.ident), "Cannot declare a parameter named", m_token.m_data.ident->impl(), " in strict mode"); | |
803 | TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident); | |
804 | TreeFormalParameterList tail = list; | |
805 | next(); | |
806 | while (match(COMMA)) { | |
807 | next(); | |
808 | matchOrFail(IDENT); | |
809 | const Identifier* ident = m_token.m_data.ident; | |
810 | failIfFalseIfStrictWithNameAndMessage(declareParameter(ident), "Cannot declare a parameter named", ident->impl(), "in strict mode"); | |
811 | next(); | |
812 | tail = context.createFormalParameterList(tail, *ident); | |
813 | } | |
814 | return list; | |
815 | } | |
816 | ||
817 | template <typename LexerType> | |
818 | template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(TreeBuilder& context) | |
819 | { | |
93a37866 A |
820 | JSTokenLocation startLocation(tokenLocation()); |
821 | unsigned startColumn = tokenColumn(); | |
822 | next(); | |
823 | ||
6fe7ccc8 | 824 | if (match(CLOSEBRACE)) |
93a37866 | 825 | return context.createFunctionBody(startLocation, tokenLocation(), startColumn, strictMode()); |
6fe7ccc8 A |
826 | DepthManager statementDepth(&m_statementDepth); |
827 | m_statementDepth = 0; | |
93a37866 | 828 | typename TreeBuilder::FunctionBodyBuilder bodyBuilder(const_cast<VM*>(m_vm), m_lexer.get()); |
6fe7ccc8 | 829 | failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder)); |
93a37866 | 830 | return context.createFunctionBody(startLocation, tokenLocation(), startColumn, strictMode()); |
6fe7ccc8 A |
831 | } |
832 | ||
833 | template <typename LexerType> | |
93a37866 | 834 | template <FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, unsigned& openBraceOffset, unsigned& closeBraceOffset, int& bodyStartLine, unsigned& bodyStartColumn) |
6fe7ccc8 A |
835 | { |
836 | AutoPopScopeRef functionScope(this, pushScope()); | |
837 | functionScope->setIsFunction(); | |
93a37866 | 838 | int functionStart = m_token.m_location.startOffset; |
6fe7ccc8 A |
839 | if (match(IDENT)) { |
840 | name = m_token.m_data.ident; | |
841 | next(); | |
842 | if (!nameIsInContainingScope) | |
843 | failIfFalseIfStrict(functionScope->declareVariable(name)); | |
844 | } else if (requirements == FunctionNeedsName) | |
845 | return false; | |
846 | consumeOrFail(OPENPAREN); | |
847 | if (!match(CLOSEPAREN)) { | |
848 | parameters = parseFormalParameters(context); | |
849 | failIfFalse(parameters); | |
850 | } | |
851 | consumeOrFail(CLOSEPAREN); | |
852 | matchOrFail(OPENBRACE); | |
853 | ||
93a37866 | 854 | openBraceOffset = m_token.m_data.offset; |
6fe7ccc8 | 855 | bodyStartLine = tokenLine(); |
93a37866 A |
856 | bodyStartColumn = m_token.m_data.offset - m_token.m_data.lineStartOffset; |
857 | JSTokenLocation startLocation(tokenLocation()); | |
6fe7ccc8 A |
858 | |
859 | // If we know about this function already, we can use the cached info and skip the parser to the end of the function. | |
93a37866 | 860 | if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBraceOffset) : 0) { |
6fe7ccc8 A |
861 | // If we're in a strict context, the cached function info must say it was strict too. |
862 | ASSERT(!strictMode() || cachedInfo->strictMode); | |
93a37866 A |
863 | JSTokenLocation endLocation; |
864 | ||
865 | endLocation.line = cachedInfo->closeBraceLine; | |
866 | endLocation.startOffset = cachedInfo->closeBraceOffset; | |
867 | endLocation.lineStartOffset = cachedInfo->closeBraceLineStartOffset; | |
868 | ASSERT(endLocation.startOffset >= endLocation.lineStartOffset); | |
869 | ||
870 | body = context.createFunctionBody(startLocation, endLocation, bodyStartColumn, cachedInfo->strictMode); | |
6fe7ccc8 | 871 | |
93a37866 | 872 | functionScope->restoreFromSourceProviderCache(cachedInfo); |
6fe7ccc8 A |
873 | failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo)); |
874 | ||
93a37866 A |
875 | closeBraceOffset = cachedInfo->closeBraceOffset; |
876 | ||
877 | context.setFunctionStart(body, functionStart); | |
6fe7ccc8 | 878 | m_token = cachedInfo->closeBraceToken(); |
93a37866 A |
879 | |
880 | m_lexer->setOffset(m_token.m_location.endOffset, m_token.m_location.lineStartOffset); | |
881 | m_lexer->setLineNumber(m_token.m_location.line); | |
6fe7ccc8 A |
882 | |
883 | next(); | |
884 | return true; | |
885 | } | |
886 | ||
6fe7ccc8 A |
887 | body = parseFunctionBody(context); |
888 | failIfFalse(body); | |
889 | if (functionScope->strictMode() && name) { | |
93a37866 A |
890 | failIfTrueWithNameAndMessage(m_vm->propertyNames->arguments == *name, "Function name", name->impl(), "is not valid in strict mode"); |
891 | failIfTrueWithNameAndMessage(m_vm->propertyNames->eval == *name, "Function name", name->impl(), "is not valid in strict mode"); | |
6fe7ccc8 | 892 | } |
93a37866 A |
893 | closeBraceOffset = m_token.m_data.offset; |
894 | unsigned closeBraceLine = m_token.m_data.line; | |
895 | unsigned closeBraceLineStartOffset = m_token.m_data.lineStartOffset; | |
6fe7ccc8 A |
896 | |
897 | // Cache the tokenizer state and the function scope the first time the function is parsed. | |
898 | // Any future reparsing can then skip the function. | |
93a37866 | 899 | static const int minimumFunctionLengthToCache = 16; |
6fe7ccc8 | 900 | OwnPtr<SourceProviderCacheItem> newInfo; |
93a37866 | 901 | int functionLength = closeBraceOffset - openBraceOffset; |
6fe7ccc8 | 902 | if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) { |
93a37866 A |
903 | SourceProviderCacheItemCreationParameters parameters; |
904 | parameters.functionStart = functionStart; | |
905 | parameters.closeBraceLine = closeBraceLine; | |
906 | parameters.closeBraceOffset = closeBraceOffset; | |
907 | parameters.closeBraceLineStartOffset = closeBraceLineStartOffset; | |
908 | functionScope->fillParametersForSourceProviderCache(parameters); | |
909 | newInfo = SourceProviderCacheItem::create(parameters); | |
910 | ||
6fe7ccc8 | 911 | } |
93a37866 | 912 | context.setFunctionStart(body, functionStart); |
6fe7ccc8 A |
913 | |
914 | failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo)); | |
915 | matchOrFail(CLOSEBRACE); | |
916 | ||
93a37866 A |
917 | if (newInfo) |
918 | m_functionCache->add(openBraceOffset, newInfo.release()); | |
6fe7ccc8 A |
919 | |
920 | next(); | |
921 | return true; | |
922 | } | |
923 | ||
924 | template <typename LexerType> | |
925 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context) | |
926 | { | |
927 | ASSERT(match(FUNCTION)); | |
93a37866 | 928 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
929 | next(); |
930 | const Identifier* name = 0; | |
931 | TreeFormalParameterList parameters = 0; | |
932 | TreeFunctionBody body = 0; | |
93a37866 A |
933 | unsigned openBraceOffset = 0; |
934 | unsigned closeBraceOffset = 0; | |
6fe7ccc8 | 935 | int bodyStartLine = 0; |
93a37866 A |
936 | unsigned bodyStartColumn = 0; |
937 | failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBraceOffset, closeBraceOffset, bodyStartLine, bodyStartColumn))); | |
6fe7ccc8 A |
938 | failIfFalse(name); |
939 | failIfFalseIfStrict(declareVariable(name)); | |
93a37866 | 940 | return context.createFuncDeclStatement(location, name, body, parameters, openBraceOffset, closeBraceOffset, bodyStartLine, m_lastLine, bodyStartColumn); |
6fe7ccc8 A |
941 | } |
942 | ||
943 | struct LabelInfo { | |
93a37866 | 944 | LabelInfo(const Identifier* ident, unsigned start, unsigned end, unsigned divotLine, unsigned divotLineStart) |
6fe7ccc8 A |
945 | : m_ident(ident) |
946 | , m_start(start) | |
947 | , m_end(end) | |
93a37866 A |
948 | , m_divotLine(divotLine) |
949 | , m_divotLineStart(divotLineStart) | |
6fe7ccc8 A |
950 | { |
951 | } | |
952 | ||
953 | const Identifier* m_ident; | |
93a37866 A |
954 | unsigned m_start; |
955 | unsigned m_end; | |
956 | unsigned m_divotLine; | |
957 | unsigned m_divotLineStart; | |
6fe7ccc8 A |
958 | }; |
959 | ||
960 | template <typename LexerType> | |
961 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionOrLabelStatement(TreeBuilder& context) | |
962 | { | |
963 | ||
964 | /* Expression and Label statements are ambiguous at LL(1), so we have a | |
965 | * special case that looks for a colon as the next character in the input. | |
966 | */ | |
967 | Vector<LabelInfo> labels; | |
93a37866 | 968 | JSTokenLocation location; |
6fe7ccc8 A |
969 | do { |
970 | int start = tokenStart(); | |
93a37866 A |
971 | int startingLine = tokenLine(); |
972 | location = tokenLocation(); | |
6fe7ccc8 A |
973 | if (!nextTokenIsColon()) { |
974 | // If we hit this path we're making a expression statement, which | |
975 | // by definition can't make use of continue/break so we can just | |
976 | // ignore any labels we might have accumulated. | |
977 | TreeExpression expression = parseExpression(context); | |
978 | failIfFalse(expression); | |
979 | failIfFalse(autoSemiColon()); | |
93a37866 | 980 | return context.createExprStatement(location, expression, startingLine, m_lastLine); |
6fe7ccc8 A |
981 | } |
982 | const Identifier* ident = m_token.m_data.ident; | |
983 | int end = tokenEnd(); | |
93a37866 A |
984 | unsigned divotLine = tokenLine(); |
985 | unsigned divotLineStart = tokenLineStart(); | |
6fe7ccc8 A |
986 | next(); |
987 | consumeOrFail(COLON); | |
988 | if (!m_syntaxAlreadyValidated) { | |
989 | // This is O(N^2) over the current list of consecutive labels, but I | |
990 | // have never seen more than one label in a row in the real world. | |
991 | for (size_t i = 0; i < labels.size(); i++) | |
992 | failIfTrue(ident->impl() == labels[i].m_ident->impl()); | |
993 | failIfTrue(getLabel(ident)); | |
93a37866 | 994 | labels.append(LabelInfo(ident, start, end, divotLine, divotLineStart)); |
6fe7ccc8 A |
995 | } |
996 | } while (match(IDENT)); | |
997 | bool isLoop = false; | |
998 | switch (m_token.m_type) { | |
999 | case FOR: | |
1000 | case WHILE: | |
1001 | case DO: | |
1002 | isLoop = true; | |
1003 | break; | |
1004 | ||
1005 | default: | |
1006 | break; | |
1007 | } | |
1008 | const Identifier* unused = 0; | |
1009 | if (!m_syntaxAlreadyValidated) { | |
1010 | for (size_t i = 0; i < labels.size(); i++) | |
1011 | pushLabel(labels[i].m_ident, isLoop); | |
1012 | } | |
1013 | TreeStatement statement = parseStatement(context, unused); | |
1014 | if (!m_syntaxAlreadyValidated) { | |
1015 | for (size_t i = 0; i < labels.size(); i++) | |
1016 | popLabel(); | |
1017 | } | |
1018 | failIfFalse(statement); | |
1019 | for (size_t i = 0; i < labels.size(); i++) { | |
1020 | const LabelInfo& info = labels[labels.size() - i - 1]; | |
93a37866 | 1021 | statement = context.createLabelStatement(location, info.m_ident, statement, info.m_start, info.m_end, info.m_divotLine, info.m_divotLineStart); |
6fe7ccc8 A |
1022 | } |
1023 | return statement; | |
1024 | } | |
1025 | ||
1026 | template <typename LexerType> | |
1027 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionStatement(TreeBuilder& context) | |
1028 | { | |
1029 | int startLine = tokenLine(); | |
93a37866 | 1030 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1031 | TreeExpression expression = parseExpression(context); |
1032 | failIfFalse(expression); | |
1033 | failIfFalse(autoSemiColon()); | |
93a37866 | 1034 | return context.createExprStatement(location, expression, startLine, m_lastLine); |
6fe7ccc8 A |
1035 | } |
1036 | ||
1037 | template <typename LexerType> | |
1038 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseIfStatement(TreeBuilder& context) | |
1039 | { | |
1040 | ASSERT(match(IF)); | |
93a37866 | 1041 | JSTokenLocation ifLocation(tokenLocation()); |
6fe7ccc8 A |
1042 | int start = tokenLine(); |
1043 | next(); | |
93a37866 | 1044 | |
6fe7ccc8 | 1045 | consumeOrFail(OPENPAREN); |
93a37866 | 1046 | |
6fe7ccc8 A |
1047 | TreeExpression condition = parseExpression(context); |
1048 | failIfFalse(condition); | |
1049 | int end = tokenLine(); | |
1050 | consumeOrFail(CLOSEPAREN); | |
93a37866 | 1051 | |
6fe7ccc8 A |
1052 | const Identifier* unused = 0; |
1053 | TreeStatement trueBlock = parseStatement(context, unused); | |
1054 | failIfFalse(trueBlock); | |
93a37866 | 1055 | |
6fe7ccc8 | 1056 | if (!match(ELSE)) |
93a37866 A |
1057 | return context.createIfStatement(ifLocation, condition, trueBlock, 0, start, end); |
1058 | ||
6fe7ccc8 A |
1059 | Vector<TreeExpression> exprStack; |
1060 | Vector<pair<int, int> > posStack; | |
93a37866 | 1061 | Vector<JSTokenLocation> tokenLocationStack; |
6fe7ccc8 A |
1062 | Vector<TreeStatement> statementStack; |
1063 | bool trailingElse = false; | |
1064 | do { | |
93a37866 | 1065 | JSTokenLocation tempLocation = tokenLocation(); |
6fe7ccc8 A |
1066 | next(); |
1067 | if (!match(IF)) { | |
1068 | const Identifier* unused = 0; | |
1069 | TreeStatement block = parseStatement(context, unused); | |
1070 | failIfFalse(block); | |
1071 | statementStack.append(block); | |
1072 | trailingElse = true; | |
1073 | break; | |
1074 | } | |
1075 | int innerStart = tokenLine(); | |
1076 | next(); | |
93a37866 | 1077 | |
6fe7ccc8 | 1078 | consumeOrFail(OPENPAREN); |
93a37866 | 1079 | |
6fe7ccc8 A |
1080 | TreeExpression innerCondition = parseExpression(context); |
1081 | failIfFalse(innerCondition); | |
1082 | int innerEnd = tokenLine(); | |
1083 | consumeOrFail(CLOSEPAREN); | |
1084 | const Identifier* unused = 0; | |
1085 | TreeStatement innerTrueBlock = parseStatement(context, unused); | |
93a37866 A |
1086 | failIfFalse(innerTrueBlock); |
1087 | tokenLocationStack.append(tempLocation); | |
6fe7ccc8 A |
1088 | exprStack.append(innerCondition); |
1089 | posStack.append(make_pair(innerStart, innerEnd)); | |
1090 | statementStack.append(innerTrueBlock); | |
1091 | } while (match(ELSE)); | |
93a37866 | 1092 | |
6fe7ccc8 A |
1093 | if (!trailingElse) { |
1094 | TreeExpression condition = exprStack.last(); | |
1095 | exprStack.removeLast(); | |
1096 | TreeStatement trueBlock = statementStack.last(); | |
1097 | statementStack.removeLast(); | |
1098 | pair<int, int> pos = posStack.last(); | |
1099 | posStack.removeLast(); | |
93a37866 A |
1100 | JSTokenLocation elseLocation = tokenLocationStack.last(); |
1101 | tokenLocationStack.removeLast(); | |
1102 | statementStack.append(context.createIfStatement(elseLocation, condition, trueBlock, 0, pos.first, pos.second)); | |
6fe7ccc8 | 1103 | } |
93a37866 | 1104 | |
6fe7ccc8 A |
1105 | while (!exprStack.isEmpty()) { |
1106 | TreeExpression condition = exprStack.last(); | |
1107 | exprStack.removeLast(); | |
1108 | TreeStatement falseBlock = statementStack.last(); | |
1109 | statementStack.removeLast(); | |
1110 | TreeStatement trueBlock = statementStack.last(); | |
1111 | statementStack.removeLast(); | |
1112 | pair<int, int> pos = posStack.last(); | |
1113 | posStack.removeLast(); | |
93a37866 A |
1114 | JSTokenLocation elseLocation = tokenLocationStack.last(); |
1115 | tokenLocationStack.removeLast(); | |
1116 | statementStack.append(context.createIfStatement(elseLocation, condition, trueBlock, falseBlock, pos.first, pos.second)); | |
6fe7ccc8 | 1117 | } |
93a37866 A |
1118 | |
1119 | return context.createIfStatement(ifLocation, condition, trueBlock, statementStack.last(), start, end); | |
6fe7ccc8 A |
1120 | } |
1121 | ||
1122 | template <typename LexerType> | |
1123 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseExpression(TreeBuilder& context) | |
1124 | { | |
1125 | failIfStackOverflow(); | |
93a37866 | 1126 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1127 | TreeExpression node = parseAssignmentExpression(context); |
1128 | failIfFalse(node); | |
1129 | if (!match(COMMA)) | |
1130 | return node; | |
1131 | next(); | |
1132 | m_nonTrivialExpressionCount++; | |
1133 | m_nonLHSCount++; | |
1134 | TreeExpression right = parseAssignmentExpression(context); | |
1135 | failIfFalse(right); | |
93a37866 | 1136 | typename TreeBuilder::Comma commaNode = context.createCommaExpr(location, node, right); |
6fe7ccc8 A |
1137 | while (match(COMMA)) { |
1138 | next(TreeBuilder::DontBuildStrings); | |
1139 | right = parseAssignmentExpression(context); | |
1140 | failIfFalse(right); | |
1141 | context.appendToComma(commaNode, right); | |
1142 | } | |
1143 | return commaNode; | |
1144 | } | |
1145 | ||
1146 | template <typename LexerType> | |
1147 | template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmentExpression(TreeBuilder& context) | |
1148 | { | |
1149 | failIfStackOverflow(); | |
1150 | int start = tokenStart(); | |
93a37866 A |
1151 | unsigned line = tokenLine(); |
1152 | unsigned lineStart = tokenLineStart(); | |
1153 | JSTokenLocation location(tokenLocation()); | |
6fe7ccc8 A |
1154 | int initialAssignmentCount = m_assignmentCount; |
1155 | int initialNonLHSCount = m_nonLHSCount; | |
1156 | TreeExpression lhs = parseConditionalExpression(context); | |
1157 | failIfFalse(lhs); | |
1158 | if (initialNonLHSCount != m_nonLHSCount) | |
1159 | return lhs; | |
1160 | ||
1161 | int assignmentStack = 0; | |
1162 | Operator op; | |
1163 | bool hadAssignment = false; | |
1164 | while (true) { | |
1165 | switch (m_token.m_type) { | |
1166 | case EQUAL: op = OpEqual; break; | |
1167 | case PLUSEQUAL: op = OpPlusEq; break; | |
1168 | case MINUSEQUAL: op = OpMinusEq; break; | |
1169 | case MULTEQUAL: op = OpMultEq; break; | |
1170 | case DIVEQUAL: op = OpDivEq; break; | |
1171 | case LSHIFTEQUAL: op = OpLShift; break; | |
1172 | case RSHIFTEQUAL: op = OpRShift; break; | |
1173 | case URSHIFTEQUAL: op = OpURShift; break; | |
1174 | case ANDEQUAL: op = OpAndEq; break; | |
1175 | case XOREQUAL: op = OpXOrEq; break; | |
1176 | case OREQUAL: op = OpOrEq; break; | |
1177 | case MODEQUAL: op = OpModEq; break; | |
1178 | default: | |
1179 | goto end; | |
1180 | } | |
1181 | m_nonTrivialExpressionCount++; | |
1182 | hadAssignment = true; | |
93a37866 | 1183 | context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), line, lineStart, m_assignmentCount, op); |
6fe7ccc8 | 1184 | start = tokenStart(); |
93a37866 A |
1185 | line = tokenLine(); |
1186 | lineStart = tokenLineStart(); | |
6fe7ccc8 A |
1187 | m_assignmentCount++; |
1188 | next(TreeBuilder::DontBuildStrings); | |
1189 | if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) { | |
93a37866 A |
1190 | failIfTrueIfStrictWithMessage(m_vm->propertyNames->eval == *m_lastIdentifier, "'eval' cannot be modified in strict mode"); |
1191 | failIfTrueIfStrictWithMessage(m_vm->propertyNames->arguments == *m_lastIdentifier, "'arguments' cannot be modified in strict mode"); | |
6fe7ccc8 A |
1192 | declareWrite(m_lastIdentifier); |
1193 | m_lastIdentifier = 0; | |
1194 | } | |
1195 | lhs = parseConditionalExpression(context); | |
1196 | failIfFalse(lhs); | |
1197 | if (initialNonLHSCount != m_nonLHSCount) | |
1198 | break; | |
1199 | } | |
1200 | end: | |
1201 | if (hadAssignment) | |
1202 | m_nonLHSCount++; | |
1203 | ||
1204 | if (!TreeBuilder::CreatesAST) | |
1205 | return lhs; | |
1206 | ||
1207 | while (assignmentStack) | |
93a37866 | 1208 | lhs = context.createAssignment(location, assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd()); |
6fe7ccc8 A |
1209 | |
1210 | return lhs; | |
1211 | } | |
1212 | ||
1213 | template <typename LexerType> | |
1214 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseConditionalExpression(TreeBuilder& context) | |
1215 | { | |
93a37866 | 1216 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1217 | TreeExpression cond = parseBinaryExpression(context); |
1218 | failIfFalse(cond); | |
1219 | if (!match(QUESTION)) | |
1220 | return cond; | |
1221 | m_nonTrivialExpressionCount++; | |
1222 | m_nonLHSCount++; | |
1223 | next(TreeBuilder::DontBuildStrings); | |
1224 | TreeExpression lhs = parseAssignmentExpression(context); | |
1225 | consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings); | |
1226 | ||
1227 | TreeExpression rhs = parseAssignmentExpression(context); | |
1228 | failIfFalse(rhs); | |
93a37866 | 1229 | return context.createConditionalExpr(location, cond, lhs, rhs); |
6fe7ccc8 A |
1230 | } |
1231 | ||
1232 | ALWAYS_INLINE static bool isUnaryOp(JSTokenType token) | |
1233 | { | |
1234 | return token & UnaryOpTokenFlag; | |
1235 | } | |
1236 | ||
1237 | template <typename LexerType> | |
1238 | int Parser<LexerType>::isBinaryOperator(JSTokenType token) | |
1239 | { | |
1240 | if (m_allowsIn) | |
1241 | return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift); | |
1242 | return token & BinaryOpTokenPrecedenceMask; | |
1243 | } | |
1244 | ||
1245 | template <typename LexerType> | |
1246 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseBinaryExpression(TreeBuilder& context) | |
1247 | { | |
1248 | ||
1249 | int operandStackDepth = 0; | |
1250 | int operatorStackDepth = 0; | |
1251 | typename TreeBuilder::BinaryExprContext binaryExprContext(context); | |
93a37866 | 1252 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1253 | while (true) { |
1254 | int exprStart = tokenStart(); | |
1255 | int initialAssignments = m_assignmentCount; | |
1256 | TreeExpression current = parseUnaryExpression(context); | |
1257 | failIfFalse(current); | |
1258 | ||
93a37866 | 1259 | context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), lastTokenLine(), lastTokenLineStart(), initialAssignments != m_assignmentCount); |
6fe7ccc8 A |
1260 | int precedence = isBinaryOperator(m_token.m_type); |
1261 | if (!precedence) | |
1262 | break; | |
1263 | m_nonTrivialExpressionCount++; | |
1264 | m_nonLHSCount++; | |
1265 | int operatorToken = m_token.m_type; | |
1266 | next(TreeBuilder::DontBuildStrings); | |
1267 | ||
1268 | while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) { | |
1269 | ASSERT(operandStackDepth > 1); | |
1270 | ||
1271 | typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1); | |
1272 | typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2); | |
1273 | context.shrinkOperandStackBy(operandStackDepth, 2); | |
93a37866 | 1274 | context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs); |
6fe7ccc8 A |
1275 | context.operatorStackPop(operatorStackDepth); |
1276 | } | |
1277 | context.operatorStackAppend(operatorStackDepth, operatorToken, precedence); | |
1278 | } | |
1279 | while (operatorStackDepth) { | |
1280 | ASSERT(operandStackDepth > 1); | |
1281 | ||
1282 | typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1); | |
1283 | typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2); | |
1284 | context.shrinkOperandStackBy(operandStackDepth, 2); | |
93a37866 | 1285 | context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs); |
6fe7ccc8 A |
1286 | context.operatorStackPop(operatorStackDepth); |
1287 | } | |
1288 | return context.popOperandStack(operandStackDepth); | |
1289 | } | |
1290 | ||
1291 | template <typename LexerType> | |
1292 | template <bool complete, class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeBuilder& context) | |
1293 | { | |
1294 | bool wasIdent = false; | |
1295 | switch (m_token.m_type) { | |
1296 | namedProperty: | |
1297 | case IDENT: | |
1298 | wasIdent = true; | |
1299 | case STRING: { | |
1300 | const Identifier* ident = m_token.m_data.ident; | |
93a37866 | 1301 | if (complete || (wasIdent && (*ident == m_vm->propertyNames->get || *ident == m_vm->propertyNames->set))) |
6fe7ccc8 A |
1302 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords); |
1303 | else | |
1304 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords); | |
1305 | ||
1306 | if (match(COLON)) { | |
1307 | next(); | |
1308 | TreeExpression node = parseAssignmentExpression(context); | |
1309 | failIfFalse(node); | |
1310 | return context.template createProperty<complete>(ident, node, PropertyNode::Constant); | |
1311 | } | |
1312 | failIfFalse(wasIdent); | |
1313 | const Identifier* accessorName = 0; | |
1314 | TreeFormalParameterList parameters = 0; | |
1315 | TreeFunctionBody body = 0; | |
93a37866 A |
1316 | unsigned openBraceOffset = 0; |
1317 | unsigned closeBraceOffset = 0; | |
6fe7ccc8 | 1318 | int bodyStartLine = 0; |
93a37866 | 1319 | unsigned bodyStartColumn = 0; |
6fe7ccc8 | 1320 | PropertyNode::Type type; |
93a37866 | 1321 | if (*ident == m_vm->propertyNames->get) |
6fe7ccc8 | 1322 | type = PropertyNode::Getter; |
93a37866 | 1323 | else if (*ident == m_vm->propertyNames->set) |
6fe7ccc8 A |
1324 | type = PropertyNode::Setter; |
1325 | else | |
1326 | fail(); | |
1327 | const Identifier* stringPropertyName = 0; | |
1328 | double numericPropertyName = 0; | |
1329 | if (m_token.m_type == IDENT || m_token.m_type == STRING) | |
1330 | stringPropertyName = m_token.m_data.ident; | |
1331 | else if (m_token.m_type == NUMBER) | |
1332 | numericPropertyName = m_token.m_data.doubleValue; | |
1333 | else | |
1334 | fail(); | |
93a37866 | 1335 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1336 | next(); |
93a37866 | 1337 | failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, accessorName, parameters, body, openBraceOffset, closeBraceOffset, bodyStartLine, bodyStartColumn))); |
6fe7ccc8 | 1338 | if (stringPropertyName) |
93a37866 A |
1339 | return context.template createGetterOrSetterProperty<complete>(location, type, stringPropertyName, parameters, body, openBraceOffset, closeBraceOffset, bodyStartLine, m_lastLine, bodyStartColumn); |
1340 | return context.template createGetterOrSetterProperty<complete>(const_cast<VM*>(m_vm), location, type, numericPropertyName, parameters, body, openBraceOffset, closeBraceOffset, bodyStartLine, m_lastLine, bodyStartColumn); | |
6fe7ccc8 A |
1341 | } |
1342 | case NUMBER: { | |
1343 | double propertyName = m_token.m_data.doubleValue; | |
1344 | next(); | |
1345 | consumeOrFail(COLON); | |
1346 | TreeExpression node = parseAssignmentExpression(context); | |
1347 | failIfFalse(node); | |
93a37866 | 1348 | return context.template createProperty<complete>(const_cast<VM*>(m_vm), propertyName, node, PropertyNode::Constant); |
6fe7ccc8 A |
1349 | } |
1350 | default: | |
1351 | failIfFalse(m_token.m_type & KeywordTokenFlag); | |
1352 | goto namedProperty; | |
1353 | } | |
1354 | } | |
1355 | ||
1356 | template <typename LexerType> | |
1357 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseObjectLiteral(TreeBuilder& context) | |
1358 | { | |
93a37866 A |
1359 | int startOffset = m_token.m_data.offset; |
1360 | unsigned oldLineStartOffset = m_lexer->currentLineStartOffset(); | |
6fe7ccc8 A |
1361 | unsigned oldLastLineNumber = m_lexer->lastLineNumber(); |
1362 | unsigned oldLineNumber = m_lexer->lineNumber(); | |
1363 | consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings); | |
93a37866 A |
1364 | JSTokenLocation location(tokenLocation()); |
1365 | ||
6fe7ccc8 A |
1366 | int oldNonLHSCount = m_nonLHSCount; |
1367 | ||
1368 | if (match(CLOSEBRACE)) { | |
1369 | next(); | |
93a37866 | 1370 | return context.createObjectLiteral(location); |
6fe7ccc8 A |
1371 | } |
1372 | ||
1373 | TreeProperty property = parseProperty<false>(context); | |
1374 | failIfFalse(property); | |
1375 | if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) { | |
93a37866 | 1376 | m_lexer->setOffset(startOffset, oldLineStartOffset); |
6fe7ccc8 A |
1377 | next(); |
1378 | m_lexer->setLastLineNumber(oldLastLineNumber); | |
1379 | m_lexer->setLineNumber(oldLineNumber); | |
1380 | return parseStrictObjectLiteral(context); | |
1381 | } | |
93a37866 | 1382 | TreePropertyList propertyList = context.createPropertyList(location, property); |
6fe7ccc8 A |
1383 | TreePropertyList tail = propertyList; |
1384 | while (match(COMMA)) { | |
1385 | next(TreeBuilder::DontBuildStrings); | |
1386 | // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 | |
1387 | if (match(CLOSEBRACE)) | |
1388 | break; | |
93a37866 | 1389 | JSTokenLocation propertyLocation(tokenLocation()); |
6fe7ccc8 A |
1390 | property = parseProperty<false>(context); |
1391 | failIfFalse(property); | |
1392 | if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) { | |
93a37866 | 1393 | m_lexer->setOffset(startOffset, oldLineStartOffset); |
6fe7ccc8 A |
1394 | next(); |
1395 | m_lexer->setLastLineNumber(oldLastLineNumber); | |
1396 | m_lexer->setLineNumber(oldLineNumber); | |
1397 | return parseStrictObjectLiteral(context); | |
1398 | } | |
93a37866 | 1399 | tail = context.createPropertyList(propertyLocation, property, tail); |
6fe7ccc8 | 1400 | } |
93a37866 A |
1401 | |
1402 | location = tokenLocation(); | |
6fe7ccc8 A |
1403 | consumeOrFail(CLOSEBRACE); |
1404 | ||
1405 | m_nonLHSCount = oldNonLHSCount; | |
1406 | ||
93a37866 | 1407 | return context.createObjectLiteral(location, propertyList); |
6fe7ccc8 A |
1408 | } |
1409 | ||
1410 | template <typename LexerType> | |
1411 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseStrictObjectLiteral(TreeBuilder& context) | |
1412 | { | |
1413 | consumeOrFail(OPENBRACE); | |
1414 | ||
1415 | int oldNonLHSCount = m_nonLHSCount; | |
1416 | ||
93a37866 | 1417 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1418 | if (match(CLOSEBRACE)) { |
1419 | next(); | |
93a37866 | 1420 | return context.createObjectLiteral(location); |
6fe7ccc8 A |
1421 | } |
1422 | ||
1423 | TreeProperty property = parseProperty<true>(context); | |
1424 | failIfFalse(property); | |
1425 | ||
1426 | typedef HashMap<RefPtr<StringImpl>, unsigned, IdentifierRepHash> ObjectValidationMap; | |
1427 | ObjectValidationMap objectValidator; | |
1428 | // Add the first property | |
1429 | if (!m_syntaxAlreadyValidated) | |
1430 | objectValidator.add(context.getName(property).impl(), context.getType(property)); | |
1431 | ||
93a37866 | 1432 | TreePropertyList propertyList = context.createPropertyList(location, property); |
6fe7ccc8 A |
1433 | TreePropertyList tail = propertyList; |
1434 | while (match(COMMA)) { | |
1435 | next(); | |
1436 | // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 | |
1437 | if (match(CLOSEBRACE)) | |
1438 | break; | |
93a37866 | 1439 | JSTokenLocation propertyLocation(tokenLocation()); |
6fe7ccc8 A |
1440 | property = parseProperty<true>(context); |
1441 | failIfFalse(property); | |
1442 | if (!m_syntaxAlreadyValidated) { | |
1443 | ObjectValidationMap::AddResult propertyEntry = objectValidator.add(context.getName(property).impl(), context.getType(property)); | |
1444 | if (!propertyEntry.isNewEntry) { | |
93a37866 | 1445 | failIfTrue(propertyEntry.iterator->value == PropertyNode::Constant); |
6fe7ccc8 | 1446 | failIfTrue(context.getType(property) == PropertyNode::Constant); |
93a37866 A |
1447 | failIfTrue(context.getType(property) & propertyEntry.iterator->value); |
1448 | propertyEntry.iterator->value |= context.getType(property); | |
6fe7ccc8 A |
1449 | } |
1450 | } | |
93a37866 | 1451 | tail = context.createPropertyList(propertyLocation, property, tail); |
6fe7ccc8 | 1452 | } |
93a37866 A |
1453 | |
1454 | location = tokenLocation(); | |
6fe7ccc8 A |
1455 | consumeOrFail(CLOSEBRACE); |
1456 | ||
1457 | m_nonLHSCount = oldNonLHSCount; | |
1458 | ||
93a37866 | 1459 | return context.createObjectLiteral(location, propertyList); |
6fe7ccc8 A |
1460 | } |
1461 | ||
1462 | template <typename LexerType> | |
1463 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrayLiteral(TreeBuilder& context) | |
1464 | { | |
1465 | consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings); | |
1466 | ||
1467 | int oldNonLHSCount = m_nonLHSCount; | |
1468 | ||
1469 | int elisions = 0; | |
1470 | while (match(COMMA)) { | |
1471 | next(TreeBuilder::DontBuildStrings); | |
1472 | elisions++; | |
1473 | } | |
1474 | if (match(CLOSEBRACKET)) { | |
93a37866 | 1475 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1476 | next(TreeBuilder::DontBuildStrings); |
93a37866 | 1477 | return context.createArray(location, elisions); |
6fe7ccc8 A |
1478 | } |
1479 | ||
1480 | TreeExpression elem = parseAssignmentExpression(context); | |
1481 | failIfFalse(elem); | |
1482 | typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem); | |
1483 | typename TreeBuilder::ElementList tail = elementList; | |
1484 | elisions = 0; | |
1485 | while (match(COMMA)) { | |
1486 | next(TreeBuilder::DontBuildStrings); | |
1487 | elisions = 0; | |
1488 | ||
1489 | while (match(COMMA)) { | |
1490 | next(); | |
1491 | elisions++; | |
1492 | } | |
1493 | ||
1494 | if (match(CLOSEBRACKET)) { | |
93a37866 | 1495 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1496 | next(TreeBuilder::DontBuildStrings); |
93a37866 | 1497 | return context.createArray(location, elisions, elementList); |
6fe7ccc8 A |
1498 | } |
1499 | TreeExpression elem = parseAssignmentExpression(context); | |
1500 | failIfFalse(elem); | |
1501 | tail = context.createElementList(tail, elisions, elem); | |
1502 | } | |
93a37866 A |
1503 | |
1504 | JSTokenLocation location(tokenLocation()); | |
6fe7ccc8 A |
1505 | consumeOrFail(CLOSEBRACKET); |
1506 | ||
1507 | m_nonLHSCount = oldNonLHSCount; | |
1508 | ||
93a37866 | 1509 | return context.createArray(location, elementList); |
6fe7ccc8 A |
1510 | } |
1511 | ||
1512 | template <typename LexerType> | |
1513 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpression(TreeBuilder& context) | |
1514 | { | |
1515 | failIfStackOverflow(); | |
1516 | switch (m_token.m_type) { | |
1517 | case OPENBRACE: | |
1518 | if (strictMode()) | |
1519 | return parseStrictObjectLiteral(context); | |
1520 | return parseObjectLiteral(context); | |
1521 | case OPENBRACKET: | |
1522 | return parseArrayLiteral(context); | |
1523 | case OPENPAREN: { | |
1524 | next(); | |
1525 | int oldNonLHSCount = m_nonLHSCount; | |
1526 | TreeExpression result = parseExpression(context); | |
1527 | m_nonLHSCount = oldNonLHSCount; | |
1528 | consumeOrFail(CLOSEPAREN); | |
1529 | ||
1530 | return result; | |
1531 | } | |
1532 | case THISTOKEN: { | |
93a37866 | 1533 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1534 | next(); |
93a37866 | 1535 | return context.thisExpr(location); |
6fe7ccc8 A |
1536 | } |
1537 | case IDENT: { | |
1538 | int start = tokenStart(); | |
93a37866 A |
1539 | int line = tokenLine(); |
1540 | int lineStart = tokenLineStart(); | |
6fe7ccc8 | 1541 | const Identifier* ident = m_token.m_data.ident; |
93a37866 | 1542 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1543 | next(); |
93a37866 | 1544 | currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident); |
6fe7ccc8 | 1545 | m_lastIdentifier = ident; |
93a37866 | 1546 | return context.createResolve(location, ident, start, line, lineStart); |
6fe7ccc8 A |
1547 | } |
1548 | case STRING: { | |
1549 | const Identifier* ident = m_token.m_data.ident; | |
93a37866 | 1550 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1551 | next(); |
93a37866 | 1552 | return context.createString(location, ident); |
6fe7ccc8 A |
1553 | } |
1554 | case NUMBER: { | |
1555 | double d = m_token.m_data.doubleValue; | |
93a37866 | 1556 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1557 | next(); |
93a37866 | 1558 | return context.createNumberExpr(location, d); |
6fe7ccc8 A |
1559 | } |
1560 | case NULLTOKEN: { | |
93a37866 | 1561 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1562 | next(); |
93a37866 | 1563 | return context.createNull(location); |
6fe7ccc8 A |
1564 | } |
1565 | case TRUETOKEN: { | |
93a37866 | 1566 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1567 | next(); |
93a37866 | 1568 | return context.createBoolean(location, true); |
6fe7ccc8 A |
1569 | } |
1570 | case FALSETOKEN: { | |
93a37866 | 1571 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 | 1572 | next(); |
93a37866 | 1573 | return context.createBoolean(location, false); |
6fe7ccc8 A |
1574 | } |
1575 | case DIVEQUAL: | |
1576 | case DIVIDE: { | |
1577 | /* regexp */ | |
1578 | const Identifier* pattern; | |
1579 | const Identifier* flags; | |
1580 | if (match(DIVEQUAL)) | |
1581 | failIfFalse(m_lexer->scanRegExp(pattern, flags, '=')); | |
1582 | else | |
1583 | failIfFalse(m_lexer->scanRegExp(pattern, flags)); | |
1584 | ||
1585 | int start = tokenStart(); | |
93a37866 A |
1586 | int line = tokenLine(); |
1587 | int lineStart = tokenLineStart(); | |
1588 | JSTokenLocation location(tokenLocation()); | |
6fe7ccc8 | 1589 | next(); |
93a37866 | 1590 | TreeExpression re = context.createRegExp(location, *pattern, *flags, start, line, lineStart); |
6fe7ccc8 | 1591 | if (!re) { |
93a37866 | 1592 | const char* yarrErrorMsg = Yarr::checkSyntax(pattern->string()); |
6fe7ccc8 A |
1593 | failWithMessage(yarrErrorMsg); |
1594 | } | |
1595 | return re; | |
1596 | } | |
1597 | default: | |
1598 | fail(); | |
1599 | } | |
1600 | } | |
1601 | ||
1602 | template <typename LexerType> | |
1603 | template <class TreeBuilder> TreeArguments Parser<LexerType>::parseArguments(TreeBuilder& context) | |
1604 | { | |
1605 | consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings); | |
93a37866 | 1606 | JSTokenLocation location(tokenLocation()); |
6fe7ccc8 A |
1607 | if (match(CLOSEPAREN)) { |
1608 | next(TreeBuilder::DontBuildStrings); | |
1609 | return context.createArguments(); | |
1610 | } | |
1611 | TreeExpression firstArg = parseAssignmentExpression(context); | |
1612 | failIfFalse(firstArg); | |
1613 | ||
93a37866 | 1614 | TreeArgumentsList argList = context.createArgumentsList(location, firstArg); |
6fe7ccc8 A |
1615 | TreeArgumentsList tail = argList; |
1616 | while (match(COMMA)) { | |
93a37866 | 1617 | JSTokenLocation argumentLocation(tokenLocation()); |
6fe7ccc8 A |
1618 | next(TreeBuilder::DontBuildStrings); |
1619 | TreeExpression arg = parseAssignmentExpression(context); | |
1620 | failIfFalse(arg); | |
93a37866 | 1621 | tail = context.createArgumentsList(argumentLocation, tail, arg); |
6fe7ccc8 A |
1622 | } |
1623 | consumeOrFail(CLOSEPAREN); | |
1624 | return context.createArguments(argList); | |
1625 | } | |
1626 | ||
1627 | template <typename LexerType> | |
1628 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpression(TreeBuilder& context) | |
1629 | { | |
1630 | TreeExpression base = 0; | |
1631 | int start = tokenStart(); | |
1632 | int expressionStart = start; | |
93a37866 A |
1633 | int expressionLine = tokenLine(); |
1634 | int expressionLineStart = tokenLineStart(); | |
6fe7ccc8 | 1635 | int newCount = 0; |
93a37866 | 1636 | JSTokenLocation location; |
6fe7ccc8 A |
1637 | while (match(NEW)) { |
1638 | next(); | |
1639 | newCount++; | |
1640 | } | |
1641 | ||
1642 | if (match(FUNCTION)) { | |
93a37866 | 1643 | const Identifier* name = &m_vm->propertyNames->nullIdentifier; |
6fe7ccc8 A |
1644 | TreeFormalParameterList parameters = 0; |
1645 | TreeFunctionBody body = 0; | |
93a37866 A |
1646 | unsigned openBraceOffset = 0; |
1647 | unsigned closeBraceOffset = 0; | |
6fe7ccc8 | 1648 | int bodyStartLine = 0; |
93a37866 A |
1649 | unsigned bodyStartColumn = 0; |
1650 | location = tokenLocation(); | |
6fe7ccc8 | 1651 | next(); |
93a37866 A |
1652 | failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, name, parameters, body, openBraceOffset, closeBraceOffset, bodyStartLine, bodyStartColumn))); |
1653 | base = context.createFunctionExpr(location, name, body, parameters, openBraceOffset, closeBraceOffset, bodyStartLine, m_lastLine, bodyStartColumn); | |
6fe7ccc8 A |
1654 | } else |
1655 | base = parsePrimaryExpression(context); | |
1656 | ||
1657 | failIfFalse(base); | |
1658 | while (true) { | |
93a37866 | 1659 | location = tokenLocation(); |
6fe7ccc8 A |
1660 | switch (m_token.m_type) { |
1661 | case OPENBRACKET: { | |
1662 | m_nonTrivialExpressionCount++; | |
1663 | int expressionEnd = lastTokenEnd(); | |
93a37866 A |
1664 | int expressionLine = lastTokenLine(); |
1665 | int expressionLineStart = lastTokenLineStart(); | |
6fe7ccc8 A |
1666 | next(); |
1667 | int nonLHSCount = m_nonLHSCount; | |
1668 | int initialAssignments = m_assignmentCount; | |
1669 | TreeExpression property = parseExpression(context); | |
1670 | failIfFalse(property); | |
93a37866 | 1671 | base = context.createBracketAccess(location, base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd(), expressionLine, expressionLineStart); |
6fe7ccc8 A |
1672 | consumeOrFail(CLOSEBRACKET); |
1673 | m_nonLHSCount = nonLHSCount; | |
1674 | break; | |
1675 | } | |
1676 | case OPENPAREN: { | |
1677 | m_nonTrivialExpressionCount++; | |
1678 | int nonLHSCount = m_nonLHSCount; | |
1679 | if (newCount) { | |
1680 | newCount--; | |
1681 | int exprEnd = lastTokenEnd(); | |
93a37866 A |
1682 | unsigned expressionLine = lastTokenLine(); |
1683 | unsigned expressionLineStart = lastTokenLineStart(); | |
6fe7ccc8 A |
1684 | TreeArguments arguments = parseArguments(context); |
1685 | failIfFalse(arguments); | |
93a37866 | 1686 | base = context.createNewExpr(location, base, arguments, start, exprEnd, lastTokenEnd(), expressionLine, expressionLineStart); |
6fe7ccc8 A |
1687 | } else { |
1688 | int expressionEnd = lastTokenEnd(); | |
93a37866 A |
1689 | unsigned expressionLine = lastTokenLine(); |
1690 | int expressionLineStart = lastTokenLineStart(); | |
6fe7ccc8 A |
1691 | TreeArguments arguments = parseArguments(context); |
1692 | failIfFalse(arguments); | |
93a37866 | 1693 | base = context.makeFunctionCallNode(location, base, arguments, expressionStart, expressionEnd, lastTokenEnd(), expressionLine, expressionLineStart); |
6fe7ccc8 A |
1694 | } |
1695 | m_nonLHSCount = nonLHSCount; | |
1696 | break; | |
1697 | } | |
1698 | case DOT: { | |
1699 | m_nonTrivialExpressionCount++; | |
1700 | int expressionEnd = lastTokenEnd(); | |
93a37866 | 1701 | expressionLineStart = lastTokenLineStart(); |
6fe7ccc8 A |
1702 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords); |
1703 | matchOrFail(IDENT); | |
93a37866 | 1704 | base = context.createDotAccess(location, base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd(), expressionLine, expressionLineStart); |
6fe7ccc8 A |
1705 | next(); |
1706 | break; | |
1707 | } | |
1708 | default: | |
1709 | goto endMemberExpression; | |
1710 | } | |
1711 | } | |
1712 | endMemberExpression: | |
1713 | while (newCount--) | |
93a37866 | 1714 | base = context.createNewExpr(location, base, start, lastTokenEnd(), expressionLine, expressionLineStart); |
6fe7ccc8 A |
1715 | return base; |
1716 | } | |
1717 | ||
1718 | template <typename LexerType> | |
1719 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpression(TreeBuilder& context) | |
1720 | { | |
1721 | typename TreeBuilder::UnaryExprContext unaryExprContext(context); | |
1722 | AllowInOverride allowInOverride(this); | |
1723 | int tokenStackDepth = 0; | |
1724 | bool modifiesExpr = false; | |
1725 | bool requiresLExpr = false; | |
1726 | while (isUnaryOp(m_token.m_type)) { | |
1727 | if (strictMode()) { | |
1728 | switch (m_token.m_type) { | |
1729 | case PLUSPLUS: | |
1730 | case MINUSMINUS: | |
1731 | case AUTOPLUSPLUS: | |
1732 | case AUTOMINUSMINUS: | |
1733 | failIfTrue(requiresLExpr); | |
1734 | modifiesExpr = true; | |
1735 | requiresLExpr = true; | |
1736 | break; | |
1737 | case DELETETOKEN: | |
1738 | failIfTrue(requiresLExpr); | |
1739 | requiresLExpr = true; | |
1740 | break; | |
1741 | default: | |
1742 | failIfTrue(requiresLExpr); | |
1743 | break; | |
1744 | } | |
1745 | } | |
1746 | m_nonLHSCount++; | |
93a37866 | 1747 | context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart(), tokenLine(), tokenLineStart()); |
6fe7ccc8 A |
1748 | next(); |
1749 | m_nonTrivialExpressionCount++; | |
1750 | } | |
1751 | int subExprStart = tokenStart(); | |
93a37866 A |
1752 | int subExprLine = tokenLine(); |
1753 | int subExprLineStartPosition = tokenLineStart(); | |
1754 | ASSERT(subExprStart >= subExprLineStartPosition); | |
1755 | JSTokenLocation location(tokenLocation()); | |
6fe7ccc8 A |
1756 | TreeExpression expr = parseMemberExpression(context); |
1757 | failIfFalse(expr); | |
1758 | bool isEvalOrArguments = false; | |
1759 | if (strictMode() && !m_syntaxAlreadyValidated) { | |
1760 | if (context.isResolve(expr)) | |
93a37866 | 1761 | isEvalOrArguments = *m_lastIdentifier == m_vm->propertyNames->eval || *m_lastIdentifier == m_vm->propertyNames->arguments; |
6fe7ccc8 A |
1762 | } |
1763 | failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments && modifiesExpr, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode"); | |
1764 | switch (m_token.m_type) { | |
1765 | case PLUSPLUS: | |
1766 | m_nonTrivialExpressionCount++; | |
1767 | m_nonLHSCount++; | |
93a37866 | 1768 | expr = context.makePostfixNode(location, expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd(), tokenLine(), tokenLineStart()); |
6fe7ccc8 A |
1769 | m_assignmentCount++; |
1770 | failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode"); | |
1771 | failIfTrueIfStrict(requiresLExpr); | |
1772 | next(); | |
1773 | break; | |
1774 | case MINUSMINUS: | |
1775 | m_nonTrivialExpressionCount++; | |
1776 | m_nonLHSCount++; | |
93a37866 | 1777 | expr = context.makePostfixNode(location, expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd(), tokenLine(), tokenLineStart()); |
6fe7ccc8 A |
1778 | m_assignmentCount++; |
1779 | failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode"); | |
1780 | failIfTrueIfStrict(requiresLExpr); | |
1781 | next(); | |
1782 | break; | |
1783 | default: | |
1784 | break; | |
1785 | } | |
1786 | ||
1787 | int end = lastTokenEnd(); | |
93a37866 A |
1788 | int endLine = lastTokenLine(); |
1789 | int endLineStartPosition = lastTokenLineStart(); | |
1790 | ||
6fe7ccc8 A |
1791 | if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode())) |
1792 | return expr; | |
93a37866 A |
1793 | |
1794 | location = tokenLocation(); | |
1795 | location.line = m_lexer->lastLineNumber(); | |
6fe7ccc8 A |
1796 | while (tokenStackDepth) { |
1797 | switch (context.unaryTokenStackLastType(tokenStackDepth)) { | |
1798 | case EXCLAMATION: | |
93a37866 | 1799 | expr = context.createLogicalNot(location, expr); |
6fe7ccc8 A |
1800 | break; |
1801 | case TILDE: | |
93a37866 | 1802 | expr = context.makeBitwiseNotNode(location, expr); |
6fe7ccc8 A |
1803 | break; |
1804 | case MINUS: | |
93a37866 | 1805 | expr = context.makeNegateNode(location, expr); |
6fe7ccc8 A |
1806 | break; |
1807 | case PLUS: | |
93a37866 | 1808 | expr = context.createUnaryPlus(location, expr); |
6fe7ccc8 A |
1809 | break; |
1810 | case PLUSPLUS: | |
1811 | case AUTOPLUSPLUS: | |
93a37866 | 1812 | expr = context.makePrefixNode(location, expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end, subExprLine, subExprLineStartPosition); |
6fe7ccc8 A |
1813 | m_assignmentCount++; |
1814 | break; | |
1815 | case MINUSMINUS: | |
1816 | case AUTOMINUSMINUS: | |
93a37866 | 1817 | expr = context.makePrefixNode(location, expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end, subExprLine, subExprLineStartPosition); |
6fe7ccc8 A |
1818 | m_assignmentCount++; |
1819 | break; | |
1820 | case TYPEOF: | |
93a37866 | 1821 | expr = context.makeTypeOfNode(location, expr); |
6fe7ccc8 A |
1822 | break; |
1823 | case VOIDTOKEN: | |
93a37866 | 1824 | expr = context.createVoid(location, expr); |
6fe7ccc8 A |
1825 | break; |
1826 | case DELETETOKEN: | |
1827 | failIfTrueIfStrictWithNameAndMessage(context.isResolve(expr), "Cannot delete unqualified property", m_lastIdentifier->impl(), "in strict mode"); | |
93a37866 | 1828 | expr = context.makeDeleteNode(location, expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end, endLine, endLineStartPosition); |
6fe7ccc8 A |
1829 | break; |
1830 | default: | |
1831 | // If we get here something has gone horribly horribly wrong | |
1832 | CRASH(); | |
1833 | } | |
1834 | subExprStart = context.unaryTokenStackLastStart(tokenStackDepth); | |
93a37866 | 1835 | subExprLineStartPosition = context.unaryTokenStackLastLineStartPosition(tokenStackDepth); |
6fe7ccc8 A |
1836 | context.unaryTokenStackRemoveLast(tokenStackDepth); |
1837 | } | |
1838 | return expr; | |
1839 | } | |
1840 | ||
1841 | // Instantiate the two flavors of Parser we need instead of putting most of this file in Parser.h | |
1842 | template class Parser< Lexer<LChar> >; | |
1843 | template class Parser< Lexer<UChar> >; | |
1844 | ||
9dae56ea | 1845 | } // namespace JSC |