source: webkit/trunk/JavaScriptCore/parser/JSParser.cpp@ 63566

Last change on this file since 63566 was 63566, checked in by [email protected], 15 years ago

2010-07-16 Oliver Hunt <[email protected]>

Reviewed by Geoffrey Garen.

ES5 allows use of reserved words as IdentifierName
https://bugs.webkit.org/show_bug.cgi?id=42471

Modify the lexer to allow us to avoid identifying reserved
words in those contexts where they are valid identifiers, and
we know it's safe. Additionally tag the reserved word tokens
so we can easily identify them in those cases where we can't
guarantee that we've skipped reserved word identification.

  • parser/JSParser.cpp: (JSC::JSParser::next): (JSC::JSParser::parseProperty): (JSC::JSParser::parseMemberExpression):
  • parser/JSParser.h: (JSC::):
  • parser/Lexer.cpp: (JSC::Lexer::lex):
  • parser/Lexer.h: (JSC::Lexer::):

2010-07-16 Oliver Hunt <[email protected]>

Reviewed by Geoffrey Garen.

ES5 allows use of reserved words as IdentifierName
https://bugs.webkit.org/show_bug.cgi?id=42471

Add tests to check for correct handling of reserved words with
the ES5 semantics.

  • fast/js/reserved-words-as-property-expected.txt: Added.
  • fast/js/reserved-words-as-property.html: Added.
  • fast/js/script-tests/reserved-words-as-property.js: Added. ():
  • fast/js/sputnik/Conformance/11_Expressions/11.1_Primary_Expressions/11.1.5_Object_Initializer/S11.1.5_A4.1-expected.txt:
  • fast/js/sputnik/Conformance/11_Expressions/11.1_Primary_Expressions/11.1.5_Object_Initializer/S11.1.5_A4.2-expected.txt: These tests are wrong, unsure how to get sputnik tests corrected.
File size: 51.7 KB
Line 
1/*
2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "JSParser.h"
29
30using namespace JSC;
31
32#include "JSGlobalData.h"
33#include "NodeInfo.h"
34#include "ASTBuilder.h"
35#include <wtf/HashFunctions.h>
36#include <utility>
37
38using namespace std;
39
40namespace JSC {
41#define fail() do { m_error = true; return 0; } while (0)
42#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
43#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
44#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
45#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
46#define failIfStackOverflow() do { failIfFalse(canRecurse()); } while (0)
47
48// Macros to make the more common TreeBuilder types a little less verbose
49#define TreeStatement typename TreeBuilder::Statement
50#define TreeExpression typename TreeBuilder::Expression
51#define TreeFormalParameterList typename TreeBuilder::FormalParameterList
52#define TreeSourceElements typename TreeBuilder::SourceElements
53#define TreeClause typename TreeBuilder::Clause
54#define TreeClauseList typename TreeBuilder::ClauseList
55#define TreeConstDeclList typename TreeBuilder::ConstDeclList
56#define TreeArguments typename TreeBuilder::Arguments
57#define TreeArgumentsList typename TreeBuilder::ArgumentsList
58#define TreeFunctionBody typename TreeBuilder::FunctionBody
59#define TreeProperty typename TreeBuilder::Property
60#define TreePropertyList typename TreeBuilder::PropertyList
61
62COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
63
64// This matches v8
65static const ptrdiff_t kMaxParserStackUsage = 128 * sizeof(void*) * 1024;
66
67class JSParser {
68public:
69 JSParser(Lexer*, JSGlobalData*, SourceProvider*);
70 bool parseProgram();
71private:
72 struct AllowInOverride {
73 AllowInOverride(JSParser* parser)
74 : m_parser(parser)
75 , m_oldAllowsIn(parser->m_allowsIn)
76 {
77 parser->m_allowsIn = true;
78 }
79 ~AllowInOverride()
80 {
81 m_parser->m_allowsIn = m_oldAllowsIn;
82 }
83 JSParser* m_parser;
84 bool m_oldAllowsIn;
85 };
86
87 const JSToken& token() { return m_token; }
88 void next(Lexer::LexType lexType = Lexer::IdentifyReservedWords)
89 {
90 m_lastLine = token().m_info.line;
91 m_lastTokenEnd = token().m_info.endOffset;
92 m_lexer->setLastLineNumber(m_lastLine);
93 m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType);
94 m_tokenCount++;
95 }
96
97 bool consume(JSTokenType expected)
98 {
99 bool result = m_token.m_type == expected;
100 failIfFalse(result);
101 next();
102 return result;
103 }
104
105 bool match(JSTokenType expected)
106 {
107 return m_token.m_type == expected;
108 }
109
110 int tokenStart()
111 {
112 return token().m_info.startOffset;
113 }
114
115 int tokenLine()
116 {
117 return token().m_info.line;
118 }
119
120 int tokenEnd()
121 {
122 return token().m_info.endOffset;
123 }
124
125 template <class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
126 template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&);
127 template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
128 template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
129 template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
130 template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
131 template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
132 template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
133 template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
134 template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
135 template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
136 template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
137 template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
138 template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
139 template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
140 template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
141 template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
142 template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
143 template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
144 template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
145 template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
146 template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&);
147 template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
148 template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
149 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
150 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
151 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
152 template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
153 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
154 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
155 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
156 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
157 template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
158 template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
159 template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
160 template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&, bool& usesArguments);
161 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
162 template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
163 enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
164 template <FunctionRequirements, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
165 ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
166 bool allowAutomaticSemicolon();
167
168 bool autoSemiColon()
169 {
170 if (token().m_type == SEMICOLON) {
171 next();
172 return true;
173 }
174 return allowAutomaticSemicolon();
175 }
176
177 bool canRecurse()
178 {
179 char sample = 0;
180 ASSERT(m_endAddress);
181 return &sample > m_endAddress;
182 }
183
184 int lastTokenEnd() const
185 {
186 return m_lastTokenEnd;
187 }
188
189 ParserArena m_arena;
190 Lexer* m_lexer;
191 char* m_endAddress;
192 bool m_error;
193 JSGlobalData* m_globalData;
194 JSToken m_token;
195 bool m_allowsIn;
196 int m_tokenCount;
197 int m_lastLine;
198 int m_lastTokenEnd;
199 int m_assignmentCount;
200 int m_nonLHSCount;
201 bool m_syntaxAlreadyValidated;
202};
203
204int jsParse(JSGlobalData* globalData, const SourceCode* source)
205{
206 JSParser parser(globalData->lexer, globalData, source->provider());
207 return parser.parseProgram();
208}
209
210JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, SourceProvider* provider)
211 : m_lexer(lexer)
212 , m_endAddress(0)
213 , m_error(false)
214 , m_globalData(globalData)
215 , m_allowsIn(true)
216 , m_tokenCount(0)
217 , m_lastLine(0)
218 , m_lastTokenEnd(0)
219 , m_assignmentCount(0)
220 , m_nonLHSCount(0)
221 , m_syntaxAlreadyValidated(provider->isValid())
222{
223 m_endAddress = *(globalData->stackGuards);
224 if (!m_endAddress) {
225 char sample = 0;
226 m_endAddress = &sample - kMaxParserStackUsage;
227 *(globalData->stackGuards) = m_endAddress;
228 }
229 next();
230 m_lexer->setLastLineNumber(tokenLine());
231}
232
233bool JSParser::parseProgram()
234{
235 ASTBuilder context(m_globalData, m_lexer);
236 SourceElements* sourceElements = parseSourceElements<ASTBuilder>(context);
237 if (!sourceElements || !consume(EOFTOK))
238 return true;
239 m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), context.features(),
240 m_lastLine, context.numConstants());
241 return false;
242}
243
244bool JSParser::allowAutomaticSemicolon()
245{
246 return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
247}
248
249template <class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
250{
251 TreeSourceElements sourceElements = context.createSourceElements();
252 while (TreeStatement statement = parseStatement(context))
253 context.appendStatement(sourceElements, statement);
254
255 if (m_error)
256 fail();
257 return sourceElements;
258}
259
260template <class TreeBuilder> TreeStatement JSParser::parseVarDeclaration(TreeBuilder& context)
261{
262 ASSERT(match(VAR));
263 int start = tokenLine();
264 int end = 0;
265 int scratch;
266 const Identifier* scratch1 = 0;
267 TreeExpression scratch2 = 0;
268 int scratch3 = 0;
269 TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
270 failIfTrue(m_error);
271 failIfFalse(autoSemiColon());
272
273 return context.createVarStatement(varDecls, start, end);
274}
275
276template <class TreeBuilder> TreeStatement JSParser::parseConstDeclaration(TreeBuilder& context)
277{
278 ASSERT(match(CONSTTOKEN));
279 int start = tokenLine();
280 int end = 0;
281 TreeConstDeclList constDecls = parseConstDeclarationList(context);
282 failIfTrue(m_error);
283 failIfFalse(autoSemiColon());
284
285 return context.createConstStatement(constDecls, start, end);
286}
287
288template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeBuilder& context)
289{
290 ASSERT(match(DO));
291 int startLine = tokenLine();
292 next();
293 TreeStatement statement = parseStatement(context);
294 failIfFalse(statement);
295 int endLine = tokenLine();
296 consumeOrFail(WHILE);
297 consumeOrFail(OPENPAREN);
298 TreeExpression expr = parseExpression(context);
299 failIfFalse(expr);
300 consumeOrFail(CLOSEPAREN);
301 if (match(SEMICOLON))
302 next(); // Always performs automatic semicolon insertion.
303 return context.createDoWhileStatement(statement, expr, startLine, endLine);
304}
305
306template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBuilder& context)
307{
308 ASSERT(match(WHILE));
309 int startLine = tokenLine();
310 next();
311 consumeOrFail(OPENPAREN);
312 TreeExpression expr = parseExpression(context);
313 failIfFalse(expr);
314 int endLine = tokenLine();
315 consumeOrFail(CLOSEPAREN);
316 TreeStatement statement = parseStatement(context);
317 failIfFalse(statement);
318 return context.createWhileStatement(expr, statement, startLine, endLine);
319}
320
321template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd)
322{
323 TreeExpression varDecls = 0;
324 do {
325 declarations++;
326 next();
327 matchOrFail(IDENT);
328
329 int varStart = tokenStart();
330 identStart = varStart;
331 const Identifier* name = token().m_data.ident;
332 lastIdent = name;
333 next();
334 bool hasInitializer = match(EQUAL);
335 context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
336 if (hasInitializer) {
337 int varDivot = tokenStart() + 1;
338 initStart = tokenStart();
339 next(); // consume '='
340 int initialAssignments = m_assignmentCount;
341 TreeExpression initializer = parseAssignmentExpression(context);
342 initEnd = lastTokenEnd();
343 lastInitializer = initializer;
344 failIfFalse(initializer);
345
346 TreeExpression node = context.createAssignResolve(*name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd());
347 if (!varDecls)
348 varDecls = node;
349 else
350 varDecls = context.combineCommaNodes(varDecls, node);
351 }
352 } while (match(COMMA));
353 return varDecls;
354}
355
356template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context)
357{
358 TreeConstDeclList constDecls = 0;
359 TreeConstDeclList tail = 0;
360 do {
361 next();
362 matchOrFail(IDENT);
363 const Identifier* name = token().m_data.ident;
364 next();
365 bool hasInitializer = match(EQUAL);
366 context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
367 TreeExpression initializer = 0;
368 if (hasInitializer) {
369 next(); // consume '='
370 initializer = parseAssignmentExpression(context);
371 }
372 tail = context.appendConstDecl(tail, name, initializer);
373 if (!constDecls)
374 constDecls = tail;
375 } while (match(COMMA));
376 return constDecls;
377}
378
379template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuilder& context)
380{
381 ASSERT(match(FOR));
382 int startLine = tokenLine();
383 next();
384 consumeOrFail(OPENPAREN);
385 int nonLHSCount = m_nonLHSCount;
386 int declarations = 0;
387 int declsStart = 0;
388 int declsEnd = 0;
389 TreeExpression decls = 0;
390 bool hasDeclaration = false;
391 if (match(VAR)) {
392 /*
393 for (var IDENT in expression) statement
394 for (var IDENT = expression in expression) statement
395 for (var varDeclarationList; expressionOpt; expressionOpt)
396 */
397 hasDeclaration = true;
398 const Identifier* forInTarget = 0;
399 TreeExpression forInInitializer = 0;
400 m_allowsIn = false;
401 int initStart = 0;
402 int initEnd = 0;
403 decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd);
404 m_allowsIn = true;
405 if (m_error)
406 fail();
407
408 // Remainder of a standard for loop is handled identically
409 if (declarations > 1 || match(SEMICOLON))
410 goto standardForLoop;
411
412 // Handle for-in with var declaration
413 int inLocation = tokenStart();
414 if (!consume(INTOKEN))
415 fail();
416
417 TreeExpression expr = parseExpression(context);
418 failIfFalse(expr);
419 int exprEnd = lastTokenEnd();
420
421 int endLine = tokenLine();
422 consumeOrFail(CLOSEPAREN);
423
424 TreeStatement statement = parseStatement(context);
425 failIfFalse(statement);
426
427 return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine);
428 }
429
430 if (!match(SEMICOLON)) {
431 m_allowsIn = false;
432 declsStart = tokenStart();
433 decls = parseExpression(context);
434 declsEnd = lastTokenEnd();
435 m_allowsIn = true;
436 failIfFalse(decls);
437 }
438
439 if (match(SEMICOLON)) {
440 standardForLoop:
441 // Standard for loop
442 next();
443 TreeExpression condition = 0;
444
445 if (!match(SEMICOLON)) {
446 condition = parseExpression(context);
447 failIfFalse(condition);
448 }
449 consumeOrFail(SEMICOLON);
450
451 TreeExpression increment = 0;
452 if (!match(CLOSEPAREN)) {
453 increment = parseExpression(context);
454 failIfFalse(increment);
455 }
456 int endLine = tokenLine();
457 consumeOrFail(CLOSEPAREN);
458 TreeStatement statement = parseStatement(context);
459 failIfFalse(statement);
460 return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine);
461 }
462
463 // For-in loop
464 failIfFalse(nonLHSCount == m_nonLHSCount);
465 consumeOrFail(INTOKEN);
466 TreeExpression expr = parseExpression(context);
467 failIfFalse(expr);
468 int exprEnd = lastTokenEnd();
469 int endLine = tokenLine();
470 consumeOrFail(CLOSEPAREN);
471 TreeStatement statement = parseStatement(context);
472 failIfFalse(statement);
473
474 return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
475}
476
477template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBuilder& context)
478{
479 ASSERT(match(BREAK));
480 int startCol = tokenStart();
481 int endCol = tokenEnd();
482 int startLine = tokenLine();
483 int endLine = tokenLine();
484 next();
485
486 if (autoSemiColon())
487 return context.createBreakStatement(startCol, endCol, startLine, endLine);
488 matchOrFail(IDENT);
489 const Identifier* ident = token().m_data.ident;
490 endCol = tokenEnd();
491 endLine = tokenLine();
492 next();
493 failIfFalse(autoSemiColon());
494 return context.createBreakStatement(ident, startCol, endCol, startLine, endLine);
495}
496
497template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(TreeBuilder& context)
498{
499 ASSERT(match(CONTINUE));
500 int startCol = tokenStart();
501 int endCol = tokenEnd();
502 int startLine = tokenLine();
503 int endLine = tokenLine();
504 next();
505
506 if (autoSemiColon())
507 return context.createContinueStatement(startCol, endCol, startLine, endLine);
508 matchOrFail(IDENT);
509 const Identifier* ident = token().m_data.ident;
510 endCol = tokenEnd();
511 endLine = tokenLine();
512 next();
513 failIfFalse(autoSemiColon());
514 return context.createContinueStatement(ident, startCol, endCol, startLine, endLine);
515}
516
517template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context)
518{
519 ASSERT(match(RETURN));
520 int startLine = tokenLine();
521 int endLine = startLine;
522 int start = tokenStart();
523 int end = tokenEnd();
524 next();
525 // We do the auto semicolon check before attempting to parse an expression
526 // as we need to ensure the a line break after the return correctly terminates
527 // the statement
528 if (match(SEMICOLON))
529 endLine = tokenLine();
530 if (autoSemiColon())
531 return context.createReturnStatement(0, start, end, startLine, endLine);
532 TreeExpression expr = parseExpression(context);
533 failIfFalse(expr);
534 end = lastTokenEnd();
535 if (match(SEMICOLON))
536 endLine = tokenLine();
537 failIfFalse(autoSemiColon());
538 return context.createReturnStatement(expr, start, end, startLine, endLine);
539}
540
541template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBuilder& context)
542{
543 ASSERT(match(THROW));
544 int eStart = tokenStart();
545 int startLine = tokenLine();
546 next();
547
548 TreeExpression expr = parseExpression(context);
549 failIfFalse(expr);
550 int eEnd = lastTokenEnd();
551 int endLine = tokenLine();
552 failIfFalse(autoSemiColon());
553
554 return context.createThrowStatement(expr, eStart, eEnd, startLine, endLine);
555}
556
557template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
558{
559 ASSERT(match(WITH));
560 int startLine = tokenLine();
561 next();
562 consumeOrFail(OPENPAREN);
563 int start = tokenStart();
564 TreeExpression expr = parseExpression(context);
565 failIfFalse(expr);
566 int end = lastTokenEnd();
567
568 int endLine = tokenLine();
569 consumeOrFail(CLOSEPAREN);
570
571 TreeStatement statement = parseStatement(context);
572 failIfFalse(statement);
573
574 return context.createWithStatement(expr, statement, start, end, startLine, endLine);
575}
576
577template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBuilder& context)
578{
579 ASSERT(match(SWITCH));
580 int startLine = tokenLine();
581 next();
582 consumeOrFail(OPENPAREN);
583 TreeExpression expr = parseExpression(context);
584 failIfFalse(expr);
585 int endLine = tokenLine();
586 consumeOrFail(CLOSEPAREN);
587 consumeOrFail(OPENBRACE);
588
589 TreeClauseList firstClauses = parseSwitchClauses(context);
590 failIfTrue(m_error);
591
592 TreeClause defaultClause = parseSwitchDefaultClause(context);
593 failIfTrue(m_error);
594
595 TreeClauseList secondClauses = parseSwitchClauses(context);
596 failIfTrue(m_error);
597 consumeOrFail(CLOSEBRACE);
598
599 return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
600
601}
602
603template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBuilder& context)
604{
605 if (!match(CASE))
606 return 0;
607 next();
608 TreeExpression condition = parseExpression(context);
609 failIfFalse(condition);
610 consumeOrFail(COLON);
611 TreeSourceElements statements = parseSourceElements(context);
612 failIfFalse(statements);
613 TreeClause clause = context.createClause(condition, statements);
614 TreeClauseList clauseList = context.createClauseList(clause);
615 TreeClauseList tail = clauseList;
616
617 while (match(CASE)) {
618 next();
619 TreeExpression condition = parseExpression(context);
620 failIfFalse(condition);
621 consumeOrFail(COLON);
622 TreeSourceElements statements = parseSourceElements(context);
623 failIfFalse(statements);
624 clause = context.createClause(condition, statements);
625 tail = context.createClauseList(tail, clause);
626 }
627 return clauseList;
628}
629
630template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context)
631{
632 if (!match(DEFAULT))
633 return 0;
634 next();
635 consumeOrFail(COLON);
636 TreeSourceElements statements = parseSourceElements(context);
637 failIfFalse(statements);
638 return context.createClause(0, statements);
639}
640
641template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuilder& context)
642{
643 ASSERT(match(TRY));
644 TreeStatement tryBlock = 0;
645 const Identifier* ident = &m_globalData->propertyNames->nullIdentifier;
646 bool catchHasEval = false;
647 TreeStatement catchBlock = 0;
648 TreeStatement finallyBlock = 0;
649 int firstLine = tokenLine();
650 next();
651 matchOrFail(OPENBRACE);
652
653 tryBlock = parseBlockStatement(context);
654 failIfFalse(tryBlock);
655 int lastLine = m_lastLine;
656
657 if (match(CATCH)) {
658 next();
659 consumeOrFail(OPENPAREN);
660 matchOrFail(IDENT);
661 ident = token().m_data.ident;
662 next();
663 consumeOrFail(CLOSEPAREN);
664 matchOrFail(OPENBRACE);
665 int initialEvalCount = context.evalCount();
666 catchBlock = parseBlockStatement(context);
667 failIfFalse(catchBlock);
668 catchHasEval = initialEvalCount != context.evalCount();
669 }
670
671 if (match(FINALLY)) {
672 next();
673 matchOrFail(OPENBRACE);
674 finallyBlock = parseBlockStatement(context);
675 failIfFalse(finallyBlock);
676 }
677 failIfFalse(catchBlock || finallyBlock);
678 return context.createTryStatement(tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine);
679}
680
681template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(TreeBuilder& context)
682{
683 ASSERT(match(DEBUGGER));
684 int startLine = tokenLine();
685 int endLine = startLine;
686 next();
687 if (match(SEMICOLON))
688 startLine = tokenLine();
689 failIfFalse(autoSemiColon());
690 return context.createDebugger(startLine, endLine);
691}
692
693template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBuilder& context)
694{
695 ASSERT(match(OPENBRACE));
696 int start = tokenLine();
697 next();
698 if (match(CLOSEBRACE)) {
699 next();
700 return context.createBlockStatement(0, start, m_lastLine);
701 }
702 TreeSourceElements subtree = parseSourceElements(context);
703 failIfFalse(subtree);
704 matchOrFail(CLOSEBRACE);
705 next();
706 return context.createBlockStatement(subtree, start, m_lastLine);
707}
708
709template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context)
710{
711 failIfStackOverflow();
712 switch (token().m_type) {
713 case OPENBRACE:
714 return parseBlockStatement(context);
715 case VAR:
716 return parseVarDeclaration(context);
717 case CONSTTOKEN:
718 return parseConstDeclaration(context);
719 case FUNCTION:
720 return parseFunctionDeclaration(context);
721 case SEMICOLON:
722 next();
723 return context.createEmptyStatement();
724 case IF:
725 return parseIfStatement(context);
726 case DO:
727 return parseDoWhileStatement(context);
728 case WHILE:
729 return parseWhileStatement(context);
730 case FOR:
731 return parseForStatement(context);
732 case CONTINUE:
733 return parseContinueStatement(context);
734 case BREAK:
735 return parseBreakStatement(context);
736 case RETURN:
737 return parseReturnStatement(context);
738 case WITH:
739 return parseWithStatement(context);
740 case SWITCH:
741 return parseSwitchStatement(context);
742 case THROW:
743 return parseThrowStatement(context);
744 case TRY:
745 return parseTryStatement(context);
746 case DEBUGGER:
747 return parseDebuggerStatement(context);
748 case EOFTOK:
749 case CASE:
750 case CLOSEBRACE:
751 case DEFAULT:
752 // These tokens imply the end of a set of source elements
753 return 0;
754 case IDENT:
755 return parseExpressionOrLabelStatement(context);
756 default:
757 return parseExpressionStatement(context);
758 }
759}
760
761template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context, bool& usesArguments)
762{
763 matchOrFail(IDENT);
764 usesArguments = m_globalData->propertyNames->arguments == *token().m_data.ident;
765 TreeFormalParameterList list = context.createFormalParameterList(*token().m_data.ident);
766 TreeFormalParameterList tail = list;
767 next();
768 while (match(COMMA)) {
769 next();
770 matchOrFail(IDENT);
771 const Identifier* ident = token().m_data.ident;
772 next();
773 usesArguments = usesArguments || m_globalData->propertyNames->arguments == *ident;
774 tail = context.createFormalParameterList(tail, *ident);
775 }
776 return list;
777}
778
779template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
780{
781 if (match(CLOSEBRACE))
782 return context.createFunctionBody();
783 typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
784 failIfFalse(parseSourceElements(bodyBuilder));
785 return context.createFunctionBody();
786}
787
788template <JSParser::FunctionRequirements requirements, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
789{
790 if (match(IDENT)) {
791 name = token().m_data.ident;
792 next();
793 } else if (requirements == FunctionNeedsName)
794 return false;
795 consumeOrFail(OPENPAREN);
796 bool usesArguments = false;
797 if (!match(CLOSEPAREN)) {
798 parameters = parseFormalParameters(context, usesArguments);
799 failIfFalse(parameters);
800 }
801 consumeOrFail(CLOSEPAREN);
802 matchOrFail(OPENBRACE);
803
804 openBracePos = token().m_data.intValue;
805 bodyStartLine = tokenLine();
806 next();
807
808 body = parseFunctionBody(context);
809 failIfFalse(body);
810 if (usesArguments)
811 context.setUsesArguments(body);
812
813 matchOrFail(CLOSEBRACE);
814 closeBracePos = token().m_data.intValue;
815 next();
816 return true;
817}
818
819template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(TreeBuilder& context)
820{
821 ASSERT(match(FUNCTION));
822 next();
823 const Identifier* name = 0;
824 TreeFormalParameterList parameters = 0;
825 TreeFunctionBody body = 0;
826 int openBracePos = 0;
827 int closeBracePos = 0;
828 int bodyStartLine = 0;
829 failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
830 failIfFalse(name);
831 return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
832}
833
834template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context)
835{
836
837 /* Expression and Label statements are ambiguous at LL(1), to avoid
838 * the cost of having a token buffer to support LL(2) we simply assume
839 * we have an expression statement, and then only look for a label if that
840 * parse fails.
841 */
842 int start = tokenStart();
843 int startLine = tokenLine();
844 const Identifier* ident = token().m_data.ident;
845 int currentToken = m_tokenCount;
846 TreeExpression expression = parseExpression(context);
847 failIfFalse(expression);
848 if (autoSemiColon())
849 return context.createExprStatement(expression, startLine, m_lastLine);
850 failIfFalse(currentToken + 1 == m_tokenCount);
851 int end = tokenEnd();
852 consumeOrFail(COLON);
853 TreeStatement statement = parseStatement(context);
854 failIfFalse(statement);
855 return context.createLabelStatement(ident, statement, start, end);
856}
857
858template <class TreeBuilder> TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context)
859{
860 int startLine = tokenLine();
861 TreeExpression expression = parseExpression(context);
862 failIfFalse(expression);
863 failIfFalse(autoSemiColon());
864 return context.createExprStatement(expression, startLine, m_lastLine);
865}
866
867template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilder& context)
868{
869 ASSERT(match(IF));
870
871 int start = tokenLine();
872 next();
873
874 consumeOrFail(OPENPAREN);
875
876 TreeExpression condition = parseExpression(context);
877 failIfFalse(condition);
878 int end = tokenLine();
879 consumeOrFail(CLOSEPAREN);
880
881 TreeStatement trueBlock = parseStatement(context);
882 failIfFalse(trueBlock);
883
884 if (!match(ELSE))
885 return context.createIfStatement(condition, trueBlock, start, end);
886
887 Vector<TreeExpression> exprStack;
888 Vector<pair<int, int> > posStack;
889 Vector<TreeStatement> statementStack;
890 bool trailingElse = false;
891 do {
892 next();
893 if (!match(IF)) {
894 TreeStatement block = parseStatement(context);
895 failIfFalse(block);
896 statementStack.append(block);
897 trailingElse = true;
898 break;
899 }
900 int innerStart = tokenLine();
901 next();
902
903 consumeOrFail(OPENPAREN);
904
905 TreeExpression innerCondition = parseExpression(context);
906 failIfFalse(innerCondition);
907 int innerEnd = tokenLine();
908 consumeOrFail(CLOSEPAREN);
909
910 TreeStatement innerTrueBlock = parseStatement(context);
911 failIfFalse(innerTrueBlock);
912 exprStack.append(innerCondition);
913 posStack.append(make_pair(innerStart, innerEnd));
914 statementStack.append(innerTrueBlock);
915 } while (match(ELSE));
916
917 if (!trailingElse) {
918 TreeExpression condition = exprStack.last();
919 exprStack.removeLast();
920 TreeStatement trueBlock = statementStack.last();
921 statementStack.removeLast();
922 pair<int, int> pos = posStack.last();
923 posStack.removeLast();
924 statementStack.append(context.createIfStatement(condition, trueBlock, pos.first, pos.second));
925 }
926
927 while (!exprStack.isEmpty()) {
928 TreeExpression condition = exprStack.last();
929 exprStack.removeLast();
930 TreeStatement falseBlock = statementStack.last();
931 statementStack.removeLast();
932 TreeStatement trueBlock = statementStack.last();
933 statementStack.removeLast();
934 pair<int, int> pos = posStack.last();
935 posStack.removeLast();
936 statementStack.append(context.createIfStatement(condition, trueBlock, falseBlock, pos.first, pos.second));
937 }
938
939 return context.createIfStatement(condition, trueBlock, statementStack.last(), start, end);
940}
941
942template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilder& context)
943{
944 failIfStackOverflow();
945 TreeExpression node = parseAssignmentExpression(context);
946 failIfFalse(node);
947 if (!match(COMMA))
948 return node;
949 next();
950 m_nonLHSCount++;
951 TreeExpression right = parseAssignmentExpression(context);
952 failIfFalse(right);
953 typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right);
954 while (match(COMMA)) {
955 next();
956 right = parseAssignmentExpression(context);
957 failIfFalse(right);
958 context.appendToComma(commaNode, right);
959 }
960 return commaNode;
961}
962
963
964template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpression(TreeBuilder& context)
965{
966 failIfStackOverflow();
967 int start = tokenStart();
968 int initialAssignmentCount = m_assignmentCount;
969 int initialNonLHSCount = m_nonLHSCount;
970 TreeExpression lhs = parseConditionalExpression(context);
971 failIfFalse(lhs);
972 if (initialNonLHSCount != m_nonLHSCount)
973 return lhs;
974
975 int assignmentStack = 0;
976 Operator op;
977 bool hadAssignment = false;
978 while (true) {
979 switch (token().m_type) {
980 case EQUAL: op = OpEqual; break;
981 case PLUSEQUAL: op = OpPlusEq; break;
982 case MINUSEQUAL: op = OpMinusEq; break;
983 case MULTEQUAL: op = OpMultEq; break;
984 case DIVEQUAL: op = OpDivEq; break;
985 case LSHIFTEQUAL: op = OpLShift; break;
986 case RSHIFTEQUAL: op = OpRShift; break;
987 case URSHIFTEQUAL: op = OpURShift; break;
988 case ANDEQUAL: op = OpAndEq; break;
989 case XOREQUAL: op = OpXOrEq; break;
990 case OREQUAL: op = OpOrEq; break;
991 case MODEQUAL: op = OpModEq; break;
992 default:
993 goto end;
994 }
995 hadAssignment = true;
996 context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
997 start = tokenStart();
998 m_assignmentCount++;
999 next();
1000 lhs = parseConditionalExpression(context);
1001 failIfFalse(lhs);
1002 if (initialNonLHSCount != m_nonLHSCount)
1003 break;
1004 }
1005end:
1006 if (hadAssignment)
1007 m_nonLHSCount++;
1008
1009 if (!ASTBuilder::CreatesAST)
1010 return lhs;
1011
1012 while (assignmentStack)
1013 lhs = context.createAssignment(assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd());
1014
1015 return lhs;
1016}
1017
1018template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression(TreeBuilder& context)
1019{
1020 TreeExpression cond = parseBinaryExpression(context);
1021 failIfFalse(cond);
1022 if (!match(QUESTION))
1023 return cond;
1024 m_nonLHSCount++;
1025 next();
1026 TreeExpression lhs = parseAssignmentExpression(context);
1027 consumeOrFail(COLON);
1028
1029 TreeExpression rhs = parseAssignmentExpression(context);
1030 failIfFalse(rhs);
1031 return context.createConditionalExpr(cond, lhs, rhs);
1032}
1033
1034ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
1035{
1036 return token & UnaryOpTokenFlag;
1037}
1038
1039int JSParser::isBinaryOperator(JSTokenType token)
1040{
1041 if (m_allowsIn)
1042 return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
1043 return token & BinaryOpTokenPrecedenceMask;
1044}
1045
1046template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context)
1047{
1048
1049 int operandStackDepth = 0;
1050 int operatorStackDepth = 0;
1051 while (true) {
1052 int exprStart = tokenStart();
1053 int initialAssignments = m_assignmentCount;
1054 TreeExpression current = parseUnaryExpression(context);
1055 failIfFalse(current);
1056
1057 context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), initialAssignments != m_assignmentCount);
1058 int precedence = isBinaryOperator(token().m_type);
1059 if (!precedence)
1060 break;
1061 m_nonLHSCount++;
1062 int operatorToken = token().m_type;
1063 next();
1064
1065 while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
1066 ASSERT(operandStackDepth > 1);
1067
1068 typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
1069 typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
1070 context.shrinkOperandStackBy(operandStackDepth, 2);
1071 context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
1072 context.operatorStackPop(operatorStackDepth);
1073 }
1074 context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
1075 }
1076
1077 while (operatorStackDepth) {
1078 ASSERT(operandStackDepth > 1);
1079
1080 typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
1081 typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
1082 context.shrinkOperandStackBy(operandStackDepth, 2);
1083 context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
1084 context.operatorStackPop(operatorStackDepth);
1085 }
1086 return context.popOperandStack(operandStackDepth);
1087}
1088
1089
1090template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context)
1091{
1092 bool wasIdent = false;
1093 switch (token().m_type) {
1094 namedProperty:
1095 case IDENT:
1096 wasIdent = true;
1097 case STRING: {
1098 const Identifier* ident = token().m_data.ident;
1099 next(Lexer::IgnoreReservedWords);
1100 if (match(COLON)) {
1101 next();
1102 TreeExpression node = parseAssignmentExpression(context);
1103 failIfFalse(node);
1104 return context.template createProperty<complete>(ident, node, PropertyNode::Constant);
1105 }
1106 failIfFalse(wasIdent);
1107 matchOrFail(IDENT);
1108 const Identifier* accessorName = 0;
1109 TreeFormalParameterList parameters = 0;
1110 TreeFunctionBody body = 0;
1111 int openBracePos = 0;
1112 int closeBracePos = 0;
1113 int bodyStartLine = 0;
1114 PropertyNode::Type type;
1115 if (*ident == m_globalData->propertyNames->get)
1116 type = PropertyNode::Getter;
1117 else if (*ident == m_globalData->propertyNames->set)
1118 type = PropertyNode::Setter;
1119 else
1120 fail();
1121 failIfFalse(parseFunctionInfo<FunctionNeedsName>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine));
1122 return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
1123 }
1124 case NUMBER: {
1125 double propertyName = token().m_data.doubleValue;
1126 next();
1127 consumeOrFail(COLON);
1128 TreeExpression node = parseAssignmentExpression(context);
1129 failIfFalse(node);
1130 return context.template createProperty<complete>(m_globalData, propertyName, node, PropertyNode::Constant);
1131 }
1132 default:
1133 failIfFalse(token().m_type & KeywordTokenFlag);
1134 goto namedProperty;
1135 }
1136}
1137
1138template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
1139{
1140 int startOffset = token().m_data.intValue;
1141 consumeOrFail(OPENBRACE);
1142
1143 if (match(CLOSEBRACE)) {
1144 next();
1145 return context.createObjectLiteral();
1146 }
1147
1148 TreeProperty property = parseProperty<false>(context);
1149 failIfFalse(property);
1150 if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
1151 m_lexer->setOffset(startOffset);
1152 next();
1153 return parseStrictObjectLiteral(context);
1154 }
1155 TreePropertyList propertyList = context.createPropertyList(property);
1156 TreePropertyList tail = propertyList;
1157 while (match(COMMA)) {
1158 next();
1159 // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
1160 if (match(CLOSEBRACE))
1161 break;
1162 property = parseProperty<false>(context);
1163 failIfFalse(property);
1164 if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
1165 m_lexer->setOffset(startOffset);
1166 next();
1167 return parseStrictObjectLiteral(context);
1168 }
1169 tail = context.createPropertyList(property, tail);
1170 }
1171
1172 consumeOrFail(CLOSEBRACE);
1173
1174 return context.createObjectLiteral(propertyList);
1175}
1176
1177template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context)
1178{
1179 consumeOrFail(OPENBRACE);
1180
1181 if (match(CLOSEBRACE)) {
1182 next();
1183 return context.createObjectLiteral();
1184 }
1185
1186 TreeProperty property = parseProperty<true>(context);
1187 failIfFalse(property);
1188
1189 typedef HashMap<RefPtr<UString::Rep>, unsigned, IdentifierRepHash> ObjectValidationMap;
1190 ObjectValidationMap objectValidator;
1191 // Add the first property
1192 if (!m_syntaxAlreadyValidated)
1193 objectValidator.add(context.getName(property).ustring().rep(), context.getType(property));
1194
1195 TreePropertyList propertyList = context.createPropertyList(property);
1196 TreePropertyList tail = propertyList;
1197 while (match(COMMA)) {
1198 next();
1199 // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
1200 if (match(CLOSEBRACE))
1201 break;
1202 property = parseProperty<true>(context);
1203 failIfFalse(property);
1204 if (!m_syntaxAlreadyValidated) {
1205 std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).ustring().rep(), context.getType(property));
1206 if (!propertyEntryIter.second) {
1207 if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) {
1208 // Can't have multiple getters or setters with the same name, nor can we define
1209 // a property as both an accessor and a constant value
1210 failIfTrue(context.getType(property) & propertyEntryIter.first->second);
1211 failIfTrue((context.getType(property) | propertyEntryIter.first->second) & PropertyNode::Constant);
1212 }
1213 }
1214 }
1215 tail = context.createPropertyList(property, tail);
1216 }
1217
1218 consumeOrFail(CLOSEBRACE);
1219
1220 return context.createObjectLiteral(propertyList);
1221}
1222
1223template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
1224{
1225 consumeOrFail(OPENBRACKET);
1226
1227 int elisions = 0;
1228 while (match(COMMA)) {
1229 next();
1230 elisions++;
1231 }
1232 if (match(CLOSEBRACKET)) {
1233 next();
1234 return context.createArray(elisions);
1235 }
1236
1237 TreeExpression elem = parseAssignmentExpression(context);
1238 failIfFalse(elem);
1239 typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem);
1240 typename TreeBuilder::ElementList tail = elementList;
1241 elisions = 0;
1242 while (match(COMMA)) {
1243 next();
1244 elisions = 0;
1245
1246 while (match(COMMA)) {
1247 next();
1248 elisions++;
1249 }
1250
1251 if (match(CLOSEBRACKET)) {
1252 next();
1253 return context.createArray(elisions, elementList);
1254 }
1255 TreeExpression elem = parseAssignmentExpression(context);
1256 failIfFalse(elem);
1257 tail = context.createElementList(tail, elisions, elem);
1258 }
1259
1260 consumeOrFail(CLOSEBRACKET);
1261
1262 return context.createArray(elementList);
1263}
1264
1265template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(TreeBuilder& context)
1266{
1267 switch (token().m_type) {
1268 case OPENBRACE:
1269 return parseObjectLiteral(context);
1270 case OPENBRACKET:
1271 return parseArrayLiteral(context);
1272 case OPENPAREN: {
1273 next();
1274 int oldNonLHSCount = m_nonLHSCount;
1275 TreeExpression result = parseExpression(context);
1276 m_nonLHSCount = oldNonLHSCount;
1277 consumeOrFail(CLOSEPAREN);
1278
1279 return result;
1280 }
1281 case THISTOKEN: {
1282 next();
1283 return context.thisExpr();
1284 }
1285 case IDENT: {
1286 int start = tokenStart();
1287 const Identifier* ident = token().m_data.ident;
1288 next();
1289 return context.createResolve(ident, start);
1290 }
1291 case STRING: {
1292 const Identifier* ident = token().m_data.ident;
1293 next();
1294 return context.createString(ident);
1295 }
1296 case NUMBER: {
1297 double d = token().m_data.doubleValue;
1298 next();
1299 return context.createNumberExpr(d);
1300 }
1301 case NULLTOKEN: {
1302 next();
1303 return context.createNull();
1304 }
1305 case TRUETOKEN: {
1306 next();
1307 return context.createBoolean(true);
1308 }
1309 case FALSETOKEN: {
1310 next();
1311 return context.createBoolean(false);
1312 }
1313 case DIVEQUAL:
1314 case DIVIDE: {
1315 /* regexp */
1316 const Identifier* pattern;
1317 const Identifier* flags;
1318 if (match(DIVEQUAL))
1319 failIfFalse(m_lexer->scanRegExp(pattern, flags, '='));
1320 else
1321 failIfFalse(m_lexer->scanRegExp(pattern, flags));
1322
1323 int start = tokenStart();
1324 next();
1325 return context.createRegex(*pattern, *flags, start);
1326 }
1327 default:
1328 fail();
1329 }
1330}
1331
1332template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
1333{
1334 consumeOrFail(OPENPAREN);
1335 if (match(CLOSEPAREN)) {
1336 next();
1337 return context.createArguments();
1338 }
1339 TreeExpression firstArg = parseAssignmentExpression(context);
1340 failIfFalse(firstArg);
1341
1342 TreeArgumentsList argList = context.createArgumentsList(firstArg);
1343 TreeArgumentsList tail = argList;
1344 while (match(COMMA)) {
1345 next();
1346 TreeExpression arg = parseAssignmentExpression(context);
1347 failIfFalse(arg);
1348 tail = context.createArgumentsList(tail, arg);
1349 }
1350 consumeOrFail(CLOSEPAREN);
1351 return context.createArguments(argList);
1352}
1353
1354template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(TreeBuilder& context)
1355{
1356 TreeExpression base = 0;
1357 int start = tokenStart();
1358 int expressionStart = start;
1359 int newCount = 0;
1360 while (match(NEW)) {
1361 next();
1362 newCount++;
1363 }
1364 if (match(FUNCTION)) {
1365 const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
1366 TreeFormalParameterList parameters = 0;
1367 TreeFunctionBody body = 0;
1368 int openBracePos = 0;
1369 int closeBracePos = 0;
1370 int bodyStartLine = 0;
1371 next();
1372 failIfFalse(parseFunctionInfo<FunctionNoRequirements>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine));
1373 base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
1374 } else
1375 base = parsePrimaryExpression(context);
1376
1377 failIfFalse(base);
1378 while (true) {
1379 switch (token().m_type) {
1380 case OPENBRACKET: {
1381 int expressionEnd = lastTokenEnd();
1382 next();
1383 int nonLHSCount = m_nonLHSCount;
1384 int initialAssignments = m_assignmentCount;
1385 TreeExpression property = parseExpression(context);
1386 failIfFalse(property);
1387 base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd());
1388 if (!consume(CLOSEBRACKET))
1389 fail();
1390 m_nonLHSCount = nonLHSCount;
1391 break;
1392 }
1393 case OPENPAREN: {
1394 if (newCount) {
1395 newCount--;
1396 if (match(OPENPAREN)) {
1397 int exprEnd = lastTokenEnd();
1398 TreeArguments arguments = parseArguments(context);
1399 failIfFalse(arguments);
1400 base = context.createNewExpr(base, arguments, start, exprEnd, lastTokenEnd());
1401 } else
1402 base = context.createNewExpr(base, start, lastTokenEnd());
1403 } else {
1404 int nonLHSCount = m_nonLHSCount;
1405 int expressionEnd = lastTokenEnd();
1406 TreeArguments arguments = parseArguments(context);
1407 failIfFalse(arguments);
1408 base = context.makeFunctionCallNode(base, arguments, expressionStart, expressionEnd, lastTokenEnd());
1409 m_nonLHSCount = nonLHSCount;
1410 }
1411 break;
1412 }
1413 case DOT: {
1414 int expressionEnd = lastTokenEnd();
1415 next(Lexer::IgnoreReservedWords);
1416 matchOrFail(IDENT);
1417 base = context.createDotAccess(base, *token().m_data.ident, expressionStart, expressionEnd, tokenEnd());
1418 next();
1419 break;
1420 }
1421 default:
1422 goto endMemberExpression;
1423 }
1424 }
1425endMemberExpression:
1426 while (newCount--)
1427 base = context.createNewExpr(base, start, lastTokenEnd());
1428 return base;
1429}
1430
1431template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeBuilder& context)
1432{
1433 AllowInOverride allowInOverride(this);
1434 int tokenStackDepth = 0;
1435 while (isUnaryOp(token().m_type)) {
1436 m_nonLHSCount++;
1437 context.appendUnaryToken(tokenStackDepth, token().m_type, tokenStart());
1438 next();
1439 }
1440 int subExprStart = tokenStart();
1441 TreeExpression expr = parseMemberExpression(context);
1442 failIfFalse(expr);
1443 switch (token().m_type) {
1444 case PLUSPLUS:
1445 m_nonLHSCount++;
1446 expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
1447 m_assignmentCount++;
1448 next();
1449 break;
1450 case MINUSMINUS:
1451 m_nonLHSCount++;
1452 expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
1453 m_assignmentCount++;
1454 next();
1455 break;
1456 default:
1457 break;
1458 }
1459
1460 int end = lastTokenEnd();
1461
1462 if (!TreeBuilder::CreatesAST)
1463 return expr;
1464
1465 while (tokenStackDepth) {
1466 switch (context.unaryTokenStackLastType(tokenStackDepth)) {
1467 case EXCLAMATION:
1468 expr = context.createLogicalNot(expr);
1469 break;
1470 case TILDE:
1471 expr = context.makeBitwiseNotNode(expr);
1472 break;
1473 case MINUS:
1474 expr = context.makeNegateNode(expr);
1475 break;
1476 case PLUS:
1477 expr = context.createUnaryPlus(expr);
1478 break;
1479 case PLUSPLUS:
1480 case AUTOPLUSPLUS:
1481 expr = context.makePrefixNode(expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
1482 m_assignmentCount++;
1483 break;
1484 case MINUSMINUS:
1485 case AUTOMINUSMINUS:
1486 expr = context.makePrefixNode(expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
1487 m_assignmentCount++;
1488 break;
1489 case TYPEOF:
1490 expr = context.makeTypeOfNode(expr);
1491 break;
1492 case VOIDTOKEN:
1493 expr = context.createVoid(expr);
1494 break;
1495 case DELETETOKEN:
1496 expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
1497 break;
1498 default:
1499 // If we get here something has gone horribly horribly wrong
1500 CRASH();
1501 }
1502 subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
1503 context.unaryTokenStackRemoveLast(tokenStackDepth);
1504 }
1505 return expr;
1506}
1507
1508}
Note: See TracBrowser for help on using the repository browser.