]>
Commit | Line | Data |
---|---|---|
1 | /* | |
2 | * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) | |
3 | * Copyright (C) 2001 Peter Kelly (pmk@post.com) | |
4 | * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010, 2013 Apple Inc. All rights reserved. | |
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 | ||
26 | #include "ASTBuilder.h" | |
27 | #include "CodeBlock.h" | |
28 | #include "Debugger.h" | |
29 | #include "JSCJSValueInlines.h" | |
30 | #include "Lexer.h" | |
31 | #include "NodeInfo.h" | |
32 | #include "SourceProvider.h" | |
33 | #include "VM.h" | |
34 | #include <utility> | |
35 | #include <wtf/HashFunctions.h> | |
36 | #include <wtf/OwnPtr.h> | |
37 | #include <wtf/WTFThreadData.h> | |
38 | ||
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 | ||
61 | using namespace std; | |
62 | ||
63 | namespace JSC { | |
64 | ||
65 | template <typename LexerType> | |
66 | Parser<LexerType>::Parser(VM* vm, const SourceCode& source, FunctionParameters* parameters, const Identifier& name, JSParserStrictness strictness, JSParserMode parserMode) | |
67 | : m_vm(vm) | |
68 | , m_source(&source) | |
69 | , m_stack(wtfThreadData().stack()) | |
70 | , m_hasStackOverflow(false) | |
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) | |
81 | { | |
82 | m_lexer = adoptPtr(new LexerType(vm)); | |
83 | m_arena = m_vm->parserArena.get(); | |
84 | m_lexer->setCode(source, m_arena); | |
85 | m_token.m_location.endOffset = source.startOffset(); | |
86 | m_token.m_location.lineStartOffset = source.startOffset(); | |
87 | ||
88 | m_functionCache = vm->addSourceProviderCache(source.provider()); | |
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 | } | |
98 | if (!name.isNull()) | |
99 | scope->declareCallee(&name); | |
100 | next(); | |
101 | } | |
102 | ||
103 | template <typename LexerType> | |
104 | Parser<LexerType>::~Parser() | |
105 | { | |
106 | } | |
107 | ||
108 | template <typename LexerType> | |
109 | String Parser<LexerType>::parseInner() | |
110 | { | |
111 | String parseError = String(); | |
112 | ||
113 | ASTBuilder context(const_cast<VM*>(m_vm), const_cast<SourceCode*>(m_source)); | |
114 | if (m_lexer->isReparsing()) | |
115 | m_statementDepth--; | |
116 | ScopeRef scope = currentScope(); | |
117 | SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context); | |
118 | if (!sourceElements || !consume(EOFTOK)) { | |
119 | if (hasError()) | |
120 | parseError = m_errorMessage; | |
121 | else | |
122 | parseError = ASCIILiteral("Parser error"); | |
123 | } | |
124 | ||
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; | |
132 | ||
133 | didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features, | |
134 | m_lastLine, context.numConstants(), capturedVariables); | |
135 | ||
136 | return parseError; | |
137 | } | |
138 | ||
139 | template <typename LexerType> | |
140 | void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack, | |
141 | ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants, IdentifierSet& capturedVars) | |
142 | { | |
143 | m_sourceElements = sourceElements; | |
144 | m_varDeclarations = varStack; | |
145 | m_funcDeclarations = funcStack; | |
146 | m_capturedVariables.swap(capturedVars); | |
147 | m_features = features; | |
148 | m_lastLine = lastLine; | |
149 | m_numConstants = numConstants; | |
150 | } | |
151 | ||
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; | |
166 | unsigned startOffset = m_token.m_location.startOffset; | |
167 | unsigned startLineStartOffset = m_token.m_location.lineStartOffset; | |
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. | |
175 | if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_vm->propertyNames->useStrictIdentifier == *directive) { | |
176 | setStrictMode(); | |
177 | hasSetStrict = true; | |
178 | failIfFalse(isValidStrictMode()); | |
179 | m_lexer->setOffset(startOffset, startLineStartOffset); | |
180 | next(); | |
181 | m_lexer->setLastLineNumber(oldLastLineNumber); | |
182 | m_lexer->setLineNumber(oldLineNumber); | |
183 | failIfTrue(hasError()); | |
184 | continue; | |
185 | } | |
186 | } else | |
187 | seenNonDirective = true; | |
188 | } | |
189 | context.appendStatement(sourceElements, statement); | |
190 | } | |
191 | ||
192 | failIfTrue(hasError()); | |
193 | return sourceElements; | |
194 | } | |
195 | ||
196 | template <typename LexerType> | |
197 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVarDeclaration(TreeBuilder& context) | |
198 | { | |
199 | ASSERT(match(VAR)); | |
200 | JSTokenLocation location(tokenLocation()); | |
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); | |
208 | failIfTrue(hasError()); | |
209 | failIfFalse(autoSemiColon()); | |
210 | ||
211 | return context.createVarStatement(location, varDecls, start, end); | |
212 | } | |
213 | ||
214 | template <typename LexerType> | |
215 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseConstDeclaration(TreeBuilder& context) | |
216 | { | |
217 | ASSERT(match(CONSTTOKEN)); | |
218 | JSTokenLocation location(tokenLocation()); | |
219 | int start = tokenLine(); | |
220 | int end = 0; | |
221 | TreeConstDeclList constDecls = parseConstDeclarationList(context); | |
222 | failIfTrue(hasError()); | |
223 | failIfFalse(autoSemiColon()); | |
224 | ||
225 | return context.createConstStatement(location, constDecls, start, end); | |
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(); | |
240 | JSTokenLocation location(tokenLocation()); | |
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. | |
248 | return context.createDoWhileStatement(location, statement, expr, startLine, endLine); | |
249 | } | |
250 | ||
251 | template <typename LexerType> | |
252 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWhileStatement(TreeBuilder& context) | |
253 | { | |
254 | ASSERT(match(WHILE)); | |
255 | JSTokenLocation location(tokenLocation()); | |
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); | |
268 | return context.createWhileStatement(location, expr, statement, startLine, endLine); | |
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++; | |
277 | JSTokenLocation location(tokenLocation()); | |
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; | |
291 | unsigned varLine = tokenLine(); | |
292 | unsigned varLineStart = tokenLineStart(); | |
293 | initStart = tokenStart(); | |
294 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
295 | TreeExpression initializer = parseAssignmentExpression(context); | |
296 | initEnd = lastTokenEnd(); | |
297 | lastInitializer = initializer; | |
298 | failIfFalse(initializer); | |
299 | ||
300 | TreeExpression node = context.createAssignResolve(location, *name, initializer, varStart, varDivot, lastTokenEnd(), varLine, varLineStart); | |
301 | if (!varDecls) | |
302 | varDecls = node; | |
303 | else | |
304 | varDecls = context.combineCommaNodes(location, varDecls, node); | |
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 { | |
317 | JSTokenLocation location(tokenLocation()); | |
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)); | |
325 | ||
326 | TreeExpression initializer = 0; | |
327 | if (hasInitializer) { | |
328 | next(TreeBuilder::DontBuildStrings); // consume '=' | |
329 | initializer = parseAssignmentExpression(context); | |
330 | } | |
331 | tail = context.appendConstDecl(location, tail, name, initializer); | |
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)); | |
342 | JSTokenLocation location(tokenLocation()); | |
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; | |
350 | unsigned declsLine = 0; | |
351 | unsigned declsLineStart = 0; | |
352 | TreeExpression decls = 0; | |
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 | */ | |
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; | |
366 | failIfTrue(hasError()); | |
367 | ||
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(); | |
376 | unsigned inLine = tokenLine(); | |
377 | unsigned inLineStart = tokenLineStart(); | |
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 | ||
393 | return context.createForInLoop(location, forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine, inLine, inLineStart); | |
394 | } | |
395 | ||
396 | if (!match(SEMICOLON)) { | |
397 | m_allowsIn = false; | |
398 | declsStart = tokenStart(); | |
399 | decls = parseExpression(context); | |
400 | declsEnd = lastTokenEnd(); | |
401 | declsLine = lastTokenLine(); | |
402 | declsLineStart = lastTokenLineStart(); | |
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); | |
431 | return context.createForLoop(location, decls, condition, increment, statement, startLine, endLine); | |
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 | ||
448 | return context.createForInLoop(location, decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine, declsLine, declsLineStart); | |
449 | } | |
450 | ||
451 | template <typename LexerType> | |
452 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBreakStatement(TreeBuilder& context) | |
453 | { | |
454 | ASSERT(match(BREAK)); | |
455 | JSTokenLocation location(tokenLocation()); | |
456 | int startCol = tokenStart(); | |
457 | int endCol = tokenEnd(); | |
458 | int startLine = tokenLine(); | |
459 | int endLine = tokenLine(); | |
460 | unsigned endLineStart = tokenLineStart(); | |
461 | next(); | |
462 | ||
463 | if (autoSemiColon()) { | |
464 | failIfFalseWithMessage(breakIsValid(), "'break' is only valid inside a switch or loop statement"); | |
465 | return context.createBreakStatement(location, startCol, endCol, startLine, endLine, endLineStart); | |
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(); | |
472 | endLineStart = tokenLineStart(); | |
473 | next(); | |
474 | failIfFalse(autoSemiColon()); | |
475 | return context.createBreakStatement(location, ident, startCol, endCol, startLine, endLine, endLineStart); | |
476 | } | |
477 | ||
478 | template <typename LexerType> | |
479 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseContinueStatement(TreeBuilder& context) | |
480 | { | |
481 | ASSERT(match(CONTINUE)); | |
482 | JSTokenLocation location(tokenLocation()); | |
483 | int startCol = tokenStart(); | |
484 | int endCol = tokenEnd(); | |
485 | int startLine = tokenLine(); | |
486 | int endLine = tokenLine(); | |
487 | unsigned endLineStart = tokenLineStart(); | |
488 | next(); | |
489 | ||
490 | if (autoSemiColon()) { | |
491 | failIfFalseWithMessage(continueIsValid(), "'continue' is only valid inside a loop statement"); | |
492 | return context.createContinueStatement(location, startCol, endCol, startLine, endLine, endLineStart); | |
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(); | |
501 | endLineStart = tokenLineStart(); | |
502 | next(); | |
503 | failIfFalse(autoSemiColon()); | |
504 | return context.createContinueStatement(location, ident, startCol, endCol, startLine, endLine, endLineStart); | |
505 | } | |
506 | ||
507 | template <typename LexerType> | |
508 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseReturnStatement(TreeBuilder& context) | |
509 | { | |
510 | ASSERT(match(RETURN)); | |
511 | JSTokenLocation location(tokenLocation()); | |
512 | failIfFalse(currentScope()->isFunction()); | |
513 | int startLine = tokenLine(); | |
514 | int endLine = startLine; | |
515 | int start = tokenStart(); | |
516 | int end = tokenEnd(); | |
517 | unsigned divotLine = tokenLine(); | |
518 | unsigned divotLineStart = tokenLineStart(); | |
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()) | |
526 | return context.createReturnStatement(location, 0, start, end, startLine, endLine, divotLine, divotLineStart); | |
527 | TreeExpression expr = parseExpression(context); | |
528 | failIfFalse(expr); | |
529 | end = lastTokenEnd(); | |
530 | divotLine = lastTokenLine(); | |
531 | divotLineStart = lastTokenLineStart(); | |
532 | if (match(SEMICOLON)) | |
533 | endLine = tokenLine(); | |
534 | failIfFalse(autoSemiColon()); | |
535 | return context.createReturnStatement(location, expr, start, end, startLine, endLine, divotLine, divotLineStart); | |
536 | } | |
537 | ||
538 | template <typename LexerType> | |
539 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseThrowStatement(TreeBuilder& context) | |
540 | { | |
541 | ASSERT(match(THROW)); | |
542 | JSTokenLocation location(tokenLocation()); | |
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(); | |
552 | unsigned divotLine = lastTokenLine(); | |
553 | unsigned divotLineStart = lastTokenLineStart(); | |
554 | int endLine = tokenLine(); | |
555 | failIfFalse(autoSemiColon()); | |
556 | ||
557 | return context.createThrowStatement(location, expr, eStart, eEnd, startLine, endLine, divotLine, divotLineStart); | |
558 | } | |
559 | ||
560 | template <typename LexerType> | |
561 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWithStatement(TreeBuilder& context) | |
562 | { | |
563 | ASSERT(match(WITH)); | |
564 | JSTokenLocation location(tokenLocation()); | |
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(); | |
574 | unsigned divotLine = lastTokenLine(); | |
575 | unsigned divotLineStart = lastTokenLineStart(); | |
576 | int endLine = tokenLine(); | |
577 | consumeOrFail(CLOSEPAREN); | |
578 | const Identifier* unused = 0; | |
579 | TreeStatement statement = parseStatement(context, unused); | |
580 | failIfFalse(statement); | |
581 | ||
582 | return context.createWithStatement(location, expr, statement, start, end, startLine, endLine, divotLine, divotLineStart); | |
583 | } | |
584 | ||
585 | template <typename LexerType> | |
586 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseSwitchStatement(TreeBuilder& context) | |
587 | { | |
588 | ASSERT(match(SWITCH)); | |
589 | JSTokenLocation location(tokenLocation()); | |
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); | |
600 | failIfTrue(hasError()); | |
601 | ||
602 | TreeClause defaultClause = parseSwitchDefaultClause(context); | |
603 | failIfTrue(hasError()); | |
604 | ||
605 | TreeClauseList secondClauses = parseSwitchClauses(context); | |
606 | failIfTrue(hasError()); | |
607 | endSwitch(); | |
608 | consumeOrFail(CLOSEBRACE); | |
609 | ||
610 | return context.createSwitchStatement(location, expr, firstClauses, defaultClause, secondClauses, startLine, endLine); | |
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)); | |
658 | JSTokenLocation location(tokenLocation()); | |
659 | TreeStatement tryBlock = 0; | |
660 | const Identifier* ident = &m_vm->propertyNames->nullIdentifier; | |
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); | |
695 | return context.createTryStatement(location, tryBlock, ident, catchBlock, finallyBlock, firstLine, lastLine); | |
696 | } | |
697 | ||
698 | template <typename LexerType> | |
699 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDebuggerStatement(TreeBuilder& context) | |
700 | { | |
701 | ASSERT(match(DEBUGGER)); | |
702 | JSTokenLocation location(tokenLocation()); | |
703 | int startLine = tokenLine(); | |
704 | int endLine = startLine; | |
705 | next(); | |
706 | if (match(SEMICOLON)) | |
707 | startLine = tokenLine(); | |
708 | failIfFalse(autoSemiColon()); | |
709 | return context.createDebugger(location, startLine, endLine); | |
710 | } | |
711 | ||
712 | template <typename LexerType> | |
713 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatement(TreeBuilder& context) | |
714 | { | |
715 | ASSERT(match(OPENBRACE)); | |
716 | JSTokenLocation location(tokenLocation()); | |
717 | int start = tokenLine(); | |
718 | next(); | |
719 | if (match(CLOSEBRACE)) { | |
720 | next(); | |
721 | return context.createBlockStatement(location, 0, start, m_lastLine); | |
722 | } | |
723 | TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context); | |
724 | failIfFalse(subtree); | |
725 | matchOrFail(CLOSEBRACE); | |
726 | next(); | |
727 | return context.createBlockStatement(location, subtree, start, m_lastLine); | |
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); | |
748 | case SEMICOLON: { | |
749 | JSTokenLocation location(tokenLocation()); | |
750 | next(); | |
751 | return context.createEmptyStatement(location); | |
752 | } | |
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) | |
788 | *directiveLiteralLength = m_token.m_location.endOffset - m_token.m_location.startOffset; | |
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 | { | |
820 | JSTokenLocation startLocation(tokenLocation()); | |
821 | unsigned startColumn = tokenColumn(); | |
822 | next(); | |
823 | ||
824 | if (match(CLOSEBRACE)) | |
825 | return context.createFunctionBody(startLocation, tokenLocation(), startColumn, strictMode()); | |
826 | DepthManager statementDepth(&m_statementDepth); | |
827 | m_statementDepth = 0; | |
828 | typename TreeBuilder::FunctionBodyBuilder bodyBuilder(const_cast<VM*>(m_vm), m_lexer.get()); | |
829 | failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder)); | |
830 | return context.createFunctionBody(startLocation, tokenLocation(), startColumn, strictMode()); | |
831 | } | |
832 | ||
833 | template <typename LexerType> | |
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) | |
835 | { | |
836 | AutoPopScopeRef functionScope(this, pushScope()); | |
837 | functionScope->setIsFunction(); | |
838 | int functionStart = m_token.m_location.startOffset; | |
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 | ||
854 | openBraceOffset = m_token.m_data.offset; | |
855 | bodyStartLine = tokenLine(); | |
856 | bodyStartColumn = m_token.m_data.offset - m_token.m_data.lineStartOffset; | |
857 | JSTokenLocation startLocation(tokenLocation()); | |
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. | |
860 | if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBraceOffset) : 0) { | |
861 | // If we're in a strict context, the cached function info must say it was strict too. | |
862 | ASSERT(!strictMode() || cachedInfo->strictMode); | |
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); | |
871 | ||
872 | functionScope->restoreFromSourceProviderCache(cachedInfo); | |
873 | failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo)); | |
874 | ||
875 | closeBraceOffset = cachedInfo->closeBraceOffset; | |
876 | ||
877 | context.setFunctionStart(body, functionStart); | |
878 | m_token = cachedInfo->closeBraceToken(); | |
879 | ||
880 | m_lexer->setOffset(m_token.m_location.endOffset, m_token.m_location.lineStartOffset); | |
881 | m_lexer->setLineNumber(m_token.m_location.line); | |
882 | ||
883 | next(); | |
884 | return true; | |
885 | } | |
886 | ||
887 | body = parseFunctionBody(context); | |
888 | failIfFalse(body); | |
889 | if (functionScope->strictMode() && name) { | |
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"); | |
892 | } | |
893 | closeBraceOffset = m_token.m_data.offset; | |
894 | unsigned closeBraceLine = m_token.m_data.line; | |
895 | unsigned closeBraceLineStartOffset = m_token.m_data.lineStartOffset; | |
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. | |
899 | static const int minimumFunctionLengthToCache = 16; | |
900 | OwnPtr<SourceProviderCacheItem> newInfo; | |
901 | int functionLength = closeBraceOffset - openBraceOffset; | |
902 | if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) { | |
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 | ||
911 | } | |
912 | context.setFunctionStart(body, functionStart); | |
913 | ||
914 | failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo)); | |
915 | matchOrFail(CLOSEBRACE); | |
916 | ||
917 | if (newInfo) | |
918 | m_functionCache->add(openBraceOffset, newInfo.release()); | |
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)); | |
928 | JSTokenLocation location(tokenLocation()); | |
929 | next(); | |
930 | const Identifier* name = 0; | |
931 | TreeFormalParameterList parameters = 0; | |
932 | TreeFunctionBody body = 0; | |
933 | unsigned openBraceOffset = 0; | |
934 | unsigned closeBraceOffset = 0; | |
935 | int bodyStartLine = 0; | |
936 | unsigned bodyStartColumn = 0; | |
937 | failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBraceOffset, closeBraceOffset, bodyStartLine, bodyStartColumn))); | |
938 | failIfFalse(name); | |
939 | failIfFalseIfStrict(declareVariable(name)); | |
940 | return context.createFuncDeclStatement(location, name, body, parameters, openBraceOffset, closeBraceOffset, bodyStartLine, m_lastLine, bodyStartColumn); | |
941 | } | |
942 | ||
943 | struct LabelInfo { | |
944 | LabelInfo(const Identifier* ident, unsigned start, unsigned end, unsigned divotLine, unsigned divotLineStart) | |
945 | : m_ident(ident) | |
946 | , m_start(start) | |
947 | , m_end(end) | |
948 | , m_divotLine(divotLine) | |
949 | , m_divotLineStart(divotLineStart) | |
950 | { | |
951 | } | |
952 | ||
953 | const Identifier* m_ident; | |
954 | unsigned m_start; | |
955 | unsigned m_end; | |
956 | unsigned m_divotLine; | |
957 | unsigned m_divotLineStart; | |
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; | |
968 | JSTokenLocation location; | |
969 | do { | |
970 | int start = tokenStart(); | |
971 | int startingLine = tokenLine(); | |
972 | location = tokenLocation(); | |
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()); | |
980 | return context.createExprStatement(location, expression, startingLine, m_lastLine); | |
981 | } | |
982 | const Identifier* ident = m_token.m_data.ident; | |
983 | int end = tokenEnd(); | |
984 | unsigned divotLine = tokenLine(); | |
985 | unsigned divotLineStart = tokenLineStart(); | |
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)); | |
994 | labels.append(LabelInfo(ident, start, end, divotLine, divotLineStart)); | |
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]; | |
1021 | statement = context.createLabelStatement(location, info.m_ident, statement, info.m_start, info.m_end, info.m_divotLine, info.m_divotLineStart); | |
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(); | |
1030 | JSTokenLocation location(tokenLocation()); | |
1031 | TreeExpression expression = parseExpression(context); | |
1032 | failIfFalse(expression); | |
1033 | failIfFalse(autoSemiColon()); | |
1034 | return context.createExprStatement(location, expression, startLine, m_lastLine); | |
1035 | } | |
1036 | ||
1037 | template <typename LexerType> | |
1038 | template <class TreeBuilder> TreeStatement Parser<LexerType>::parseIfStatement(TreeBuilder& context) | |
1039 | { | |
1040 | ASSERT(match(IF)); | |
1041 | JSTokenLocation ifLocation(tokenLocation()); | |
1042 | int start = tokenLine(); | |
1043 | next(); | |
1044 | ||
1045 | consumeOrFail(OPENPAREN); | |
1046 | ||
1047 | TreeExpression condition = parseExpression(context); | |
1048 | failIfFalse(condition); | |
1049 | int end = tokenLine(); | |
1050 | consumeOrFail(CLOSEPAREN); | |
1051 | ||
1052 | const Identifier* unused = 0; | |
1053 | TreeStatement trueBlock = parseStatement(context, unused); | |
1054 | failIfFalse(trueBlock); | |
1055 | ||
1056 | if (!match(ELSE)) | |
1057 | return context.createIfStatement(ifLocation, condition, trueBlock, 0, start, end); | |
1058 | ||
1059 | Vector<TreeExpression> exprStack; | |
1060 | Vector<pair<int, int> > posStack; | |
1061 | Vector<JSTokenLocation> tokenLocationStack; | |
1062 | Vector<TreeStatement> statementStack; | |
1063 | bool trailingElse = false; | |
1064 | do { | |
1065 | JSTokenLocation tempLocation = tokenLocation(); | |
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(); | |
1077 | ||
1078 | consumeOrFail(OPENPAREN); | |
1079 | ||
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); | |
1086 | failIfFalse(innerTrueBlock); | |
1087 | tokenLocationStack.append(tempLocation); | |
1088 | exprStack.append(innerCondition); | |
1089 | posStack.append(make_pair(innerStart, innerEnd)); | |
1090 | statementStack.append(innerTrueBlock); | |
1091 | } while (match(ELSE)); | |
1092 | ||
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(); | |
1100 | JSTokenLocation elseLocation = tokenLocationStack.last(); | |
1101 | tokenLocationStack.removeLast(); | |
1102 | statementStack.append(context.createIfStatement(elseLocation, condition, trueBlock, 0, pos.first, pos.second)); | |
1103 | } | |
1104 | ||
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(); | |
1114 | JSTokenLocation elseLocation = tokenLocationStack.last(); | |
1115 | tokenLocationStack.removeLast(); | |
1116 | statementStack.append(context.createIfStatement(elseLocation, condition, trueBlock, falseBlock, pos.first, pos.second)); | |
1117 | } | |
1118 | ||
1119 | return context.createIfStatement(ifLocation, condition, trueBlock, statementStack.last(), start, end); | |
1120 | } | |
1121 | ||
1122 | template <typename LexerType> | |
1123 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseExpression(TreeBuilder& context) | |
1124 | { | |
1125 | failIfStackOverflow(); | |
1126 | JSTokenLocation location(tokenLocation()); | |
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); | |
1136 | typename TreeBuilder::Comma commaNode = context.createCommaExpr(location, node, right); | |
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(); | |
1151 | unsigned line = tokenLine(); | |
1152 | unsigned lineStart = tokenLineStart(); | |
1153 | JSTokenLocation location(tokenLocation()); | |
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; | |
1183 | context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), line, lineStart, m_assignmentCount, op); | |
1184 | start = tokenStart(); | |
1185 | line = tokenLine(); | |
1186 | lineStart = tokenLineStart(); | |
1187 | m_assignmentCount++; | |
1188 | next(TreeBuilder::DontBuildStrings); | |
1189 | if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) { | |
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"); | |
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) | |
1208 | lhs = context.createAssignment(location, assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd()); | |
1209 | ||
1210 | return lhs; | |
1211 | } | |
1212 | ||
1213 | template <typename LexerType> | |
1214 | template <class TreeBuilder> TreeExpression Parser<LexerType>::parseConditionalExpression(TreeBuilder& context) | |
1215 | { | |
1216 | JSTokenLocation location(tokenLocation()); | |
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); | |
1229 | return context.createConditionalExpr(location, cond, lhs, rhs); | |
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); | |
1252 | JSTokenLocation location(tokenLocation()); | |
1253 | while (true) { | |
1254 | int exprStart = tokenStart(); | |
1255 | int initialAssignments = m_assignmentCount; | |
1256 | TreeExpression current = parseUnaryExpression(context); | |
1257 | failIfFalse(current); | |
1258 | ||
1259 | context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), lastTokenLine(), lastTokenLineStart(), initialAssignments != m_assignmentCount); | |
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); | |
1274 | context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs); | |
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); | |
1285 | context.appendBinaryOperation(location, operandStackDepth, operatorStackDepth, lhs, rhs); | |
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; | |
1301 | if (complete || (wasIdent && (*ident == m_vm->propertyNames->get || *ident == m_vm->propertyNames->set))) | |
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; | |
1316 | unsigned openBraceOffset = 0; | |
1317 | unsigned closeBraceOffset = 0; | |
1318 | int bodyStartLine = 0; | |
1319 | unsigned bodyStartColumn = 0; | |
1320 | PropertyNode::Type type; | |
1321 | if (*ident == m_vm->propertyNames->get) | |
1322 | type = PropertyNode::Getter; | |
1323 | else if (*ident == m_vm->propertyNames->set) | |
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(); | |
1335 | JSTokenLocation location(tokenLocation()); | |
1336 | next(); | |
1337 | failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, accessorName, parameters, body, openBraceOffset, closeBraceOffset, bodyStartLine, bodyStartColumn))); | |
1338 | if (stringPropertyName) | |
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); | |
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); | |
1348 | return context.template createProperty<complete>(const_cast<VM*>(m_vm), propertyName, node, PropertyNode::Constant); | |
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 | { | |
1359 | int startOffset = m_token.m_data.offset; | |
1360 | unsigned oldLineStartOffset = m_lexer->currentLineStartOffset(); | |
1361 | unsigned oldLastLineNumber = m_lexer->lastLineNumber(); | |
1362 | unsigned oldLineNumber = m_lexer->lineNumber(); | |
1363 | consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings); | |
1364 | JSTokenLocation location(tokenLocation()); | |
1365 | ||
1366 | int oldNonLHSCount = m_nonLHSCount; | |
1367 | ||
1368 | if (match(CLOSEBRACE)) { | |
1369 | next(); | |
1370 | return context.createObjectLiteral(location); | |
1371 | } | |
1372 | ||
1373 | TreeProperty property = parseProperty<false>(context); | |
1374 | failIfFalse(property); | |
1375 | if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) { | |
1376 | m_lexer->setOffset(startOffset, oldLineStartOffset); | |
1377 | next(); | |
1378 | m_lexer->setLastLineNumber(oldLastLineNumber); | |
1379 | m_lexer->setLineNumber(oldLineNumber); | |
1380 | return parseStrictObjectLiteral(context); | |
1381 | } | |
1382 | TreePropertyList propertyList = context.createPropertyList(location, property); | |
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; | |
1389 | JSTokenLocation propertyLocation(tokenLocation()); | |
1390 | property = parseProperty<false>(context); | |
1391 | failIfFalse(property); | |
1392 | if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) { | |
1393 | m_lexer->setOffset(startOffset, oldLineStartOffset); | |
1394 | next(); | |
1395 | m_lexer->setLastLineNumber(oldLastLineNumber); | |
1396 | m_lexer->setLineNumber(oldLineNumber); | |
1397 | return parseStrictObjectLiteral(context); | |
1398 | } | |
1399 | tail = context.createPropertyList(propertyLocation, property, tail); | |
1400 | } | |
1401 | ||
1402 | location = tokenLocation(); | |
1403 | consumeOrFail(CLOSEBRACE); | |
1404 | ||
1405 | m_nonLHSCount = oldNonLHSCount; | |
1406 | ||
1407 | return context.createObjectLiteral(location, propertyList); | |
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 | ||
1417 | JSTokenLocation location(tokenLocation()); | |
1418 | if (match(CLOSEBRACE)) { | |
1419 | next(); | |
1420 | return context.createObjectLiteral(location); | |
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 | ||
1432 | TreePropertyList propertyList = context.createPropertyList(location, property); | |
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; | |
1439 | JSTokenLocation propertyLocation(tokenLocation()); | |
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) { | |
1445 | failIfTrue(propertyEntry.iterator->value == PropertyNode::Constant); | |
1446 | failIfTrue(context.getType(property) == PropertyNode::Constant); | |
1447 | failIfTrue(context.getType(property) & propertyEntry.iterator->value); | |
1448 | propertyEntry.iterator->value |= context.getType(property); | |
1449 | } | |
1450 | } | |
1451 | tail = context.createPropertyList(propertyLocation, property, tail); | |
1452 | } | |
1453 | ||
1454 | location = tokenLocation(); | |
1455 | consumeOrFail(CLOSEBRACE); | |
1456 | ||
1457 | m_nonLHSCount = oldNonLHSCount; | |
1458 | ||
1459 | return context.createObjectLiteral(location, propertyList); | |
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)) { | |
1475 | JSTokenLocation location(tokenLocation()); | |
1476 | next(TreeBuilder::DontBuildStrings); | |
1477 | return context.createArray(location, elisions); | |
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)) { | |
1495 | JSTokenLocation location(tokenLocation()); | |
1496 | next(TreeBuilder::DontBuildStrings); | |
1497 | return context.createArray(location, elisions, elementList); | |
1498 | } | |
1499 | TreeExpression elem = parseAssignmentExpression(context); | |
1500 | failIfFalse(elem); | |
1501 | tail = context.createElementList(tail, elisions, elem); | |
1502 | } | |
1503 | ||
1504 | JSTokenLocation location(tokenLocation()); | |
1505 | consumeOrFail(CLOSEBRACKET); | |
1506 | ||
1507 | m_nonLHSCount = oldNonLHSCount; | |
1508 | ||
1509 | return context.createArray(location, elementList); | |
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: { | |
1533 | JSTokenLocation location(tokenLocation()); | |
1534 | next(); | |
1535 | return context.thisExpr(location); | |
1536 | } | |
1537 | case IDENT: { | |
1538 | int start = tokenStart(); | |
1539 | int line = tokenLine(); | |
1540 | int lineStart = tokenLineStart(); | |
1541 | const Identifier* ident = m_token.m_data.ident; | |
1542 | JSTokenLocation location(tokenLocation()); | |
1543 | next(); | |
1544 | currentScope()->useVariable(ident, m_vm->propertyNames->eval == *ident); | |
1545 | m_lastIdentifier = ident; | |
1546 | return context.createResolve(location, ident, start, line, lineStart); | |
1547 | } | |
1548 | case STRING: { | |
1549 | const Identifier* ident = m_token.m_data.ident; | |
1550 | JSTokenLocation location(tokenLocation()); | |
1551 | next(); | |
1552 | return context.createString(location, ident); | |
1553 | } | |
1554 | case NUMBER: { | |
1555 | double d = m_token.m_data.doubleValue; | |
1556 | JSTokenLocation location(tokenLocation()); | |
1557 | next(); | |
1558 | return context.createNumberExpr(location, d); | |
1559 | } | |
1560 | case NULLTOKEN: { | |
1561 | JSTokenLocation location(tokenLocation()); | |
1562 | next(); | |
1563 | return context.createNull(location); | |
1564 | } | |
1565 | case TRUETOKEN: { | |
1566 | JSTokenLocation location(tokenLocation()); | |
1567 | next(); | |
1568 | return context.createBoolean(location, true); | |
1569 | } | |
1570 | case FALSETOKEN: { | |
1571 | JSTokenLocation location(tokenLocation()); | |
1572 | next(); | |
1573 | return context.createBoolean(location, false); | |
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(); | |
1586 | int line = tokenLine(); | |
1587 | int lineStart = tokenLineStart(); | |
1588 | JSTokenLocation location(tokenLocation()); | |
1589 | next(); | |
1590 | TreeExpression re = context.createRegExp(location, *pattern, *flags, start, line, lineStart); | |
1591 | if (!re) { | |
1592 | const char* yarrErrorMsg = Yarr::checkSyntax(pattern->string()); | |
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); | |
1606 | JSTokenLocation location(tokenLocation()); | |
1607 | if (match(CLOSEPAREN)) { | |
1608 | next(TreeBuilder::DontBuildStrings); | |
1609 | return context.createArguments(); | |
1610 | } | |
1611 | TreeExpression firstArg = parseAssignmentExpression(context); | |
1612 | failIfFalse(firstArg); | |
1613 | ||
1614 | TreeArgumentsList argList = context.createArgumentsList(location, firstArg); | |
1615 | TreeArgumentsList tail = argList; | |
1616 | while (match(COMMA)) { | |
1617 | JSTokenLocation argumentLocation(tokenLocation()); | |
1618 | next(TreeBuilder::DontBuildStrings); | |
1619 | TreeExpression arg = parseAssignmentExpression(context); | |
1620 | failIfFalse(arg); | |
1621 | tail = context.createArgumentsList(argumentLocation, tail, arg); | |
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; | |
1633 | int expressionLine = tokenLine(); | |
1634 | int expressionLineStart = tokenLineStart(); | |
1635 | int newCount = 0; | |
1636 | JSTokenLocation location; | |
1637 | while (match(NEW)) { | |
1638 | next(); | |
1639 | newCount++; | |
1640 | } | |
1641 | ||
1642 | if (match(FUNCTION)) { | |
1643 | const Identifier* name = &m_vm->propertyNames->nullIdentifier; | |
1644 | TreeFormalParameterList parameters = 0; | |
1645 | TreeFunctionBody body = 0; | |
1646 | unsigned openBraceOffset = 0; | |
1647 | unsigned closeBraceOffset = 0; | |
1648 | int bodyStartLine = 0; | |
1649 | unsigned bodyStartColumn = 0; | |
1650 | location = tokenLocation(); | |
1651 | next(); | |
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); | |
1654 | } else | |
1655 | base = parsePrimaryExpression(context); | |
1656 | ||
1657 | failIfFalse(base); | |
1658 | while (true) { | |
1659 | location = tokenLocation(); | |
1660 | switch (m_token.m_type) { | |
1661 | case OPENBRACKET: { | |
1662 | m_nonTrivialExpressionCount++; | |
1663 | int expressionEnd = lastTokenEnd(); | |
1664 | int expressionLine = lastTokenLine(); | |
1665 | int expressionLineStart = lastTokenLineStart(); | |
1666 | next(); | |
1667 | int nonLHSCount = m_nonLHSCount; | |
1668 | int initialAssignments = m_assignmentCount; | |
1669 | TreeExpression property = parseExpression(context); | |
1670 | failIfFalse(property); | |
1671 | base = context.createBracketAccess(location, base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd(), expressionLine, expressionLineStart); | |
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(); | |
1682 | unsigned expressionLine = lastTokenLine(); | |
1683 | unsigned expressionLineStart = lastTokenLineStart(); | |
1684 | TreeArguments arguments = parseArguments(context); | |
1685 | failIfFalse(arguments); | |
1686 | base = context.createNewExpr(location, base, arguments, start, exprEnd, lastTokenEnd(), expressionLine, expressionLineStart); | |
1687 | } else { | |
1688 | int expressionEnd = lastTokenEnd(); | |
1689 | unsigned expressionLine = lastTokenLine(); | |
1690 | int expressionLineStart = lastTokenLineStart(); | |
1691 | TreeArguments arguments = parseArguments(context); | |
1692 | failIfFalse(arguments); | |
1693 | base = context.makeFunctionCallNode(location, base, arguments, expressionStart, expressionEnd, lastTokenEnd(), expressionLine, expressionLineStart); | |
1694 | } | |
1695 | m_nonLHSCount = nonLHSCount; | |
1696 | break; | |
1697 | } | |
1698 | case DOT: { | |
1699 | m_nonTrivialExpressionCount++; | |
1700 | int expressionEnd = lastTokenEnd(); | |
1701 | expressionLineStart = lastTokenLineStart(); | |
1702 | nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords); | |
1703 | matchOrFail(IDENT); | |
1704 | base = context.createDotAccess(location, base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd(), expressionLine, expressionLineStart); | |
1705 | next(); | |
1706 | break; | |
1707 | } | |
1708 | default: | |
1709 | goto endMemberExpression; | |
1710 | } | |
1711 | } | |
1712 | endMemberExpression: | |
1713 | while (newCount--) | |
1714 | base = context.createNewExpr(location, base, start, lastTokenEnd(), expressionLine, expressionLineStart); | |
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++; | |
1747 | context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart(), tokenLine(), tokenLineStart()); | |
1748 | next(); | |
1749 | m_nonTrivialExpressionCount++; | |
1750 | } | |
1751 | int subExprStart = tokenStart(); | |
1752 | int subExprLine = tokenLine(); | |
1753 | int subExprLineStartPosition = tokenLineStart(); | |
1754 | ASSERT(subExprStart >= subExprLineStartPosition); | |
1755 | JSTokenLocation location(tokenLocation()); | |
1756 | TreeExpression expr = parseMemberExpression(context); | |
1757 | failIfFalse(expr); | |
1758 | bool isEvalOrArguments = false; | |
1759 | if (strictMode() && !m_syntaxAlreadyValidated) { | |
1760 | if (context.isResolve(expr)) | |
1761 | isEvalOrArguments = *m_lastIdentifier == m_vm->propertyNames->eval || *m_lastIdentifier == m_vm->propertyNames->arguments; | |
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++; | |
1768 | expr = context.makePostfixNode(location, expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd(), tokenLine(), tokenLineStart()); | |
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++; | |
1777 | expr = context.makePostfixNode(location, expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd(), tokenLine(), tokenLineStart()); | |
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(); | |
1788 | int endLine = lastTokenLine(); | |
1789 | int endLineStartPosition = lastTokenLineStart(); | |
1790 | ||
1791 | if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode())) | |
1792 | return expr; | |
1793 | ||
1794 | location = tokenLocation(); | |
1795 | location.line = m_lexer->lastLineNumber(); | |
1796 | while (tokenStackDepth) { | |
1797 | switch (context.unaryTokenStackLastType(tokenStackDepth)) { | |
1798 | case EXCLAMATION: | |
1799 | expr = context.createLogicalNot(location, expr); | |
1800 | break; | |
1801 | case TILDE: | |
1802 | expr = context.makeBitwiseNotNode(location, expr); | |
1803 | break; | |
1804 | case MINUS: | |
1805 | expr = context.makeNegateNode(location, expr); | |
1806 | break; | |
1807 | case PLUS: | |
1808 | expr = context.createUnaryPlus(location, expr); | |
1809 | break; | |
1810 | case PLUSPLUS: | |
1811 | case AUTOPLUSPLUS: | |
1812 | expr = context.makePrefixNode(location, expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end, subExprLine, subExprLineStartPosition); | |
1813 | m_assignmentCount++; | |
1814 | break; | |
1815 | case MINUSMINUS: | |
1816 | case AUTOMINUSMINUS: | |
1817 | expr = context.makePrefixNode(location, expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end, subExprLine, subExprLineStartPosition); | |
1818 | m_assignmentCount++; | |
1819 | break; | |
1820 | case TYPEOF: | |
1821 | expr = context.makeTypeOfNode(location, expr); | |
1822 | break; | |
1823 | case VOIDTOKEN: | |
1824 | expr = context.createVoid(location, expr); | |
1825 | break; | |
1826 | case DELETETOKEN: | |
1827 | failIfTrueIfStrictWithNameAndMessage(context.isResolve(expr), "Cannot delete unqualified property", m_lastIdentifier->impl(), "in strict mode"); | |
1828 | expr = context.makeDeleteNode(location, expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end, endLine, endLineStartPosition); | |
1829 | break; | |
1830 | default: | |
1831 | // If we get here something has gone horribly horribly wrong | |
1832 | CRASH(); | |
1833 | } | |
1834 | subExprStart = context.unaryTokenStackLastStart(tokenStackDepth); | |
1835 | subExprLineStartPosition = context.unaryTokenStackLastLineStartPosition(tokenStackDepth); | |
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 | ||
1845 | } // namespace JSC |