2 * Copyright (C) 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
32 #include "CodeBlock.h"
33 #include "JSGlobalData.h"
35 #include "ASTBuilder.h"
36 #include "SourceProvider.h"
37 #include "SourceProviderCacheItem.h"
38 #include <wtf/HashFunctions.h>
39 #include <wtf/OwnPtr.h>
40 #include <wtf/WTFThreadData.h>
46 #define fail() do { if (!m_error) updateErrorMessage(); return 0; } while (0)
47 #define failWithToken(tok) do { if (!m_error) updateErrorMessage(tok); return 0; } while (0)
48 #define failWithMessage(msg) do { if (!m_error) updateErrorMessage(msg); return 0; } while (0)
49 #define failWithNameAndMessage(before, name, after) do { if (!m_error) updateErrorWithNameAndMessage(before, name, after); return 0; } while (0)
50 #define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
51 #define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0)
52 #define failIfFalseWithNameAndMessage(cond, before, name, msg) do { if (!(cond)) failWithNameAndMessage(before, name, msg); } while (0)
53 #define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
54 #define failIfTrueWithMessage(cond, msg) do { if ((cond)) failWithMessage(msg); } while (0)
55 #define failIfTrueWithNameAndMessage(cond, before, name, msg) do { if ((cond)) failWithNameAndMessage(before, name, msg); } while (0)
56 #define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
57 #define failIfTrueIfStrictWithMessage(cond, msg) do { if ((cond) && strictMode()) failWithMessage(msg); } while (0)
58 #define failIfTrueIfStrictWithNameAndMessage(cond, before, name, after) do { if ((cond) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
59 #define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
60 #define failIfFalseIfStrictWithMessage(cond, msg) do { if ((!(cond)) && strictMode()) failWithMessage(msg); } while (0)
61 #define failIfFalseIfStrictWithNameAndMessage(cond, before, name, after) do { if ((!(cond)) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
62 #define consumeOrFail(tokenType) do { if (!consume(tokenType)) failWithToken(tokenType); } while (0)
63 #define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0)
64 #define matchOrFail(tokenType) do { if (!match(tokenType)) failWithToken(tokenType); } while (0)
65 #define failIfStackOverflow() do { failIfFalseWithMessage(canRecurse(), "Code nested too deeply."); } while (0)
67 // Macros to make the more common TreeBuilder types a little less verbose
68 #define TreeStatement typename TreeBuilder::Statement
69 #define TreeExpression typename TreeBuilder::Expression
70 #define TreeFormalParameterList typename TreeBuilder::FormalParameterList
71 #define TreeSourceElements typename TreeBuilder::SourceElements
72 #define TreeClause typename TreeBuilder::Clause
73 #define TreeClauseList typename TreeBuilder::ClauseList
74 #define TreeConstDeclList typename TreeBuilder::ConstDeclList
75 #define TreeArguments typename TreeBuilder::Arguments
76 #define TreeArgumentsList typename TreeBuilder::ArgumentsList
77 #define TreeFunctionBody typename TreeBuilder::FunctionBody
78 #define TreeProperty typename TreeBuilder::Property
79 #define TreePropertyList typename TreeBuilder::PropertyList
81 COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
85 JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, const SourceCode*);
86 UString parseProgram();
88 struct AllowInOverride {
89 AllowInOverride(JSParser* parser)
91 , m_oldAllowsIn(parser->m_allowsIn)
93 parser->m_allowsIn = true;
97 m_parser->m_allowsIn = m_oldAllowsIn;
103 struct ScopeLabelInfo {
104 ScopeLabelInfo(StringImpl* ident, bool isLoop)
113 ALWAYS_INLINE void next(unsigned lexType = 0)
115 m_lastLine = m_token.m_info.line;
116 m_lastTokenEnd = m_token.m_info.endOffset;
117 m_lexer->setLastLineNumber(m_lastLine);
118 m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexType, strictMode());
121 ALWAYS_INLINE void nextExpectIdentifier(unsigned lexType = 0)
123 m_lastLine = m_token.m_info.line;
124 m_lastTokenEnd = m_token.m_info.endOffset;
125 m_lexer->setLastLineNumber(m_lastLine);
126 m_token.m_type = m_lexer->lexExpectIdentifier(&m_token.m_data, &m_token.m_info, lexType, strictMode());
129 ALWAYS_INLINE bool nextTokenIsColon()
131 return m_lexer->nextTokenIsColon();
134 ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0)
136 bool result = m_token.m_type == expected;
142 ALWAYS_INLINE UString getToken() {
143 SourceProvider* sourceProvider = m_source->provider();
144 return UString(sourceProvider->getRange(tokenStart(), tokenEnd()).impl());
147 ALWAYS_INLINE bool match(JSTokenType expected)
149 return m_token.m_type == expected;
152 ALWAYS_INLINE int tokenStart()
154 return m_token.m_info.startOffset;
157 ALWAYS_INLINE int tokenLine()
159 return m_token.m_info.line;
162 ALWAYS_INLINE int tokenEnd()
164 return m_token.m_info.endOffset;
167 const char* getTokenName(JSTokenType tok)
327 case RESERVED_IF_STRICT:
335 case LastUntaggedToken:
338 ASSERT_NOT_REACHED();
339 return "internal error";
342 ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken)
345 switch (expectedToken) {
346 case RESERVED_IF_STRICT:
347 errorMessage = "Use of reserved word '";
348 errorMessage += getToken().impl();
349 errorMessage += "' in strict mode";
350 m_errorMessage = errorMessage.impl();
353 errorMessage = "Use of reserved word '";
354 errorMessage += getToken().impl();
356 m_errorMessage = errorMessage.impl();
359 errorMessage = "Unexpected number '";
360 errorMessage += getToken().impl();
362 m_errorMessage = errorMessage.impl();
365 errorMessage = "Expected an identifier but found '";
366 errorMessage += getToken().impl();
367 errorMessage += "' instead";
368 m_errorMessage = errorMessage.impl();
371 errorMessage = "Unexpected string ";
372 errorMessage += getToken().impl();
373 m_errorMessage = errorMessage.impl();
376 errorMessage = "Unrecognized token '";
377 errorMessage += getToken().impl();
379 m_errorMessage = errorMessage.impl();
382 m_errorMessage = "Unexpected EOF";
385 m_errorMessage = "Return statements are only valid inside functions";
388 ASSERT_NOT_REACHED();
389 m_errorMessage = "internal error";
394 NEVER_INLINE void updateErrorMessage()
397 const char* name = getTokenName(m_token.m_type);
399 updateErrorMessageSpecialCase(m_token.m_type);
401 m_errorMessage = UString(String::format("Unexpected token '%s'", name).impl());
404 NEVER_INLINE void updateErrorMessage(JSTokenType expectedToken)
407 const char* name = getTokenName(expectedToken);
409 m_errorMessage = UString(String::format("Expected token '%s'", name).impl());
411 if (!getTokenName(m_token.m_type))
412 updateErrorMessageSpecialCase(m_token.m_type);
414 updateErrorMessageSpecialCase(expectedToken);
418 NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, UString name, const char* afterMsg)
421 String prefix(beforeMsg);
422 String postfix(afterMsg);
424 prefix += name.impl();
427 m_errorMessage = prefix.impl();
430 NEVER_INLINE void updateErrorMessage(const char* msg)
433 m_errorMessage = UString(msg);
436 void startLoop() { currentScope()->startLoop(); }
437 void endLoop() { currentScope()->endLoop(); }
438 void startSwitch() { currentScope()->startSwitch(); }
439 void endSwitch() { currentScope()->endSwitch(); }
440 void setStrictMode() { currentScope()->setStrictMode(); }
441 bool strictMode() { return currentScope()->strictMode(); }
442 bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
443 bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
446 ScopeRef current = currentScope();
447 while (!current->breakIsValid()) {
448 if (!current.hasContainingScope())
450 current = current.containingScope();
454 bool continueIsValid()
456 ScopeRef current = currentScope();
457 while (!current->continueIsValid()) {
458 if (!current.hasContainingScope())
460 current = current.containingScope();
464 void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
465 void popLabel() { currentScope()->popLabel(); }
466 ScopeLabelInfo* getLabel(const Identifier* label)
468 ScopeRef current = currentScope();
469 ScopeLabelInfo* result = 0;
470 while (!(result = current->getLabel(label))) {
471 if (!current.hasContainingScope())
473 current = current.containingScope();
478 enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
479 template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
480 template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive);
481 template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
482 template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
483 template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
484 template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
485 template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
486 template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
487 template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
488 template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
489 template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
490 template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
491 template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
492 template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
493 template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
494 template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
495 template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
496 template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
497 template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
498 template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
499 template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
500 template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&);
501 template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
502 template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
503 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
504 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
505 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
506 template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
507 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
508 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
509 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
510 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
511 template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
512 template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
513 template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
514 template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
515 template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
516 template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
517 enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
518 template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
519 ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
520 bool allowAutomaticSemicolon();
524 if (m_token.m_type == SEMICOLON) {
528 return allowAutomaticSemicolon();
533 return m_stack.recursionCheck();
536 int lastTokenEnd() const
538 return m_lastTokenEnd;
545 UString m_errorMessage;
546 JSGlobalData* m_globalData;
551 int m_assignmentCount;
553 bool m_syntaxAlreadyValidated;
554 int m_statementDepth;
555 int m_nonTrivialExpressionCount;
556 const Identifier* m_lastIdentifier;
558 struct DepthManager {
559 DepthManager(int* depth)
560 : m_originalDepth(*depth)
567 *m_depth = m_originalDepth;
576 Scope(JSGlobalData* globalData, bool isFunction, bool strictMode)
577 : m_globalData(globalData)
578 , m_shadowsArguments(false)
580 , m_needsFullActivation(false)
581 , m_allowsNewDecls(true)
582 , m_strictMode(strictMode)
583 , m_isFunction(isFunction)
584 , m_isFunctionBoundary(false)
585 , m_isValidStrictMode(true)
591 Scope(const Scope& rhs)
592 : m_globalData(rhs.m_globalData)
593 , m_shadowsArguments(rhs.m_shadowsArguments)
594 , m_usesEval(rhs.m_usesEval)
595 , m_needsFullActivation(rhs.m_needsFullActivation)
596 , m_allowsNewDecls(rhs.m_allowsNewDecls)
597 , m_strictMode(rhs.m_strictMode)
598 , m_isFunction(rhs.m_isFunction)
599 , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
600 , m_isValidStrictMode(rhs.m_isValidStrictMode)
601 , m_loopDepth(rhs.m_loopDepth)
602 , m_switchDepth(rhs.m_switchDepth)
605 m_labels = adoptPtr(new LabelStack);
607 typedef LabelStack::const_iterator iterator;
608 iterator end = rhs.m_labels->end();
609 for (iterator it = rhs.m_labels->begin(); it != end; ++it)
610 m_labels->append(ScopeLabelInfo(it->m_ident, it->m_isLoop));
614 void startSwitch() { m_switchDepth++; }
615 void endSwitch() { m_switchDepth--; }
616 void startLoop() { m_loopDepth++; }
617 void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
618 bool inLoop() { return !!m_loopDepth; }
619 bool breakIsValid() { return m_loopDepth || m_switchDepth; }
620 bool continueIsValid() { return m_loopDepth; }
622 void pushLabel(const Identifier* label, bool isLoop)
625 m_labels = adoptPtr(new LabelStack);
626 m_labels->append(ScopeLabelInfo(label->impl(), isLoop));
632 ASSERT(m_labels->size());
633 m_labels->removeLast();
636 ScopeLabelInfo* getLabel(const Identifier* label)
640 for (int i = m_labels->size(); i > 0; i--) {
641 if (m_labels->at(i - 1).m_ident == label->impl())
642 return &m_labels->at(i - 1);
650 m_isFunctionBoundary = true;
652 bool isFunction() { return m_isFunction; }
653 bool isFunctionBoundary() { return m_isFunctionBoundary; }
655 bool declareVariable(const Identifier* ident)
657 bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
658 m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
659 m_declaredVariables.add(ident->ustring().impl());
660 return isValidStrictMode;
663 void declareWrite(const Identifier* ident)
665 ASSERT(m_strictMode);
666 m_writtenVariables.add(ident->impl());
669 void preventNewDecls() { m_allowsNewDecls = false; }
670 bool allowsNewDecls() const { return m_allowsNewDecls; }
672 bool declareParameter(const Identifier* ident)
674 bool isArguments = m_globalData->propertyNames->arguments == *ident;
675 bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && !isArguments;
676 m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
678 m_shadowsArguments = true;
679 return isValidStrictMode;
682 void useVariable(const Identifier* ident, bool isEval)
684 m_usesEval |= isEval;
685 m_usedVariables.add(ident->ustring().impl());
688 void setNeedsFullActivation() { m_needsFullActivation = true; }
690 bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
692 if (nestedScope->m_usesEval)
694 IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
695 for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
696 if (nestedScope->m_declaredVariables.contains(*ptr))
698 m_usedVariables.add(*ptr);
699 if (shouldTrackClosedVariables)
700 m_closedVariables.add(*ptr);
702 if (nestedScope->m_writtenVariables.size()) {
703 IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
704 for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
705 if (nestedScope->m_declaredVariables.contains(*ptr))
707 m_writtenVariables.add(*ptr);
714 void getUncapturedWrittenVariables(IdentifierSet& writtenVariables)
716 IdentifierSet::iterator end = m_writtenVariables.end();
717 for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
718 if (!m_declaredVariables.contains(*ptr))
719 writtenVariables.add(*ptr);
723 void getCapturedVariables(IdentifierSet& capturedVariables)
725 if (m_needsFullActivation || m_usesEval) {
726 capturedVariables.swap(m_declaredVariables);
729 for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) {
730 if (!m_declaredVariables.contains(*ptr))
732 capturedVariables.add(*ptr);
735 void setStrictMode() { m_strictMode = true; }
736 bool strictMode() const { return m_strictMode; }
737 bool isValidStrictMode() const { return m_isValidStrictMode; }
738 bool shadowsArguments() const { return m_shadowsArguments; }
740 void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector)
742 IdentifierSet::iterator end = capturedVariables.end();
743 for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
744 if (m_declaredVariables.contains(*it))
748 vector.shrinkToFit();
751 void saveFunctionInfo(SourceProviderCacheItem* info)
753 ASSERT(m_isFunction);
754 info->usesEval = m_usesEval;
755 copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
756 copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
759 void restoreFunctionInfo(const SourceProviderCacheItem* info)
761 ASSERT(m_isFunction);
762 m_usesEval = info->usesEval;
763 unsigned size = info->usedVariables.size();
764 for (unsigned i = 0; i < size; ++i)
765 m_usedVariables.add(info->usedVariables[i]);
766 size = info->writtenVariables.size();
767 for (unsigned i = 0; i < size; ++i)
768 m_writtenVariables.add(info->writtenVariables[i]);
772 JSGlobalData* m_globalData;
773 bool m_shadowsArguments : 1;
775 bool m_needsFullActivation : 1;
776 bool m_allowsNewDecls : 1;
777 bool m_strictMode : 1;
778 bool m_isFunction : 1;
779 bool m_isFunctionBoundary : 1;
780 bool m_isValidStrictMode : 1;
784 typedef Vector<ScopeLabelInfo, 2> LabelStack;
785 OwnPtr<LabelStack> m_labels;
786 IdentifierSet m_declaredVariables;
787 IdentifierSet m_usedVariables;
788 IdentifierSet m_closedVariables;
789 IdentifierSet m_writtenVariables;
792 typedef Vector<Scope, 10> ScopeStack;
795 ScopeRef(ScopeStack* scopeStack, unsigned index)
796 : m_scopeStack(scopeStack)
800 Scope* operator->() { return &m_scopeStack->at(m_index); }
801 unsigned index() const { return m_index; }
803 bool hasContainingScope()
805 return m_index && !m_scopeStack->at(m_index).isFunctionBoundary();
808 ScopeRef containingScope()
810 ASSERT(hasContainingScope());
811 return ScopeRef(m_scopeStack, m_index - 1);
815 ScopeStack* m_scopeStack;
819 struct AutoPopScopeRef : public ScopeRef {
820 AutoPopScopeRef(JSParser* parser, ScopeRef scope)
829 m_parser->popScope(*this, false);
841 ScopeRef currentScope()
843 return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
848 bool isFunction = false;
849 bool isStrict = false;
850 if (!m_scopeStack.isEmpty()) {
851 isStrict = m_scopeStack.last().strictMode();
852 isFunction = m_scopeStack.last().isFunction();
854 m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
855 return currentScope();
858 bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
860 ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
861 ASSERT(m_scopeStack.size() > 1);
862 bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
863 m_scopeStack.removeLast();
867 bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
869 return popScopeInternal(scope, shouldTrackClosedVariables);
872 bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
875 return popScopeInternal(scope, shouldTrackClosedVariables);
878 bool declareVariable(const Identifier* ident)
880 unsigned i = m_scopeStack.size() - 1;
881 ASSERT(i < m_scopeStack.size());
882 while (!m_scopeStack[i].allowsNewDecls()) {
884 ASSERT(i < m_scopeStack.size());
886 return m_scopeStack[i].declareVariable(ident);
889 void declareWrite(const Identifier* ident)
891 if (!m_syntaxAlreadyValidated)
892 m_scopeStack.last().declareWrite(ident);
895 ScopeStack m_scopeStack;
897 const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos)
899 return m_functionCache ? m_functionCache->get(openBracePos) : 0;
902 SourceProviderCache* m_functionCache;
903 const SourceCode* m_source;
906 UString jsParse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)
908 JSParser parser(globalData->lexer, globalData, parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source);
909 return parser.parseProgram();
912 JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, const SourceCode* source)
914 , m_stack(globalData->stack())
916 , m_errorMessage("Parse error")
917 , m_globalData(globalData)
921 , m_assignmentCount(0)
923 , m_syntaxAlreadyValidated(source->provider()->isValid())
924 , m_statementDepth(0)
925 , m_nonTrivialExpressionCount(0)
926 , m_lastIdentifier(0)
927 , m_functionCache(m_lexer->sourceProvider()->cache())
930 ScopeRef scope = pushScope();
932 scope->setIsFunction();
934 scope->setStrictMode();
936 for (unsigned i = 0; i < parameters->size(); i++)
937 scope->declareParameter(¶meters->at(i));
940 m_lexer->setLastLineNumber(tokenLine());
943 UString JSParser::parseProgram()
945 unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
946 ASTBuilder context(m_globalData, m_lexer);
947 if (m_lexer->isReparsing())
949 ScopeRef scope = currentScope();
950 SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
951 if (!sourceElements || !consume(EOFTOK))
952 return m_errorMessage;
953 IdentifierSet capturedVariables;
954 scope->getCapturedVariables(capturedVariables);
955 CodeFeatures features = context.features();
956 if (scope->strictMode())
957 features |= StrictModeFeature;
958 if (scope->shadowsArguments())
959 features |= ShadowsArgumentsFeature;
961 unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
962 if (functionCacheSize != oldFunctionCacheSize)
963 m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize);
965 m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
966 m_lastLine, context.numConstants(), capturedVariables);
970 bool JSParser::allowAutomaticSemicolon()
972 return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
975 template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
977 TreeSourceElements sourceElements = context.createSourceElements();
978 bool seenNonDirective = false;
979 const Identifier* directive = 0;
980 unsigned startOffset = m_token.m_info.startOffset;
981 unsigned oldLastLineNumber = m_lexer->lastLineNumber();
982 unsigned oldLineNumber = m_lexer->lineNumber();
983 bool hasSetStrict = false;
984 while (TreeStatement statement = parseStatement(context, directive)) {
985 if (mode == CheckForStrictMode && !seenNonDirective) {
987 if (!hasSetStrict && m_globalData->propertyNames->useStrictIdentifier == *directive) {
990 failIfFalse(isValidStrictMode());
991 m_lexer->setOffset(startOffset);
993 m_lexer->setLastLineNumber(oldLastLineNumber);
994 m_lexer->setLineNumber(oldLineNumber);
999 seenNonDirective = true;
1001 context.appendStatement(sourceElements, statement);
1006 return sourceElements;
1009 template <class TreeBuilder> TreeStatement JSParser::parseVarDeclaration(TreeBuilder& context)
1012 int start = tokenLine();
1015 const Identifier* scratch1 = 0;
1016 TreeExpression scratch2 = 0;
1018 TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
1019 failIfTrue(m_error);
1020 failIfFalse(autoSemiColon());
1022 return context.createVarStatement(varDecls, start, end);
1025 template <class TreeBuilder> TreeStatement JSParser::parseConstDeclaration(TreeBuilder& context)
1027 ASSERT(match(CONSTTOKEN));
1028 int start = tokenLine();
1030 TreeConstDeclList constDecls = parseConstDeclarationList(context);
1031 failIfTrue(m_error);
1032 failIfFalse(autoSemiColon());
1034 return context.createConstStatement(constDecls, start, end);
1037 template <class TreeBuilder> TreeStatement JSParser::parseDoWhileStatement(TreeBuilder& context)
1040 int startLine = tokenLine();
1042 const Identifier* unused = 0;
1044 TreeStatement statement = parseStatement(context, unused);
1046 failIfFalse(statement);
1047 int endLine = tokenLine();
1048 consumeOrFail(WHILE);
1049 consumeOrFail(OPENPAREN);
1050 TreeExpression expr = parseExpression(context);
1052 consumeOrFail(CLOSEPAREN);
1053 if (match(SEMICOLON))
1054 next(); // Always performs automatic semicolon insertion.
1055 return context.createDoWhileStatement(statement, expr, startLine, endLine);
1058 template <class TreeBuilder> TreeStatement JSParser::parseWhileStatement(TreeBuilder& context)
1060 ASSERT(match(WHILE));
1061 int startLine = tokenLine();
1063 consumeOrFail(OPENPAREN);
1064 TreeExpression expr = parseExpression(context);
1066 int endLine = tokenLine();
1067 consumeOrFail(CLOSEPAREN);
1068 const Identifier* unused = 0;
1070 TreeStatement statement = parseStatement(context, unused);
1072 failIfFalse(statement);
1073 return context.createWhileStatement(expr, statement, startLine, endLine);
1076 template <class TreeBuilder> TreeExpression JSParser::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd)
1078 TreeExpression varDecls = 0;
1084 int varStart = tokenStart();
1085 identStart = varStart;
1086 const Identifier* name = m_token.m_data.ident;
1089 bool hasInitializer = match(EQUAL);
1090 failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode.");
1091 context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
1092 if (hasInitializer) {
1093 int varDivot = tokenStart() + 1;
1094 initStart = tokenStart();
1095 next(TreeBuilder::DontBuildStrings); // consume '='
1096 int initialAssignments = m_assignmentCount;
1097 TreeExpression initializer = parseAssignmentExpression(context);
1098 initEnd = lastTokenEnd();
1099 lastInitializer = initializer;
1100 failIfFalse(initializer);
1102 TreeExpression node = context.createAssignResolve(*name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd());
1106 varDecls = context.combineCommaNodes(varDecls, node);
1108 } while (match(COMMA));
1112 template <class TreeBuilder> TreeConstDeclList JSParser::parseConstDeclarationList(TreeBuilder& context)
1114 failIfTrue(strictMode());
1115 TreeConstDeclList constDecls = 0;
1116 TreeConstDeclList tail = 0;
1120 const Identifier* name = m_token.m_data.ident;
1122 bool hasInitializer = match(EQUAL);
1123 declareVariable(name);
1124 context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
1125 TreeExpression initializer = 0;
1126 if (hasInitializer) {
1127 next(TreeBuilder::DontBuildStrings); // consume '='
1128 initializer = parseAssignmentExpression(context);
1130 tail = context.appendConstDecl(tail, name, initializer);
1133 } while (match(COMMA));
1137 template <class TreeBuilder> TreeStatement JSParser::parseForStatement(TreeBuilder& context)
1140 int startLine = tokenLine();
1142 consumeOrFail(OPENPAREN);
1143 int nonLHSCount = m_nonLHSCount;
1144 int declarations = 0;
1147 TreeExpression decls = 0;
1148 bool hasDeclaration = false;
1151 for (var IDENT in expression) statement
1152 for (var IDENT = expression in expression) statement
1153 for (var varDeclarationList; expressionOpt; expressionOpt)
1155 hasDeclaration = true;
1156 const Identifier* forInTarget = 0;
1157 TreeExpression forInInitializer = 0;
1161 decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd);
1166 // Remainder of a standard for loop is handled identically
1167 if (match(SEMICOLON))
1168 goto standardForLoop;
1170 failIfFalse(declarations == 1);
1172 // Handle for-in with var declaration
1173 int inLocation = tokenStart();
1174 consumeOrFail(INTOKEN);
1176 TreeExpression expr = parseExpression(context);
1178 int exprEnd = lastTokenEnd();
1180 int endLine = tokenLine();
1181 consumeOrFail(CLOSEPAREN);
1183 const Identifier* unused = 0;
1185 TreeStatement statement = parseStatement(context, unused);
1187 failIfFalse(statement);
1189 return context.createForInLoop(forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine);
1192 if (!match(SEMICOLON)) {
1194 declsStart = tokenStart();
1195 decls = parseExpression(context);
1196 declsEnd = lastTokenEnd();
1201 if (match(SEMICOLON)) {
1203 // Standard for loop
1205 TreeExpression condition = 0;
1207 if (!match(SEMICOLON)) {
1208 condition = parseExpression(context);
1209 failIfFalse(condition);
1211 consumeOrFail(SEMICOLON);
1213 TreeExpression increment = 0;
1214 if (!match(CLOSEPAREN)) {
1215 increment = parseExpression(context);
1216 failIfFalse(increment);
1218 int endLine = tokenLine();
1219 consumeOrFail(CLOSEPAREN);
1220 const Identifier* unused = 0;
1222 TreeStatement statement = parseStatement(context, unused);
1224 failIfFalse(statement);
1225 return context.createForLoop(decls, condition, increment, statement, hasDeclaration, startLine, endLine);
1229 failIfFalse(nonLHSCount == m_nonLHSCount);
1230 consumeOrFail(INTOKEN);
1231 TreeExpression expr = parseExpression(context);
1233 int exprEnd = lastTokenEnd();
1234 int endLine = tokenLine();
1235 consumeOrFail(CLOSEPAREN);
1236 const Identifier* unused = 0;
1238 TreeStatement statement = parseStatement(context, unused);
1240 failIfFalse(statement);
1242 return context.createForInLoop(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
1245 template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBuilder& context)
1247 ASSERT(match(BREAK));
1248 int startCol = tokenStart();
1249 int endCol = tokenEnd();
1250 int startLine = tokenLine();
1251 int endLine = tokenLine();
1254 if (autoSemiColon()) {
1255 failIfFalseWithMessage(breakIsValid(), "'break' is only valid inside a switch or loop statement");
1256 return context.createBreakStatement(startCol, endCol, startLine, endLine);
1259 const Identifier* ident = m_token.m_data.ident;
1260 failIfFalseWithNameAndMessage(getLabel(ident), "Label", ident->impl(), "is not defined");
1261 endCol = tokenEnd();
1262 endLine = tokenLine();
1264 failIfFalse(autoSemiColon());
1265 return context.createBreakStatement(ident, startCol, endCol, startLine, endLine);
1268 template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(TreeBuilder& context)
1270 ASSERT(match(CONTINUE));
1271 int startCol = tokenStart();
1272 int endCol = tokenEnd();
1273 int startLine = tokenLine();
1274 int endLine = tokenLine();
1277 if (autoSemiColon()) {
1278 failIfFalseWithMessage(continueIsValid(), "'continue' is only valid inside a loop statement");
1279 return context.createContinueStatement(startCol, endCol, startLine, endLine);
1282 const Identifier* ident = m_token.m_data.ident;
1283 ScopeLabelInfo* label = getLabel(ident);
1284 failIfFalseWithNameAndMessage(label, "Label", ident->impl(), "is not defined");
1285 failIfFalseWithMessage(label->m_isLoop, "'continue' is only valid inside a loop statement");
1286 endCol = tokenEnd();
1287 endLine = tokenLine();
1289 failIfFalse(autoSemiColon());
1290 return context.createContinueStatement(ident, startCol, endCol, startLine, endLine);
1293 template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context)
1295 ASSERT(match(RETURN));
1296 failIfFalse(currentScope()->isFunction());
1297 int startLine = tokenLine();
1298 int endLine = startLine;
1299 int start = tokenStart();
1300 int end = tokenEnd();
1302 // We do the auto semicolon check before attempting to parse an expression
1303 // as we need to ensure the a line break after the return correctly terminates
1305 if (match(SEMICOLON))
1306 endLine = tokenLine();
1307 if (autoSemiColon())
1308 return context.createReturnStatement(0, start, end, startLine, endLine);
1309 TreeExpression expr = parseExpression(context);
1311 end = lastTokenEnd();
1312 if (match(SEMICOLON))
1313 endLine = tokenLine();
1314 failIfFalse(autoSemiColon());
1315 return context.createReturnStatement(expr, start, end, startLine, endLine);
1318 template <class TreeBuilder> TreeStatement JSParser::parseThrowStatement(TreeBuilder& context)
1320 ASSERT(match(THROW));
1321 int eStart = tokenStart();
1322 int startLine = tokenLine();
1325 failIfTrue(autoSemiColon());
1327 TreeExpression expr = parseExpression(context);
1329 int eEnd = lastTokenEnd();
1330 int endLine = tokenLine();
1331 failIfFalse(autoSemiColon());
1333 return context.createThrowStatement(expr, eStart, eEnd, startLine, endLine);
1336 template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
1338 ASSERT(match(WITH));
1339 failIfTrueWithMessage(strictMode(), "'with' statements are not valid in strict mode");
1340 currentScope()->setNeedsFullActivation();
1341 int startLine = tokenLine();
1343 consumeOrFail(OPENPAREN);
1344 int start = tokenStart();
1345 TreeExpression expr = parseExpression(context);
1347 int end = lastTokenEnd();
1349 int endLine = tokenLine();
1350 consumeOrFail(CLOSEPAREN);
1351 const Identifier* unused = 0;
1352 TreeStatement statement = parseStatement(context, unused);
1353 failIfFalse(statement);
1355 return context.createWithStatement(expr, statement, start, end, startLine, endLine);
1358 template <class TreeBuilder> TreeStatement JSParser::parseSwitchStatement(TreeBuilder& context)
1360 ASSERT(match(SWITCH));
1361 int startLine = tokenLine();
1363 consumeOrFail(OPENPAREN);
1364 TreeExpression expr = parseExpression(context);
1366 int endLine = tokenLine();
1367 consumeOrFail(CLOSEPAREN);
1368 consumeOrFail(OPENBRACE);
1370 TreeClauseList firstClauses = parseSwitchClauses(context);
1371 failIfTrue(m_error);
1373 TreeClause defaultClause = parseSwitchDefaultClause(context);
1374 failIfTrue(m_error);
1376 TreeClauseList secondClauses = parseSwitchClauses(context);
1377 failIfTrue(m_error);
1379 consumeOrFail(CLOSEBRACE);
1381 return context.createSwitchStatement(expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
1385 template <class TreeBuilder> TreeClauseList JSParser::parseSwitchClauses(TreeBuilder& context)
1390 TreeExpression condition = parseExpression(context);
1391 failIfFalse(condition);
1392 consumeOrFail(COLON);
1393 TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
1394 failIfFalse(statements);
1395 TreeClause clause = context.createClause(condition, statements);
1396 TreeClauseList clauseList = context.createClauseList(clause);
1397 TreeClauseList tail = clauseList;
1399 while (match(CASE)) {
1401 TreeExpression condition = parseExpression(context);
1402 failIfFalse(condition);
1403 consumeOrFail(COLON);
1404 TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
1405 failIfFalse(statements);
1406 clause = context.createClause(condition, statements);
1407 tail = context.createClauseList(tail, clause);
1412 template <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context)
1414 if (!match(DEFAULT))
1417 consumeOrFail(COLON);
1418 TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
1419 failIfFalse(statements);
1420 return context.createClause(0, statements);
1423 template <class TreeBuilder> TreeStatement JSParser::parseTryStatement(TreeBuilder& context)
1426 TreeStatement tryBlock = 0;
1427 const Identifier* ident = &m_globalData->propertyNames->nullIdentifier;
1428 bool catchHasEval = false;
1429 TreeStatement catchBlock = 0;
1430 TreeStatement finallyBlock = 0;
1431 int firstLine = tokenLine();
1433 matchOrFail(OPENBRACE);
1435 tryBlock = parseBlockStatement(context);
1436 failIfFalse(tryBlock);
1437 int lastLine = m_lastLine;
1440 currentScope()->setNeedsFullActivation();
1442 consumeOrFail(OPENPAREN);
1444 ident = m_token.m_data.ident;
1446 AutoPopScopeRef catchScope(this, pushScope());
1447 failIfFalseIfStrictWithNameAndMessage(catchScope->declareVariable(ident), "Cannot declare a variable named", ident->impl(), "in strict mode");
1448 catchScope->preventNewDecls();
1449 consumeOrFail(CLOSEPAREN);
1450 matchOrFail(OPENBRACE);
1451 int initialEvalCount = context.evalCount();
1452 catchBlock = parseBlockStatement(context);
1453 failIfFalseWithMessage(catchBlock, "'try' must have a catch or finally block");
1454 catchHasEval = initialEvalCount != context.evalCount();
1455 failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo));
1458 if (match(FINALLY)) {
1460 matchOrFail(OPENBRACE);
1461 finallyBlock = parseBlockStatement(context);
1462 failIfFalse(finallyBlock);
1464 failIfFalse(catchBlock || finallyBlock);
1465 return context.createTryStatement(tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine);
1468 template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(TreeBuilder& context)
1470 ASSERT(match(DEBUGGER));
1471 int startLine = tokenLine();
1472 int endLine = startLine;
1474 if (match(SEMICOLON))
1475 startLine = tokenLine();
1476 failIfFalse(autoSemiColon());
1477 return context.createDebugger(startLine, endLine);
1480 template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBuilder& context)
1482 ASSERT(match(OPENBRACE));
1483 int start = tokenLine();
1485 if (match(CLOSEBRACE)) {
1487 return context.createBlockStatement(0, start, m_lastLine);
1489 TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context);
1490 failIfFalse(subtree);
1491 matchOrFail(CLOSEBRACE);
1493 return context.createBlockStatement(subtree, start, m_lastLine);
1496 template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context, const Identifier*& directive)
1498 DepthManager statementDepth(&m_statementDepth);
1501 int nonTrivialExpressionCount = 0;
1502 failIfStackOverflow();
1503 switch (m_token.m_type) {
1505 return parseBlockStatement(context);
1507 return parseVarDeclaration(context);
1509 return parseConstDeclaration(context);
1511 failIfFalseIfStrictWithMessage(m_statementDepth == 1, "Functions cannot be declared in a nested block in strict mode");
1512 return parseFunctionDeclaration(context);
1515 return context.createEmptyStatement();
1517 return parseIfStatement(context);
1519 return parseDoWhileStatement(context);
1521 return parseWhileStatement(context);
1523 return parseForStatement(context);
1525 return parseContinueStatement(context);
1527 return parseBreakStatement(context);
1529 return parseReturnStatement(context);
1531 return parseWithStatement(context);
1533 return parseSwitchStatement(context);
1535 return parseThrowStatement(context);
1537 return parseTryStatement(context);
1539 return parseDebuggerStatement(context);
1544 // These tokens imply the end of a set of source elements
1547 return parseExpressionOrLabelStatement(context);
1549 directive = m_token.m_data.ident;
1550 nonTrivialExpressionCount = m_nonTrivialExpressionCount;
1552 TreeStatement exprStatement = parseExpressionStatement(context);
1553 if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
1555 return exprStatement;
1559 template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context)
1562 failIfFalseIfStrictWithNameAndMessage(declareParameter(m_token.m_data.ident), "Cannot declare a parameter named", m_token.m_data.ident->impl(), " in strict mode");
1563 TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
1564 TreeFormalParameterList tail = list;
1566 while (match(COMMA)) {
1569 const Identifier* ident = m_token.m_data.ident;
1570 failIfFalseIfStrictWithNameAndMessage(declareParameter(ident), "Cannot declare a parameter named", ident->impl(), "in strict mode");
1572 tail = context.createFormalParameterList(tail, *ident);
1577 template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
1579 if (match(CLOSEBRACE))
1580 return context.createFunctionBody(strictMode());
1581 DepthManager statementDepth(&m_statementDepth);
1582 m_statementDepth = 0;
1583 typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
1584 failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
1585 return context.createFunctionBody(strictMode());
1588 template <JSParser::FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
1590 AutoPopScopeRef functionScope(this, pushScope());
1591 functionScope->setIsFunction();
1593 name = m_token.m_data.ident;
1594 failIfTrueWithMessage(*name == m_globalData->propertyNames->underscoreProto, "Cannot name a function __proto__");
1596 if (!nameIsInContainingScope)
1597 failIfFalseIfStrict(functionScope->declareVariable(name));
1598 } else if (requirements == FunctionNeedsName)
1600 consumeOrFail(OPENPAREN);
1601 if (!match(CLOSEPAREN)) {
1602 parameters = parseFormalParameters(context);
1603 failIfFalse(parameters);
1605 consumeOrFail(CLOSEPAREN);
1606 matchOrFail(OPENBRACE);
1608 openBracePos = m_token.m_data.intValue;
1609 bodyStartLine = tokenLine();
1611 if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) {
1612 // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
1613 body = context.createFunctionBody(strictMode());
1615 functionScope->restoreFunctionInfo(cachedInfo);
1616 failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
1618 closeBracePos = cachedInfo->closeBracePos;
1619 m_token = cachedInfo->closeBraceToken();
1620 m_lexer->setOffset(m_token.m_info.endOffset);
1621 m_lexer->setLineNumber(m_token.m_info.line);
1629 body = parseFunctionBody(context);
1631 if (functionScope->strictMode() && name) {
1632 failIfTrueWithNameAndMessage(m_globalData->propertyNames->arguments == *name, "Function name", name->impl(), "is not valid in strict mode");
1633 failIfTrueWithNameAndMessage(m_globalData->propertyNames->eval == *name, "Function name", name->impl(), "is not valid in strict mode");
1635 closeBracePos = m_token.m_data.intValue;
1637 // Cache the tokenizer state and the function scope the first time the function is parsed.
1638 // Any future reparsing can then skip the function.
1639 static const int minimumFunctionLengthToCache = 64;
1640 OwnPtr<SourceProviderCacheItem> newInfo;
1641 int functionLength = closeBracePos - openBracePos;
1642 if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {
1643 newInfo = adoptPtr(new SourceProviderCacheItem(m_token.m_info.line, closeBracePos));
1644 functionScope->saveFunctionInfo(newInfo.get());
1647 failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
1648 matchOrFail(CLOSEBRACE);
1651 unsigned approximateByteSize = newInfo->approximateByteSize();
1652 m_functionCache->add(openBracePos, newInfo.release(), approximateByteSize);
1659 template <class TreeBuilder> TreeStatement JSParser::parseFunctionDeclaration(TreeBuilder& context)
1661 ASSERT(match(FUNCTION));
1663 const Identifier* name = 0;
1664 TreeFormalParameterList parameters = 0;
1665 TreeFunctionBody body = 0;
1666 int openBracePos = 0;
1667 int closeBracePos = 0;
1668 int bodyStartLine = 0;
1669 failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
1671 failIfFalseIfStrict(declareVariable(name));
1672 return context.createFuncDeclStatement(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
1676 LabelInfo(const Identifier* ident, int start, int end)
1683 const Identifier* m_ident;
1688 template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context)
1691 /* Expression and Label statements are ambiguous at LL(1), so we have a
1692 * special case that looks for a colon as the next character in the input.
1694 Vector<LabelInfo> labels;
1697 int start = tokenStart();
1698 int startLine = tokenLine();
1699 if (!nextTokenIsColon()) {
1700 // If we hit this path we're making a expression statement, which
1701 // by definition can't make use of continue/break so we can just
1702 // ignore any labels we might have accumulated.
1703 TreeExpression expression = parseExpression(context);
1704 failIfFalse(expression);
1705 failIfFalse(autoSemiColon());
1706 return context.createExprStatement(expression, startLine, m_lastLine);
1708 const Identifier* ident = m_token.m_data.ident;
1709 int end = tokenEnd();
1711 consumeOrFail(COLON);
1712 if (!m_syntaxAlreadyValidated) {
1713 // This is O(N^2) over the current list of consecutive labels, but I
1714 // have never seen more than one label in a row in the real world.
1715 for (size_t i = 0; i < labels.size(); i++)
1716 failIfTrue(ident->impl() == labels[i].m_ident->impl());
1717 failIfTrue(getLabel(ident));
1718 labels.append(LabelInfo(ident, start, end));
1720 } while (match(IDENT));
1721 bool isLoop = false;
1722 switch (m_token.m_type) {
1732 const Identifier* unused = 0;
1733 if (!m_syntaxAlreadyValidated) {
1734 for (size_t i = 0; i < labels.size(); i++)
1735 pushLabel(labels[i].m_ident, isLoop);
1737 TreeStatement statement = parseStatement(context, unused);
1738 if (!m_syntaxAlreadyValidated) {
1739 for (size_t i = 0; i < labels.size(); i++)
1742 failIfFalse(statement);
1743 for (size_t i = 0; i < labels.size(); i++) {
1744 const LabelInfo& info = labels[labels.size() - i - 1];
1745 statement = context.createLabelStatement(info.m_ident, statement, info.m_start, info.m_end);
1750 template <class TreeBuilder> TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context)
1752 int startLine = tokenLine();
1753 TreeExpression expression = parseExpression(context);
1754 failIfFalse(expression);
1755 failIfFalse(autoSemiColon());
1756 return context.createExprStatement(expression, startLine, m_lastLine);
1759 template <class TreeBuilder> TreeStatement JSParser::parseIfStatement(TreeBuilder& context)
1763 int start = tokenLine();
1766 consumeOrFail(OPENPAREN);
1768 TreeExpression condition = parseExpression(context);
1769 failIfFalse(condition);
1770 int end = tokenLine();
1771 consumeOrFail(CLOSEPAREN);
1773 const Identifier* unused = 0;
1774 TreeStatement trueBlock = parseStatement(context, unused);
1775 failIfFalse(trueBlock);
1778 return context.createIfStatement(condition, trueBlock, start, end);
1780 Vector<TreeExpression> exprStack;
1781 Vector<pair<int, int> > posStack;
1782 Vector<TreeStatement> statementStack;
1783 bool trailingElse = false;
1787 const Identifier* unused = 0;
1788 TreeStatement block = parseStatement(context, unused);
1790 statementStack.append(block);
1791 trailingElse = true;
1794 int innerStart = tokenLine();
1797 consumeOrFail(OPENPAREN);
1799 TreeExpression innerCondition = parseExpression(context);
1800 failIfFalse(innerCondition);
1801 int innerEnd = tokenLine();
1802 consumeOrFail(CLOSEPAREN);
1803 const Identifier* unused = 0;
1804 TreeStatement innerTrueBlock = parseStatement(context, unused);
1805 failIfFalse(innerTrueBlock);
1806 exprStack.append(innerCondition);
1807 posStack.append(make_pair(innerStart, innerEnd));
1808 statementStack.append(innerTrueBlock);
1809 } while (match(ELSE));
1811 if (!trailingElse) {
1812 TreeExpression condition = exprStack.last();
1813 exprStack.removeLast();
1814 TreeStatement trueBlock = statementStack.last();
1815 statementStack.removeLast();
1816 pair<int, int> pos = posStack.last();
1817 posStack.removeLast();
1818 statementStack.append(context.createIfStatement(condition, trueBlock, pos.first, pos.second));
1821 while (!exprStack.isEmpty()) {
1822 TreeExpression condition = exprStack.last();
1823 exprStack.removeLast();
1824 TreeStatement falseBlock = statementStack.last();
1825 statementStack.removeLast();
1826 TreeStatement trueBlock = statementStack.last();
1827 statementStack.removeLast();
1828 pair<int, int> pos = posStack.last();
1829 posStack.removeLast();
1830 statementStack.append(context.createIfStatement(condition, trueBlock, falseBlock, pos.first, pos.second));
1833 return context.createIfStatement(condition, trueBlock, statementStack.last(), start, end);
1836 template <class TreeBuilder> TreeExpression JSParser::parseExpression(TreeBuilder& context)
1838 failIfStackOverflow();
1839 TreeExpression node = parseAssignmentExpression(context);
1844 m_nonTrivialExpressionCount++;
1846 TreeExpression right = parseAssignmentExpression(context);
1848 typename TreeBuilder::Comma commaNode = context.createCommaExpr(node, right);
1849 while (match(COMMA)) {
1850 next(TreeBuilder::DontBuildStrings);
1851 right = parseAssignmentExpression(context);
1853 context.appendToComma(commaNode, right);
1859 template <typename TreeBuilder> TreeExpression JSParser::parseAssignmentExpression(TreeBuilder& context)
1861 failIfStackOverflow();
1862 int start = tokenStart();
1863 int initialAssignmentCount = m_assignmentCount;
1864 int initialNonLHSCount = m_nonLHSCount;
1865 TreeExpression lhs = parseConditionalExpression(context);
1867 if (initialNonLHSCount != m_nonLHSCount)
1870 int assignmentStack = 0;
1872 bool hadAssignment = false;
1874 switch (m_token.m_type) {
1875 case EQUAL: op = OpEqual; break;
1876 case PLUSEQUAL: op = OpPlusEq; break;
1877 case MINUSEQUAL: op = OpMinusEq; break;
1878 case MULTEQUAL: op = OpMultEq; break;
1879 case DIVEQUAL: op = OpDivEq; break;
1880 case LSHIFTEQUAL: op = OpLShift; break;
1881 case RSHIFTEQUAL: op = OpRShift; break;
1882 case URSHIFTEQUAL: op = OpURShift; break;
1883 case ANDEQUAL: op = OpAndEq; break;
1884 case XOREQUAL: op = OpXOrEq; break;
1885 case OREQUAL: op = OpOrEq; break;
1886 case MODEQUAL: op = OpModEq; break;
1890 m_nonTrivialExpressionCount++;
1891 hadAssignment = true;
1892 context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
1893 start = tokenStart();
1894 m_assignmentCount++;
1895 next(TreeBuilder::DontBuildStrings);
1896 if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
1897 failIfTrueIfStrictWithMessage(m_globalData->propertyNames->eval == *m_lastIdentifier, "'eval' cannot be modified in strict mode");
1898 failIfTrueIfStrictWithMessage(m_globalData->propertyNames->arguments == *m_lastIdentifier, "'arguments' cannot be modified in strict mode");
1899 declareWrite(m_lastIdentifier);
1900 m_lastIdentifier = 0;
1902 lhs = parseConditionalExpression(context);
1904 if (initialNonLHSCount != m_nonLHSCount)
1911 if (!TreeBuilder::CreatesAST)
1914 while (assignmentStack)
1915 lhs = context.createAssignment(assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd());
1920 template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression(TreeBuilder& context)
1922 TreeExpression cond = parseBinaryExpression(context);
1924 if (!match(QUESTION))
1926 m_nonTrivialExpressionCount++;
1928 next(TreeBuilder::DontBuildStrings);
1929 TreeExpression lhs = parseAssignmentExpression(context);
1930 consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings);
1932 TreeExpression rhs = parseAssignmentExpression(context);
1934 return context.createConditionalExpr(cond, lhs, rhs);
1937 ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
1939 return token & UnaryOpTokenFlag;
1942 int JSParser::isBinaryOperator(JSTokenType token)
1945 return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
1946 return token & BinaryOpTokenPrecedenceMask;
1949 template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context)
1952 int operandStackDepth = 0;
1953 int operatorStackDepth = 0;
1954 typename TreeBuilder::BinaryExprContext binaryExprContext(context);
1956 int exprStart = tokenStart();
1957 int initialAssignments = m_assignmentCount;
1958 TreeExpression current = parseUnaryExpression(context);
1959 failIfFalse(current);
1961 context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), initialAssignments != m_assignmentCount);
1962 int precedence = isBinaryOperator(m_token.m_type);
1965 m_nonTrivialExpressionCount++;
1967 int operatorToken = m_token.m_type;
1968 next(TreeBuilder::DontBuildStrings);
1970 while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
1971 ASSERT(operandStackDepth > 1);
1973 typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
1974 typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
1975 context.shrinkOperandStackBy(operandStackDepth, 2);
1976 context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
1977 context.operatorStackPop(operatorStackDepth);
1979 context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
1981 while (operatorStackDepth) {
1982 ASSERT(operandStackDepth > 1);
1984 typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
1985 typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
1986 context.shrinkOperandStackBy(operandStackDepth, 2);
1987 context.appendBinaryOperation(operandStackDepth, operatorStackDepth, lhs, rhs);
1988 context.operatorStackPop(operatorStackDepth);
1990 return context.popOperandStack(operandStackDepth);
1994 template <bool complete, class TreeBuilder> TreeProperty JSParser::parseProperty(TreeBuilder& context)
1996 bool wasIdent = false;
1997 switch (m_token.m_type) {
2002 const Identifier* ident = m_token.m_data.ident;
2003 if (complete || (wasIdent && (*ident == m_globalData->propertyNames->get || *ident == m_globalData->propertyNames->set)))
2004 nextExpectIdentifier(Lexer::IgnoreReservedWords);
2006 nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
2010 TreeExpression node = parseAssignmentExpression(context);
2012 return context.template createProperty<complete>(ident, node, PropertyNode::Constant);
2014 failIfFalse(wasIdent);
2016 const Identifier* accessorName = 0;
2017 TreeFormalParameterList parameters = 0;
2018 TreeFunctionBody body = 0;
2019 int openBracePos = 0;
2020 int closeBracePos = 0;
2021 int bodyStartLine = 0;
2022 PropertyNode::Type type;
2023 if (*ident == m_globalData->propertyNames->get)
2024 type = PropertyNode::Getter;
2025 else if (*ident == m_globalData->propertyNames->set)
2026 type = PropertyNode::Setter;
2029 failIfFalse((parseFunctionInfo<FunctionNeedsName, false>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
2030 return context.template createGetterOrSetterProperty<complete>(type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
2033 double propertyName = m_token.m_data.doubleValue;
2035 consumeOrFail(COLON);
2036 TreeExpression node = parseAssignmentExpression(context);
2038 return context.template createProperty<complete>(m_globalData, propertyName, node, PropertyNode::Constant);
2041 failIfFalse(m_token.m_type & KeywordTokenFlag);
2046 template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
2048 int startOffset = m_token.m_data.intValue;
2049 consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings);
2051 if (match(CLOSEBRACE)) {
2053 return context.createObjectLiteral();
2056 TreeProperty property = parseProperty<false>(context);
2057 failIfFalse(property);
2058 if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
2059 m_lexer->setOffset(startOffset);
2061 return parseStrictObjectLiteral(context);
2063 TreePropertyList propertyList = context.createPropertyList(property);
2064 TreePropertyList tail = propertyList;
2065 while (match(COMMA)) {
2066 next(TreeBuilder::DontBuildStrings);
2067 // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
2068 if (match(CLOSEBRACE))
2070 property = parseProperty<false>(context);
2071 failIfFalse(property);
2072 if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
2073 m_lexer->setOffset(startOffset);
2075 return parseStrictObjectLiteral(context);
2077 tail = context.createPropertyList(property, tail);
2080 consumeOrFail(CLOSEBRACE);
2082 return context.createObjectLiteral(propertyList);
2085 template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context)
2087 consumeOrFail(OPENBRACE);
2089 if (match(CLOSEBRACE)) {
2091 return context.createObjectLiteral();
2094 TreeProperty property = parseProperty<true>(context);
2095 failIfFalse(property);
2097 typedef HashMap<RefPtr<StringImpl>, unsigned, IdentifierRepHash> ObjectValidationMap;
2098 ObjectValidationMap objectValidator;
2099 // Add the first property
2100 if (!m_syntaxAlreadyValidated)
2101 objectValidator.add(context.getName(property).impl(), context.getType(property));
2103 TreePropertyList propertyList = context.createPropertyList(property);
2104 TreePropertyList tail = propertyList;
2105 while (match(COMMA)) {
2107 // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
2108 if (match(CLOSEBRACE))
2110 property = parseProperty<true>(context);
2111 failIfFalse(property);
2112 if (!m_syntaxAlreadyValidated) {
2113 std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).impl(), context.getType(property));
2114 if (!propertyEntryIter.second) {
2115 failIfTrue(propertyEntryIter.first->second == PropertyNode::Constant);
2116 failIfTrue(context.getType(property) == PropertyNode::Constant);
2117 failIfTrue(context.getType(property) & propertyEntryIter.first->second);
2118 propertyEntryIter.first->second |= context.getType(property);
2121 tail = context.createPropertyList(property, tail);
2124 consumeOrFail(CLOSEBRACE);
2126 return context.createObjectLiteral(propertyList);
2129 template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
2131 consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings);
2134 while (match(COMMA)) {
2135 next(TreeBuilder::DontBuildStrings);
2138 if (match(CLOSEBRACKET)) {
2139 next(TreeBuilder::DontBuildStrings);
2140 return context.createArray(elisions);
2143 TreeExpression elem = parseAssignmentExpression(context);
2145 typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem);
2146 typename TreeBuilder::ElementList tail = elementList;
2148 while (match(COMMA)) {
2149 next(TreeBuilder::DontBuildStrings);
2152 while (match(COMMA)) {
2157 if (match(CLOSEBRACKET)) {
2158 next(TreeBuilder::DontBuildStrings);
2159 return context.createArray(elisions, elementList);
2161 TreeExpression elem = parseAssignmentExpression(context);
2163 tail = context.createElementList(tail, elisions, elem);
2166 consumeOrFail(CLOSEBRACKET);
2168 return context.createArray(elementList);
2171 template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(TreeBuilder& context)
2173 switch (m_token.m_type) {
2176 return parseStrictObjectLiteral(context);
2177 return parseObjectLiteral(context);
2179 return parseArrayLiteral(context);
2182 int oldNonLHSCount = m_nonLHSCount;
2183 TreeExpression result = parseExpression(context);
2184 m_nonLHSCount = oldNonLHSCount;
2185 consumeOrFail(CLOSEPAREN);
2191 return context.thisExpr();
2194 int start = tokenStart();
2195 const Identifier* ident = m_token.m_data.ident;
2197 currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
2198 m_lastIdentifier = ident;
2199 return context.createResolve(ident, start);
2202 const Identifier* ident = m_token.m_data.ident;
2204 return context.createString(ident);
2207 double d = m_token.m_data.doubleValue;
2209 return context.createNumberExpr(d);
2213 return context.createNull();
2217 return context.createBoolean(true);
2221 return context.createBoolean(false);
2226 const Identifier* pattern;
2227 const Identifier* flags;
2228 if (match(DIVEQUAL))
2229 failIfFalse(m_lexer->scanRegExp(pattern, flags, '='));
2231 failIfFalse(m_lexer->scanRegExp(pattern, flags));
2233 int start = tokenStart();
2235 TreeExpression re = context.createRegExp(*pattern, *flags, start);
2237 const char* yarrErrorMsg = Yarr::checkSyntax(pattern->ustring());
2238 ASSERT(!m_errorMessage.isNull());
2239 failWithMessage(yarrErrorMsg);
2248 template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
2250 consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings);
2251 if (match(CLOSEPAREN)) {
2252 next(TreeBuilder::DontBuildStrings);
2253 return context.createArguments();
2255 TreeExpression firstArg = parseAssignmentExpression(context);
2256 failIfFalse(firstArg);
2258 TreeArgumentsList argList = context.createArgumentsList(firstArg);
2259 TreeArgumentsList tail = argList;
2260 while (match(COMMA)) {
2261 next(TreeBuilder::DontBuildStrings);
2262 TreeExpression arg = parseAssignmentExpression(context);
2264 tail = context.createArgumentsList(tail, arg);
2266 consumeOrFail(CLOSEPAREN);
2267 return context.createArguments(argList);
2270 template <class TreeBuilder> TreeExpression JSParser::parseMemberExpression(TreeBuilder& context)
2272 TreeExpression base = 0;
2273 int start = tokenStart();
2274 int expressionStart = start;
2276 while (match(NEW)) {
2281 if (match(FUNCTION)) {
2282 const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
2283 TreeFormalParameterList parameters = 0;
2284 TreeFunctionBody body = 0;
2285 int openBracePos = 0;
2286 int closeBracePos = 0;
2287 int bodyStartLine = 0;
2289 failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
2290 base = context.createFunctionExpr(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
2292 base = parsePrimaryExpression(context);
2296 switch (m_token.m_type) {
2298 m_nonTrivialExpressionCount++;
2299 int expressionEnd = lastTokenEnd();
2301 int nonLHSCount = m_nonLHSCount;
2302 int initialAssignments = m_assignmentCount;
2303 TreeExpression property = parseExpression(context);
2304 failIfFalse(property);
2305 base = context.createBracketAccess(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd());
2306 consumeOrFail(CLOSEBRACKET);
2307 m_nonLHSCount = nonLHSCount;
2311 m_nonTrivialExpressionCount++;
2314 if (match(OPENPAREN)) {
2315 int exprEnd = lastTokenEnd();
2316 TreeArguments arguments = parseArguments(context);
2317 failIfFalse(arguments);
2318 base = context.createNewExpr(base, arguments, start, exprEnd, lastTokenEnd());
2320 base = context.createNewExpr(base, start, lastTokenEnd());
2322 int nonLHSCount = m_nonLHSCount;
2323 int expressionEnd = lastTokenEnd();
2324 TreeArguments arguments = parseArguments(context);
2325 failIfFalse(arguments);
2326 base = context.makeFunctionCallNode(base, arguments, expressionStart, expressionEnd, lastTokenEnd());
2327 m_nonLHSCount = nonLHSCount;
2332 m_nonTrivialExpressionCount++;
2333 int expressionEnd = lastTokenEnd();
2334 nextExpectIdentifier(Lexer::IgnoreReservedWords | TreeBuilder::DontBuildKeywords);
2336 base = context.createDotAccess(base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd());
2341 goto endMemberExpression;
2344 endMemberExpression:
2346 base = context.createNewExpr(base, start, lastTokenEnd());
2350 template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeBuilder& context)
2352 typename TreeBuilder::UnaryExprContext unaryExprContext(context);
2353 AllowInOverride allowInOverride(this);
2354 int tokenStackDepth = 0;
2355 bool modifiesExpr = false;
2356 bool requiresLExpr = false;
2357 while (isUnaryOp(m_token.m_type)) {
2359 switch (m_token.m_type) {
2363 case AUTOMINUSMINUS:
2364 failIfTrue(requiresLExpr);
2365 modifiesExpr = true;
2366 requiresLExpr = true;
2369 failIfTrue(requiresLExpr);
2370 requiresLExpr = true;
2373 failIfTrue(requiresLExpr);
2378 context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart());
2380 m_nonTrivialExpressionCount++;
2382 int subExprStart = tokenStart();
2383 TreeExpression expr = parseMemberExpression(context);
2385 bool isEvalOrArguments = false;
2386 if (strictMode() && !m_syntaxAlreadyValidated) {
2387 if (context.isResolve(expr)) {
2388 isEvalOrArguments = *m_lastIdentifier == m_globalData->propertyNames->eval || *m_lastIdentifier == m_globalData->propertyNames->arguments;
2391 failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments && modifiesExpr, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode");
2392 switch (m_token.m_type) {
2394 m_nonTrivialExpressionCount++;
2396 expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
2397 m_assignmentCount++;
2398 failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode");
2399 failIfTrueIfStrict(requiresLExpr);
2403 m_nonTrivialExpressionCount++;
2405 expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
2406 m_assignmentCount++;
2407 failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode");
2408 failIfTrueIfStrict(requiresLExpr);
2415 int end = lastTokenEnd();
2417 if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
2420 while (tokenStackDepth) {
2421 switch (context.unaryTokenStackLastType(tokenStackDepth)) {
2423 expr = context.createLogicalNot(expr);
2426 expr = context.makeBitwiseNotNode(expr);
2429 expr = context.makeNegateNode(expr);
2432 expr = context.createUnaryPlus(expr);
2436 expr = context.makePrefixNode(expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
2437 m_assignmentCount++;
2440 case AUTOMINUSMINUS:
2441 expr = context.makePrefixNode(expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
2442 m_assignmentCount++;
2445 expr = context.makeTypeOfNode(expr);
2448 expr = context.createVoid(expr);
2451 failIfTrueIfStrictWithNameAndMessage(context.isResolve(expr), "Cannot delete unqualified property", m_lastIdentifier->impl(), "in strict mode");
2452 expr = context.makeDeleteNode(expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
2455 // If we get here something has gone horribly horribly wrong
2458 subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
2459 context.unaryTokenStackRemoveLast(tokenStackDepth);
2468 template <> struct VectorTraits<JSC::JSParser::Scope> : SimpleClassVectorTraits {
2469 static const bool canInitializeWithMemset = false; // Not all Scope data members initialize to 0.