summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/parser
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
commit40736c5763bf61337c8c14e16d8587db021a87d4 (patch)
treeb17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/JavaScriptCore/parser
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/JavaScriptCore/parser')
-rw-r--r--Source/JavaScriptCore/parser/ASTBuilder.h979
-rw-r--r--Source/JavaScriptCore/parser/Keywords.table58
-rw-r--r--Source/JavaScriptCore/parser/Lexer.cpp1543
-rw-r--r--Source/JavaScriptCore/parser/Lexer.h297
-rw-r--r--Source/JavaScriptCore/parser/NodeConstructors.h898
-rw-r--r--Source/JavaScriptCore/parser/NodeInfo.h62
-rw-r--r--Source/JavaScriptCore/parser/Nodes.cpp196
-rw-r--r--Source/JavaScriptCore/parser/Nodes.h1616
-rw-r--r--Source/JavaScriptCore/parser/Parser.cpp1672
-rw-r--r--Source/JavaScriptCore/parser/Parser.h1046
-rw-r--r--Source/JavaScriptCore/parser/ParserArena.cpp122
-rw-r--r--Source/JavaScriptCore/parser/ParserArena.h189
-rw-r--r--Source/JavaScriptCore/parser/ParserTokens.h162
-rw-r--r--Source/JavaScriptCore/parser/ResultType.h182
-rw-r--r--Source/JavaScriptCore/parser/SourceCode.h105
-rw-r--r--Source/JavaScriptCore/parser/SourceProvider.h108
-rw-r--r--Source/JavaScriptCore/parser/SourceProviderCache.cpp56
-rw-r--r--Source/JavaScriptCore/parser/SourceProviderCache.h53
-rw-r--r--Source/JavaScriptCore/parser/SourceProviderCacheItem.h73
-rw-r--r--Source/JavaScriptCore/parser/SyntaxChecker.h256
20 files changed, 9673 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
new file mode 100644
index 000000000..2e81c2546
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -0,0 +1,979 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ASTBuilder_h
+#define ASTBuilder_h
+
+#include "NodeConstructors.h"
+#include "SyntaxChecker.h"
+#include <utility>
+
+namespace JSC {
+
+class ASTBuilder {
+ struct BinaryOpInfo {
+ BinaryOpInfo() {}
+ BinaryOpInfo(int s, int d, int e, bool r)
+ : start(s)
+ , divot(d)
+ , end(e)
+ , hasAssignment(r)
+ {
+ }
+ BinaryOpInfo(const BinaryOpInfo& lhs, const BinaryOpInfo& rhs)
+ : start(lhs.start)
+ , divot(rhs.start)
+ , end(rhs.end)
+ , hasAssignment(lhs.hasAssignment || rhs.hasAssignment)
+ {
+ }
+ int start;
+ int divot;
+ int end;
+ bool hasAssignment;
+ };
+
+
+ struct AssignmentInfo {
+ AssignmentInfo() {}
+ AssignmentInfo(ExpressionNode* node, int start, int divot, int initAssignments, Operator op)
+ : m_node(node)
+ , m_start(start)
+ , m_divot(divot)
+ , m_initAssignments(initAssignments)
+ , m_op(op)
+ {
+ }
+ ExpressionNode* m_node;
+ int m_start;
+ int m_divot;
+ int m_initAssignments;
+ Operator m_op;
+ };
+public:
+ ASTBuilder(JSGlobalData* globalData, SourceCode* sourceCode)
+ : m_globalData(globalData)
+ , m_sourceCode(sourceCode)
+ , m_scope(globalData)
+ , m_evalCount(0)
+ {
+ }
+
+ struct BinaryExprContext {
+ BinaryExprContext(ASTBuilder&) {}
+ };
+ struct UnaryExprContext {
+ UnaryExprContext(ASTBuilder&) {}
+ };
+
+ typedef SyntaxChecker FunctionBodyBuilder;
+
+ typedef ExpressionNode* Expression;
+ typedef JSC::SourceElements* SourceElements;
+ typedef ArgumentsNode* Arguments;
+ typedef CommaNode* Comma;
+ typedef PropertyNode* Property;
+ typedef PropertyListNode* PropertyList;
+ typedef ElementNode* ElementList;
+ typedef ArgumentListNode* ArgumentsList;
+ typedef ParameterNode* FormalParameterList;
+ typedef FunctionBodyNode* FunctionBody;
+ typedef StatementNode* Statement;
+ typedef ClauseListNode* ClauseList;
+ typedef CaseClauseNode* Clause;
+ typedef ConstDeclNode* ConstDeclList;
+ typedef std::pair<ExpressionNode*, BinaryOpInfo> BinaryOperand;
+
+ static const bool CreatesAST = true;
+ static const bool NeedsFreeVariableInfo = true;
+ static const bool CanUseFunctionCache = true;
+ static const int DontBuildKeywords = 0;
+ static const int DontBuildStrings = 0;
+
+ ExpressionNode* makeBinaryNode(int lineNumber, int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
+ ExpressionNode* makeFunctionCallNode(int lineNumber, ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end);
+
+ JSC::SourceElements* createSourceElements() { return new (m_globalData) JSC::SourceElements(); }
+
+ ParserArenaData<DeclarationStacks::VarStack>* varDeclarations() { return m_scope.m_varDeclarations; }
+ ParserArenaData<DeclarationStacks::FunctionStack>* funcDeclarations() { return m_scope.m_funcDeclarations; }
+ int features() const { return m_scope.m_features; }
+ int numConstants() const { return m_scope.m_numConstants; }
+
+ void appendToComma(CommaNode* commaNode, ExpressionNode* expr) { commaNode->append(expr); }
+
+ CommaNode* createCommaExpr(int lineNumber, ExpressionNode* lhs, ExpressionNode* rhs) { return new (m_globalData) CommaNode(lineNumber, lhs, rhs); }
+
+ ExpressionNode* makeAssignNode(int lineNumber, ExpressionNode* left, Operator, ExpressionNode* right, bool leftHasAssignments, bool rightHasAssignments, int start, int divot, int end);
+ ExpressionNode* makePrefixNode(int lineNumber, ExpressionNode*, Operator, int start, int divot, int end);
+ ExpressionNode* makePostfixNode(int lineNumber, ExpressionNode*, Operator, int start, int divot, int end);
+ ExpressionNode* makeTypeOfNode(int lineNumber, ExpressionNode*);
+ ExpressionNode* makeDeleteNode(int lineNumber, ExpressionNode*, int start, int divot, int end);
+ ExpressionNode* makeNegateNode(int lineNumber, ExpressionNode*);
+ ExpressionNode* makeBitwiseNotNode(int lineNumber, ExpressionNode*);
+ ExpressionNode* makeMultNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeDivNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeModNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeAddNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeSubNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitXOrNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitAndNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitOrNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeLeftShiftNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeRightShiftNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeURightShiftNode(int lineNumber, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+
+ ExpressionNode* createLogicalNot(int lineNumber, ExpressionNode* expr) { return new (m_globalData) LogicalNotNode(lineNumber, expr); }
+ ExpressionNode* createUnaryPlus(int lineNumber, ExpressionNode* expr) { return new (m_globalData) UnaryPlusNode(lineNumber, expr); }
+ ExpressionNode* createVoid(int lineNumber, ExpressionNode* expr)
+ {
+ incConstants();
+ return new (m_globalData) VoidNode(lineNumber, expr);
+ }
+ ExpressionNode* thisExpr(int lineNumber)
+ {
+ usesThis();
+ return new (m_globalData) ThisNode(lineNumber);
+ }
+ ExpressionNode* createResolve(int lineNumber, const Identifier* ident, int start)
+ {
+ if (m_globalData->propertyNames->arguments == *ident)
+ usesArguments();
+ return new (m_globalData) ResolveNode(lineNumber, *ident, start);
+ }
+ ExpressionNode* createObjectLiteral(int lineNumber) { return new (m_globalData) ObjectLiteralNode(lineNumber); }
+ ExpressionNode* createObjectLiteral(int lineNumber, PropertyListNode* properties) { return new (m_globalData) ObjectLiteralNode(lineNumber, properties); }
+
+ ExpressionNode* createArray(int lineNumber, int elisions)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_globalData) ArrayNode(lineNumber, elisions);
+ }
+
+ ExpressionNode* createArray(int lineNumber, ElementNode* elems) { return new (m_globalData) ArrayNode(lineNumber, elems); }
+ ExpressionNode* createArray(int lineNumber, int elisions, ElementNode* elems)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_globalData) ArrayNode(lineNumber, elisions, elems);
+ }
+ ExpressionNode* createNumberExpr(int lineNumber, double d)
+ {
+ incConstants();
+ return new (m_globalData) NumberNode(lineNumber, d);
+ }
+
+ ExpressionNode* createString(int lineNumber, const Identifier* string)
+ {
+ incConstants();
+ return new (m_globalData) StringNode(lineNumber, *string);
+ }
+
+ ExpressionNode* createBoolean(int lineNumber, bool b)
+ {
+ incConstants();
+ return new (m_globalData) BooleanNode(lineNumber, b);
+ }
+
+ ExpressionNode* createNull(int lineNumber)
+ {
+ incConstants();
+ return new (m_globalData) NullNode(lineNumber);
+ }
+
+ ExpressionNode* createBracketAccess(int lineNumber, ExpressionNode* base, ExpressionNode* property, bool propertyHasAssignments, int start, int divot, int end)
+ {
+ BracketAccessorNode* node = new (m_globalData) BracketAccessorNode(lineNumber, base, property, propertyHasAssignments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createDotAccess(int lineNumber, ExpressionNode* base, const Identifier* property, int start, int divot, int end)
+ {
+ DotAccessorNode* node = new (m_globalData) DotAccessorNode(lineNumber, base, *property);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createRegExp(int lineNumber, const Identifier& pattern, const Identifier& flags, int start)
+ {
+ if (Yarr::checkSyntax(pattern.ustring()))
+ return 0;
+ RegExpNode* node = new (m_globalData) RegExpNode(lineNumber, pattern, flags);
+ int size = pattern.length() + 2; // + 2 for the two /'s
+ setExceptionLocation(node, start, start + size, start + size);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(int lineNumber, ExpressionNode* expr, ArgumentsNode* arguments, int start, int divot, int end)
+ {
+ NewExprNode* node = new (m_globalData) NewExprNode(lineNumber, expr, arguments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(int lineNumber, ExpressionNode* expr, int start, int end)
+ {
+ NewExprNode* node = new (m_globalData) NewExprNode(lineNumber, expr);
+ setExceptionLocation(node, start, end, end);
+ return node;
+ }
+
+ ExpressionNode* createConditionalExpr(int lineNumber, ExpressionNode* condition, ExpressionNode* lhs, ExpressionNode* rhs)
+ {
+ return new (m_globalData) ConditionalNode(lineNumber, condition, lhs, rhs);
+ }
+
+ ExpressionNode* createAssignResolve(int lineNumber, const Identifier& ident, ExpressionNode* rhs, bool rhsHasAssignment, int start, int divot, int end)
+ {
+ AssignResolveNode* node = new (m_globalData) AssignResolveNode(lineNumber, ident, rhs, rhsHasAssignment);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createFunctionExpr(int lineNumber, const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ FuncExprNode* result = new (m_globalData) FuncExprNode(lineNumber, *name, body, m_sourceCode->subExpression(openBracePos, closeBracePos, bodyStartLine), parameters);
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return result;
+ }
+
+ FunctionBodyNode* createFunctionBody(int lineNumber, bool inStrictContext)
+ {
+ usesClosures();
+ return FunctionBodyNode::create(m_globalData, lineNumber, inStrictContext);
+ }
+
+ template <bool> PropertyNode* createGetterOrSetterProperty(int lineNumber, PropertyNode::Type type, const Identifier* name, ParameterNode* params, FunctionBodyNode* body, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ ASSERT(name);
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return new (m_globalData) PropertyNode(m_globalData, *name, new (m_globalData) FuncExprNode(lineNumber, m_globalData->propertyNames->nullIdentifier, body, m_sourceCode->subExpression(openBracePos, closeBracePos, bodyStartLine), params), type);
+ }
+
+
+ ArgumentsNode* createArguments() { return new (m_globalData) ArgumentsNode(); }
+ ArgumentsNode* createArguments(ArgumentListNode* args) { return new (m_globalData) ArgumentsNode(args); }
+ ArgumentListNode* createArgumentsList(int lineNumber, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(lineNumber, arg); }
+ ArgumentListNode* createArgumentsList(int lineNumber, ArgumentListNode* args, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(lineNumber, args, arg); }
+
+ template <bool> PropertyNode* createProperty(const Identifier* propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, *propertyName, node, type); }
+ template <bool> PropertyNode* createProperty(JSGlobalData*, double propertyName, ExpressionNode* node, PropertyNode::Type type) { return new (m_globalData) PropertyNode(m_globalData, propertyName, node, type); }
+ PropertyListNode* createPropertyList(int lineNumber, PropertyNode* property) { return new (m_globalData) PropertyListNode(lineNumber, property); }
+ PropertyListNode* createPropertyList(int lineNumber, PropertyNode* property, PropertyListNode* tail) { return new (m_globalData) PropertyListNode(lineNumber, property, tail); }
+
+ ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(elisions, expr); }
+ ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(elems, elisions, expr); }
+
+ ParameterNode* createFormalParameterList(const Identifier& ident) { return new (m_globalData) ParameterNode(ident); }
+ ParameterNode* createFormalParameterList(ParameterNode* list, const Identifier& ident) { return new (m_globalData) ParameterNode(list, ident); }
+
+ CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_globalData) CaseClauseNode(expr, statements); }
+ ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(clause); }
+ ClauseListNode* createClauseList(ClauseListNode* tail, CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(tail, clause); }
+
+ void setUsesArguments(FunctionBodyNode* node) { node->setUsesArguments(); }
+
+ StatementNode* createFuncDeclStatement(int lineNumber, const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ FuncDeclNode* decl = new (m_globalData) FuncDeclNode(lineNumber, *name, body, m_sourceCode->subExpression(openBracePos, closeBracePos, bodyStartLine), parameters);
+ if (*name == m_globalData->propertyNames->arguments)
+ usesArguments();
+ m_scope.m_funcDeclarations->data.append(decl->body());
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return decl;
+ }
+
+ StatementNode* createBlockStatement(int lineNumber, JSC::SourceElements* elements, int startLine, int endLine)
+ {
+ BlockNode* block = new (m_globalData) BlockNode(lineNumber, elements);
+ block->setLoc(startLine, endLine);
+ return block;
+ }
+
+ StatementNode* createExprStatement(int lineNumber, ExpressionNode* expr, int start, int end)
+ {
+ ExprStatementNode* result = new (m_globalData) ExprStatementNode(lineNumber, expr);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createIfStatement(int lineNumber, ExpressionNode* condition, StatementNode* trueBlock, int start, int end)
+ {
+ IfNode* result = new (m_globalData) IfNode(lineNumber, condition, trueBlock);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createIfStatement(int lineNumber, ExpressionNode* condition, StatementNode* trueBlock, StatementNode* falseBlock, int start, int end)
+ {
+ IfNode* result = new (m_globalData) IfElseNode(lineNumber, condition, trueBlock, falseBlock);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createForLoop(int lineNumber, ExpressionNode* initializer, ExpressionNode* condition, ExpressionNode* iter, StatementNode* statements, bool b, int start, int end)
+ {
+ ForNode* result = new (m_globalData) ForNode(lineNumber, initializer, condition, iter, statements, b);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createForInLoop(int lineNumber, const Identifier* ident, ExpressionNode* initializer, ExpressionNode* iter, StatementNode* statements, int start, int divot, int end, int initStart, int initEnd, int startLine, int endLine)
+ {
+ ForInNode* result = new (m_globalData) ForInNode(m_globalData, lineNumber, *ident, initializer, iter, statements, initStart, initStart - start, initEnd - initStart);
+ result->setLoc(startLine, endLine);
+ setExceptionLocation(result, start, divot + 1, end);
+ return result;
+ }
+
+ StatementNode* createForInLoop(int lineNumber, ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, int eStart, int eDivot, int eEnd, int start, int end)
+ {
+ ForInNode* result = new (m_globalData) ForInNode(m_globalData, lineNumber, lhs, iter, statements);
+ result->setLoc(start, end);
+ setExceptionLocation(result, eStart, eDivot, eEnd);
+ return result;
+ }
+
+ StatementNode* createEmptyStatement(int lineNumber) { return new (m_globalData) EmptyStatementNode(lineNumber); }
+
+ StatementNode* createVarStatement(int lineNumber, ExpressionNode* expr, int start, int end)
+ {
+ StatementNode* result;
+ if (!expr)
+ result = new (m_globalData) EmptyStatementNode(lineNumber);
+ else
+ result = new (m_globalData) VarStatementNode(lineNumber, expr);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createReturnStatement(int lineNumber, ExpressionNode* expression, int eStart, int eEnd, int startLine, int endLine)
+ {
+ ReturnNode* result = new (m_globalData) ReturnNode(lineNumber, expression);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createBreakStatement(int lineNumber, int eStart, int eEnd, int startLine, int endLine)
+ {
+ BreakNode* result = new (m_globalData) BreakNode(m_globalData, lineNumber);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createBreakStatement(int lineNumber, const Identifier* ident, int eStart, int eEnd, int startLine, int endLine)
+ {
+ BreakNode* result = new (m_globalData) BreakNode(lineNumber, *ident);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createContinueStatement(int lineNumber, int eStart, int eEnd, int startLine, int endLine)
+ {
+ ContinueNode* result = new (m_globalData) ContinueNode(m_globalData, lineNumber);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createContinueStatement(int lineNumber, const Identifier* ident, int eStart, int eEnd, int startLine, int endLine)
+ {
+ ContinueNode* result = new (m_globalData) ContinueNode(lineNumber, *ident);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createTryStatement(int lineNumber, StatementNode* tryBlock, const Identifier* ident, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine)
+ {
+ TryNode* result = new (m_globalData) TryNode(lineNumber, tryBlock, *ident, catchHasEval, catchBlock, finallyBlock);
+ if (catchBlock)
+ usesCatch();
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createSwitchStatement(int lineNumber, ExpressionNode* expr, ClauseListNode* firstClauses, CaseClauseNode* defaultClause, ClauseListNode* secondClauses, int startLine, int endLine)
+ {
+ CaseBlockNode* cases = new (m_globalData) CaseBlockNode(firstClauses, defaultClause, secondClauses);
+ SwitchNode* result = new (m_globalData) SwitchNode(lineNumber, expr, cases);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createWhileStatement(int lineNumber, ExpressionNode* expr, StatementNode* statement, int startLine, int endLine)
+ {
+ WhileNode* result = new (m_globalData) WhileNode(lineNumber, expr, statement);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createDoWhileStatement(int lineNumber, StatementNode* statement, ExpressionNode* expr, int startLine, int endLine)
+ {
+ DoWhileNode* result = new (m_globalData) DoWhileNode(lineNumber, statement, expr);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createLabelStatement(int lineNumber, const Identifier* ident, StatementNode* statement, int start, int end)
+ {
+ LabelNode* result = new (m_globalData) LabelNode(lineNumber, *ident, statement);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createWithStatement(int lineNumber, ExpressionNode* expr, StatementNode* statement, int start, int end, int startLine, int endLine)
+ {
+ usesWith();
+ WithNode* result = new (m_globalData) WithNode(lineNumber, expr, statement, end, end - start);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createThrowStatement(int lineNumber, ExpressionNode* expr, int start, int end, int startLine, int endLine)
+ {
+ ThrowNode* result = new (m_globalData) ThrowNode(lineNumber, expr);
+ result->setLoc(startLine, endLine);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createDebugger(int lineNumber, int startLine, int endLine)
+ {
+ DebuggerStatementNode* result = new (m_globalData) DebuggerStatementNode(lineNumber);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createConstStatement(int lineNumber, ConstDeclNode* decls, int startLine, int endLine)
+ {
+ ConstStatementNode* result = new (m_globalData) ConstStatementNode(lineNumber, decls);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ ConstDeclNode* appendConstDecl(int lineNumber, ConstDeclNode* tail, const Identifier* name, ExpressionNode* initializer)
+ {
+ ConstDeclNode* result = new (m_globalData) ConstDeclNode(lineNumber, *name, initializer);
+ if (tail)
+ tail->m_next = result;
+ return result;
+ }
+
+ void appendStatement(JSC::SourceElements* elements, JSC::StatementNode* statement)
+ {
+ elements->append(statement);
+ }
+
+ void addVar(const Identifier* ident, int attrs)
+ {
+ if (m_globalData->propertyNames->arguments == *ident)
+ usesArguments();
+ m_scope.m_varDeclarations->data.append(std::make_pair(ident, attrs));
+ }
+
+ ExpressionNode* combineCommaNodes(int lineNumber, ExpressionNode* list, ExpressionNode* init)
+ {
+ if (!list)
+ return init;
+ if (list->isCommaNode()) {
+ static_cast<CommaNode*>(list)->append(init);
+ return list;
+ }
+ return new (m_globalData) CommaNode(lineNumber, list, init);
+ }
+
+ int evalCount() const { return m_evalCount; }
+
+ void appendBinaryExpressionInfo(int& operandStackDepth, ExpressionNode* current, int exprStart, int lhs, int rhs, bool hasAssignments)
+ {
+ operandStackDepth++;
+ m_binaryOperandStack.append(std::make_pair(current, BinaryOpInfo(exprStart, lhs, rhs, hasAssignments)));
+ }
+
+ // Logic to handle datastructures used during parsing of binary expressions
+ void operatorStackPop(int& operatorStackDepth)
+ {
+ operatorStackDepth--;
+ m_binaryOperatorStack.removeLast();
+ }
+ bool operatorStackHasHigherPrecedence(int&, int precedence)
+ {
+ return precedence <= m_binaryOperatorStack.last().second;
+ }
+ const BinaryOperand& getFromOperandStack(int i) { return m_binaryOperandStack[m_binaryOperandStack.size() + i]; }
+ void shrinkOperandStackBy(int& operandStackDepth, int amount)
+ {
+ operandStackDepth -= amount;
+ ASSERT(operandStackDepth >= 0);
+ m_binaryOperandStack.resize(m_binaryOperandStack.size() - amount);
+ }
+ void appendBinaryOperation(int lineNumber, int& operandStackDepth, int&, const BinaryOperand& lhs, const BinaryOperand& rhs)
+ {
+ operandStackDepth++;
+ m_binaryOperandStack.append(std::make_pair(makeBinaryNode(lineNumber, m_binaryOperatorStack.last().first, lhs, rhs), BinaryOpInfo(lhs.second, rhs.second)));
+ }
+ void operatorStackAppend(int& operatorStackDepth, int op, int precedence)
+ {
+ operatorStackDepth++;
+ m_binaryOperatorStack.append(std::make_pair(op, precedence));
+ }
+ ExpressionNode* popOperandStack(int&)
+ {
+ ExpressionNode* result = m_binaryOperandStack.last().first;
+ m_binaryOperandStack.removeLast();
+ return result;
+ }
+
+ void appendUnaryToken(int& tokenStackDepth, int type, int start)
+ {
+ tokenStackDepth++;
+ m_unaryTokenStack.append(std::make_pair(type, start));
+ }
+
+ int unaryTokenStackLastType(int&)
+ {
+ return m_unaryTokenStack.last().first;
+ }
+
+ int unaryTokenStackLastStart(int&)
+ {
+ return m_unaryTokenStack.last().second;
+ }
+
+ void unaryTokenStackRemoveLast(int& tokenStackDepth)
+ {
+ tokenStackDepth--;
+ m_unaryTokenStack.removeLast();
+ }
+
+ void assignmentStackAppend(int& assignmentStackDepth, ExpressionNode* node, int start, int divot, int assignmentCount, Operator op)
+ {
+ assignmentStackDepth++;
+ m_assignmentInfoStack.append(AssignmentInfo(node, start, divot, assignmentCount, op));
+ }
+
+ ExpressionNode* createAssignment(int lineNumber, int& assignmentStackDepth, ExpressionNode* rhs, int initialAssignmentCount, int currentAssignmentCount, int lastTokenEnd)
+ {
+ ExpressionNode* result = makeAssignNode(lineNumber, m_assignmentInfoStack.last().m_node, m_assignmentInfoStack.last().m_op, rhs, m_assignmentInfoStack.last().m_initAssignments != initialAssignmentCount, m_assignmentInfoStack.last().m_initAssignments != currentAssignmentCount, m_assignmentInfoStack.last().m_start, m_assignmentInfoStack.last().m_divot + 1, lastTokenEnd);
+ m_assignmentInfoStack.removeLast();
+ assignmentStackDepth--;
+ return result;
+ }
+
+ const Identifier& getName(Property property) const { return property->name(); }
+ PropertyNode::Type getType(Property property) const { return property->type(); }
+
+ bool isResolve(ExpressionNode* expr) const { return expr->isResolveNode(); }
+
+private:
+ struct Scope {
+ Scope(JSGlobalData* globalData)
+ : m_varDeclarations(new (globalData) ParserArenaData<DeclarationStacks::VarStack>)
+ , m_funcDeclarations(new (globalData) ParserArenaData<DeclarationStacks::FunctionStack>)
+ , m_features(0)
+ , m_numConstants(0)
+ {
+ }
+ ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ int m_features;
+ int m_numConstants;
+ };
+
+ static void setExceptionLocation(ThrowableExpressionData* node, unsigned start, unsigned divot, unsigned end)
+ {
+ node->setExceptionSourceCode(divot, divot - start, end - divot);
+ }
+
+ void incConstants() { m_scope.m_numConstants++; }
+ void usesThis() { m_scope.m_features |= ThisFeature; }
+ void usesCatch() { m_scope.m_features |= CatchFeature; }
+ void usesClosures() { m_scope.m_features |= ClosureFeature; }
+ void usesArguments() { m_scope.m_features |= ArgumentsFeature; }
+ void usesAssignment() { m_scope.m_features |= AssignFeature; }
+ void usesWith() { m_scope.m_features |= WithFeature; }
+ void usesEval()
+ {
+ m_evalCount++;
+ m_scope.m_features |= EvalFeature;
+ }
+ ExpressionNode* createNumber(int lineNumber, double d)
+ {
+ return new (m_globalData) NumberNode(lineNumber, d);
+ }
+
+ JSGlobalData* m_globalData;
+ SourceCode* m_sourceCode;
+ Scope m_scope;
+ Vector<BinaryOperand, 10> m_binaryOperandStack;
+ Vector<AssignmentInfo, 10> m_assignmentInfoStack;
+ Vector<pair<int, int>, 10> m_binaryOperatorStack;
+ Vector<pair<int, int>, 10> m_unaryTokenStack;
+ int m_evalCount;
+};
+
+ExpressionNode* ASTBuilder::makeTypeOfNode(int lineNumber, ExpressionNode* expr)
+{
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) TypeOfResolveNode(lineNumber, resolve->identifier());
+ }
+ return new (m_globalData) TypeOfValueNode(lineNumber, expr);
+}
+
+ExpressionNode* ASTBuilder::makeDeleteNode(int lineNumber, ExpressionNode* expr, int start, int divot, int end)
+{
+ if (!expr->isLocation())
+ return new (m_globalData) DeleteValueNode(lineNumber, expr);
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) DeleteResolveNode(lineNumber, resolve->identifier(), divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ return new (m_globalData) DeleteBracketNode(lineNumber, bracket->base(), bracket->subscript(), divot, divot - start, end - divot);
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ return new (m_globalData) DeleteDotNode(lineNumber, dot->base(), dot->identifier(), divot, divot - start, end - divot);
+}
+
+ExpressionNode* ASTBuilder::makeNegateNode(int lineNumber, ExpressionNode* n)
+{
+ if (n->isNumber()) {
+ NumberNode* numberNode = static_cast<NumberNode*>(n);
+ numberNode->setValue(-numberNode->value());
+ return numberNode;
+ }
+
+ return new (m_globalData) NegateNode(lineNumber, n);
+}
+
+ExpressionNode* ASTBuilder::makeBitwiseNotNode(int lineNumber, ExpressionNode* expr)
+{
+ if (expr->isNumber())
+ return createNumber(lineNumber, ~toInt32(static_cast<NumberNode*>(expr)->value()));
+ return new (m_globalData) BitwiseNotNode(lineNumber, expr);
+}
+
+ExpressionNode* ASTBuilder::makeMultNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
+
+ if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
+ return new (m_globalData) UnaryPlusNode(lineNumber, expr2);
+
+ if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
+ return new (m_globalData) UnaryPlusNode(lineNumber, expr1);
+
+ return new (m_globalData) MultNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeDivNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) DivNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeModNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, fmod(static_cast<NumberNode*>(expr1)->value(), static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) ModNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeAddNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) AddNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeSubNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) SubNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeLeftShiftNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) LeftShiftNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeRightShiftNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) RightShiftNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeURightShiftNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, toUInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) UnsignedRightShiftNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitOrNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, toInt32(static_cast<NumberNode*>(expr1)->value()) | toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitOrNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitAndNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, toInt32(static_cast<NumberNode*>(expr1)->value()) & toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitAndNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitXOrNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(lineNumber, toInt32(static_cast<NumberNode*>(expr1)->value()) ^ toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitXOrNode(lineNumber, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeFunctionCallNode(int lineNumber, ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end)
+{
+ if (!func->isLocation())
+ return new (m_globalData) FunctionCallValueNode(lineNumber, func, args, divot, divot - start, end - divot);
+ if (func->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(func);
+ const Identifier& identifier = resolve->identifier();
+ if (identifier == m_globalData->propertyNames->eval) {
+ usesEval();
+ return new (m_globalData) EvalFunctionCallNode(lineNumber, args, divot, divot - start, end - divot);
+ }
+ return new (m_globalData) FunctionCallResolveNode(lineNumber, identifier, args, divot, divot - start, end - divot);
+ }
+ if (func->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func);
+ FunctionCallBracketNode* node = new (m_globalData) FunctionCallBracketNode(lineNumber, bracket->base(), bracket->subscript(), args, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+ }
+ ASSERT(func->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(func);
+ FunctionCallDotNode* node;
+ if (dot->identifier() == m_globalData->propertyNames->call)
+ node = new (m_globalData) CallFunctionCallDotNode(lineNumber, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ else if (dot->identifier() == m_globalData->propertyNames->apply)
+ node = new (m_globalData) ApplyFunctionCallDotNode(lineNumber, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ else
+ node = new (m_globalData) FunctionCallDotNode(lineNumber, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makeBinaryNode(int lineNumber, int token, pair<ExpressionNode*, BinaryOpInfo> lhs, pair<ExpressionNode*, BinaryOpInfo> rhs)
+{
+ switch (token) {
+ case OR:
+ return new (m_globalData) LogicalOpNode(lineNumber, lhs.first, rhs.first, OpLogicalOr);
+
+ case AND:
+ return new (m_globalData) LogicalOpNode(lineNumber, lhs.first, rhs.first, OpLogicalAnd);
+
+ case BITOR:
+ return makeBitOrNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITXOR:
+ return makeBitXOrNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITAND:
+ return makeBitAndNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case EQEQ:
+ return new (m_globalData) EqualNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case NE:
+ return new (m_globalData) NotEqualNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STREQ:
+ return new (m_globalData) StrictEqualNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STRNEQ:
+ return new (m_globalData) NotStrictEqualNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LT:
+ return new (m_globalData) LessNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GT:
+ return new (m_globalData) GreaterNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LE:
+ return new (m_globalData) LessEqNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GE:
+ return new (m_globalData) GreaterEqNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case INSTANCEOF: {
+ InstanceOfNode* node = new (m_globalData) InstanceOfNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+ setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end);
+ return node;
+ }
+
+ case INTOKEN: {
+ InNode* node = new (m_globalData) InNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+ setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end);
+ return node;
+ }
+
+ case LSHIFT:
+ return makeLeftShiftNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case RSHIFT:
+ return makeRightShiftNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case URSHIFT:
+ return makeURightShiftNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case PLUS:
+ return makeAddNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MINUS:
+ return makeSubNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case TIMES:
+ return makeMultNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case DIVIDE:
+ return makeDivNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MOD:
+ return makeModNode(lineNumber, lhs.first, rhs.first, rhs.second.hasAssignment);
+ }
+ CRASH();
+ return 0;
+}
+
+ExpressionNode* ASTBuilder::makeAssignNode(int lineNumber, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!loc->isLocation())
+ return new (m_globalData) AssignErrorNode(lineNumber, loc, op, expr, divot, divot - start, end - divot);
+
+ if (loc->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(loc);
+ if (op == OpEqual) {
+ AssignResolveNode* node = new (m_globalData) AssignResolveNode(lineNumber, resolve->identifier(), expr, exprHasAssignments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+ return new (m_globalData) ReadModifyResolveNode(lineNumber, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
+ }
+ if (loc->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
+ if (op == OpEqual)
+ return new (m_globalData) AssignBracketNode(lineNumber, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot());
+ ReadModifyBracketNode* node = new (m_globalData) ReadModifyBracketNode(lineNumber, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+ }
+ ASSERT(loc->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
+ if (op == OpEqual)
+ return new (m_globalData) AssignDotNode(lineNumber, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot());
+
+ ReadModifyDotNode* node = new (m_globalData) ReadModifyDotNode(lineNumber, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makePrefixNode(int lineNumber, ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!expr->isLocation())
+ return new (m_globalData) PrefixErrorNode(lineNumber, expr, op, divot, divot - start, end - divot);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) PrefixResolveNode(lineNumber, resolve->identifier(), op, divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ PrefixBracketNode* node = new (m_globalData) PrefixBracketNode(lineNumber, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->startOffset());
+ return node;
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ PrefixDotNode* node = new (m_globalData) PrefixDotNode(lineNumber, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->startOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makePostfixNode(int lineNumber, ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!expr->isLocation())
+ return new (m_globalData) PostfixErrorNode(lineNumber, expr, op, divot, divot - start, end - divot);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) PostfixResolveNode(lineNumber, resolve->identifier(), op, divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ PostfixBracketNode* node = new (m_globalData) PostfixBracketNode(lineNumber, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ PostfixDotNode* node = new (m_globalData) PostfixDotNode(lineNumber, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/parser/Keywords.table b/Source/JavaScriptCore/parser/Keywords.table
new file mode 100644
index 000000000..fab0e23cc
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Keywords.table
@@ -0,0 +1,58 @@
+# main keywords
+@begin mainTable 47
+
+# types
+null NULLTOKEN
+true TRUETOKEN
+false FALSETOKEN
+
+# keywords
+break BREAK
+case CASE
+catch CATCH
+const CONSTTOKEN
+default DEFAULT
+finally FINALLY
+for FOR
+instanceof INSTANCEOF
+new NEW
+var VAR
+continue CONTINUE
+function FUNCTION
+return RETURN
+void VOIDTOKEN
+delete DELETETOKEN
+if IF
+this THISTOKEN
+do DO
+while WHILE
+else ELSE
+in INTOKEN
+switch SWITCH
+throw THROW
+try TRY
+typeof TYPEOF
+with WITH
+debugger DEBUGGER
+
+# reserved for future use
+class RESERVED
+enum RESERVED
+export RESERVED
+extends RESERVED
+import RESERVED
+super RESERVED
+
+# reserved for future use in strict code
+implements RESERVED_IF_STRICT
+interface RESERVED_IF_STRICT
+let RESERVED_IF_STRICT
+package RESERVED_IF_STRICT
+private RESERVED_IF_STRICT
+protected RESERVED_IF_STRICT
+public RESERVED_IF_STRICT
+static RESERVED_IF_STRICT
+yield RESERVED_IF_STRICT
+
+@end
+
diff --git a/Source/JavaScriptCore/parser/Lexer.cpp b/Source/JavaScriptCore/parser/Lexer.cpp
new file mode 100644
index 000000000..e38b52480
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Lexer.cpp
@@ -0,0 +1,1543 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Lexer.h"
+
+#include "JSFunction.h"
+
+#include "JSGlobalObjectFunctions.h"
+#include "Identifier.h"
+#include "NodeInfo.h"
+#include "Nodes.h"
+#include "dtoa.h"
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+#include "KeywordLookup.h"
+#include "Lexer.lut.h"
+#include "Parser.h"
+
+namespace JSC {
+
+Keywords::Keywords(JSGlobalData* globalData)
+ : m_globalData(globalData)
+ , m_keywordTable(JSC::mainTable)
+{
+}
+
+enum CharacterType {
+ // Types for the main switch
+
+ // The first three types are fixed, and also used for identifying
+ // ASCII alpha and alphanumeric characters (see isIdentStart and isIdentPart).
+ CharacterIdentifierStart,
+ CharacterZero,
+ CharacterNumber,
+
+ CharacterInvalid,
+ CharacterLineTerminator,
+ CharacterExclamationMark,
+ CharacterOpenParen,
+ CharacterCloseParen,
+ CharacterOpenBracket,
+ CharacterCloseBracket,
+ CharacterComma,
+ CharacterColon,
+ CharacterQuestion,
+ CharacterTilde,
+ CharacterQuote,
+ CharacterDot,
+ CharacterSlash,
+ CharacterBackSlash,
+ CharacterSemicolon,
+ CharacterOpenBrace,
+ CharacterCloseBrace,
+
+ CharacterAdd,
+ CharacterSub,
+ CharacterMultiply,
+ CharacterModulo,
+ CharacterAnd,
+ CharacterXor,
+ CharacterOr,
+ CharacterLess,
+ CharacterGreater,
+ CharacterEqual,
+
+ // Other types (only one so far)
+ CharacterWhiteSpace,
+};
+
+// 128 ASCII codes
+static const unsigned short typesOfASCIICharacters[128] = {
+/* 0 - Null */ CharacterInvalid,
+/* 1 - Start of Heading */ CharacterInvalid,
+/* 2 - Start of Text */ CharacterInvalid,
+/* 3 - End of Text */ CharacterInvalid,
+/* 4 - End of Transm. */ CharacterInvalid,
+/* 5 - Enquiry */ CharacterInvalid,
+/* 6 - Acknowledgment */ CharacterInvalid,
+/* 7 - Bell */ CharacterInvalid,
+/* 8 - Back Space */ CharacterInvalid,
+/* 9 - Horizontal Tab */ CharacterWhiteSpace,
+/* 10 - Line Feed */ CharacterLineTerminator,
+/* 11 - Vertical Tab */ CharacterWhiteSpace,
+/* 12 - Form Feed */ CharacterWhiteSpace,
+/* 13 - Carriage Return */ CharacterLineTerminator,
+/* 14 - Shift Out */ CharacterInvalid,
+/* 15 - Shift In */ CharacterInvalid,
+/* 16 - Data Line Escape */ CharacterInvalid,
+/* 17 - Device Control 1 */ CharacterInvalid,
+/* 18 - Device Control 2 */ CharacterInvalid,
+/* 19 - Device Control 3 */ CharacterInvalid,
+/* 20 - Device Control 4 */ CharacterInvalid,
+/* 21 - Negative Ack. */ CharacterInvalid,
+/* 22 - Synchronous Idle */ CharacterInvalid,
+/* 23 - End of Transmit */ CharacterInvalid,
+/* 24 - Cancel */ CharacterInvalid,
+/* 25 - End of Medium */ CharacterInvalid,
+/* 26 - Substitute */ CharacterInvalid,
+/* 27 - Escape */ CharacterInvalid,
+/* 28 - File Separator */ CharacterInvalid,
+/* 29 - Group Separator */ CharacterInvalid,
+/* 30 - Record Separator */ CharacterInvalid,
+/* 31 - Unit Separator */ CharacterInvalid,
+/* 32 - Space */ CharacterWhiteSpace,
+/* 33 - ! */ CharacterExclamationMark,
+/* 34 - " */ CharacterQuote,
+/* 35 - # */ CharacterInvalid,
+/* 36 - $ */ CharacterIdentifierStart,
+/* 37 - % */ CharacterModulo,
+/* 38 - & */ CharacterAnd,
+/* 39 - ' */ CharacterQuote,
+/* 40 - ( */ CharacterOpenParen,
+/* 41 - ) */ CharacterCloseParen,
+/* 42 - * */ CharacterMultiply,
+/* 43 - + */ CharacterAdd,
+/* 44 - , */ CharacterComma,
+/* 45 - - */ CharacterSub,
+/* 46 - . */ CharacterDot,
+/* 47 - / */ CharacterSlash,
+/* 48 - 0 */ CharacterZero,
+/* 49 - 1 */ CharacterNumber,
+/* 50 - 2 */ CharacterNumber,
+/* 51 - 3 */ CharacterNumber,
+/* 52 - 4 */ CharacterNumber,
+/* 53 - 5 */ CharacterNumber,
+/* 54 - 6 */ CharacterNumber,
+/* 55 - 7 */ CharacterNumber,
+/* 56 - 8 */ CharacterNumber,
+/* 57 - 9 */ CharacterNumber,
+/* 58 - : */ CharacterColon,
+/* 59 - ; */ CharacterSemicolon,
+/* 60 - < */ CharacterLess,
+/* 61 - = */ CharacterEqual,
+/* 62 - > */ CharacterGreater,
+/* 63 - ? */ CharacterQuestion,
+/* 64 - @ */ CharacterInvalid,
+/* 65 - A */ CharacterIdentifierStart,
+/* 66 - B */ CharacterIdentifierStart,
+/* 67 - C */ CharacterIdentifierStart,
+/* 68 - D */ CharacterIdentifierStart,
+/* 69 - E */ CharacterIdentifierStart,
+/* 70 - F */ CharacterIdentifierStart,
+/* 71 - G */ CharacterIdentifierStart,
+/* 72 - H */ CharacterIdentifierStart,
+/* 73 - I */ CharacterIdentifierStart,
+/* 74 - J */ CharacterIdentifierStart,
+/* 75 - K */ CharacterIdentifierStart,
+/* 76 - L */ CharacterIdentifierStart,
+/* 77 - M */ CharacterIdentifierStart,
+/* 78 - N */ CharacterIdentifierStart,
+/* 79 - O */ CharacterIdentifierStart,
+/* 80 - P */ CharacterIdentifierStart,
+/* 81 - Q */ CharacterIdentifierStart,
+/* 82 - R */ CharacterIdentifierStart,
+/* 83 - S */ CharacterIdentifierStart,
+/* 84 - T */ CharacterIdentifierStart,
+/* 85 - U */ CharacterIdentifierStart,
+/* 86 - V */ CharacterIdentifierStart,
+/* 87 - W */ CharacterIdentifierStart,
+/* 88 - X */ CharacterIdentifierStart,
+/* 89 - Y */ CharacterIdentifierStart,
+/* 90 - Z */ CharacterIdentifierStart,
+/* 91 - [ */ CharacterOpenBracket,
+/* 92 - \ */ CharacterBackSlash,
+/* 93 - ] */ CharacterCloseBracket,
+/* 94 - ^ */ CharacterXor,
+/* 95 - _ */ CharacterIdentifierStart,
+/* 96 - ` */ CharacterInvalid,
+/* 97 - a */ CharacterIdentifierStart,
+/* 98 - b */ CharacterIdentifierStart,
+/* 99 - c */ CharacterIdentifierStart,
+/* 100 - d */ CharacterIdentifierStart,
+/* 101 - e */ CharacterIdentifierStart,
+/* 102 - f */ CharacterIdentifierStart,
+/* 103 - g */ CharacterIdentifierStart,
+/* 104 - h */ CharacterIdentifierStart,
+/* 105 - i */ CharacterIdentifierStart,
+/* 106 - j */ CharacterIdentifierStart,
+/* 107 - k */ CharacterIdentifierStart,
+/* 108 - l */ CharacterIdentifierStart,
+/* 109 - m */ CharacterIdentifierStart,
+/* 110 - n */ CharacterIdentifierStart,
+/* 111 - o */ CharacterIdentifierStart,
+/* 112 - p */ CharacterIdentifierStart,
+/* 113 - q */ CharacterIdentifierStart,
+/* 114 - r */ CharacterIdentifierStart,
+/* 115 - s */ CharacterIdentifierStart,
+/* 116 - t */ CharacterIdentifierStart,
+/* 117 - u */ CharacterIdentifierStart,
+/* 118 - v */ CharacterIdentifierStart,
+/* 119 - w */ CharacterIdentifierStart,
+/* 120 - x */ CharacterIdentifierStart,
+/* 121 - y */ CharacterIdentifierStart,
+/* 122 - z */ CharacterIdentifierStart,
+/* 123 - { */ CharacterOpenBrace,
+/* 124 - | */ CharacterOr,
+/* 125 - } */ CharacterCloseBrace,
+/* 126 - ~ */ CharacterTilde,
+/* 127 - Delete */ CharacterInvalid,
+};
+
+template <typename T>
+Lexer<T>::Lexer(JSGlobalData* globalData)
+ : m_isReparsing(false)
+ , m_globalData(globalData)
+{
+}
+
+template <typename T>
+Lexer<T>::~Lexer()
+{
+}
+
+template <typename T>
+UString Lexer<T>::getInvalidCharMessage()
+{
+ switch (m_current) {
+ case 0:
+ return "Invalid character: '\\0'";
+ case 10:
+ return "Invalid character: '\\n'";
+ case 11:
+ return "Invalid character: '\\v'";
+ case 13:
+ return "Invalid character: '\\r'";
+ case 35:
+ return "Invalid character: '#'";
+ case 64:
+ return "Invalid character: '@'";
+ case 96:
+ return "Invalid character: '`'";
+ default:
+ return String::format("Invalid character '\\u%04u'", m_current).impl();
+ }
+}
+
+template <typename T>
+ALWAYS_INLINE const T* Lexer<T>::currentCharacter() const
+{
+ ASSERT(m_code <= m_codeEnd);
+ return m_code;
+}
+
+template <typename T>
+void Lexer<T>::setCode(const SourceCode& source, ParserArena* arena)
+{
+ m_arena = &arena->identifierArena();
+
+ m_lineNumber = source.firstLine();
+ m_delimited = false;
+ m_lastToken = -1;
+
+ const StringImpl* sourceString = source.provider()->data();
+
+ if (sourceString)
+ setCodeStart(sourceString);
+ else
+ m_codeStart = 0;
+
+ m_source = &source;
+ m_code = m_codeStart + source.startOffset();
+ m_codeEnd = m_codeStart + source.endOffset();
+ m_error = false;
+ m_atLineStart = true;
+ m_lexErrorMessage = UString();
+
+ m_buffer8.reserveInitialCapacity(initialReadBufferCapacity);
+ m_buffer16.reserveInitialCapacity((m_codeEnd - m_code) / 2);
+
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+ else
+ m_current = -1;
+ ASSERT(currentOffset() == source.startOffset());
+}
+
+template <typename T>
+template <int shiftAmount> ALWAYS_INLINE void Lexer<T>::internalShift()
+{
+ m_code += shiftAmount;
+ m_current = *m_code;
+}
+
+template <typename T>
+ALWAYS_INLINE void Lexer<T>::shift()
+{
+ // Faster than an if-else sequence
+ ASSERT(m_current != -1);
+ m_current = -1;
+ m_code++;
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+}
+
+template <typename T>
+ALWAYS_INLINE int Lexer<T>::peek(int offset)
+{
+ // Only use if necessary
+ ASSERT(offset > 0 && offset < 5);
+ const T* code = m_code + offset;
+ return (code < m_codeEnd) ? *code : -1;
+}
+
+template <typename T>
+int Lexer<T>::getUnicodeCharacter()
+{
+ int char1 = peek(1);
+ int char2 = peek(2);
+ int char3 = peek(3);
+
+ if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(char1) || !isASCIIHexDigit(char2) || !isASCIIHexDigit(char3)))
+ return -1;
+
+ int result = convertUnicode(m_current, char1, char2, char3);
+ shift();
+ shift();
+ shift();
+ shift();
+ return result;
+}
+
+template <typename T>
+void Lexer<T>::shiftLineTerminator()
+{
+ ASSERT(isLineTerminator(m_current));
+
+ int m_prev = m_current;
+ shift();
+
+ // Allow both CRLF and LFCR.
+ if (m_prev + m_current == '\n' + '\r')
+ shift();
+
+ ++m_lineNumber;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::lastTokenWasRestrKeyword() const
+{
+ return m_lastToken == CONTINUE || m_lastToken == BREAK || m_lastToken == RETURN || m_lastToken == THROW;
+}
+
+static NEVER_INLINE bool isNonASCIIIdentStart(int c)
+{
+ return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other);
+}
+
+static inline bool isIdentStart(int c)
+{
+ return isASCII(c) ? typesOfASCIICharacters[c] == CharacterIdentifierStart : isNonASCIIIdentStart(c);
+}
+
+static NEVER_INLINE bool isNonASCIIIdentPart(int c)
+{
+ return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other
+ | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector);
+}
+
+static ALWAYS_INLINE bool isIdentPart(int c)
+{
+ // Character types are divided into two groups depending on whether they can be part of an
+ // identifier or not. Those whose type value is less or equal than CharacterNumber can be
+ // part of an identifier. (See the CharacterType definition for more details.)
+ return isASCII(c) ? typesOfASCIICharacters[c] <= CharacterNumber : isNonASCIIIdentPart(c);
+}
+
+static inline int singleEscape(int c)
+{
+ switch (c) {
+ case 'b':
+ return 0x08;
+ case 't':
+ return 0x09;
+ case 'n':
+ return 0x0A;
+ case 'v':
+ return 0x0B;
+ case 'f':
+ return 0x0C;
+ case 'r':
+ return 0x0D;
+ case '\\':
+ return '\\';
+ case '\'':
+ return '\'';
+ case '"':
+ return '"';
+ default:
+ return 0;
+ }
+}
+
+template <typename T>
+inline void Lexer<T>::record8(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= 0xFF);
+ m_buffer8.append(static_cast<LChar>(c));
+}
+
+template <typename T>
+inline void assertCharIsIn8BitRange(T c)
+{
+ UNUSED_PARAM(c);
+ ASSERT(c >= 0);
+ ASSERT(c <= 0xFF);
+}
+
+template <>
+inline void assertCharIsIn8BitRange(UChar c)
+{
+ UNUSED_PARAM(c);
+ ASSERT(c <= 0xFF);
+}
+
+template <>
+inline void assertCharIsIn8BitRange(LChar)
+{
+}
+
+template <typename T>
+inline void Lexer<T>::append8(const T* p, size_t length)
+{
+ size_t currentSize = m_buffer8.size();
+ m_buffer8.grow(currentSize + length);
+ LChar* rawBuffer = m_buffer8.data() + currentSize;
+
+ for (size_t i = 0; i < length; i++) {
+ T c = p[i];
+ assertCharIsIn8BitRange(c);
+ rawBuffer[i] = c;
+ }
+}
+
+template <typename T>
+inline void Lexer<T>::append16(const LChar* p, size_t length)
+{
+ size_t currentSize = m_buffer16.size();
+ m_buffer16.grow(currentSize + length);
+ UChar* rawBuffer = m_buffer16.data() + currentSize;
+
+ for (size_t i = 0; i < length; i++)
+ rawBuffer[i] = p[i];
+}
+
+template <typename T>
+inline void Lexer<T>::record16(T c)
+{
+ m_buffer16.append(c);
+}
+
+template <typename T>
+inline void Lexer<T>::record16(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= USHRT_MAX);
+ m_buffer16.append(static_cast<UChar>(c));
+}
+
+template <>
+ template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<LChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
+{
+ const ptrdiff_t remaining = m_codeEnd - m_code;
+ if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
+ JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
+ if (keyword != IDENT) {
+ ASSERT((!shouldCreateIdentifier) || tokenData->ident);
+ return keyword == RESERVED_IF_STRICT && !strictMode ? IDENT : keyword;
+ }
+ }
+
+ const LChar* identifierStart = currentCharacter();
+
+ while (isIdentPart(m_current))
+ shift();
+
+ if (UNLIKELY(m_current == '\\')) {
+ setOffsetFromCharOffset(identifierStart);
+ return parseIdentifierSlowCase<shouldCreateIdentifier>(tokenData, lexerFlags, strictMode);
+ }
+
+ const Identifier* ident = 0;
+
+ if (shouldCreateIdentifier) {
+ int identifierLength = currentCharacter() - identifierStart;
+ ident = makeIdentifier(identifierStart, identifierLength);
+
+ tokenData->ident = ident;
+ } else
+ tokenData->ident = 0;
+
+ m_delimited = false;
+
+ if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords))) {
+ ASSERT(shouldCreateIdentifier);
+ if (remaining < maxTokenLength) {
+ const HashEntry* entry = m_globalData->keywords->getKeyword(*ident);
+ ASSERT((remaining < maxTokenLength) || !entry);
+ if (!entry)
+ return IDENT;
+ JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
+ return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
+ }
+ return IDENT;
+ }
+
+ return IDENT;
+}
+
+template <>
+template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType Lexer<UChar>::parseIdentifier(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
+{
+ const ptrdiff_t remaining = m_codeEnd - m_code;
+ if ((remaining >= maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords)) {
+ JSTokenType keyword = parseKeyword<shouldCreateIdentifier>(tokenData);
+ if (keyword != IDENT) {
+ ASSERT((!shouldCreateIdentifier) || tokenData->ident);
+ return keyword == RESERVED_IF_STRICT && !strictMode ? IDENT : keyword;
+ }
+ }
+ const UChar* identifierStart = currentCharacter();
+
+ UChar orAllChars = 0;
+
+ while (isIdentPart(m_current)) {
+ orAllChars |= m_current;
+ shift();
+ }
+
+ if (UNLIKELY(m_current == '\\')) {
+ setOffsetFromCharOffset(identifierStart);
+ return parseIdentifierSlowCase<shouldCreateIdentifier>(tokenData, lexerFlags, strictMode);
+ }
+
+ bool isAll8Bit = false;
+
+ if (!(orAllChars & ~0xff))
+ isAll8Bit = true;
+
+ const Identifier* ident = 0;
+
+ if (shouldCreateIdentifier) {
+ int identifierLength = currentCharacter() - identifierStart;
+ if (isAll8Bit)
+ ident = makeIdentifierLCharFromUChar(identifierStart, identifierLength);
+ else
+ ident = makeIdentifier(identifierStart, identifierLength);
+
+ tokenData->ident = ident;
+ } else
+ tokenData->ident = 0;
+
+ m_delimited = false;
+
+ if (UNLIKELY((remaining < maxTokenLength) && !(lexerFlags & LexerFlagsIgnoreReservedWords))) {
+ ASSERT(shouldCreateIdentifier);
+ if (remaining < maxTokenLength) {
+ const HashEntry* entry = m_globalData->keywords->getKeyword(*ident);
+ ASSERT((remaining < maxTokenLength) || !entry);
+ if (!entry)
+ return IDENT;
+ JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
+ return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
+ }
+ return IDENT;
+ }
+
+ return IDENT;
+}
+
+template <typename T>
+template <bool shouldCreateIdentifier> JSTokenType Lexer<T>::parseIdentifierSlowCase(JSTokenData* tokenData, unsigned lexerFlags, bool strictMode)
+{
+ const ptrdiff_t remaining = m_codeEnd - m_code;
+ const T* identifierStart = currentCharacter();
+ bool bufferRequired = false;
+
+ while (true) {
+ if (LIKELY(isIdentPart(m_current))) {
+ shift();
+ continue;
+ }
+ if (LIKELY(m_current != '\\'))
+ break;
+
+ // \uXXXX unicode characters.
+ bufferRequired = true;
+ if (identifierStart != currentCharacter())
+ m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
+ shift();
+ if (UNLIKELY(m_current != 'u'))
+ return ERRORTOK;
+ shift();
+ int character = getUnicodeCharacter();
+ if (UNLIKELY(character == -1))
+ return ERRORTOK;
+ if (UNLIKELY(m_buffer16.size() ? !isIdentPart(character) : !isIdentStart(character)))
+ return ERRORTOK;
+ if (shouldCreateIdentifier)
+ record16(character);
+ identifierStart = currentCharacter();
+ }
+
+ int identifierLength;
+ const Identifier* ident = 0;
+ if (shouldCreateIdentifier) {
+ if (!bufferRequired) {
+ identifierLength = currentCharacter() - identifierStart;
+ ident = makeIdentifier(identifierStart, identifierLength);
+ } else {
+ if (identifierStart != currentCharacter())
+ m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
+ ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ }
+
+ tokenData->ident = ident;
+ } else
+ tokenData->ident = 0;
+
+ m_delimited = false;
+
+ if (LIKELY(!bufferRequired && !(lexerFlags & LexerFlagsIgnoreReservedWords))) {
+ ASSERT(shouldCreateIdentifier);
+ // Keywords must not be recognized if there was an \uXXXX in the identifier.
+ if (remaining < maxTokenLength) {
+ const HashEntry* entry = m_globalData->keywords->getKeyword(*ident);
+ ASSERT((remaining < maxTokenLength) || !entry);
+ if (!entry)
+ return IDENT;
+ JSTokenType token = static_cast<JSTokenType>(entry->lexerValue());
+ return (token != RESERVED_IF_STRICT) || strictMode ? token : IDENT;
+ }
+ return IDENT;
+ }
+
+ m_buffer16.resize(0);
+ return IDENT;
+}
+
+template <typename T>
+template <bool shouldBuildStrings> ALWAYS_INLINE bool Lexer<T>::parseString(JSTokenData* tokenData, bool strictMode)
+{
+ int startingOffset = currentOffset();
+ int startingLineNumber = lineNumber();
+ int stringQuoteCharacter = m_current;
+ shift();
+
+ const T* stringStart = currentCharacter();
+
+ while (m_current != stringQuoteCharacter) {
+ if (UNLIKELY((m_current == '\\'))) {
+ if (stringStart != currentCharacter() && shouldBuildStrings)
+ append8(stringStart, currentCharacter() - stringStart);
+ shift();
+
+ int escape = singleEscape(m_current);
+
+ // Most common escape sequences first
+ if (escape) {
+ if (shouldBuildStrings)
+ record8(escape);
+ shift();
+ } else if (UNLIKELY(isLineTerminator(m_current)))
+ shiftLineTerminator();
+ else if (m_current == 'x') {
+ shift();
+ if (isASCIIHexDigit(m_current) && isASCIIHexDigit(peek(1))) {
+ int prev = m_current;
+ shift();
+ if (shouldBuildStrings)
+ record8(convertHex(prev, m_current));
+ shift();
+ } else if (shouldBuildStrings)
+ record8('x');
+ } else {
+ setOffset(startingOffset);
+ setLineNumber(startingLineNumber);
+ m_buffer8.resize(0);
+ return parseStringSlowCase<shouldBuildStrings>(tokenData, strictMode);
+ }
+ stringStart = currentCharacter();
+ continue;
+ }
+
+ if (UNLIKELY(((m_current > 0xff) || (m_current < 0xe)))) {
+ setOffset(startingOffset);
+ setLineNumber(startingLineNumber);
+ m_buffer8.resize(0);
+ return parseStringSlowCase<shouldBuildStrings>(tokenData, strictMode);
+ }
+
+ shift();
+ }
+
+ if (currentCharacter() != stringStart && shouldBuildStrings)
+ append8(stringStart, currentCharacter() - stringStart);
+ if (shouldBuildStrings) {
+ tokenData->ident = makeIdentifier(m_buffer8.data(), m_buffer8.size());
+ m_buffer8.resize(0);
+ } else
+ tokenData->ident = 0;
+
+ return true;
+}
+
+template <typename T>
+template <bool shouldBuildStrings> bool Lexer<T>::parseStringSlowCase(JSTokenData* tokenData, bool strictMode)
+{
+ int stringQuoteCharacter = m_current;
+ shift();
+
+ const T* stringStart = currentCharacter();
+
+ while (m_current != stringQuoteCharacter) {
+ if (UNLIKELY(m_current == '\\')) {
+ if (stringStart != currentCharacter() && shouldBuildStrings)
+ append16(stringStart, currentCharacter() - stringStart);
+ shift();
+
+ int escape = singleEscape(m_current);
+
+ // Most common escape sequences first
+ if (escape) {
+ if (shouldBuildStrings)
+ record16(escape);
+ shift();
+ } else if (UNLIKELY(isLineTerminator(m_current)))
+ shiftLineTerminator();
+ else if (m_current == 'x') {
+ shift();
+ if (isASCIIHexDigit(m_current) && isASCIIHexDigit(peek(1))) {
+ int prev = m_current;
+ shift();
+ if (shouldBuildStrings)
+ record16(convertHex(prev, m_current));
+ shift();
+ } else if (shouldBuildStrings)
+ record16('x');
+ } else if (m_current == 'u') {
+ shift();
+ int character = getUnicodeCharacter();
+ if (character != -1) {
+ if (shouldBuildStrings)
+ record16(character);
+ } else if (m_current == stringQuoteCharacter) {
+ if (shouldBuildStrings)
+ record16('u');
+ } else {
+ m_lexErrorMessage = "\\u can only be followed by a Unicode character sequence";
+ return false;
+ }
+ } else if (strictMode && isASCIIDigit(m_current)) {
+ // The only valid numeric escape in strict mode is '\0', and this must not be followed by a decimal digit.
+ int character1 = m_current;
+ shift();
+ if (character1 != '0' || isASCIIDigit(m_current)) {
+ m_lexErrorMessage = "The only valid numeric escape in strict mode is '\\0'";
+ return false;
+ }
+ if (shouldBuildStrings)
+ record16(0);
+ } else if (!strictMode && isASCIIOctalDigit(m_current)) {
+ // Octal character sequences
+ int character1 = m_current;
+ shift();
+ if (isASCIIOctalDigit(m_current)) {
+ // Two octal characters
+ int character2 = m_current;
+ shift();
+ if (character1 >= '0' && character1 <= '3' && isASCIIOctalDigit(m_current)) {
+ if (shouldBuildStrings)
+ record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
+ shift();
+ } else {
+ if (shouldBuildStrings)
+ record16((character1 - '0') * 8 + character2 - '0');
+ }
+ } else {
+ if (shouldBuildStrings)
+ record16(character1 - '0');
+ }
+ } else if (m_current != -1) {
+ if (shouldBuildStrings)
+ record16(m_current);
+ shift();
+ } else {
+ m_lexErrorMessage = "Unterminated string constant";
+ return false;
+ }
+
+ stringStart = currentCharacter();
+ continue;
+ }
+ // Fast check for characters that require special handling.
+ // Catches -1, \n, \r, 0x2028, and 0x2029 as efficiently
+ // as possible, and lets through all common ASCII characters.
+ if (UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) {
+ // New-line or end of input is not allowed
+ if (UNLIKELY(isLineTerminator(m_current)) || UNLIKELY(m_current == -1)) {
+ m_lexErrorMessage = "Unexpected EOF";
+ return false;
+ }
+ // Anything else is just a normal character
+ }
+ shift();
+ }
+
+ if (currentCharacter() != stringStart && shouldBuildStrings)
+ append16(stringStart, currentCharacter() - stringStart);
+ if (shouldBuildStrings)
+ tokenData->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ else
+ tokenData->ident = 0;
+
+ m_buffer16.resize(0);
+ return true;
+}
+
+template <typename T>
+ALWAYS_INLINE void Lexer<T>::parseHex(double& returnValue)
+{
+ // Optimization: most hexadecimal values fit into 4 bytes.
+ uint32_t hexValue = 0;
+ int maximumDigits = 7;
+
+ // Shift out the 'x' prefix.
+ shift();
+
+ do {
+ hexValue = (hexValue << 4) + toASCIIHexValue(m_current);
+ shift();
+ --maximumDigits;
+ } while (isASCIIHexDigit(m_current) && maximumDigits >= 0);
+
+ if (maximumDigits >= 0) {
+ returnValue = hexValue;
+ return;
+ }
+
+ // No more place in the hexValue buffer.
+ // The values are shifted out and placed into the m_buffer8 vector.
+ for (int i = 0; i < 8; ++i) {
+ int digit = hexValue >> 28;
+ if (digit < 10)
+ record8(digit + '0');
+ else
+ record8(digit - 10 + 'a');
+ hexValue <<= 4;
+ }
+
+ while (isASCIIHexDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 16);
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseOctal(double& returnValue)
+{
+ // Optimization: most octal values fit into 4 bytes.
+ uint32_t octalValue = 0;
+ int maximumDigits = 9;
+ // Temporary buffer for the digits. Makes easier
+ // to reconstruct the input characters when needed.
+ LChar digits[10];
+
+ do {
+ octalValue = octalValue * 8 + (m_current - '0');
+ digits[maximumDigits] = m_current;
+ shift();
+ --maximumDigits;
+ } while (isASCIIOctalDigit(m_current) && maximumDigits >= 0);
+
+ if (!isASCIIDigit(m_current) && maximumDigits >= 0) {
+ returnValue = octalValue;
+ return true;
+ }
+
+ for (int i = 9; i > maximumDigits; --i)
+ record8(digits[i]);
+
+ while (isASCIIOctalDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ if (isASCIIDigit(m_current))
+ return false;
+
+ returnValue = parseIntOverflow(m_buffer8.data(), m_buffer8.size(), 8);
+ return true;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseDecimal(double& returnValue)
+{
+ // Optimization: most decimal values fit into 4 bytes.
+ uint32_t decimalValue = 0;
+
+ // Since parseOctal may be executed before parseDecimal,
+ // the m_buffer8 may hold ascii digits.
+ if (!m_buffer8.size()) {
+ int maximumDigits = 9;
+ // Temporary buffer for the digits. Makes easier
+ // to reconstruct the input characters when needed.
+ LChar digits[10];
+
+ do {
+ decimalValue = decimalValue * 10 + (m_current - '0');
+ digits[maximumDigits] = m_current;
+ shift();
+ --maximumDigits;
+ } while (isASCIIDigit(m_current) && maximumDigits >= 0);
+
+ if (maximumDigits >= 0 && m_current != '.' && (m_current | 0x20) != 'e') {
+ returnValue = decimalValue;
+ return true;
+ }
+
+ for (int i = 9; i > maximumDigits; --i)
+ record8(digits[i]);
+ }
+
+ while (isASCIIDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+
+ return false;
+}
+
+template <typename T>
+ALWAYS_INLINE void Lexer<T>::parseNumberAfterDecimalPoint()
+{
+ record8('.');
+ while (isASCIIDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseNumberAfterExponentIndicator()
+{
+ record8('e');
+ shift();
+ if (m_current == '+' || m_current == '-') {
+ record8(m_current);
+ shift();
+ }
+
+ if (!isASCIIDigit(m_current))
+ return false;
+
+ do {
+ record8(m_current);
+ shift();
+ } while (isASCIIDigit(m_current));
+ return true;
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::parseMultilineComment()
+{
+ while (true) {
+ while (UNLIKELY(m_current == '*')) {
+ shift();
+ if (m_current == '/') {
+ shift();
+ return true;
+ }
+ }
+
+ if (UNLIKELY(m_current == -1))
+ return false;
+
+ if (isLineTerminator(m_current)) {
+ shiftLineTerminator();
+ m_terminator = true;
+ } else
+ shift();
+ }
+}
+
+template <typename T>
+bool Lexer<T>::nextTokenIsColon()
+{
+ const T* code = m_code;
+ while (code < m_codeEnd && (isWhiteSpace(*code) || isLineTerminator(*code)))
+ code++;
+
+ return code < m_codeEnd && *code == ':';
+}
+
+template <typename T>
+JSTokenType Lexer<T>::lex(JSTokenData* tokenData, JSTokenInfo* tokenInfo, unsigned lexerFlags, bool strictMode)
+{
+ ASSERT(!m_error);
+ ASSERT(m_buffer8.isEmpty());
+ ASSERT(m_buffer16.isEmpty());
+
+ JSTokenType token = ERRORTOK;
+ m_terminator = false;
+
+start:
+ while (isWhiteSpace(m_current))
+ shift();
+
+ int startOffset = currentOffset();
+
+ if (UNLIKELY(m_current == -1))
+ return EOFTOK;
+
+ m_delimited = false;
+
+ CharacterType type;
+ if (LIKELY(isASCII(m_current)))
+ type = static_cast<CharacterType>(typesOfASCIICharacters[m_current]);
+ else if (isNonASCIIIdentStart(m_current))
+ type = CharacterIdentifierStart;
+ else if (isLineTerminator(m_current))
+ type = CharacterLineTerminator;
+ else
+ type = CharacterInvalid;
+
+ switch (type) {
+ case CharacterGreater:
+ shift();
+ if (m_current == '>') {
+ shift();
+ if (m_current == '>') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = URSHIFTEQUAL;
+ break;
+ }
+ token = URSHIFT;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = RSHIFTEQUAL;
+ break;
+ }
+ token = RSHIFT;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = GE;
+ break;
+ }
+ token = GT;
+ break;
+ case CharacterEqual:
+ shift();
+ if (m_current == '=') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = STREQ;
+ break;
+ }
+ token = EQEQ;
+ break;
+ }
+ token = EQUAL;
+ break;
+ case CharacterLess:
+ shift();
+ if (m_current == '!' && peek(1) == '-' && peek(2) == '-') {
+ // <!-- marks the beginning of a line comment (for www usage)
+ goto inSingleLineComment;
+ }
+ if (m_current == '<') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = LSHIFTEQUAL;
+ break;
+ }
+ token = LSHIFT;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = LE;
+ break;
+ }
+ token = LT;
+ break;
+ case CharacterExclamationMark:
+ shift();
+ if (m_current == '=') {
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = STRNEQ;
+ break;
+ }
+ token = NE;
+ break;
+ }
+ token = EXCLAMATION;
+ break;
+ case CharacterAdd:
+ shift();
+ if (m_current == '+') {
+ shift();
+ token = (!m_terminator) ? PLUSPLUS : AUTOPLUSPLUS;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = PLUSEQUAL;
+ break;
+ }
+ token = PLUS;
+ break;
+ case CharacterSub:
+ shift();
+ if (m_current == '-') {
+ shift();
+ if (m_atLineStart && m_current == '>') {
+ shift();
+ goto inSingleLineComment;
+ }
+ token = (!m_terminator) ? MINUSMINUS : AUTOMINUSMINUS;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = MINUSEQUAL;
+ break;
+ }
+ token = MINUS;
+ break;
+ case CharacterMultiply:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = MULTEQUAL;
+ break;
+ }
+ token = TIMES;
+ break;
+ case CharacterSlash:
+ shift();
+ if (m_current == '/') {
+ shift();
+ goto inSingleLineComment;
+ }
+ if (m_current == '*') {
+ shift();
+ if (parseMultilineComment())
+ goto start;
+ m_lexErrorMessage = "Multiline comment was not closed properly";
+ goto returnError;
+ }
+ if (m_current == '=') {
+ shift();
+ token = DIVEQUAL;
+ break;
+ }
+ token = DIVIDE;
+ break;
+ case CharacterAnd:
+ shift();
+ if (m_current == '&') {
+ shift();
+ token = AND;
+ break;
+ }
+ if (m_current == '=') {
+ shift();
+ token = ANDEQUAL;
+ break;
+ }
+ token = BITAND;
+ break;
+ case CharacterXor:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = XOREQUAL;
+ break;
+ }
+ token = BITXOR;
+ break;
+ case CharacterModulo:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = MODEQUAL;
+ break;
+ }
+ token = MOD;
+ break;
+ case CharacterOr:
+ shift();
+ if (m_current == '=') {
+ shift();
+ token = OREQUAL;
+ break;
+ }
+ if (m_current == '|') {
+ shift();
+ token = OR;
+ break;
+ }
+ token = BITOR;
+ break;
+ case CharacterOpenParen:
+ token = OPENPAREN;
+ shift();
+ break;
+ case CharacterCloseParen:
+ token = CLOSEPAREN;
+ shift();
+ break;
+ case CharacterOpenBracket:
+ token = OPENBRACKET;
+ shift();
+ break;
+ case CharacterCloseBracket:
+ token = CLOSEBRACKET;
+ shift();
+ break;
+ case CharacterComma:
+ token = COMMA;
+ shift();
+ break;
+ case CharacterColon:
+ token = COLON;
+ shift();
+ break;
+ case CharacterQuestion:
+ token = QUESTION;
+ shift();
+ break;
+ case CharacterTilde:
+ token = TILDE;
+ shift();
+ break;
+ case CharacterSemicolon:
+ m_delimited = true;
+ shift();
+ token = SEMICOLON;
+ break;
+ case CharacterOpenBrace:
+ tokenData->intValue = currentOffset();
+ shift();
+ token = OPENBRACE;
+ break;
+ case CharacterCloseBrace:
+ tokenData->intValue = currentOffset();
+ m_delimited = true;
+ shift();
+ token = CLOSEBRACE;
+ break;
+ case CharacterDot:
+ shift();
+ if (!isASCIIDigit(m_current)) {
+ token = DOT;
+ break;
+ }
+ goto inNumberAfterDecimalPoint;
+ case CharacterZero:
+ shift();
+ if ((m_current | 0x20) == 'x' && isASCIIHexDigit(peek(1))) {
+ parseHex(tokenData->doubleValue);
+ token = NUMBER;
+ } else {
+ record8('0');
+ if (isASCIIOctalDigit(m_current)) {
+ if (parseOctal(tokenData->doubleValue)) {
+ if (strictMode) {
+ m_lexErrorMessage = "Octal escapes are forbidden in strict mode";
+ goto returnError;
+ }
+ token = NUMBER;
+ }
+ }
+ }
+ // Fall through into CharacterNumber
+ case CharacterNumber:
+ if (LIKELY(token != NUMBER)) {
+ if (!parseDecimal(tokenData->doubleValue)) {
+ if (m_current == '.') {
+ shift();
+inNumberAfterDecimalPoint:
+ parseNumberAfterDecimalPoint();
+ }
+ if ((m_current | 0x20) == 'e')
+ if (!parseNumberAfterExponentIndicator()) {
+ m_lexErrorMessage = "Non-number found after exponent indicator";
+ goto returnError;
+ }
+ // Null-terminate string for strtod.
+ m_buffer8.append('\0');
+ tokenData->doubleValue = WTF::strtod(reinterpret_cast<const char*>(m_buffer8.data()), 0);
+ }
+ token = NUMBER;
+ }
+
+ // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
+ if (UNLIKELY(isIdentStart(m_current))) {
+ m_lexErrorMessage = "At least one digit must occur after a decimal point";
+ goto returnError;
+ }
+ m_buffer8.resize(0);
+ m_delimited = false;
+ break;
+ case CharacterQuote:
+ if (lexerFlags & LexerFlagsDontBuildStrings) {
+ if (UNLIKELY(!parseString<false>(tokenData, strictMode)))
+ goto returnError;
+ } else {
+ if (UNLIKELY(!parseString<true>(tokenData, strictMode)))
+ goto returnError;
+ }
+ shift();
+ m_delimited = false;
+ token = STRING;
+ break;
+ case CharacterIdentifierStart:
+ ASSERT(isIdentStart(m_current));
+ // Fall through into CharacterBackSlash.
+ case CharacterBackSlash:
+ if (lexerFlags & LexexFlagsDontBuildKeywords)
+ token = parseIdentifier<false>(tokenData, lexerFlags, strictMode);
+ else
+ token = parseIdentifier<true>(tokenData, lexerFlags, strictMode);
+ break;
+ case CharacterLineTerminator:
+ ASSERT(isLineTerminator(m_current));
+ shiftLineTerminator();
+ m_atLineStart = true;
+ m_terminator = true;
+ goto start;
+ case CharacterInvalid:
+ m_lexErrorMessage = getInvalidCharMessage();
+ goto returnError;
+ default:
+ ASSERT_NOT_REACHED();
+ m_lexErrorMessage = "Internal Error";
+ goto returnError;
+ }
+
+ m_atLineStart = false;
+ goto returnToken;
+
+inSingleLineComment:
+ while (!isLineTerminator(m_current)) {
+ if (UNLIKELY(m_current == -1))
+ return EOFTOK;
+ shift();
+ }
+ shiftLineTerminator();
+ m_atLineStart = true;
+ m_terminator = true;
+ if (!lastTokenWasRestrKeyword())
+ goto start;
+
+ token = SEMICOLON;
+ m_delimited = true;
+ // Fall through into returnToken.
+
+returnToken:
+ tokenInfo->line = m_lineNumber;
+ tokenInfo->startOffset = startOffset;
+ tokenInfo->endOffset = currentOffset();
+ m_lastToken = token;
+ return token;
+
+returnError:
+ m_error = true;
+ tokenInfo->line = m_lineNumber;
+ tokenInfo->startOffset = startOffset;
+ tokenInfo->endOffset = currentOffset();
+ return ERRORTOK;
+}
+
+template <typename T>
+bool Lexer<T>::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix)
+{
+ ASSERT(m_buffer16.isEmpty());
+
+ bool lastWasEscape = false;
+ bool inBrackets = false;
+
+ if (patternPrefix) {
+ ASSERT(!isLineTerminator(patternPrefix));
+ ASSERT(patternPrefix != '/');
+ ASSERT(patternPrefix != '[');
+ record16(patternPrefix);
+ }
+
+ while (true) {
+ int current = m_current;
+
+ if (isLineTerminator(current) || current == -1) {
+ m_buffer16.resize(0);
+ return false;
+ }
+
+ shift();
+
+ if (current == '/' && !lastWasEscape && !inBrackets)
+ break;
+
+ record16(current);
+
+ if (lastWasEscape) {
+ lastWasEscape = false;
+ continue;
+ }
+
+ switch (current) {
+ case '[':
+ inBrackets = true;
+ break;
+ case ']':
+ inBrackets = false;
+ break;
+ case '\\':
+ lastWasEscape = true;
+ break;
+ }
+ }
+
+ pattern = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ m_buffer16.resize(0);
+
+ while (isIdentPart(m_current)) {
+ record16(m_current);
+ shift();
+ }
+
+ flags = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ m_buffer16.resize(0);
+
+ return true;
+}
+
+template <typename T>
+bool Lexer<T>::skipRegExp()
+{
+ bool lastWasEscape = false;
+ bool inBrackets = false;
+
+ while (true) {
+ int current = m_current;
+
+ if (isLineTerminator(current) || current == -1)
+ return false;
+
+ shift();
+
+ if (current == '/' && !lastWasEscape && !inBrackets)
+ break;
+
+ if (lastWasEscape) {
+ lastWasEscape = false;
+ continue;
+ }
+
+ switch (current) {
+ case '[':
+ inBrackets = true;
+ break;
+ case ']':
+ inBrackets = false;
+ break;
+ case '\\':
+ lastWasEscape = true;
+ break;
+ }
+ }
+
+ while (isIdentPart(m_current))
+ shift();
+
+ return true;
+}
+
+template <typename T>
+void Lexer<T>::clear()
+{
+ m_arena = 0;
+
+ Vector<LChar> newBuffer8;
+ m_buffer8.swap(newBuffer8);
+
+ Vector<UChar> newBuffer16;
+ m_buffer16.swap(newBuffer16);
+
+ m_isReparsing = false;
+}
+
+template <typename T>
+SourceCode Lexer<T>::sourceCode(int openBrace, int closeBrace, int firstLine)
+{
+ ASSERT((*m_source->provider()->data())[openBrace] == '{');
+ ASSERT((*m_source->provider()->data())[closeBrace] == '}');
+ return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine);
+}
+
+// Instantiate the two flavors of Lexer we need instead of putting most of this file in Lexer.h
+template class Lexer<LChar>;
+template class Lexer<UChar>;
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Lexer.h b/Source/JavaScriptCore/parser/Lexer.h
new file mode 100644
index 000000000..6fe0c9a1c
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Lexer.h
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Lexer_h
+#define Lexer_h
+
+#include "Lookup.h"
+#include "ParserArena.h"
+#include "ParserTokens.h"
+#include "SourceCode.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/AlwaysInline.h>
+#include <wtf/SegmentedVector.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace JSC {
+
+class Keywords {
+public:
+ bool isKeyword(const Identifier& ident) const
+ {
+ return m_keywordTable.entry(m_globalData, ident);
+ }
+
+ const HashEntry* getKeyword(const Identifier& ident) const
+ {
+ return m_keywordTable.entry(m_globalData, ident);
+ }
+
+ ~Keywords()
+ {
+ m_keywordTable.deleteTable();
+ }
+
+private:
+ friend class JSGlobalData;
+
+ Keywords(JSGlobalData*);
+
+ JSGlobalData* m_globalData;
+ const HashTable m_keywordTable;
+};
+
+enum LexerFlags {
+ LexerFlagsIgnoreReservedWords = 1,
+ LexerFlagsDontBuildStrings = 2,
+ LexexFlagsDontBuildKeywords = 4
+};
+
+class RegExp;
+
+template <typename T>
+class Lexer {
+ WTF_MAKE_NONCOPYABLE(Lexer);
+ WTF_MAKE_FAST_ALLOCATED;
+
+public:
+ Lexer(JSGlobalData*);
+ ~Lexer();
+
+ // Character manipulation functions.
+ static bool isWhiteSpace(int character);
+ static bool isLineTerminator(int character);
+ static unsigned char convertHex(int c1, int c2);
+ static UChar convertUnicode(int c1, int c2, int c3, int c4);
+
+ // Functions to set up parsing.
+ void setCode(const SourceCode&, ParserArena*);
+ void setIsReparsing() { m_isReparsing = true; }
+ bool isReparsing() const { return m_isReparsing; }
+
+ JSTokenType lex(JSTokenData*, JSTokenInfo*, unsigned, bool strictMode);
+ bool nextTokenIsColon();
+ int lineNumber() const { return m_lineNumber; }
+ void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
+ int lastLineNumber() const { return m_lastLineNumber; }
+ bool prevTerminator() const { return m_terminator; }
+ SourceCode sourceCode(int openBrace, int closeBrace, int firstLine);
+ bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0);
+ bool skipRegExp();
+
+ // Functions for use after parsing.
+ bool sawError() const { return m_error; }
+ UString getErrorMessage() const { return m_lexErrorMessage; }
+ void clear();
+ void setOffset(int offset)
+ {
+ m_error = 0;
+ m_lexErrorMessage = UString();
+ m_code = m_codeStart + offset;
+ m_buffer8.resize(0);
+ m_buffer16.resize(0);
+ // Faster than an if-else sequence
+ m_current = -1;
+ if (LIKELY(m_code < m_codeEnd))
+ m_current = *m_code;
+ }
+ void setLineNumber(int line)
+ {
+ m_lineNumber = line;
+ }
+
+ SourceProvider* sourceProvider() const { return m_source->provider(); }
+
+ JSTokenType lexExpectIdentifier(JSTokenData*, JSTokenInfo*, unsigned, bool strictMode);
+
+private:
+ void record8(int);
+ void append8(const T*, size_t);
+ void record16(int);
+ void record16(T);
+ void append16(const LChar*, size_t);
+ void append16(const UChar* characters, size_t length) { m_buffer16.append(characters, length); }
+
+ ALWAYS_INLINE void shift();
+ ALWAYS_INLINE int peek(int offset);
+ int getUnicodeCharacter();
+ void shiftLineTerminator();
+
+ UString getInvalidCharMessage();
+ ALWAYS_INLINE const T* currentCharacter() const;
+ ALWAYS_INLINE int currentOffset() const { return m_code - m_codeStart; }
+ ALWAYS_INLINE void setOffsetFromCharOffset(const T* charOffset) { setOffset(charOffset - m_codeStart); }
+
+ ALWAYS_INLINE void setCodeStart(const StringImpl*);
+
+ ALWAYS_INLINE const Identifier* makeIdentifier(const LChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeIdentifier(const UChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier* makeIdentifierLCharFromUChar(const UChar* characters, size_t length);
+
+ ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
+
+ template <int shiftAmount> void internalShift();
+ template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType parseKeyword(JSTokenData*);
+ template <bool shouldBuildIdentifiers> ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, unsigned lexerFlags, bool strictMode);
+ template <bool shouldBuildIdentifiers> NEVER_INLINE JSTokenType parseIdentifierSlowCase(JSTokenData*, unsigned lexerFlags, bool strictMode);
+ template <bool shouldBuildStrings> ALWAYS_INLINE bool parseString(JSTokenData*, bool strictMode);
+ template <bool shouldBuildStrings> NEVER_INLINE bool parseStringSlowCase(JSTokenData*, bool strictMode);
+ ALWAYS_INLINE void parseHex(double& returnValue);
+ ALWAYS_INLINE bool parseOctal(double& returnValue);
+ ALWAYS_INLINE bool parseDecimal(double& returnValue);
+ ALWAYS_INLINE void parseNumberAfterDecimalPoint();
+ ALWAYS_INLINE bool parseNumberAfterExponentIndicator();
+ ALWAYS_INLINE bool parseMultilineComment();
+
+ static const size_t initialReadBufferCapacity = 32;
+
+ int m_lineNumber;
+ int m_lastLineNumber;
+
+ Vector<LChar> m_buffer8;
+ Vector<UChar> m_buffer16;
+ bool m_terminator;
+ bool m_delimited; // encountered delimiter like "'" and "}" on last run
+ int m_lastToken;
+
+ const SourceCode* m_source;
+ const T* m_code;
+ const T* m_codeStart;
+ const T* m_codeEnd;
+ bool m_isReparsing;
+ bool m_atLineStart;
+ bool m_error;
+ UString m_lexErrorMessage;
+
+ // current and following unicode characters (int to allow for -1 for end-of-file marker)
+ int m_current;
+
+ IdentifierArena* m_arena;
+
+ JSGlobalData* m_globalData;
+};
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::isWhiteSpace(int ch)
+{
+ return isASCII(ch) ? (ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC) : (WTF::Unicode::isSeparatorSpace(ch) || ch == 0xFEFF);
+}
+
+template <typename T>
+ALWAYS_INLINE bool Lexer<T>::isLineTerminator(int ch)
+{
+ return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028;
+}
+
+template <typename T>
+inline unsigned char Lexer<T>::convertHex(int c1, int c2)
+{
+ return (toASCIIHexValue(c1) << 4) | toASCIIHexValue(c2);
+}
+
+template <typename T>
+inline UChar Lexer<T>::convertUnicode(int c1, int c2, int c3, int c4)
+{
+ return (convertHex(c1, c2) << 8) | convertHex(c3, c4);
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const LChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifier(m_globalData, characters, length);
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const UChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifier(m_globalData, characters, length);
+}
+
+template <>
+ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const StringImpl* sourceString)
+{
+ ASSERT(sourceString->is8Bit());
+ m_codeStart = sourceString->characters8();
+}
+
+template <>
+ALWAYS_INLINE void Lexer<UChar>::setCodeStart(const StringImpl* sourceString)
+{
+ ASSERT(!sourceString->is8Bit());
+ m_codeStart = sourceString->characters16();
+}
+
+template <typename T>
+ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifierLCharFromUChar(const UChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifierLCharFromUChar(m_globalData, characters, length);
+}
+
+template <typename T>
+ALWAYS_INLINE JSTokenType Lexer<T>::lexExpectIdentifier(JSTokenData* tokenData, JSTokenInfo* tokenInfo, unsigned lexerFlags, bool strictMode)
+{
+ ASSERT((lexerFlags & LexerFlagsIgnoreReservedWords));
+ const T* start = m_code;
+ const T* ptr = start;
+ const T* end = m_codeEnd;
+ if (ptr >= end) {
+ ASSERT(ptr == end);
+ goto slowCase;
+ }
+ if (!WTF::isASCIIAlpha(*ptr))
+ goto slowCase;
+ ++ptr;
+ while (ptr < end) {
+ if (!WTF::isASCIIAlphanumeric(*ptr))
+ break;
+ ++ptr;
+ }
+
+ // Here's the shift
+ if (ptr < end) {
+ if ((!WTF::isASCII(*ptr)) || (*ptr == '\\') || (*ptr == '_') || (*ptr == '$'))
+ goto slowCase;
+ m_current = *ptr;
+ } else
+ m_current = -1;
+
+ m_code = ptr;
+
+ // Create the identifier if needed
+ if (lexerFlags & LexexFlagsDontBuildKeywords)
+ tokenData->ident = 0;
+ else
+ tokenData->ident = makeIdentifier(start, ptr - start);
+ tokenInfo->line = m_lineNumber;
+ tokenInfo->startOffset = start - m_codeStart;
+ tokenInfo->endOffset = currentOffset();
+ m_lastToken = IDENT;
+ return IDENT;
+
+slowCase:
+ return lex(tokenData, tokenInfo, lexerFlags, strictMode);
+}
+
+} // namespace JSC
+
+#endif // Lexer_h
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
new file mode 100644
index 000000000..6c069490d
--- /dev/null
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -0,0 +1,898 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef NodeConstructors_h
+#define NodeConstructors_h
+
+#include "Nodes.h"
+#include "Lexer.h"
+#include "Parser.h"
+
+namespace JSC {
+
+ inline void* ParserArenaFreeable::operator new(size_t size, JSGlobalData* globalData)
+ {
+ return globalData->parserArena->allocateFreeable(size);
+ }
+
+ inline void* ParserArenaDeletable::operator new(size_t size, JSGlobalData* globalData)
+ {
+ return globalData->parserArena->allocateDeletable(size);
+ }
+
+ inline ParserArenaRefCounted::ParserArenaRefCounted(JSGlobalData* globalData)
+ {
+ globalData->parserArena->derefWithArena(adoptRef(this));
+ }
+
+ inline Node::Node(int lineNumber)
+ : m_lineNumber(lineNumber)
+ {
+ }
+
+ inline ExpressionNode::ExpressionNode(int lineNumber, ResultType resultType)
+ : Node(lineNumber)
+ , m_resultType(resultType)
+ {
+ }
+
+ inline StatementNode::StatementNode(int lineNumber)
+ : Node(lineNumber)
+ , m_lastLine(-1)
+ {
+ }
+
+ inline NullNode::NullNode(int lineNumber)
+ : ExpressionNode(lineNumber, ResultType::nullType())
+ {
+ }
+
+ inline BooleanNode::BooleanNode(int lineNumber, bool value)
+ : ExpressionNode(lineNumber, ResultType::booleanType())
+ , m_value(value)
+ {
+ }
+
+ inline NumberNode::NumberNode(int lineNumber, double value)
+ : ExpressionNode(lineNumber, ResultType::numberType())
+ , m_value(value)
+ {
+ }
+
+ inline StringNode::StringNode(int lineNumber, const Identifier& value)
+ : ExpressionNode(lineNumber, ResultType::stringType())
+ , m_value(value)
+ {
+ }
+
+ inline RegExpNode::RegExpNode(int lineNumber, const Identifier& pattern, const Identifier& flags)
+ : ExpressionNode(lineNumber)
+ , m_pattern(pattern)
+ , m_flags(flags)
+ {
+ }
+
+ inline ThisNode::ThisNode(int lineNumber)
+ : ExpressionNode(lineNumber)
+ {
+ }
+
+ inline ResolveNode::ResolveNode(int lineNumber, const Identifier& ident, int startOffset)
+ : ExpressionNode(lineNumber)
+ , m_ident(ident)
+ , m_startOffset(startOffset)
+ {
+ }
+
+ inline ElementNode::ElementNode(int elision, ExpressionNode* node)
+ : m_next(0)
+ , m_elision(elision)
+ , m_node(node)
+ {
+ }
+
+ inline ElementNode::ElementNode(ElementNode* l, int elision, ExpressionNode* node)
+ : m_next(0)
+ , m_elision(elision)
+ , m_node(node)
+ {
+ l->m_next = this;
+ }
+
+ inline ArrayNode::ArrayNode(int lineNumber, int elision)
+ : ExpressionNode(lineNumber)
+ , m_element(0)
+ , m_elision(elision)
+ , m_optional(true)
+ {
+ }
+
+ inline ArrayNode::ArrayNode(int lineNumber, ElementNode* element)
+ : ExpressionNode(lineNumber)
+ , m_element(element)
+ , m_elision(0)
+ , m_optional(false)
+ {
+ }
+
+ inline ArrayNode::ArrayNode(int lineNumber, int elision, ElementNode* element)
+ : ExpressionNode(lineNumber)
+ , m_element(element)
+ , m_elision(elision)
+ , m_optional(true)
+ {
+ }
+
+ inline PropertyNode::PropertyNode(JSGlobalData*, const Identifier& name, ExpressionNode* assign, Type type)
+ : m_name(name)
+ , m_assign(assign)
+ , m_type(type)
+ {
+ }
+
+ inline PropertyNode::PropertyNode(JSGlobalData* globalData, double name, ExpressionNode* assign, Type type)
+ : m_name(globalData->parserArena->identifierArena().makeNumericIdentifier(globalData, name))
+ , m_assign(assign)
+ , m_type(type)
+ {
+ }
+
+ inline PropertyListNode::PropertyListNode(int lineNumber, PropertyNode* node)
+ : Node(lineNumber)
+ , m_node(node)
+ , m_next(0)
+ {
+ }
+
+ inline PropertyListNode::PropertyListNode(int lineNumber, PropertyNode* node, PropertyListNode* list)
+ : Node(lineNumber)
+ , m_node(node)
+ , m_next(0)
+ {
+ list->m_next = this;
+ }
+
+ inline ObjectLiteralNode::ObjectLiteralNode(int lineNumber)
+ : ExpressionNode(lineNumber)
+ , m_list(0)
+ {
+ }
+
+ inline ObjectLiteralNode::ObjectLiteralNode(int lineNumber, PropertyListNode* list)
+ : ExpressionNode(lineNumber)
+ , m_list(list)
+ {
+ }
+
+ inline BracketAccessorNode::BracketAccessorNode(int lineNumber, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments)
+ : ExpressionNode(lineNumber)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ {
+ }
+
+ inline DotAccessorNode::DotAccessorNode(int lineNumber, ExpressionNode* base, const Identifier& ident)
+ : ExpressionNode(lineNumber)
+ , m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ inline ArgumentListNode::ArgumentListNode(int lineNumber, ExpressionNode* expr)
+ : Node(lineNumber)
+ , m_next(0)
+ , m_expr(expr)
+ {
+ }
+
+ inline ArgumentListNode::ArgumentListNode(int lineNumber, ArgumentListNode* listNode, ExpressionNode* expr)
+ : Node(lineNumber)
+ , m_next(0)
+ , m_expr(expr)
+ {
+ listNode->m_next = this;
+ }
+
+ inline ArgumentsNode::ArgumentsNode()
+ : m_listNode(0)
+ {
+ }
+
+ inline ArgumentsNode::ArgumentsNode(ArgumentListNode* listNode)
+ : m_listNode(listNode)
+ {
+ }
+
+ inline NewExprNode::NewExprNode(int lineNumber, ExpressionNode* expr)
+ : ExpressionNode(lineNumber)
+ , m_expr(expr)
+ , m_args(0)
+ {
+ }
+
+ inline NewExprNode::NewExprNode(int lineNumber, ExpressionNode* expr, ArgumentsNode* args)
+ : ExpressionNode(lineNumber)
+ , m_expr(expr)
+ , m_args(args)
+ {
+ }
+
+ inline EvalFunctionCallNode::EvalFunctionCallNode(int lineNumber, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallValueNode::FunctionCallValueNode(int lineNumber, ExpressionNode* expr, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallResolveNode::FunctionCallResolveNode(int lineNumber, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallBracketNode::FunctionCallBracketNode(int lineNumber, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallDotNode::FunctionCallDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ inline CallFunctionCallDotNode::CallFunctionCallDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : FunctionCallDotNode(lineNumber, base, ident, args, divot, startOffset, endOffset)
+ {
+ }
+
+ inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : FunctionCallDotNode(lineNumber, base, ident, args, divot, startOffset, endOffset)
+ {
+ }
+
+ inline PrePostResolveNode::PrePostResolveNode(int lineNumber, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber, ResultType::numberType()) // could be reusable for pre?
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ {
+ }
+
+ inline PostfixResolveNode::PostfixResolveNode(int lineNumber, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : PrePostResolveNode(lineNumber, ident, divot, startOffset, endOffset)
+ , m_operator(oper)
+ {
+ }
+
+ inline PostfixBracketNode::PostfixBracketNode(int lineNumber, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_operator(oper)
+ {
+ }
+
+ inline PostfixDotNode::PostfixDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_operator(oper)
+ {
+ }
+
+ inline PostfixErrorNode::PostfixErrorNode(int lineNumber, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
+ , m_operator(oper)
+ {
+ }
+
+ inline DeleteResolveNode::DeleteResolveNode(int lineNumber, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ {
+ }
+
+ inline DeleteBracketNode::DeleteBracketNode(int lineNumber, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ {
+ }
+
+ inline DeleteDotNode::DeleteDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ inline DeleteValueNode::DeleteValueNode(int lineNumber, ExpressionNode* expr)
+ : ExpressionNode(lineNumber)
+ , m_expr(expr)
+ {
+ }
+
+ inline VoidNode::VoidNode(int lineNumber, ExpressionNode* expr)
+ : ExpressionNode(lineNumber)
+ , m_expr(expr)
+ {
+ }
+
+ inline TypeOfResolveNode::TypeOfResolveNode(int lineNumber, const Identifier& ident)
+ : ExpressionNode(lineNumber, ResultType::stringType())
+ , m_ident(ident)
+ {
+ }
+
+ inline TypeOfValueNode::TypeOfValueNode(int lineNumber, ExpressionNode* expr)
+ : ExpressionNode(lineNumber, ResultType::stringType())
+ , m_expr(expr)
+ {
+ }
+
+ inline PrefixResolveNode::PrefixResolveNode(int lineNumber, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : PrePostResolveNode(lineNumber, ident, divot, startOffset, endOffset)
+ , m_operator(oper)
+ {
+ }
+
+ inline PrefixBracketNode::PrefixBracketNode(int lineNumber, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_operator(oper)
+ {
+ }
+
+ inline PrefixDotNode::PrefixDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_operator(oper)
+ {
+ }
+
+ inline PrefixErrorNode::PrefixErrorNode(int lineNumber, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
+ , m_operator(oper)
+ {
+ }
+
+ inline UnaryOpNode::UnaryOpNode(int lineNumber, ResultType type, ExpressionNode* expr, OpcodeID opcodeID)
+ : ExpressionNode(lineNumber, type)
+ , m_expr(expr)
+ , m_opcodeID(opcodeID)
+ {
+ }
+
+ inline UnaryPlusNode::UnaryPlusNode(int lineNumber, ExpressionNode* expr)
+ : UnaryOpNode(lineNumber, ResultType::numberType(), expr, op_to_jsnumber)
+ {
+ }
+
+ inline NegateNode::NegateNode(int lineNumber, ExpressionNode* expr)
+ : UnaryOpNode(lineNumber, ResultType::numberTypeCanReuse(), expr, op_negate)
+ {
+ }
+
+ inline BitwiseNotNode::BitwiseNotNode(int lineNumber, ExpressionNode* expr)
+ : UnaryOpNode(lineNumber, ResultType::forBitOp(), expr, op_bitnot)
+ {
+ }
+
+ inline LogicalNotNode::LogicalNotNode(int lineNumber, ExpressionNode* expr)
+ : UnaryOpNode(lineNumber, ResultType::booleanType(), expr, op_not)
+ {
+ }
+
+ inline BinaryOpNode::BinaryOpNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : ExpressionNode(lineNumber)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_opcodeID(opcodeID)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline BinaryOpNode::BinaryOpNode(int lineNumber, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : ExpressionNode(lineNumber, type)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_opcodeID(opcodeID)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline MultNode::MultNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::numberTypeCanReuse(), expr1, expr2, op_mul, rightHasAssignments)
+ {
+ }
+
+ inline DivNode::DivNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::numberTypeCanReuse(), expr1, expr2, op_div, rightHasAssignments)
+ {
+ }
+
+
+ inline ModNode::ModNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::numberTypeCanReuse(), expr1, expr2, op_mod, rightHasAssignments)
+ {
+ }
+
+ inline AddNode::AddNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_add, rightHasAssignments)
+ {
+ }
+
+ inline SubNode::SubNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::numberTypeCanReuse(), expr1, expr2, op_sub, rightHasAssignments)
+ {
+ }
+
+ inline LeftShiftNode::LeftShiftNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::forBitOp(), expr1, expr2, op_lshift, rightHasAssignments)
+ {
+ }
+
+ inline RightShiftNode::RightShiftNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::forBitOp(), expr1, expr2, op_rshift, rightHasAssignments)
+ {
+ }
+
+ inline UnsignedRightShiftNode::UnsignedRightShiftNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::numberTypeCanReuse(), expr1, expr2, op_urshift, rightHasAssignments)
+ {
+ }
+
+ inline LessNode::LessNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_less, rightHasAssignments)
+ {
+ }
+
+ inline GreaterNode::GreaterNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_greater, rightHasAssignments)
+ {
+ }
+
+ inline LessEqNode::LessEqNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_lesseq, rightHasAssignments)
+ {
+ }
+
+ inline GreaterEqNode::GreaterEqNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_greatereq, rightHasAssignments)
+ {
+ }
+
+ inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(int lineNumber, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, type, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline InstanceOfNode::InstanceOfNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ThrowableBinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_instanceof, rightHasAssignments)
+ {
+ }
+
+ inline InNode::InNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ThrowableBinaryOpNode(lineNumber, expr1, expr2, op_in, rightHasAssignments)
+ {
+ }
+
+ inline EqualNode::EqualNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_eq, rightHasAssignments)
+ {
+ }
+
+ inline NotEqualNode::NotEqualNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_neq, rightHasAssignments)
+ {
+ }
+
+ inline StrictEqualNode::StrictEqualNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_stricteq, rightHasAssignments)
+ {
+ }
+
+ inline NotStrictEqualNode::NotStrictEqualNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::booleanType(), expr1, expr2, op_nstricteq, rightHasAssignments)
+ {
+ }
+
+ inline BitAndNode::BitAndNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::forBitOp(), expr1, expr2, op_bitand, rightHasAssignments)
+ {
+ }
+
+ inline BitOrNode::BitOrNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::forBitOp(), expr1, expr2, op_bitor, rightHasAssignments)
+ {
+ }
+
+ inline BitXOrNode::BitXOrNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(lineNumber, ResultType::forBitOp(), expr1, expr2, op_bitxor, rightHasAssignments)
+ {
+ }
+
+ inline LogicalOpNode::LogicalOpNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper)
+ : ExpressionNode(lineNumber, ResultType::booleanType())
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_operator(oper)
+ {
+ }
+
+ inline ConditionalNode::ConditionalNode(int lineNumber, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2)
+ : ExpressionNode(lineNumber)
+ , m_logical(logical)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ inline ReadModifyResolveNode::ReadModifyResolveNode(int lineNumber, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignResolveNode::AssignResolveNode(int lineNumber, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments)
+ : ExpressionNode(lineNumber)
+ , m_ident(ident)
+ , m_right(right)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline ReadModifyBracketNode::ReadModifyBracketNode(int lineNumber, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_right(right)
+ , m_operator(oper)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignBracketNode::AssignBracketNode(int lineNumber, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_right(right)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignDotNode::AssignDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline ReadModifyDotNode::ReadModifyDotNode(int lineNumber, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignErrorNode::AssignErrorNode(int lineNumber, ExpressionNode* left, Operator oper, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(lineNumber)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_left(left)
+ , m_operator(oper)
+ , m_right(right)
+ {
+ }
+
+ inline CommaNode::CommaNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2)
+ : ExpressionNode(lineNumber)
+ {
+ m_expressions.append(expr1);
+ m_expressions.append(expr2);
+ }
+
+ inline ConstStatementNode::ConstStatementNode(int lineNumber, ConstDeclNode* next)
+ : StatementNode(lineNumber)
+ , m_next(next)
+ {
+ }
+
+ inline SourceElements::SourceElements()
+ {
+ }
+
+ inline EmptyStatementNode::EmptyStatementNode(int lineNumber)
+ : StatementNode(lineNumber)
+ {
+ }
+
+ inline DebuggerStatementNode::DebuggerStatementNode(int lineNumber)
+ : StatementNode(lineNumber)
+ {
+ }
+
+ inline ExprStatementNode::ExprStatementNode(int lineNumber, ExpressionNode* expr)
+ : StatementNode(lineNumber)
+ , m_expr(expr)
+ {
+ }
+
+ inline VarStatementNode::VarStatementNode(int lineNumber, ExpressionNode* expr)
+ : StatementNode(lineNumber)
+ , m_expr(expr)
+ {
+ }
+
+ inline IfNode::IfNode(int lineNumber, ExpressionNode* condition, StatementNode* ifBlock)
+ : StatementNode(lineNumber)
+ , m_condition(condition)
+ , m_ifBlock(ifBlock)
+ {
+ }
+
+ inline IfElseNode::IfElseNode(int lineNumber, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock)
+ : IfNode(lineNumber, condition, ifBlock)
+ , m_elseBlock(elseBlock)
+ {
+ }
+
+ inline DoWhileNode::DoWhileNode(int lineNumber, StatementNode* statement, ExpressionNode* expr)
+ : StatementNode(lineNumber)
+ , m_statement(statement)
+ , m_expr(expr)
+ {
+ }
+
+ inline WhileNode::WhileNode(int lineNumber, ExpressionNode* expr, StatementNode* statement)
+ : StatementNode(lineNumber)
+ , m_expr(expr)
+ , m_statement(statement)
+ {
+ }
+
+ inline ForNode::ForNode(int lineNumber, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl)
+ : StatementNode(lineNumber)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_expr3(expr3)
+ , m_statement(statement)
+ , m_expr1WasVarDecl(expr1 && expr1WasVarDecl)
+ {
+ ASSERT(statement);
+ }
+
+ inline ContinueNode::ContinueNode(JSGlobalData* globalData, int lineNumber)
+ : StatementNode(lineNumber)
+ , m_ident(globalData->propertyNames->nullIdentifier)
+ {
+ }
+
+ inline ContinueNode::ContinueNode(int lineNumber, const Identifier& ident)
+ : StatementNode(lineNumber)
+ , m_ident(ident)
+ {
+ }
+
+ inline BreakNode::BreakNode(JSGlobalData* globalData, int lineNumber)
+ : StatementNode(lineNumber)
+ , m_ident(globalData->propertyNames->nullIdentifier)
+ {
+ }
+
+ inline BreakNode::BreakNode(int lineNumber, const Identifier& ident)
+ : StatementNode(lineNumber)
+ , m_ident(ident)
+ {
+ }
+
+ inline ReturnNode::ReturnNode(int lineNumber, ExpressionNode* value)
+ : StatementNode(lineNumber)
+ , m_value(value)
+ {
+ }
+
+ inline WithNode::WithNode(int lineNumber, ExpressionNode* expr, StatementNode* statement, uint32_t divot, uint32_t expressionLength)
+ : StatementNode(lineNumber)
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_divot(divot)
+ , m_expressionLength(expressionLength)
+ {
+ }
+
+ inline LabelNode::LabelNode(int lineNumber, const Identifier& name, StatementNode* statement)
+ : StatementNode(lineNumber)
+ , m_name(name)
+ , m_statement(statement)
+ {
+ }
+
+ inline ThrowNode::ThrowNode(int lineNumber, ExpressionNode* expr)
+ : StatementNode(lineNumber)
+ , m_expr(expr)
+ {
+ }
+
+ inline TryNode::TryNode(int lineNumber, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock)
+ : StatementNode(lineNumber)
+ , m_tryBlock(tryBlock)
+ , m_exceptionIdent(exceptionIdent)
+ , m_catchBlock(catchBlock)
+ , m_finallyBlock(finallyBlock)
+ , m_catchHasEval(catchHasEval)
+ {
+ }
+
+ inline ParameterNode::ParameterNode(const Identifier& ident)
+ : m_ident(ident)
+ , m_next(0)
+ {
+ }
+
+ inline ParameterNode::ParameterNode(ParameterNode* l, const Identifier& ident)
+ : m_ident(ident)
+ , m_next(0)
+ {
+ l->m_next = this;
+ }
+
+ inline FuncExprNode::FuncExprNode(int lineNumber, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter)
+ : ExpressionNode(lineNumber)
+ , m_body(body)
+ {
+ m_body->finishParsing(source, parameter, ident);
+ }
+
+ inline FuncDeclNode::FuncDeclNode(int lineNumber, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter)
+ : StatementNode(lineNumber)
+ , m_body(body)
+ {
+ m_body->finishParsing(source, parameter, ident);
+ }
+
+ inline CaseClauseNode::CaseClauseNode(ExpressionNode* expr, SourceElements* statements)
+ : m_expr(expr)
+ , m_statements(statements)
+ {
+ }
+
+ inline ClauseListNode::ClauseListNode(CaseClauseNode* clause)
+ : m_clause(clause)
+ , m_next(0)
+ {
+ }
+
+ inline ClauseListNode::ClauseListNode(ClauseListNode* clauseList, CaseClauseNode* clause)
+ : m_clause(clause)
+ , m_next(0)
+ {
+ clauseList->m_next = this;
+ }
+
+ inline CaseBlockNode::CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2)
+ : m_list1(list1)
+ , m_defaultClause(defaultClause)
+ , m_list2(list2)
+ {
+ }
+
+ inline SwitchNode::SwitchNode(int lineNumber, ExpressionNode* expr, CaseBlockNode* block)
+ : StatementNode(lineNumber)
+ , m_expr(expr)
+ , m_block(block)
+ {
+ }
+
+ inline ConstDeclNode::ConstDeclNode(int lineNumber, const Identifier& ident, ExpressionNode* init)
+ : ExpressionNode(lineNumber)
+ , m_ident(ident)
+ , m_next(0)
+ , m_init(init)
+ {
+ }
+
+ inline BlockNode::BlockNode(int lineNumber, SourceElements* statements)
+ : StatementNode(lineNumber)
+ , m_statements(statements)
+ {
+ }
+
+ inline ForInNode::ForInNode(JSGlobalData* globalData, int lineNumber, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
+ : StatementNode(lineNumber)
+ , m_ident(globalData->propertyNames->nullIdentifier)
+ , m_init(0)
+ , m_lexpr(l)
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_identIsVarDecl(false)
+ {
+ }
+
+ inline ForInNode::ForInNode(JSGlobalData* globalData, int lineNumber, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement, int divot, int startOffset, int endOffset)
+ : StatementNode(lineNumber)
+ , m_ident(ident)
+ , m_init(0)
+ , m_lexpr(new (globalData) ResolveNode(lineNumber, ident, divot - startOffset))
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_identIsVarDecl(true)
+ {
+ if (in) {
+ AssignResolveNode* node = new (globalData) AssignResolveNode(lineNumber, ident, in, true);
+ node->setExceptionSourceCode(divot, divot - startOffset, endOffset - divot);
+ m_init = node;
+ }
+ // for( var foo = bar in baz )
+ }
+
+} // namespace JSC
+
+#endif // NodeConstructors_h
diff --git a/Source/JavaScriptCore/parser/NodeInfo.h b/Source/JavaScriptCore/parser/NodeInfo.h
new file mode 100644
index 000000000..4853aec42
--- /dev/null
+++ b/Source/JavaScriptCore/parser/NodeInfo.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef NodeInfo_h
+#define NodeInfo_h
+
+#include "Nodes.h"
+
+namespace JSC {
+
+ template <typename T> struct NodeInfo {
+ T m_node;
+ CodeFeatures m_features;
+ int m_numConstants;
+ };
+
+ typedef NodeInfo<FuncDeclNode*> FuncDeclNodeInfo;
+ typedef NodeInfo<FuncExprNode*> FuncExprNodeInfo;
+ typedef NodeInfo<ExpressionNode*> ExpressionNodeInfo;
+ typedef NodeInfo<ArgumentsNode*> ArgumentsNodeInfo;
+ typedef NodeInfo<ConstDeclNode*> ConstDeclNodeInfo;
+ typedef NodeInfo<PropertyNode*> PropertyNodeInfo;
+ typedef NodeInfo<PropertyList> PropertyListInfo;
+ typedef NodeInfo<ElementList> ElementListInfo;
+ typedef NodeInfo<ArgumentList> ArgumentListInfo;
+
+ template <typename T> struct NodeDeclarationInfo {
+ T m_node;
+ ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ CodeFeatures m_features;
+ int m_numConstants;
+ };
+
+ typedef NodeDeclarationInfo<StatementNode*> StatementNodeInfo;
+ typedef NodeDeclarationInfo<CaseBlockNode*> CaseBlockNodeInfo;
+ typedef NodeDeclarationInfo<CaseClauseNode*> CaseClauseNodeInfo;
+ typedef NodeDeclarationInfo<SourceElements*> SourceElementsInfo;
+ typedef NodeDeclarationInfo<ClauseList> ClauseListInfo;
+ typedef NodeDeclarationInfo<ExpressionNode*> VarDeclListInfo;
+ typedef NodeDeclarationInfo<ConstDeclList> ConstDeclListInfo;
+ typedef NodeDeclarationInfo<ParameterList> ParameterListInfo;
+
+} // namespace JSC
+
+#endif // NodeInfo_h
diff --git a/Source/JavaScriptCore/parser/Nodes.cpp b/Source/JavaScriptCore/parser/Nodes.cpp
new file mode 100644
index 000000000..8ad474e54
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Nodes.cpp
@@ -0,0 +1,196 @@
+/*
+* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+* Copyright (C) 2001 Peter Kelly (pmk@post.com)
+* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+* Copyright (C) 2007 Maks Orlovich
+* Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Library General Public
+* License as published by the Free Software Foundation; either
+* version 2 of the License, or (at your option) any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Library General Public License for more details.
+*
+* You should have received a copy of the GNU Library General Public License
+* along with this library; see the file COPYING.LIB. If not, write to
+* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+* Boston, MA 02110-1301, USA.
+*
+*/
+
+#include "config.h"
+#include "Nodes.h"
+#include "NodeConstructors.h"
+
+#include "BytecodeGenerator.h"
+#include "CallFrame.h"
+#include "Debugger.h"
+#include "JIT.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "JSStaticScopeObject.h"
+#include "LabelScope.h"
+#include "Lexer.h"
+#include "Operations.h"
+#include "Parser.h"
+#include "PropertyNameArray.h"
+#include "RegExpObject.h"
+#include "SamplingTool.h"
+#include <wtf/Assertions.h>
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/Threading.h>
+
+using namespace WTF;
+
+namespace JSC {
+
+
+// ------------------------------ StatementNode --------------------------------
+
+void StatementNode::setLoc(int firstLine, int lastLine)
+{
+ m_lineNumber = firstLine;
+ m_lastLine = lastLine;
+}
+
+// ------------------------------ SourceElements --------------------------------
+
+void SourceElements::append(StatementNode* statement)
+{
+ if (statement->isEmptyStatement())
+ return;
+ m_statements.append(statement);
+}
+
+StatementNode* SourceElements::singleStatement() const
+{
+ size_t size = m_statements.size();
+ return size == 1 ? m_statements[0] : 0;
+}
+
+// -----------------------------ScopeNodeData ---------------------------
+
+ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, int numConstants)
+ : m_numConstants(numConstants)
+ , m_statements(statements)
+{
+ m_arena.swap(arena);
+ if (varStack)
+ m_varStack.swap(*varStack);
+ if (funcStack)
+ m_functionStack.swap(*funcStack);
+ m_capturedVariables.swap(capturedVariables);
+}
+
+// ------------------------------ ScopeNode -----------------------------
+
+ScopeNode::ScopeNode(JSGlobalData* globalData, int lineNumber, bool inStrictContext)
+ : StatementNode(lineNumber)
+ , ParserArenaRefCounted(globalData)
+ , m_features(inStrictContext ? StrictModeFeature : NoFeatures)
+{
+}
+
+ScopeNode::ScopeNode(JSGlobalData* globalData, int lineNumber, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, CodeFeatures features, int numConstants)
+ : StatementNode(lineNumber)
+ , ParserArenaRefCounted(globalData)
+ , m_data(adoptPtr(new ScopeNodeData(*globalData->parserArena, children, varStack, funcStack, capturedVariables, numConstants)))
+ , m_features(features)
+ , m_source(source)
+{
+}
+
+StatementNode* ScopeNode::singleStatement() const
+{
+ return m_data->m_statements ? m_data->m_statements->singleStatement() : 0;
+}
+
+// ------------------------------ ProgramNode -----------------------------
+
+inline ProgramNode::ProgramNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, lineNumber, source, children, varStack, funcStack, capturedVariables, features, numConstants)
+{
+}
+
+PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+{
+ RefPtr<ProgramNode> node = new ProgramNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, source, features, numConstants);
+
+ ASSERT(node->data()->m_arena.last() == node);
+ node->data()->m_arena.removeLast();
+ ASSERT(!node->data()->m_arena.contains(node.get()));
+
+ return node.release();
+}
+
+// ------------------------------ EvalNode -----------------------------
+
+inline EvalNode::EvalNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, lineNumber, source, children, varStack, funcStack, capturedVariables, features, numConstants)
+{
+}
+
+PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+{
+ RefPtr<EvalNode> node = new EvalNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, source, features, numConstants);
+
+ ASSERT(node->data()->m_arena.last() == node);
+ node->data()->m_arena.removeLast();
+ ASSERT(!node->data()->m_arena.contains(node.get()));
+
+ return node.release();
+}
+
+// ------------------------------ FunctionBodyNode -----------------------------
+
+FunctionParameters::FunctionParameters(ParameterNode* firstParameter)
+{
+ for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
+ append(parameter->ident());
+}
+
+inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, int lineNumber, bool inStrictContext)
+ : ScopeNode(globalData, lineNumber, inStrictContext)
+{
+}
+
+inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, lineNumber, sourceCode, children, varStack, funcStack, capturedVariables, features, numConstants)
+{
+}
+
+void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter, const Identifier& ident)
+{
+ setSource(source);
+ finishParsing(FunctionParameters::create(firstParameter), ident);
+}
+
+void FunctionBodyNode::finishParsing(PassRefPtr<FunctionParameters> parameters, const Identifier& ident)
+{
+ ASSERT(!source().isNull());
+ m_parameters = parameters;
+ m_ident = ident;
+}
+
+FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, int lineNumber, bool inStrictContext)
+{
+ return new FunctionBodyNode(globalData, lineNumber, inStrictContext);
+}
+
+PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, int lineNumber, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+{
+ RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, lineNumber, children, varStack, funcStack, capturedVariables, sourceCode, features, numConstants);
+
+ ASSERT(node->data()->m_arena.last() == node);
+ node->data()->m_arena.removeLast();
+ ASSERT(!node->data()->m_arena.contains(node.get()));
+
+ return node.release();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Nodes.h b/Source/JavaScriptCore/parser/Nodes.h
new file mode 100644
index 000000000..23f2cde9c
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -0,0 +1,1616 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Nodes_h
+#define Nodes_h
+
+#include "Error.h"
+#include "JITCode.h"
+#include "Opcode.h"
+#include "ParserArena.h"
+#include "ResultType.h"
+#include "SourceCode.h"
+#include "SymbolTable.h"
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+ class ArgumentListNode;
+ class BytecodeGenerator;
+ class FunctionBodyNode;
+ class Label;
+ class PropertyListNode;
+ class ReadModifyResolveNode;
+ class RegisterID;
+ class ScopeChainNode;
+ class ScopeNode;
+
+ typedef unsigned CodeFeatures;
+
+ const CodeFeatures NoFeatures = 0;
+ const CodeFeatures EvalFeature = 1 << 0;
+ const CodeFeatures ClosureFeature = 1 << 1;
+ const CodeFeatures AssignFeature = 1 << 2;
+ const CodeFeatures ArgumentsFeature = 1 << 3;
+ const CodeFeatures WithFeature = 1 << 4;
+ const CodeFeatures CatchFeature = 1 << 5;
+ const CodeFeatures ThisFeature = 1 << 6;
+ const CodeFeatures StrictModeFeature = 1 << 7;
+ const CodeFeatures ShadowsArgumentsFeature = 1 << 8;
+
+
+ const CodeFeatures AllFeatures = EvalFeature | ClosureFeature | AssignFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature | StrictModeFeature | ShadowsArgumentsFeature;
+
+ enum Operator {
+ OpEqual,
+ OpPlusEq,
+ OpMinusEq,
+ OpMultEq,
+ OpDivEq,
+ OpPlusPlus,
+ OpMinusMinus,
+ OpAndEq,
+ OpXOrEq,
+ OpOrEq,
+ OpModEq,
+ OpLShift,
+ OpRShift,
+ OpURShift
+ };
+
+ enum LogicalOperator {
+ OpLogicalAnd,
+ OpLogicalOr
+ };
+
+ typedef HashSet<RefPtr<StringImpl>, IdentifierRepHash> IdentifierSet;
+
+ namespace DeclarationStacks {
+ enum VarAttrs { IsConstant = 1, HasInitializer = 2 };
+ typedef Vector<std::pair<const Identifier*, unsigned> > VarStack;
+ typedef Vector<FunctionBodyNode*> FunctionStack;
+ }
+
+ struct SwitchInfo {
+ enum SwitchType { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString };
+ uint32_t bytecodeOffset;
+ SwitchType switchType;
+ };
+
+ class ParserArenaFreeable {
+ public:
+ // ParserArenaFreeable objects are are freed when the arena is deleted.
+ // Destructors are not called. Clients must not call delete on such objects.
+ void* operator new(size_t, JSGlobalData*);
+ };
+
+ class ParserArenaDeletable {
+ public:
+ virtual ~ParserArenaDeletable() { }
+
+ // ParserArenaDeletable objects are deleted when the arena is deleted.
+ // Clients must not call delete directly on such objects.
+ void* operator new(size_t, JSGlobalData*);
+ };
+
+ template <typename T>
+ struct ParserArenaData : ParserArenaDeletable {
+ T data;
+ };
+
+ class ParserArenaRefCounted : public RefCounted<ParserArenaRefCounted> {
+ protected:
+ ParserArenaRefCounted(JSGlobalData*);
+
+ public:
+ virtual ~ParserArenaRefCounted()
+ {
+ ASSERT(deletionHasBegun());
+ }
+ };
+
+ class Node : public ParserArenaFreeable {
+ protected:
+ Node(int);
+
+ public:
+ virtual ~Node() { }
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* destination = 0) = 0;
+
+ int lineNo() const { return m_lineNumber; }
+
+ protected:
+ int m_lineNumber;
+ };
+
+ class ExpressionNode : public Node {
+ protected:
+ ExpressionNode(int, ResultType = ResultType::unknownType());
+
+ public:
+ virtual bool isNumber() const { return false; }
+ virtual bool isString() const { return false; }
+ virtual bool isNull() const { return false; }
+ virtual bool isPure(BytecodeGenerator&) const { return false; }
+ virtual bool isLocation() const { return false; }
+ virtual bool isResolveNode() const { return false; }
+ virtual bool isBracketAccessorNode() const { return false; }
+ virtual bool isDotAccessorNode() const { return false; }
+ virtual bool isFuncExprNode() const { return false; }
+ virtual bool isCommaNode() const { return false; }
+ virtual bool isSimpleArray() const { return false; }
+ virtual bool isAdd() const { return false; }
+ virtual bool isSubtract() const { return false; }
+ virtual bool hasConditionContextCodegen() const { return false; }
+
+ virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, bool) { ASSERT_NOT_REACHED(); }
+
+ virtual ExpressionNode* stripUnaryPlus() { return this; }
+
+ ResultType resultDescriptor() const { return m_resultType; }
+
+ private:
+ ResultType m_resultType;
+ };
+
+ class StatementNode : public Node {
+ protected:
+ StatementNode(int);
+
+ public:
+ void setLoc(int firstLine, int lastLine);
+ int firstLine() const { return lineNo(); }
+ int lastLine() const { return m_lastLine; }
+
+ virtual bool isEmptyStatement() const { return false; }
+ virtual bool isReturnNode() const { return false; }
+ virtual bool isExprStatement() const { return false; }
+
+ virtual bool isBlock() const { return false; }
+
+ private:
+ int m_lastLine;
+ };
+
+ class NullNode : public ExpressionNode {
+ public:
+ NullNode(int);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isNull() const { return true; }
+ };
+
+ class BooleanNode : public ExpressionNode {
+ public:
+ BooleanNode(int, bool value);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isPure(BytecodeGenerator&) const { return true; }
+
+ bool m_value;
+ };
+
+ class NumberNode : public ExpressionNode {
+ public:
+ NumberNode(int, double value);
+
+ double value() const { return m_value; }
+ void setValue(double value) { m_value = value; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isNumber() const { return true; }
+ virtual bool isPure(BytecodeGenerator&) const { return true; }
+
+ double m_value;
+ };
+
+ class StringNode : public ExpressionNode {
+ public:
+ StringNode(int, const Identifier&);
+
+ const Identifier& value() { return m_value; }
+
+ private:
+ virtual bool isPure(BytecodeGenerator&) const { return true; }
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isString() const { return true; }
+
+ const Identifier& m_value;
+ };
+
+ class ThrowableExpressionData {
+ public:
+ ThrowableExpressionData()
+ : m_divot(static_cast<uint32_t>(-1))
+ , m_startOffset(static_cast<uint16_t>(-1))
+ , m_endOffset(static_cast<uint16_t>(-1))
+ {
+ }
+
+ ThrowableExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+ : m_divot(divot)
+ , m_startOffset(startOffset)
+ , m_endOffset(endOffset)
+ {
+ }
+
+ void setExceptionSourceCode(unsigned divot, unsigned startOffset, unsigned endOffset)
+ {
+ m_divot = divot;
+ m_startOffset = startOffset;
+ m_endOffset = endOffset;
+ }
+
+ uint32_t divot() const { return m_divot; }
+ uint16_t startOffset() const { return m_startOffset; }
+ uint16_t endOffset() const { return m_endOffset; }
+
+ protected:
+ RegisterID* emitThrowReferenceError(BytecodeGenerator&, const UString& message);
+
+ private:
+ uint32_t m_divot;
+ uint16_t m_startOffset;
+ uint16_t m_endOffset;
+ };
+
+ class ThrowableSubExpressionData : public ThrowableExpressionData {
+ public:
+ ThrowableSubExpressionData()
+ : m_subexpressionDivotOffset(0)
+ , m_subexpressionEndOffset(0)
+ {
+ }
+
+ ThrowableSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionEndOffset(0)
+ {
+ }
+
+ void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset)
+ {
+ ASSERT(subexpressionDivot <= divot());
+ if ((divot() - subexpressionDivot) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot
+ return;
+ m_subexpressionDivotOffset = divot() - subexpressionDivot;
+ m_subexpressionEndOffset = subexpressionOffset;
+ }
+
+ protected:
+ uint16_t m_subexpressionDivotOffset;
+ uint16_t m_subexpressionEndOffset;
+ };
+
+ class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData {
+ public:
+ ThrowablePrefixedSubExpressionData()
+ : m_subexpressionDivotOffset(0)
+ , m_subexpressionStartOffset(0)
+ {
+ }
+
+ ThrowablePrefixedSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionStartOffset(0)
+ {
+ }
+
+ void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset)
+ {
+ ASSERT(subexpressionDivot >= divot());
+ if ((subexpressionDivot - divot()) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot
+ return;
+ m_subexpressionDivotOffset = subexpressionDivot - divot();
+ m_subexpressionStartOffset = subexpressionOffset;
+ }
+
+ protected:
+ uint16_t m_subexpressionDivotOffset;
+ uint16_t m_subexpressionStartOffset;
+ };
+
+ class RegExpNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ RegExpNode(int, const Identifier& pattern, const Identifier& flags);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_pattern;
+ const Identifier& m_flags;
+ };
+
+ class ThisNode : public ExpressionNode {
+ public:
+ ThisNode(int);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ResolveNode : public ExpressionNode {
+ public:
+ ResolveNode(int, const Identifier&, int startOffset);
+
+ const Identifier& identifier() const { return m_ident; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isPure(BytecodeGenerator&) const ;
+ virtual bool isLocation() const { return true; }
+ virtual bool isResolveNode() const { return true; }
+
+ const Identifier& m_ident;
+ int32_t m_startOffset;
+ };
+
+ class ElementNode : public ParserArenaFreeable {
+ public:
+ ElementNode(int elision, ExpressionNode*);
+ ElementNode(ElementNode*, int elision, ExpressionNode*);
+
+ int elision() const { return m_elision; }
+ ExpressionNode* value() { return m_node; }
+ ElementNode* next() { return m_next; }
+
+ private:
+ ElementNode* m_next;
+ int m_elision;
+ ExpressionNode* m_node;
+ };
+
+ class ArrayNode : public ExpressionNode {
+ public:
+ ArrayNode(int, int elision);
+ ArrayNode(int, ElementNode*);
+ ArrayNode(int, int elision, ElementNode*);
+
+ ArgumentListNode* toArgumentList(JSGlobalData*, int) const;
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isSimpleArray() const ;
+
+ ElementNode* m_element;
+ int m_elision;
+ bool m_optional;
+ };
+
+ class PropertyNode : public ParserArenaFreeable {
+ public:
+ enum Type { Constant = 1, Getter = 2, Setter = 4 };
+
+ PropertyNode(JSGlobalData*, const Identifier&, ExpressionNode*, Type);
+ PropertyNode(JSGlobalData*, double, ExpressionNode*, Type);
+
+ const Identifier& name() const { return m_name; }
+ Type type() const { return m_type; }
+
+ private:
+ friend class PropertyListNode;
+ const Identifier& m_name;
+ ExpressionNode* m_assign;
+ Type m_type;
+ };
+
+ class PropertyListNode : public Node {
+ public:
+ PropertyListNode(int, PropertyNode*);
+ PropertyListNode(int, PropertyNode*, PropertyListNode*);
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ private:
+ PropertyNode* m_node;
+ PropertyListNode* m_next;
+ };
+
+ class ObjectLiteralNode : public ExpressionNode {
+ public:
+ ObjectLiteralNode(int);
+ ObjectLiteralNode(int, PropertyListNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ PropertyListNode* m_list;
+ };
+
+ class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ BracketAccessorNode(int, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments);
+
+ ExpressionNode* base() const { return m_base; }
+ ExpressionNode* subscript() const { return m_subscript; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isLocation() const { return true; }
+ virtual bool isBracketAccessorNode() const { return true; }
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ bool m_subscriptHasAssignments;
+ };
+
+ class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DotAccessorNode(int, ExpressionNode* base, const Identifier&);
+
+ ExpressionNode* base() const { return m_base; }
+ const Identifier& identifier() const { return m_ident; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isLocation() const { return true; }
+ virtual bool isDotAccessorNode() const { return true; }
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ };
+
+ class ArgumentListNode : public Node {
+ public:
+ ArgumentListNode(int, ExpressionNode*);
+ ArgumentListNode(int, ArgumentListNode*, ExpressionNode*);
+
+ ArgumentListNode* m_next;
+ ExpressionNode* m_expr;
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ArgumentsNode : public ParserArenaFreeable {
+ public:
+ ArgumentsNode();
+ ArgumentsNode(ArgumentListNode*);
+
+ ArgumentListNode* m_listNode;
+ };
+
+ class NewExprNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ NewExprNode(int, ExpressionNode*);
+ NewExprNode(int, ExpressionNode*, ArgumentsNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ ArgumentsNode* m_args;
+ };
+
+ class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ EvalFunctionCallNode(int, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ArgumentsNode* m_args;
+ };
+
+ class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ FunctionCallValueNode(int, ExpressionNode*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ ArgumentsNode* m_args;
+ };
+
+ class FunctionCallResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ FunctionCallResolveNode(int, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ ArgumentsNode* m_args;
+ size_t m_index; // Used by LocalVarFunctionCallNode.
+ size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode
+ };
+
+ class FunctionCallBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ FunctionCallBracketNode(int, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ ArgumentsNode* m_args;
+ };
+
+ class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ FunctionCallDotNode(int, ExpressionNode* base, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ protected:
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ ArgumentsNode* m_args;
+ };
+
+ class CallFunctionCallDotNode : public FunctionCallDotNode {
+ public:
+ CallFunctionCallDotNode(int, ExpressionNode* base, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ApplyFunctionCallDotNode : public FunctionCallDotNode {
+ public:
+ ApplyFunctionCallDotNode(int, ExpressionNode* base, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ PrePostResolveNode(int, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ protected:
+ const Identifier& m_ident;
+ };
+
+ class PostfixResolveNode : public PrePostResolveNode {
+ public:
+ PostfixResolveNode(int, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ Operator m_operator;
+ };
+
+ class PostfixBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ PostfixBracketNode(int, ExpressionNode* base, ExpressionNode* subscript, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ Operator m_operator;
+ };
+
+ class PostfixDotNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ PostfixDotNode(int, ExpressionNode* base, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ Operator m_operator;
+ };
+
+ class PostfixErrorNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ PostfixErrorNode(int, ExpressionNode*, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ Operator m_operator;
+ };
+
+ class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DeleteResolveNode(int, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ };
+
+ class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DeleteBracketNode(int, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ };
+
+ class DeleteDotNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ DeleteDotNode(int, ExpressionNode* base, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ };
+
+ class DeleteValueNode : public ExpressionNode {
+ public:
+ DeleteValueNode(int, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class VoidNode : public ExpressionNode {
+ public:
+ VoidNode(int, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class TypeOfResolveNode : public ExpressionNode {
+ public:
+ TypeOfResolveNode(int, const Identifier&);
+
+ const Identifier& identifier() const { return m_ident; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ };
+
+ class TypeOfValueNode : public ExpressionNode {
+ public:
+ TypeOfValueNode(int, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class PrefixResolveNode : public PrePostResolveNode {
+ public:
+ PrefixResolveNode(int, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ Operator m_operator;
+ };
+
+ class PrefixBracketNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData {
+ public:
+ PrefixBracketNode(int, ExpressionNode* base, ExpressionNode* subscript, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ Operator m_operator;
+ };
+
+ class PrefixDotNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData {
+ public:
+ PrefixDotNode(int, ExpressionNode* base, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ Operator m_operator;
+ };
+
+ class PrefixErrorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ PrefixErrorNode(int, ExpressionNode*, Operator, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ Operator m_operator;
+ };
+
+ class UnaryOpNode : public ExpressionNode {
+ public:
+ UnaryOpNode(int, ResultType, ExpressionNode*, OpcodeID);
+
+ protected:
+ ExpressionNode* expr() { return m_expr; }
+ const ExpressionNode* expr() const { return m_expr; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ OpcodeID opcodeID() const { return m_opcodeID; }
+
+ ExpressionNode* m_expr;
+ OpcodeID m_opcodeID;
+ };
+
+ class UnaryPlusNode : public UnaryOpNode {
+ public:
+ UnaryPlusNode(int, ExpressionNode*);
+
+ private:
+ virtual ExpressionNode* stripUnaryPlus() { return expr(); }
+ };
+
+ class NegateNode : public UnaryOpNode {
+ public:
+ NegateNode(int, ExpressionNode*);
+ };
+
+ class BitwiseNotNode : public UnaryOpNode {
+ public:
+ BitwiseNotNode(int, ExpressionNode*);
+ };
+
+ class LogicalNotNode : public UnaryOpNode {
+ public:
+ LogicalNotNode(int, ExpressionNode*);
+ private:
+ void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue);
+ virtual bool hasConditionContextCodegen() const { return expr()->hasConditionContextCodegen(); }
+ };
+
+ class BinaryOpNode : public ExpressionNode {
+ public:
+ BinaryOpNode(int, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+ BinaryOpNode(int, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+
+ RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* destination, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0);
+
+ ExpressionNode* lhs() { return m_expr1; };
+ ExpressionNode* rhs() { return m_expr2; };
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ protected:
+ OpcodeID opcodeID() const { return m_opcodeID; }
+
+ protected:
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ private:
+ OpcodeID m_opcodeID;
+ protected:
+ bool m_rightHasAssignments;
+ };
+
+ class MultNode : public BinaryOpNode {
+ public:
+ MultNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class DivNode : public BinaryOpNode {
+ public:
+ DivNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class ModNode : public BinaryOpNode {
+ public:
+ ModNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class AddNode : public BinaryOpNode {
+ public:
+ AddNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ virtual bool isAdd() const { return true; }
+ };
+
+ class SubNode : public BinaryOpNode {
+ public:
+ SubNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ virtual bool isSubtract() const { return true; }
+ };
+
+ class LeftShiftNode : public BinaryOpNode {
+ public:
+ LeftShiftNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class RightShiftNode : public BinaryOpNode {
+ public:
+ RightShiftNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class UnsignedRightShiftNode : public BinaryOpNode {
+ public:
+ UnsignedRightShiftNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class LessNode : public BinaryOpNode {
+ public:
+ LessNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class GreaterNode : public BinaryOpNode {
+ public:
+ GreaterNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class LessEqNode : public BinaryOpNode {
+ public:
+ LessEqNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class GreaterEqNode : public BinaryOpNode {
+ public:
+ GreaterEqNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData {
+ public:
+ ThrowableBinaryOpNode(int, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+ ThrowableBinaryOpNode(int, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class InstanceOfNode : public ThrowableBinaryOpNode {
+ public:
+ InstanceOfNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class InNode : public ThrowableBinaryOpNode {
+ public:
+ InNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class EqualNode : public BinaryOpNode {
+ public:
+ EqualNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class NotEqualNode : public BinaryOpNode {
+ public:
+ NotEqualNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class StrictEqualNode : public BinaryOpNode {
+ public:
+ StrictEqualNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class NotStrictEqualNode : public BinaryOpNode {
+ public:
+ NotStrictEqualNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitAndNode : public BinaryOpNode {
+ public:
+ BitAndNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitOrNode : public BinaryOpNode {
+ public:
+ BitOrNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitXOrNode : public BinaryOpNode {
+ public:
+ BitXOrNode(int, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ // m_expr1 && m_expr2, m_expr1 || m_expr2
+ class LogicalOpNode : public ExpressionNode {
+ public:
+ LogicalOpNode(int, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue);
+ virtual bool hasConditionContextCodegen() const { return true; }
+
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ LogicalOperator m_operator;
+ };
+
+ // The ternary operator, "m_logical ? m_expr1 : m_expr2"
+ class ConditionalNode : public ExpressionNode {
+ public:
+ ConditionalNode(int, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_logical;
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ };
+
+ class ReadModifyResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ ReadModifyResolveNode(int, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ size_t m_index; // Used by ReadModifyLocalVarNode.
+ Operator m_operator;
+ bool m_rightHasAssignments;
+ };
+
+ class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignResolveNode(int, const Identifier&, ExpressionNode* right, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ size_t m_index; // Used by ReadModifyLocalVarNode.
+ bool m_rightHasAssignments;
+ };
+
+ class ReadModifyBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ ReadModifyBracketNode(int, ExpressionNode* base, ExpressionNode* subscript, Operator, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ ExpressionNode* m_right;
+ Operator m_operator : 30;
+ bool m_subscriptHasAssignments : 1;
+ bool m_rightHasAssignments : 1;
+ };
+
+ class AssignBracketNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignBracketNode(int, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ ExpressionNode* m_subscript;
+ ExpressionNode* m_right;
+ bool m_subscriptHasAssignments : 1;
+ bool m_rightHasAssignments : 1;
+ };
+
+ class AssignDotNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignDotNode(int, ExpressionNode* base, const Identifier&, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ bool m_rightHasAssignments;
+ };
+
+ class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData {
+ public:
+ ReadModifyDotNode(int, ExpressionNode* base, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_base;
+ const Identifier& m_ident;
+ ExpressionNode* m_right;
+ Operator m_operator : 31;
+ bool m_rightHasAssignments : 1;
+ };
+
+ class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ AssignErrorNode(int, ExpressionNode* left, Operator, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_left;
+ Operator m_operator;
+ ExpressionNode* m_right;
+ };
+
+ typedef Vector<ExpressionNode*, 8> ExpressionVector;
+
+ class CommaNode : public ExpressionNode, public ParserArenaDeletable {
+ public:
+ CommaNode(int, ExpressionNode* expr1, ExpressionNode* expr2);
+
+ using ParserArenaDeletable::operator new;
+
+ void append(ExpressionNode* expr) { m_expressions.append(expr); }
+
+ private:
+ virtual bool isCommaNode() const { return true; }
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionVector m_expressions;
+ };
+
+ class ConstDeclNode : public ExpressionNode {
+ public:
+ ConstDeclNode(int, const Identifier&, ExpressionNode*);
+
+ bool hasInitializer() const { return m_init; }
+ const Identifier& ident() { return m_ident; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ virtual RegisterID* emitCodeSingle(BytecodeGenerator&);
+
+ const Identifier& m_ident;
+
+ public:
+ ConstDeclNode* m_next;
+
+ private:
+ ExpressionNode* m_init;
+ };
+
+ class ConstStatementNode : public StatementNode {
+ public:
+ ConstStatementNode(int, ConstDeclNode* next);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ConstDeclNode* m_next;
+ };
+
+ class SourceElements : public ParserArenaDeletable {
+ public:
+ SourceElements();
+
+ void append(StatementNode*);
+
+ StatementNode* singleStatement() const;
+ StatementNode* lastStatement() const;
+
+ void emitBytecode(BytecodeGenerator&, RegisterID* destination);
+
+ private:
+ Vector<StatementNode*> m_statements;
+ };
+
+ class BlockNode : public StatementNode {
+ public:
+ BlockNode(int, SourceElements* = 0);
+
+ StatementNode* singleStatement() const;
+ StatementNode* lastStatement() const;
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isBlock() const { return true; }
+
+ SourceElements* m_statements;
+ };
+
+ class EmptyStatementNode : public StatementNode {
+ public:
+ EmptyStatementNode(int);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isEmptyStatement() const { return true; }
+ };
+
+ class DebuggerStatementNode : public StatementNode {
+ public:
+ DebuggerStatementNode(int);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ExprStatementNode : public StatementNode {
+ public:
+ ExprStatementNode(int, ExpressionNode*);
+
+ ExpressionNode* expr() const { return m_expr; }
+
+ private:
+ virtual bool isExprStatement() const { return true; }
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class VarStatementNode : public StatementNode {
+ public:
+ VarStatementNode(int, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class IfNode : public StatementNode {
+ public:
+ IfNode(int, ExpressionNode* condition, StatementNode* ifBlock);
+
+ protected:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_condition;
+ StatementNode* m_ifBlock;
+ };
+
+ class IfElseNode : public IfNode {
+ public:
+ IfElseNode(int, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ StatementNode* m_elseBlock;
+ };
+
+ class DoWhileNode : public StatementNode {
+ public:
+ DoWhileNode(int, StatementNode*, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ StatementNode* m_statement;
+ ExpressionNode* m_expr;
+ };
+
+ class WhileNode : public StatementNode {
+ public:
+ WhileNode(int, ExpressionNode*, StatementNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ StatementNode* m_statement;
+ };
+
+ class ForNode : public StatementNode {
+ public:
+ ForNode(int, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode*, bool expr1WasVarDecl);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr1;
+ ExpressionNode* m_expr2;
+ ExpressionNode* m_expr3;
+ StatementNode* m_statement;
+ bool m_expr1WasVarDecl;
+ };
+
+ class ForInNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ForInNode(JSGlobalData*, int, ExpressionNode*, ExpressionNode*, StatementNode*);
+ ForInNode(JSGlobalData*, int, const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*, int divot, int startOffset, int endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ ExpressionNode* m_init;
+ ExpressionNode* m_lexpr;
+ ExpressionNode* m_expr;
+ StatementNode* m_statement;
+ bool m_identIsVarDecl;
+ };
+
+ class ContinueNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ContinueNode(JSGlobalData*, int);
+ ContinueNode(int, const Identifier&);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ };
+
+ class BreakNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ BreakNode(JSGlobalData*, int);
+ BreakNode(int, const Identifier&);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ };
+
+ class ReturnNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ReturnNode(int, ExpressionNode* value);
+
+ ExpressionNode* value() { return m_value; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isReturnNode() const { return true; }
+
+ ExpressionNode* m_value;
+ };
+
+ class WithNode : public StatementNode {
+ public:
+ WithNode(int, ExpressionNode*, StatementNode*, uint32_t divot, uint32_t expressionLength);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ StatementNode* m_statement;
+ uint32_t m_divot;
+ uint32_t m_expressionLength;
+ };
+
+ class LabelNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ LabelNode(int, const Identifier& name, StatementNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_name;
+ StatementNode* m_statement;
+ };
+
+ class ThrowNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ThrowNode(int, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class TryNode : public StatementNode {
+ public:
+ TryNode(int, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ StatementNode* m_tryBlock;
+ const Identifier& m_exceptionIdent;
+ StatementNode* m_catchBlock;
+ StatementNode* m_finallyBlock;
+ bool m_catchHasEval;
+ };
+
+ class ParameterNode : public ParserArenaFreeable {
+ public:
+ ParameterNode(const Identifier&);
+ ParameterNode(ParameterNode*, const Identifier&);
+
+ const Identifier& ident() const { return m_ident; }
+ ParameterNode* nextParam() const { return m_next; }
+
+ private:
+ const Identifier& m_ident;
+ ParameterNode* m_next;
+ };
+
+ struct ScopeNodeData {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ typedef DeclarationStacks::VarStack VarStack;
+ typedef DeclarationStacks::FunctionStack FunctionStack;
+
+ ScopeNodeData(ParserArena&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, int numConstants);
+
+ ParserArena m_arena;
+ VarStack m_varStack;
+ FunctionStack m_functionStack;
+ int m_numConstants;
+ SourceElements* m_statements;
+ IdentifierSet m_capturedVariables;
+ };
+
+ class ScopeNode : public StatementNode, public ParserArenaRefCounted {
+ public:
+ typedef DeclarationStacks::VarStack VarStack;
+ typedef DeclarationStacks::FunctionStack FunctionStack;
+
+ ScopeNode(JSGlobalData*, int, bool inStrictContext);
+ ScopeNode(JSGlobalData*, int, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, CodeFeatures, int numConstants);
+
+ using ParserArenaRefCounted::operator new;
+
+ ScopeNodeData* data() const { return m_data.get(); }
+ void destroyData() { m_data.clear(); }
+
+ const SourceCode& source() const { return m_source; }
+ const UString& sourceURL() const { return m_source.provider()->url(); }
+ intptr_t sourceID() const { return m_source.provider()->asID(); }
+
+ void setFeatures(CodeFeatures features) { m_features = features; }
+ CodeFeatures features() { return m_features; }
+
+ bool usesEval() const { return m_features & EvalFeature; }
+ bool usesArguments() const { return (m_features & ArgumentsFeature) && !(m_features & ShadowsArgumentsFeature); }
+ bool isStrictMode() const { return m_features & StrictModeFeature; }
+ void setUsesArguments() { m_features |= ArgumentsFeature; }
+ bool usesThis() const { return m_features & ThisFeature; }
+ bool needsActivationForMoreThanVariables() const { ASSERT(m_data); return m_features & (EvalFeature | WithFeature | CatchFeature); }
+ bool needsActivation() const { ASSERT(m_data); return (hasCapturedVariables()) || (m_features & (EvalFeature | WithFeature | CatchFeature)); }
+ bool hasCapturedVariables() const { return !!m_data->m_capturedVariables.size(); }
+ size_t capturedVariableCount() const { return m_data->m_capturedVariables.size(); }
+ bool captures(const Identifier& ident) { return m_data->m_capturedVariables.contains(ident.impl()); }
+
+ VarStack& varStack() { ASSERT(m_data); return m_data->m_varStack; }
+ FunctionStack& functionStack() { ASSERT(m_data); return m_data->m_functionStack; }
+
+ int neededConstants()
+ {
+ ASSERT(m_data);
+ // We may need 2 more constants than the count given by the parser,
+ // because of the various uses of jsUndefined() and jsNull().
+ return m_data->m_numConstants + 2;
+ }
+
+ StatementNode* singleStatement() const;
+
+ void emitStatementsBytecode(BytecodeGenerator&, RegisterID* destination);
+
+ protected:
+ void setSource(const SourceCode& source) { m_source = source; }
+
+ private:
+ OwnPtr<ScopeNodeData> m_data;
+ CodeFeatures m_features;
+ SourceCode m_source;
+ };
+
+ class ProgramNode : public ScopeNode {
+ public:
+ static const bool isFunctionNode = false;
+ static PassRefPtr<ProgramNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ static const bool scopeIsFunction = false;
+
+ private:
+ ProgramNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class EvalNode : public ScopeNode {
+ public:
+ static const bool isFunctionNode = false;
+ static PassRefPtr<EvalNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ static const bool scopeIsFunction = false;
+
+ private:
+ EvalNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class FunctionParameters : public Vector<Identifier>, public RefCounted<FunctionParameters> {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ static PassRefPtr<FunctionParameters> create(ParameterNode* firstParameter) { return adoptRef(new FunctionParameters(firstParameter)); }
+
+ private:
+ FunctionParameters(ParameterNode*);
+ };
+
+ class FunctionBodyNode : public ScopeNode {
+ public:
+ static const bool isFunctionNode = true;
+ static FunctionBodyNode* create(JSGlobalData*, int, bool isStrictMode);
+ static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ FunctionParameters* parameters() const { return m_parameters.get(); }
+ size_t parameterCount() const { return m_parameters->size(); }
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ void finishParsing(const SourceCode&, ParameterNode*, const Identifier&);
+ void finishParsing(PassRefPtr<FunctionParameters>, const Identifier&);
+
+ const Identifier& ident() { return m_ident; }
+
+ static const bool scopeIsFunction = true;
+
+ private:
+ FunctionBodyNode(JSGlobalData*, int, bool inStrictContext);
+ FunctionBodyNode(JSGlobalData*, int, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ Identifier m_ident;
+ RefPtr<FunctionParameters> m_parameters;
+ };
+
+ class FuncExprNode : public ExpressionNode {
+ public:
+ FuncExprNode(int, const Identifier&, FunctionBodyNode*, const SourceCode&, ParameterNode* = 0);
+
+ FunctionBodyNode* body() { return m_body; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isFuncExprNode() const { return true; }
+
+ FunctionBodyNode* m_body;
+ };
+
+ class FuncDeclNode : public StatementNode {
+ public:
+ FuncDeclNode(int, const Identifier&, FunctionBodyNode*, const SourceCode&, ParameterNode* = 0);
+
+ FunctionBodyNode* body() { return m_body; }
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ FunctionBodyNode* m_body;
+ };
+
+ class CaseClauseNode : public ParserArenaFreeable {
+ public:
+ CaseClauseNode(ExpressionNode*, SourceElements* = 0);
+
+ ExpressionNode* expr() const { return m_expr; }
+
+ void emitBytecode(BytecodeGenerator&, RegisterID* destination);
+
+ private:
+ ExpressionNode* m_expr;
+ SourceElements* m_statements;
+ };
+
+ class ClauseListNode : public ParserArenaFreeable {
+ public:
+ ClauseListNode(CaseClauseNode*);
+ ClauseListNode(ClauseListNode*, CaseClauseNode*);
+
+ CaseClauseNode* getClause() const { return m_clause; }
+ ClauseListNode* getNext() const { return m_next; }
+
+ private:
+ CaseClauseNode* m_clause;
+ ClauseListNode* m_next;
+ };
+
+ class CaseBlockNode : public ParserArenaFreeable {
+ public:
+ CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2);
+
+ RegisterID* emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* destination);
+
+ private:
+ SwitchInfo::SwitchType tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num);
+ ClauseListNode* m_list1;
+ CaseClauseNode* m_defaultClause;
+ ClauseListNode* m_list2;
+ };
+
+ class SwitchNode : public StatementNode {
+ public:
+ SwitchNode(int, ExpressionNode*, CaseBlockNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ CaseBlockNode* m_block;
+ };
+
+ struct ElementList {
+ ElementNode* head;
+ ElementNode* tail;
+ };
+
+ struct PropertyList {
+ PropertyListNode* head;
+ PropertyListNode* tail;
+ };
+
+ struct ArgumentList {
+ ArgumentListNode* head;
+ ArgumentListNode* tail;
+ };
+
+ struct ConstDeclList {
+ ConstDeclNode* head;
+ ConstDeclNode* tail;
+ };
+
+ struct ParameterList {
+ ParameterNode* head;
+ ParameterNode* tail;
+ };
+
+ struct ClauseList {
+ ClauseListNode* head;
+ ClauseListNode* tail;
+ };
+
+} // namespace JSC
+
+#endif // Nodes_h
diff --git a/Source/JavaScriptCore/parser/Parser.cpp b/Source/JavaScriptCore/parser/Parser.cpp
new file mode 100644
index 000000000..7fb285a6b
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -0,0 +1,1672 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Parser.h"
+
+#include "ASTBuilder.h"
+#include "CodeBlock.h"
+#include "Debugger.h"
+#include "JSGlobalData.h"
+#include "Lexer.h"
+#include "NodeInfo.h"
+#include "SourceProvider.h"
+#include "SourceProviderCacheItem.h"
+#include <utility>
+#include <wtf/HashFunctions.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/WTFThreadData.h>
+
+using namespace std;
+
+namespace JSC {
+
+template <typename LexerType>
+Parser<LexerType>::Parser(JSGlobalData* globalData, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode)
+ : m_globalData(globalData)
+ , m_source(&source)
+ , m_stack(globalData->stack())
+ , m_error(false)
+ , m_errorMessage("Parse error")
+ , m_allowsIn(true)
+ , m_lastLine(0)
+ , m_lastTokenEnd(0)
+ , m_assignmentCount(0)
+ , m_nonLHSCount(0)
+ , m_syntaxAlreadyValidated(source.provider()->isValid())
+ , m_statementDepth(0)
+ , m_nonTrivialExpressionCount(0)
+ , m_lastIdentifier(0)
+ , m_sourceElements(0)
+{
+ m_lexer = adoptPtr(new LexerType(globalData));
+ m_arena = m_globalData->parserArena.get();
+ m_lexer->setCode(source, m_arena);
+
+ m_functionCache = source.provider()->cache();
+ ScopeRef scope = pushScope();
+ if (parserMode == JSParseFunctionCode)
+ scope->setIsFunction();
+ if (strictness == JSParseStrict)
+ scope->setStrictMode();
+ if (parameters) {
+ for (unsigned i = 0; i < parameters->size(); i++)
+ scope->declareParameter(&parameters->at(i));
+ }
+ next();
+ m_lexer->setLastLineNumber(tokenLine());
+}
+
+template <typename LexerType>
+Parser<LexerType>::~Parser()
+{
+}
+
+template <typename LexerType>
+UString Parser<LexerType>::parseInner()
+{
+ UString parseError = UString();
+
+ unsigned oldFunctionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
+ ASTBuilder context(const_cast<JSGlobalData*>(m_globalData), const_cast<SourceCode*>(m_source));
+ if (m_lexer->isReparsing())
+ m_statementDepth--;
+ ScopeRef scope = currentScope();
+ SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
+ if (!sourceElements || !consume(EOFTOK))
+ parseError = m_errorMessage;
+
+ IdentifierSet capturedVariables;
+ scope->getCapturedVariables(capturedVariables);
+ CodeFeatures features = context.features();
+ if (scope->strictMode())
+ features |= StrictModeFeature;
+ if (scope->shadowsArguments())
+ features |= ShadowsArgumentsFeature;
+ unsigned functionCacheSize = m_functionCache ? m_functionCache->byteSize() : 0;
+ if (functionCacheSize != oldFunctionCacheSize)
+ m_lexer->sourceProvider()->notifyCacheSizeChanged(functionCacheSize - oldFunctionCacheSize);
+
+ didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
+ m_lastLine, context.numConstants(), capturedVariables);
+
+ return parseError;
+}
+
+template <typename LexerType>
+void Parser<LexerType>::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack,
+ ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants, IdentifierSet& capturedVars)
+{
+ m_sourceElements = sourceElements;
+ m_varDeclarations = varStack;
+ m_funcDeclarations = funcStack;
+ m_capturedVariables.swap(capturedVars);
+ m_features = features;
+ m_lastLine = lastLine;
+ m_numConstants = numConstants;
+}
+
+template <typename LexerType>
+bool Parser<LexerType>::allowAutomaticSemicolon()
+{
+ return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
+}
+
+template <typename LexerType>
+template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements Parser<LexerType>::parseSourceElements(TreeBuilder& context)
+{
+ const unsigned lengthOfUseStrictLiteral = 12; // "use strict".length
+ TreeSourceElements sourceElements = context.createSourceElements();
+ bool seenNonDirective = false;
+ const Identifier* directive = 0;
+ unsigned directiveLiteralLength = 0;
+ unsigned startOffset = m_token.m_info.startOffset;
+ unsigned oldLastLineNumber = m_lexer->lastLineNumber();
+ unsigned oldLineNumber = m_lexer->lineNumber();
+ bool hasSetStrict = false;
+ while (TreeStatement statement = parseStatement(context, directive, &directiveLiteralLength)) {
+ if (mode == CheckForStrictMode && !seenNonDirective) {
+ if (directive) {
+ // "use strict" must be the exact literal without escape sequences or line continuation.
+ if (!hasSetStrict && directiveLiteralLength == lengthOfUseStrictLiteral && m_globalData->propertyNames->useStrictIdentifier == *directive) {
+ setStrictMode();
+ hasSetStrict = true;
+ failIfFalse(isValidStrictMode());
+ m_lexer->setOffset(startOffset);
+ next();
+ m_lexer->setLastLineNumber(oldLastLineNumber);
+ m_lexer->setLineNumber(oldLineNumber);
+ failIfTrue(m_error);
+ continue;
+ }
+ } else
+ seenNonDirective = true;
+ }
+ context.appendStatement(sourceElements, statement);
+ }
+
+ if (m_error)
+ fail();
+ return sourceElements;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseVarDeclaration(TreeBuilder& context)
+{
+ ASSERT(match(VAR));
+ int start = tokenLine();
+ int end = 0;
+ int scratch;
+ const Identifier* scratch1 = 0;
+ TreeExpression scratch2 = 0;
+ int scratch3 = 0;
+ TreeExpression varDecls = parseVarDeclarationList(context, scratch, scratch1, scratch2, scratch3, scratch3, scratch3);
+ failIfTrue(m_error);
+ failIfFalse(autoSemiColon());
+
+ return context.createVarStatement(m_lexer->lastLineNumber(), varDecls, start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseConstDeclaration(TreeBuilder& context)
+{
+ ASSERT(match(CONSTTOKEN));
+ int start = tokenLine();
+ int end = 0;
+ TreeConstDeclList constDecls = parseConstDeclarationList(context);
+ failIfTrue(m_error);
+ failIfFalse(autoSemiColon());
+
+ return context.createConstStatement(m_lexer->lastLineNumber(), constDecls, start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDoWhileStatement(TreeBuilder& context)
+{
+ ASSERT(match(DO));
+ int startLine = tokenLine();
+ next();
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+ int endLine = tokenLine();
+ consumeOrFail(WHILE);
+ consumeOrFail(OPENPAREN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ consumeOrFail(CLOSEPAREN);
+ if (match(SEMICOLON))
+ next(); // Always performs automatic semicolon insertion.
+ return context.createDoWhileStatement(m_lexer->lastLineNumber(), statement, expr, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWhileStatement(TreeBuilder& context)
+{
+ ASSERT(match(WHILE));
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+ return context.createWhileStatement(m_lexer->lastLineNumber(), expr, statement, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseVarDeclarationList(TreeBuilder& context, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd)
+{
+ TreeExpression varDecls = 0;
+ do {
+ declarations++;
+ next();
+ matchOrFail(IDENT);
+
+ int varStart = tokenStart();
+ identStart = varStart;
+ const Identifier* name = m_token.m_data.ident;
+ lastIdent = name;
+ next();
+ bool hasInitializer = match(EQUAL);
+ failIfFalseIfStrictWithNameAndMessage(declareVariable(name), "Cannot declare a variable named", name->impl(), "in strict mode.");
+ context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
+ if (hasInitializer) {
+ int varDivot = tokenStart() + 1;
+ initStart = tokenStart();
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ int initialAssignments = m_assignmentCount;
+ TreeExpression initializer = parseAssignmentExpression(context);
+ initEnd = lastTokenEnd();
+ lastInitializer = initializer;
+ failIfFalse(initializer);
+
+ TreeExpression node = context.createAssignResolve(m_lexer->lastLineNumber(), *name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd());
+ if (!varDecls)
+ varDecls = node;
+ else
+ varDecls = context.combineCommaNodes(m_lexer->lastLineNumber(), varDecls, node);
+ }
+ } while (match(COMMA));
+ return varDecls;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeConstDeclList Parser<LexerType>::parseConstDeclarationList(TreeBuilder& context)
+{
+ failIfTrue(strictMode());
+ TreeConstDeclList constDecls = 0;
+ TreeConstDeclList tail = 0;
+ do {
+ next();
+ matchOrFail(IDENT);
+ const Identifier* name = m_token.m_data.ident;
+ next();
+ bool hasInitializer = match(EQUAL);
+ declareVariable(name);
+ context.addVar(name, DeclarationStacks::IsConstant | (hasInitializer ? DeclarationStacks::HasInitializer : 0));
+ TreeExpression initializer = 0;
+ if (hasInitializer) {
+ next(TreeBuilder::DontBuildStrings); // consume '='
+ initializer = parseAssignmentExpression(context);
+ }
+ tail = context.appendConstDecl(m_lexer->lastLineNumber(), tail, name, initializer);
+ if (!constDecls)
+ constDecls = tail;
+ } while (match(COMMA));
+ return constDecls;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseForStatement(TreeBuilder& context)
+{
+ ASSERT(match(FOR));
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ int nonLHSCount = m_nonLHSCount;
+ int declarations = 0;
+ int declsStart = 0;
+ int declsEnd = 0;
+ TreeExpression decls = 0;
+ bool hasDeclaration = false;
+ if (match(VAR)) {
+ /*
+ for (var IDENT in expression) statement
+ for (var IDENT = expression in expression) statement
+ for (var varDeclarationList; expressionOpt; expressionOpt)
+ */
+ hasDeclaration = true;
+ const Identifier* forInTarget = 0;
+ TreeExpression forInInitializer = 0;
+ m_allowsIn = false;
+ int initStart = 0;
+ int initEnd = 0;
+ decls = parseVarDeclarationList(context, declarations, forInTarget, forInInitializer, declsStart, initStart, initEnd);
+ m_allowsIn = true;
+ if (m_error)
+ fail();
+
+ // Remainder of a standard for loop is handled identically
+ if (match(SEMICOLON))
+ goto standardForLoop;
+
+ failIfFalse(declarations == 1);
+
+ // Handle for-in with var declaration
+ int inLocation = tokenStart();
+ consumeOrFail(INTOKEN);
+
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int exprEnd = lastTokenEnd();
+
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+
+ return context.createForInLoop(m_lexer->lastLineNumber(), forInTarget, forInInitializer, expr, statement, declsStart, inLocation, exprEnd, initStart, initEnd, startLine, endLine);
+ }
+
+ if (!match(SEMICOLON)) {
+ m_allowsIn = false;
+ declsStart = tokenStart();
+ decls = parseExpression(context);
+ declsEnd = lastTokenEnd();
+ m_allowsIn = true;
+ failIfFalse(decls);
+ }
+
+ if (match(SEMICOLON)) {
+ standardForLoop:
+ // Standard for loop
+ next();
+ TreeExpression condition = 0;
+
+ if (!match(SEMICOLON)) {
+ condition = parseExpression(context);
+ failIfFalse(condition);
+ }
+ consumeOrFail(SEMICOLON);
+
+ TreeExpression increment = 0;
+ if (!match(CLOSEPAREN)) {
+ increment = parseExpression(context);
+ failIfFalse(increment);
+ }
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+ return context.createForLoop(m_lexer->lastLineNumber(), decls, condition, increment, statement, hasDeclaration, startLine, endLine);
+ }
+
+ // For-in loop
+ failIfFalse(nonLHSCount == m_nonLHSCount);
+ consumeOrFail(INTOKEN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int exprEnd = lastTokenEnd();
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ startLoop();
+ TreeStatement statement = parseStatement(context, unused);
+ endLoop();
+ failIfFalse(statement);
+
+ return context.createForInLoop(m_lexer->lastLineNumber(), decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBreakStatement(TreeBuilder& context)
+{
+ ASSERT(match(BREAK));
+ int startCol = tokenStart();
+ int endCol = tokenEnd();
+ int startLine = tokenLine();
+ int endLine = tokenLine();
+ next();
+
+ if (autoSemiColon()) {
+ failIfFalseWithMessage(breakIsValid(), "'break' is only valid inside a switch or loop statement");
+ return context.createBreakStatement(m_lexer->lastLineNumber(), startCol, endCol, startLine, endLine);
+ }
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ failIfFalseWithNameAndMessage(getLabel(ident), "Label", ident->impl(), "is not defined");
+ endCol = tokenEnd();
+ endLine = tokenLine();
+ next();
+ failIfFalse(autoSemiColon());
+ return context.createBreakStatement(m_lexer->lastLineNumber(), ident, startCol, endCol, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseContinueStatement(TreeBuilder& context)
+{
+ ASSERT(match(CONTINUE));
+ int startCol = tokenStart();
+ int endCol = tokenEnd();
+ int startLine = tokenLine();
+ int endLine = tokenLine();
+ next();
+
+ if (autoSemiColon()) {
+ failIfFalseWithMessage(continueIsValid(), "'continue' is only valid inside a loop statement");
+ return context.createContinueStatement(m_lexer->lastLineNumber(), startCol, endCol, startLine, endLine);
+ }
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ ScopeLabelInfo* label = getLabel(ident);
+ failIfFalseWithNameAndMessage(label, "Label", ident->impl(), "is not defined");
+ failIfFalseWithMessage(label->m_isLoop, "'continue' is only valid inside a loop statement");
+ endCol = tokenEnd();
+ endLine = tokenLine();
+ next();
+ failIfFalse(autoSemiColon());
+ return context.createContinueStatement(m_lexer->lastLineNumber(), ident, startCol, endCol, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseReturnStatement(TreeBuilder& context)
+{
+ ASSERT(match(RETURN));
+ failIfFalse(currentScope()->isFunction());
+ int startLine = tokenLine();
+ int endLine = startLine;
+ int start = tokenStart();
+ int end = tokenEnd();
+ next();
+ // We do the auto semicolon check before attempting to parse an expression
+ // as we need to ensure the a line break after the return correctly terminates
+ // the statement
+ if (match(SEMICOLON))
+ endLine = tokenLine();
+ if (autoSemiColon())
+ return context.createReturnStatement(m_lexer->lastLineNumber(), 0, start, end, startLine, endLine);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ end = lastTokenEnd();
+ if (match(SEMICOLON))
+ endLine = tokenLine();
+ failIfFalse(autoSemiColon());
+ return context.createReturnStatement(m_lexer->lastLineNumber(), expr, start, end, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseThrowStatement(TreeBuilder& context)
+{
+ ASSERT(match(THROW));
+ int eStart = tokenStart();
+ int startLine = tokenLine();
+ next();
+
+ failIfTrue(autoSemiColon());
+
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int eEnd = lastTokenEnd();
+ int endLine = tokenLine();
+ failIfFalse(autoSemiColon());
+
+ return context.createThrowStatement(m_lexer->lastLineNumber(), expr, eStart, eEnd, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseWithStatement(TreeBuilder& context)
+{
+ ASSERT(match(WITH));
+ failIfTrueWithMessage(strictMode(), "'with' statements are not valid in strict mode");
+ currentScope()->setNeedsFullActivation();
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ int start = tokenStart();
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int end = lastTokenEnd();
+
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ TreeStatement statement = parseStatement(context, unused);
+ failIfFalse(statement);
+
+ return context.createWithStatement(m_lexer->lastLineNumber(), expr, statement, start, end, startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseSwitchStatement(TreeBuilder& context)
+{
+ ASSERT(match(SWITCH));
+ int startLine = tokenLine();
+ next();
+ consumeOrFail(OPENPAREN);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ int endLine = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ consumeOrFail(OPENBRACE);
+ startSwitch();
+ TreeClauseList firstClauses = parseSwitchClauses(context);
+ failIfTrue(m_error);
+
+ TreeClause defaultClause = parseSwitchDefaultClause(context);
+ failIfTrue(m_error);
+
+ TreeClauseList secondClauses = parseSwitchClauses(context);
+ failIfTrue(m_error);
+ endSwitch();
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createSwitchStatement(m_lexer->lastLineNumber(), expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
+
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeClauseList Parser<LexerType>::parseSwitchClauses(TreeBuilder& context)
+{
+ if (!match(CASE))
+ return 0;
+ next();
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition);
+ consumeOrFail(COLON);
+ TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(statements);
+ TreeClause clause = context.createClause(condition, statements);
+ TreeClauseList clauseList = context.createClauseList(clause);
+ TreeClauseList tail = clauseList;
+
+ while (match(CASE)) {
+ next();
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition);
+ consumeOrFail(COLON);
+ TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(statements);
+ clause = context.createClause(condition, statements);
+ tail = context.createClauseList(tail, clause);
+ }
+ return clauseList;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeClause Parser<LexerType>::parseSwitchDefaultClause(TreeBuilder& context)
+{
+ if (!match(DEFAULT))
+ return 0;
+ next();
+ consumeOrFail(COLON);
+ TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(statements);
+ return context.createClause(0, statements);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseTryStatement(TreeBuilder& context)
+{
+ ASSERT(match(TRY));
+ TreeStatement tryBlock = 0;
+ const Identifier* ident = &m_globalData->propertyNames->nullIdentifier;
+ bool catchHasEval = false;
+ TreeStatement catchBlock = 0;
+ TreeStatement finallyBlock = 0;
+ int firstLine = tokenLine();
+ next();
+ matchOrFail(OPENBRACE);
+
+ tryBlock = parseBlockStatement(context);
+ failIfFalse(tryBlock);
+ int lastLine = m_lastLine;
+
+ if (match(CATCH)) {
+ currentScope()->setNeedsFullActivation();
+ next();
+ consumeOrFail(OPENPAREN);
+ matchOrFail(IDENT);
+ ident = m_token.m_data.ident;
+ next();
+ AutoPopScopeRef catchScope(this, pushScope());
+ failIfFalseIfStrictWithNameAndMessage(declareVariable(ident), "Cannot declare a variable named", ident->impl(), "in strict mode");
+ catchScope->preventNewDecls();
+ consumeOrFail(CLOSEPAREN);
+ matchOrFail(OPENBRACE);
+ int initialEvalCount = context.evalCount();
+ catchBlock = parseBlockStatement(context);
+ failIfFalseWithMessage(catchBlock, "'try' must have a catch or finally block");
+ catchHasEval = initialEvalCount != context.evalCount();
+ failIfFalse(popScope(catchScope, TreeBuilder::NeedsFreeVariableInfo));
+ }
+
+ if (match(FINALLY)) {
+ next();
+ matchOrFail(OPENBRACE);
+ finallyBlock = parseBlockStatement(context);
+ failIfFalse(finallyBlock);
+ }
+ failIfFalse(catchBlock || finallyBlock);
+ return context.createTryStatement(m_lexer->lastLineNumber(), tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseDebuggerStatement(TreeBuilder& context)
+{
+ ASSERT(match(DEBUGGER));
+ int startLine = tokenLine();
+ int endLine = startLine;
+ next();
+ if (match(SEMICOLON))
+ startLine = tokenLine();
+ failIfFalse(autoSemiColon());
+ return context.createDebugger(m_lexer->lastLineNumber(), startLine, endLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseBlockStatement(TreeBuilder& context)
+{
+ ASSERT(match(OPENBRACE));
+ int start = tokenLine();
+ next();
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createBlockStatement(m_lexer->lastLineNumber(), 0, start, m_lastLine);
+ }
+ TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(subtree);
+ matchOrFail(CLOSEBRACE);
+ next();
+ return context.createBlockStatement(m_lexer->lastLineNumber(), subtree, start, m_lastLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseStatement(TreeBuilder& context, const Identifier*& directive, unsigned* directiveLiteralLength)
+{
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth++;
+ directive = 0;
+ int nonTrivialExpressionCount = 0;
+ failIfStackOverflow();
+ switch (m_token.m_type) {
+ case OPENBRACE:
+ return parseBlockStatement(context);
+ case VAR:
+ return parseVarDeclaration(context);
+ case CONSTTOKEN:
+ return parseConstDeclaration(context);
+ case FUNCTION:
+ failIfFalseIfStrictWithMessage(m_statementDepth == 1, "Functions cannot be declared in a nested block in strict mode");
+ return parseFunctionDeclaration(context);
+ case SEMICOLON:
+ next();
+ return context.createEmptyStatement(m_lexer->lastLineNumber());
+ case IF:
+ return parseIfStatement(context);
+ case DO:
+ return parseDoWhileStatement(context);
+ case WHILE:
+ return parseWhileStatement(context);
+ case FOR:
+ return parseForStatement(context);
+ case CONTINUE:
+ return parseContinueStatement(context);
+ case BREAK:
+ return parseBreakStatement(context);
+ case RETURN:
+ return parseReturnStatement(context);
+ case WITH:
+ return parseWithStatement(context);
+ case SWITCH:
+ return parseSwitchStatement(context);
+ case THROW:
+ return parseThrowStatement(context);
+ case TRY:
+ return parseTryStatement(context);
+ case DEBUGGER:
+ return parseDebuggerStatement(context);
+ case EOFTOK:
+ case CASE:
+ case CLOSEBRACE:
+ case DEFAULT:
+ // These tokens imply the end of a set of source elements
+ return 0;
+ case IDENT:
+ return parseExpressionOrLabelStatement(context);
+ case STRING:
+ directive = m_token.m_data.ident;
+ if (directiveLiteralLength)
+ *directiveLiteralLength = m_token.m_info.endOffset - m_token.m_info.startOffset;
+ nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+ default:
+ TreeStatement exprStatement = parseExpressionStatement(context);
+ if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
+ directive = 0;
+ return exprStatement;
+ }
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeFormalParameterList Parser<LexerType>::parseFormalParameters(TreeBuilder& context)
+{
+ matchOrFail(IDENT);
+ failIfFalseIfStrictWithNameAndMessage(declareParameter(m_token.m_data.ident), "Cannot declare a parameter named", m_token.m_data.ident->impl(), " in strict mode");
+ TreeFormalParameterList list = context.createFormalParameterList(*m_token.m_data.ident);
+ TreeFormalParameterList tail = list;
+ next();
+ while (match(COMMA)) {
+ next();
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ failIfFalseIfStrictWithNameAndMessage(declareParameter(ident), "Cannot declare a parameter named", ident->impl(), "in strict mode");
+ next();
+ tail = context.createFormalParameterList(tail, *ident);
+ }
+ return list;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeFunctionBody Parser<LexerType>::parseFunctionBody(TreeBuilder& context)
+{
+ if (match(CLOSEBRACE))
+ return context.createFunctionBody(m_lexer->lastLineNumber(), strictMode());
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth = 0;
+ typename TreeBuilder::FunctionBodyBuilder bodyBuilder(const_cast<JSGlobalData*>(m_globalData), m_lexer.get());
+ failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
+ return context.createFunctionBody(m_lexer->lastLineNumber(), strictMode());
+}
+
+template <typename LexerType>
+template <FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool Parser<LexerType>::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
+{
+ AutoPopScopeRef functionScope(this, pushScope());
+ functionScope->setIsFunction();
+ if (match(IDENT)) {
+ name = m_token.m_data.ident;
+ failIfTrueWithMessage(*name == m_globalData->propertyNames->underscoreProto, "Cannot name a function __proto__");
+ next();
+ if (!nameIsInContainingScope)
+ failIfFalseIfStrict(functionScope->declareVariable(name));
+ } else if (requirements == FunctionNeedsName)
+ return false;
+ consumeOrFail(OPENPAREN);
+ if (!match(CLOSEPAREN)) {
+ parameters = parseFormalParameters(context);
+ failIfFalse(parameters);
+ }
+ consumeOrFail(CLOSEPAREN);
+ matchOrFail(OPENBRACE);
+
+ openBracePos = m_token.m_data.intValue;
+ bodyStartLine = tokenLine();
+
+ // If we know about this function already, we can use the cached info and skip the parser to the end of the function.
+ if (const SourceProviderCacheItem* cachedInfo = TreeBuilder::CanUseFunctionCache ? findCachedFunctionInfo(openBracePos) : 0) {
+ // If we're in a strict context, the cached function info must say it was strict too.
+ ASSERT(!strictMode() || cachedInfo->strictMode);
+ body = context.createFunctionBody(m_lexer->lastLineNumber(), cachedInfo->strictMode);
+
+ functionScope->restoreFunctionInfo(cachedInfo);
+ failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
+
+ closeBracePos = cachedInfo->closeBracePos;
+ m_token = cachedInfo->closeBraceToken();
+ m_lexer->setOffset(m_token.m_info.endOffset);
+ m_lexer->setLineNumber(m_token.m_info.line);
+
+ next();
+ return true;
+ }
+
+ next();
+
+ body = parseFunctionBody(context);
+ failIfFalse(body);
+ if (functionScope->strictMode() && name) {
+ failIfTrueWithNameAndMessage(m_globalData->propertyNames->arguments == *name, "Function name", name->impl(), "is not valid in strict mode");
+ failIfTrueWithNameAndMessage(m_globalData->propertyNames->eval == *name, "Function name", name->impl(), "is not valid in strict mode");
+ }
+ closeBracePos = m_token.m_data.intValue;
+
+ // Cache the tokenizer state and the function scope the first time the function is parsed.
+ // Any future reparsing can then skip the function.
+ static const int minimumFunctionLengthToCache = 64;
+ OwnPtr<SourceProviderCacheItem> newInfo;
+ int functionLength = closeBracePos - openBracePos;
+ if (TreeBuilder::CanUseFunctionCache && m_functionCache && functionLength > minimumFunctionLengthToCache) {
+ newInfo = adoptPtr(new SourceProviderCacheItem(m_token.m_info.line, closeBracePos));
+ functionScope->saveFunctionInfo(newInfo.get());
+ }
+
+ failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
+ matchOrFail(CLOSEBRACE);
+
+ if (newInfo) {
+ unsigned approximateByteSize = newInfo->approximateByteSize();
+ m_functionCache->add(openBracePos, newInfo.release(), approximateByteSize);
+ }
+
+ next();
+ return true;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseFunctionDeclaration(TreeBuilder& context)
+{
+ ASSERT(match(FUNCTION));
+ next();
+ const Identifier* name = 0;
+ TreeFormalParameterList parameters = 0;
+ TreeFunctionBody body = 0;
+ int openBracePos = 0;
+ int closeBracePos = 0;
+ int bodyStartLine = 0;
+ failIfFalse((parseFunctionInfo<FunctionNeedsName, true>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
+ failIfFalse(name);
+ failIfFalseIfStrict(declareVariable(name));
+ return context.createFuncDeclStatement(m_lexer->lastLineNumber(), name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+}
+
+struct LabelInfo {
+ LabelInfo(const Identifier* ident, int start, int end)
+ : m_ident(ident)
+ , m_start(start)
+ , m_end(end)
+ {
+ }
+
+ const Identifier* m_ident;
+ int m_start;
+ int m_end;
+};
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionOrLabelStatement(TreeBuilder& context)
+{
+
+ /* Expression and Label statements are ambiguous at LL(1), so we have a
+ * special case that looks for a colon as the next character in the input.
+ */
+ Vector<LabelInfo> labels;
+
+ do {
+ int start = tokenStart();
+ int startLine = tokenLine();
+ if (!nextTokenIsColon()) {
+ // If we hit this path we're making a expression statement, which
+ // by definition can't make use of continue/break so we can just
+ // ignore any labels we might have accumulated.
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression);
+ failIfFalse(autoSemiColon());
+ return context.createExprStatement(m_lexer->lastLineNumber(), expression, startLine, m_lastLine);
+ }
+ const Identifier* ident = m_token.m_data.ident;
+ int end = tokenEnd();
+ next();
+ consumeOrFail(COLON);
+ if (!m_syntaxAlreadyValidated) {
+ // This is O(N^2) over the current list of consecutive labels, but I
+ // have never seen more than one label in a row in the real world.
+ for (size_t i = 0; i < labels.size(); i++)
+ failIfTrue(ident->impl() == labels[i].m_ident->impl());
+ failIfTrue(getLabel(ident));
+ labels.append(LabelInfo(ident, start, end));
+ }
+ } while (match(IDENT));
+ bool isLoop = false;
+ switch (m_token.m_type) {
+ case FOR:
+ case WHILE:
+ case DO:
+ isLoop = true;
+ break;
+
+ default:
+ break;
+ }
+ const Identifier* unused = 0;
+ if (!m_syntaxAlreadyValidated) {
+ for (size_t i = 0; i < labels.size(); i++)
+ pushLabel(labels[i].m_ident, isLoop);
+ }
+ TreeStatement statement = parseStatement(context, unused);
+ if (!m_syntaxAlreadyValidated) {
+ for (size_t i = 0; i < labels.size(); i++)
+ popLabel();
+ }
+ failIfFalse(statement);
+ for (size_t i = 0; i < labels.size(); i++) {
+ const LabelInfo& info = labels[labels.size() - i - 1];
+ statement = context.createLabelStatement(m_lexer->lastLineNumber(), info.m_ident, statement, info.m_start, info.m_end);
+ }
+ return statement;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseExpressionStatement(TreeBuilder& context)
+{
+ int startLine = tokenLine();
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression);
+ failIfFalse(autoSemiColon());
+ return context.createExprStatement(m_lexer->lastLineNumber(), expression, startLine, m_lastLine);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeStatement Parser<LexerType>::parseIfStatement(TreeBuilder& context)
+{
+ ASSERT(match(IF));
+
+ int start = tokenLine();
+ next();
+
+ consumeOrFail(OPENPAREN);
+
+ TreeExpression condition = parseExpression(context);
+ failIfFalse(condition);
+ int end = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+
+ const Identifier* unused = 0;
+ TreeStatement trueBlock = parseStatement(context, unused);
+ failIfFalse(trueBlock);
+
+ if (!match(ELSE))
+ return context.createIfStatement(m_lexer->lastLineNumber(), condition, trueBlock, start, end);
+
+ Vector<TreeExpression> exprStack;
+ Vector<pair<int, int> > posStack;
+ Vector<TreeStatement> statementStack;
+ bool trailingElse = false;
+ do {
+ next();
+ if (!match(IF)) {
+ const Identifier* unused = 0;
+ TreeStatement block = parseStatement(context, unused);
+ failIfFalse(block);
+ statementStack.append(block);
+ trailingElse = true;
+ break;
+ }
+ int innerStart = tokenLine();
+ next();
+
+ consumeOrFail(OPENPAREN);
+
+ TreeExpression innerCondition = parseExpression(context);
+ failIfFalse(innerCondition);
+ int innerEnd = tokenLine();
+ consumeOrFail(CLOSEPAREN);
+ const Identifier* unused = 0;
+ TreeStatement innerTrueBlock = parseStatement(context, unused);
+ failIfFalse(innerTrueBlock);
+ exprStack.append(innerCondition);
+ posStack.append(make_pair(innerStart, innerEnd));
+ statementStack.append(innerTrueBlock);
+ } while (match(ELSE));
+
+ if (!trailingElse) {
+ TreeExpression condition = exprStack.last();
+ exprStack.removeLast();
+ TreeStatement trueBlock = statementStack.last();
+ statementStack.removeLast();
+ pair<int, int> pos = posStack.last();
+ posStack.removeLast();
+ statementStack.append(context.createIfStatement(m_lexer->lastLineNumber(), condition, trueBlock, pos.first, pos.second));
+ }
+
+ while (!exprStack.isEmpty()) {
+ TreeExpression condition = exprStack.last();
+ exprStack.removeLast();
+ TreeStatement falseBlock = statementStack.last();
+ statementStack.removeLast();
+ TreeStatement trueBlock = statementStack.last();
+ statementStack.removeLast();
+ pair<int, int> pos = posStack.last();
+ posStack.removeLast();
+ statementStack.append(context.createIfStatement(m_lexer->lastLineNumber(), condition, trueBlock, falseBlock, pos.first, pos.second));
+ }
+
+ return context.createIfStatement(m_lexer->lastLineNumber(), condition, trueBlock, statementStack.last(), start, end);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node);
+ if (!match(COMMA))
+ return node;
+ next();
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ TreeExpression right = parseAssignmentExpression(context);
+ failIfFalse(right);
+ typename TreeBuilder::Comma commaNode = context.createCommaExpr(m_lexer->lastLineNumber(), node, right);
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ right = parseAssignmentExpression(context);
+ failIfFalse(right);
+ context.appendToComma(commaNode, right);
+ }
+ return commaNode;
+}
+
+template <typename LexerType>
+template <typename TreeBuilder> TreeExpression Parser<LexerType>::parseAssignmentExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ int start = tokenStart();
+ int initialAssignmentCount = m_assignmentCount;
+ int initialNonLHSCount = m_nonLHSCount;
+ TreeExpression lhs = parseConditionalExpression(context);
+ failIfFalse(lhs);
+ if (initialNonLHSCount != m_nonLHSCount)
+ return lhs;
+
+ int assignmentStack = 0;
+ Operator op;
+ bool hadAssignment = false;
+ while (true) {
+ switch (m_token.m_type) {
+ case EQUAL: op = OpEqual; break;
+ case PLUSEQUAL: op = OpPlusEq; break;
+ case MINUSEQUAL: op = OpMinusEq; break;
+ case MULTEQUAL: op = OpMultEq; break;
+ case DIVEQUAL: op = OpDivEq; break;
+ case LSHIFTEQUAL: op = OpLShift; break;
+ case RSHIFTEQUAL: op = OpRShift; break;
+ case URSHIFTEQUAL: op = OpURShift; break;
+ case ANDEQUAL: op = OpAndEq; break;
+ case XOREQUAL: op = OpXOrEq; break;
+ case OREQUAL: op = OpOrEq; break;
+ case MODEQUAL: op = OpModEq; break;
+ default:
+ goto end;
+ }
+ m_nonTrivialExpressionCount++;
+ hadAssignment = true;
+ context.assignmentStackAppend(assignmentStack, lhs, start, tokenStart(), m_assignmentCount, op);
+ start = tokenStart();
+ m_assignmentCount++;
+ next(TreeBuilder::DontBuildStrings);
+ if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
+ failIfTrueIfStrictWithMessage(m_globalData->propertyNames->eval == *m_lastIdentifier, "'eval' cannot be modified in strict mode");
+ failIfTrueIfStrictWithMessage(m_globalData->propertyNames->arguments == *m_lastIdentifier, "'arguments' cannot be modified in strict mode");
+ declareWrite(m_lastIdentifier);
+ m_lastIdentifier = 0;
+ }
+ lhs = parseConditionalExpression(context);
+ failIfFalse(lhs);
+ if (initialNonLHSCount != m_nonLHSCount)
+ break;
+ }
+end:
+ if (hadAssignment)
+ m_nonLHSCount++;
+
+ if (!TreeBuilder::CreatesAST)
+ return lhs;
+
+ while (assignmentStack)
+ lhs = context.createAssignment(m_lexer->lastLineNumber(), assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd());
+
+ return lhs;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseConditionalExpression(TreeBuilder& context)
+{
+ TreeExpression cond = parseBinaryExpression(context);
+ failIfFalse(cond);
+ if (!match(QUESTION))
+ return cond;
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ next(TreeBuilder::DontBuildStrings);
+ TreeExpression lhs = parseAssignmentExpression(context);
+ consumeOrFailWithFlags(COLON, TreeBuilder::DontBuildStrings);
+
+ TreeExpression rhs = parseAssignmentExpression(context);
+ failIfFalse(rhs);
+ return context.createConditionalExpr(m_lexer->lastLineNumber(), cond, lhs, rhs);
+}
+
+ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
+{
+ return token & UnaryOpTokenFlag;
+}
+
+template <typename LexerType>
+int Parser<LexerType>::isBinaryOperator(JSTokenType token)
+{
+ if (m_allowsIn)
+ return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
+ return token & BinaryOpTokenPrecedenceMask;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseBinaryExpression(TreeBuilder& context)
+{
+
+ int operandStackDepth = 0;
+ int operatorStackDepth = 0;
+ typename TreeBuilder::BinaryExprContext binaryExprContext(context);
+ while (true) {
+ int exprStart = tokenStart();
+ int initialAssignments = m_assignmentCount;
+ TreeExpression current = parseUnaryExpression(context);
+ failIfFalse(current);
+
+ context.appendBinaryExpressionInfo(operandStackDepth, current, exprStart, lastTokenEnd(), lastTokenEnd(), initialAssignments != m_assignmentCount);
+ int precedence = isBinaryOperator(m_token.m_type);
+ if (!precedence)
+ break;
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ int operatorToken = m_token.m_type;
+ next(TreeBuilder::DontBuildStrings);
+
+ while (operatorStackDepth && context.operatorStackHasHigherPrecedence(operatorStackDepth, precedence)) {
+ ASSERT(operandStackDepth > 1);
+
+ typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
+ typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
+ context.shrinkOperandStackBy(operandStackDepth, 2);
+ context.appendBinaryOperation(m_lexer->lastLineNumber(), operandStackDepth, operatorStackDepth, lhs, rhs);
+ context.operatorStackPop(operatorStackDepth);
+ }
+ context.operatorStackAppend(operatorStackDepth, operatorToken, precedence);
+ }
+ while (operatorStackDepth) {
+ ASSERT(operandStackDepth > 1);
+
+ typename TreeBuilder::BinaryOperand rhs = context.getFromOperandStack(-1);
+ typename TreeBuilder::BinaryOperand lhs = context.getFromOperandStack(-2);
+ context.shrinkOperandStackBy(operandStackDepth, 2);
+ context.appendBinaryOperation(m_lexer->lastLineNumber(), operandStackDepth, operatorStackDepth, lhs, rhs);
+ context.operatorStackPop(operatorStackDepth);
+ }
+ return context.popOperandStack(operandStackDepth);
+}
+
+template <typename LexerType>
+template <bool complete, class TreeBuilder> TreeProperty Parser<LexerType>::parseProperty(TreeBuilder& context)
+{
+ bool wasIdent = false;
+ switch (m_token.m_type) {
+ namedProperty:
+ case IDENT:
+ wasIdent = true;
+ case STRING: {
+ const Identifier* ident = m_token.m_data.ident;
+ if (complete || (wasIdent && (*ident == m_globalData->propertyNames->get || *ident == m_globalData->propertyNames->set)))
+ nextExpectIdentifier(LexerFlagsIgnoreReservedWords);
+ else
+ nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+
+ if (match(COLON)) {
+ next();
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node);
+ return context.template createProperty<complete>(ident, node, PropertyNode::Constant);
+ }
+ failIfFalse(wasIdent);
+ matchOrFail(IDENT);
+ const Identifier* accessorName = 0;
+ TreeFormalParameterList parameters = 0;
+ TreeFunctionBody body = 0;
+ int openBracePos = 0;
+ int closeBracePos = 0;
+ int bodyStartLine = 0;
+ PropertyNode::Type type;
+ if (*ident == m_globalData->propertyNames->get)
+ type = PropertyNode::Getter;
+ else if (*ident == m_globalData->propertyNames->set)
+ type = PropertyNode::Setter;
+ else
+ fail();
+ failIfFalse((parseFunctionInfo<FunctionNeedsName, false>(context, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
+ return context.template createGetterOrSetterProperty<complete>(m_lexer->lastLineNumber(), type, accessorName, parameters, body, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+ }
+ case NUMBER: {
+ double propertyName = m_token.m_data.doubleValue;
+ next();
+ consumeOrFail(COLON);
+ TreeExpression node = parseAssignmentExpression(context);
+ failIfFalse(node);
+ return context.template createProperty<complete>(const_cast<JSGlobalData*>(m_globalData), propertyName, node, PropertyNode::Constant);
+ }
+ default:
+ failIfFalse(m_token.m_type & KeywordTokenFlag);
+ goto namedProperty;
+ }
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseObjectLiteral(TreeBuilder& context)
+{
+ int startOffset = m_token.m_data.intValue;
+ consumeOrFailWithFlags(OPENBRACE, TreeBuilder::DontBuildStrings);
+
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral(m_lexer->lastLineNumber());
+ }
+
+ TreeProperty property = parseProperty<false>(context);
+ failIfFalse(property);
+ if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
+ m_lexer->setOffset(startOffset);
+ next();
+ return parseStrictObjectLiteral(context);
+ }
+ TreePropertyList propertyList = context.createPropertyList(m_lexer->lastLineNumber(), property);
+ TreePropertyList tail = propertyList;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
+ if (match(CLOSEBRACE))
+ break;
+ property = parseProperty<false>(context);
+ failIfFalse(property);
+ if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
+ m_lexer->setOffset(startOffset);
+ next();
+ return parseStrictObjectLiteral(context);
+ }
+ tail = context.createPropertyList(m_lexer->lastLineNumber(), property, tail);
+ }
+
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createObjectLiteral(m_lexer->lastLineNumber(), propertyList);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseStrictObjectLiteral(TreeBuilder& context)
+{
+ consumeOrFail(OPENBRACE);
+
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral(m_lexer->lastLineNumber());
+ }
+
+ TreeProperty property = parseProperty<true>(context);
+ failIfFalse(property);
+
+ typedef HashMap<RefPtr<StringImpl>, unsigned, IdentifierRepHash> ObjectValidationMap;
+ ObjectValidationMap objectValidator;
+ // Add the first property
+ if (!m_syntaxAlreadyValidated)
+ objectValidator.add(context.getName(property).impl(), context.getType(property));
+
+ TreePropertyList propertyList = context.createPropertyList(m_lexer->lastLineNumber(), property);
+ TreePropertyList tail = propertyList;
+ while (match(COMMA)) {
+ next();
+ // allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939
+ if (match(CLOSEBRACE))
+ break;
+ property = parseProperty<true>(context);
+ failIfFalse(property);
+ if (!m_syntaxAlreadyValidated) {
+ std::pair<ObjectValidationMap::iterator, bool> propertyEntryIter = objectValidator.add(context.getName(property).impl(), context.getType(property));
+ if (!propertyEntryIter.second) {
+ failIfTrue(propertyEntryIter.first->second == PropertyNode::Constant);
+ failIfTrue(context.getType(property) == PropertyNode::Constant);
+ failIfTrue(context.getType(property) & propertyEntryIter.first->second);
+ propertyEntryIter.first->second |= context.getType(property);
+ }
+ }
+ tail = context.createPropertyList(m_lexer->lastLineNumber(), property, tail);
+ }
+
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createObjectLiteral(m_lexer->lastLineNumber(), propertyList);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseArrayLiteral(TreeBuilder& context)
+{
+ consumeOrFailWithFlags(OPENBRACKET, TreeBuilder::DontBuildStrings);
+
+ int elisions = 0;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ elisions++;
+ }
+ if (match(CLOSEBRACKET)) {
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArray(m_lexer->lastLineNumber(), elisions);
+ }
+
+ TreeExpression elem = parseAssignmentExpression(context);
+ failIfFalse(elem);
+ typename TreeBuilder::ElementList elementList = context.createElementList(elisions, elem);
+ typename TreeBuilder::ElementList tail = elementList;
+ elisions = 0;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ elisions = 0;
+
+ while (match(COMMA)) {
+ next();
+ elisions++;
+ }
+
+ if (match(CLOSEBRACKET)) {
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArray(m_lexer->lastLineNumber(), elisions, elementList);
+ }
+ TreeExpression elem = parseAssignmentExpression(context);
+ failIfFalse(elem);
+ tail = context.createElementList(tail, elisions, elem);
+ }
+
+ consumeOrFail(CLOSEBRACKET);
+
+ return context.createArray(m_lexer->lastLineNumber(), elementList);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parsePrimaryExpression(TreeBuilder& context)
+{
+ failIfStackOverflow();
+ switch (m_token.m_type) {
+ case OPENBRACE:
+ if (strictMode())
+ return parseStrictObjectLiteral(context);
+ return parseObjectLiteral(context);
+ case OPENBRACKET:
+ return parseArrayLiteral(context);
+ case OPENPAREN: {
+ next();
+ int oldNonLHSCount = m_nonLHSCount;
+ TreeExpression result = parseExpression(context);
+ m_nonLHSCount = oldNonLHSCount;
+ consumeOrFail(CLOSEPAREN);
+
+ return result;
+ }
+ case THISTOKEN: {
+ next();
+ return context.thisExpr(m_lexer->lastLineNumber());
+ }
+ case IDENT: {
+ int start = tokenStart();
+ const Identifier* ident = m_token.m_data.ident;
+ next();
+ currentScope()->useVariable(ident, m_globalData->propertyNames->eval == *ident);
+ m_lastIdentifier = ident;
+ return context.createResolve(m_lexer->lastLineNumber(), ident, start);
+ }
+ case STRING: {
+ const Identifier* ident = m_token.m_data.ident;
+ next();
+ return context.createString(m_lexer->lastLineNumber(), ident);
+ }
+ case NUMBER: {
+ double d = m_token.m_data.doubleValue;
+ next();
+ return context.createNumberExpr(m_lexer->lastLineNumber(), d);
+ }
+ case NULLTOKEN: {
+ next();
+ return context.createNull(m_lexer->lastLineNumber());
+ }
+ case TRUETOKEN: {
+ next();
+ return context.createBoolean(m_lexer->lastLineNumber(), true);
+ }
+ case FALSETOKEN: {
+ next();
+ return context.createBoolean(m_lexer->lastLineNumber(), false);
+ }
+ case DIVEQUAL:
+ case DIVIDE: {
+ /* regexp */
+ const Identifier* pattern;
+ const Identifier* flags;
+ if (match(DIVEQUAL))
+ failIfFalse(m_lexer->scanRegExp(pattern, flags, '='));
+ else
+ failIfFalse(m_lexer->scanRegExp(pattern, flags));
+
+ int start = tokenStart();
+ next();
+ TreeExpression re = context.createRegExp(m_lexer->lastLineNumber(), *pattern, *flags, start);
+ if (!re) {
+ const char* yarrErrorMsg = Yarr::checkSyntax(pattern->ustring());
+ ASSERT(!m_errorMessage.isNull());
+ failWithMessage(yarrErrorMsg);
+ }
+ return re;
+ }
+ default:
+ fail();
+ }
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeArguments Parser<LexerType>::parseArguments(TreeBuilder& context)
+{
+ consumeOrFailWithFlags(OPENPAREN, TreeBuilder::DontBuildStrings);
+ if (match(CLOSEPAREN)) {
+ next(TreeBuilder::DontBuildStrings);
+ return context.createArguments();
+ }
+ TreeExpression firstArg = parseAssignmentExpression(context);
+ failIfFalse(firstArg);
+
+ TreeArgumentsList argList = context.createArgumentsList(m_lexer->lastLineNumber(), firstArg);
+ TreeArgumentsList tail = argList;
+ while (match(COMMA)) {
+ next(TreeBuilder::DontBuildStrings);
+ TreeExpression arg = parseAssignmentExpression(context);
+ failIfFalse(arg);
+ tail = context.createArgumentsList(m_lexer->lastLineNumber(), tail, arg);
+ }
+ consumeOrFail(CLOSEPAREN);
+ return context.createArguments(argList);
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseMemberExpression(TreeBuilder& context)
+{
+ TreeExpression base = 0;
+ int start = tokenStart();
+ int expressionStart = start;
+ int newCount = 0;
+ while (match(NEW)) {
+ next();
+ newCount++;
+ }
+
+ if (match(FUNCTION)) {
+ const Identifier* name = &m_globalData->propertyNames->nullIdentifier;
+ TreeFormalParameterList parameters = 0;
+ TreeFunctionBody body = 0;
+ int openBracePos = 0;
+ int closeBracePos = 0;
+ int bodyStartLine = 0;
+ next();
+ failIfFalse((parseFunctionInfo<FunctionNoRequirements, false>(context, name, parameters, body, openBracePos, closeBracePos, bodyStartLine)));
+ base = context.createFunctionExpr(m_lexer->lastLineNumber(), name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+ } else
+ base = parsePrimaryExpression(context);
+
+ failIfFalse(base);
+ while (true) {
+ switch (m_token.m_type) {
+ case OPENBRACKET: {
+ m_nonTrivialExpressionCount++;
+ int expressionEnd = lastTokenEnd();
+ next();
+ int nonLHSCount = m_nonLHSCount;
+ int initialAssignments = m_assignmentCount;
+ TreeExpression property = parseExpression(context);
+ failIfFalse(property);
+ base = context.createBracketAccess(m_lexer->lastLineNumber(), base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd());
+ consumeOrFail(CLOSEBRACKET);
+ m_nonLHSCount = nonLHSCount;
+ break;
+ }
+ case OPENPAREN: {
+ m_nonTrivialExpressionCount++;
+ if (newCount) {
+ newCount--;
+ if (match(OPENPAREN)) {
+ int exprEnd = lastTokenEnd();
+ TreeArguments arguments = parseArguments(context);
+ failIfFalse(arguments);
+ base = context.createNewExpr(m_lexer->lastLineNumber(), base, arguments, start, exprEnd, lastTokenEnd());
+ } else
+ base = context.createNewExpr(m_lexer->lastLineNumber(), base, start, lastTokenEnd());
+ } else {
+ int nonLHSCount = m_nonLHSCount;
+ int expressionEnd = lastTokenEnd();
+ TreeArguments arguments = parseArguments(context);
+ failIfFalse(arguments);
+ base = context.makeFunctionCallNode(m_lexer->lastLineNumber(), base, arguments, expressionStart, expressionEnd, lastTokenEnd());
+ m_nonLHSCount = nonLHSCount;
+ }
+ break;
+ }
+ case DOT: {
+ m_nonTrivialExpressionCount++;
+ int expressionEnd = lastTokenEnd();
+ nextExpectIdentifier(LexerFlagsIgnoreReservedWords | TreeBuilder::DontBuildKeywords);
+ matchOrFail(IDENT);
+ base = context.createDotAccess(m_lexer->lastLineNumber(), base, m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd());
+ next();
+ break;
+ }
+ default:
+ goto endMemberExpression;
+ }
+ }
+endMemberExpression:
+ while (newCount--)
+ base = context.createNewExpr(m_lexer->lastLineNumber(), base, start, lastTokenEnd());
+ return base;
+}
+
+template <typename LexerType>
+template <class TreeBuilder> TreeExpression Parser<LexerType>::parseUnaryExpression(TreeBuilder& context)
+{
+ typename TreeBuilder::UnaryExprContext unaryExprContext(context);
+ AllowInOverride allowInOverride(this);
+ int tokenStackDepth = 0;
+ bool modifiesExpr = false;
+ bool requiresLExpr = false;
+ while (isUnaryOp(m_token.m_type)) {
+ if (strictMode()) {
+ switch (m_token.m_type) {
+ case PLUSPLUS:
+ case MINUSMINUS:
+ case AUTOPLUSPLUS:
+ case AUTOMINUSMINUS:
+ failIfTrue(requiresLExpr);
+ modifiesExpr = true;
+ requiresLExpr = true;
+ break;
+ case DELETETOKEN:
+ failIfTrue(requiresLExpr);
+ requiresLExpr = true;
+ break;
+ default:
+ failIfTrue(requiresLExpr);
+ break;
+ }
+ }
+ m_nonLHSCount++;
+ context.appendUnaryToken(tokenStackDepth, m_token.m_type, tokenStart());
+ next();
+ m_nonTrivialExpressionCount++;
+ }
+ int subExprStart = tokenStart();
+ TreeExpression expr = parseMemberExpression(context);
+ failIfFalse(expr);
+ bool isEvalOrArguments = false;
+ if (strictMode() && !m_syntaxAlreadyValidated) {
+ if (context.isResolve(expr))
+ isEvalOrArguments = *m_lastIdentifier == m_globalData->propertyNames->eval || *m_lastIdentifier == m_globalData->propertyNames->arguments;
+ }
+ failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments && modifiesExpr, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode");
+ switch (m_token.m_type) {
+ case PLUSPLUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(m_lexer->lastLineNumber(), expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
+ m_assignmentCount++;
+ failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode");
+ failIfTrueIfStrict(requiresLExpr);
+ next();
+ break;
+ case MINUSMINUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(m_lexer->lastLineNumber(), expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
+ m_assignmentCount++;
+ failIfTrueIfStrictWithNameAndMessage(isEvalOrArguments, "'", m_lastIdentifier->impl(), "' cannot be modified in strict mode");
+ failIfTrueIfStrict(requiresLExpr);
+ next();
+ break;
+ default:
+ break;
+ }
+
+ int end = lastTokenEnd();
+
+ if (!TreeBuilder::CreatesAST && (m_syntaxAlreadyValidated || !strictMode()))
+ return expr;
+
+ while (tokenStackDepth) {
+ switch (context.unaryTokenStackLastType(tokenStackDepth)) {
+ case EXCLAMATION:
+ expr = context.createLogicalNot(m_lexer->lastLineNumber(), expr);
+ break;
+ case TILDE:
+ expr = context.makeBitwiseNotNode(m_lexer->lastLineNumber(), expr);
+ break;
+ case MINUS:
+ expr = context.makeNegateNode(m_lexer->lastLineNumber(), expr);
+ break;
+ case PLUS:
+ expr = context.createUnaryPlus(m_lexer->lastLineNumber(), expr);
+ break;
+ case PLUSPLUS:
+ case AUTOPLUSPLUS:
+ expr = context.makePrefixNode(m_lexer->lastLineNumber(), expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case MINUSMINUS:
+ case AUTOMINUSMINUS:
+ expr = context.makePrefixNode(m_lexer->lastLineNumber(), expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case TYPEOF:
+ expr = context.makeTypeOfNode(m_lexer->lastLineNumber(), expr);
+ break;
+ case VOIDTOKEN:
+ expr = context.createVoid(m_lexer->lastLineNumber(), expr);
+ break;
+ case DELETETOKEN:
+ failIfTrueIfStrictWithNameAndMessage(context.isResolve(expr), "Cannot delete unqualified property", m_lastIdentifier->impl(), "in strict mode");
+ expr = context.makeDeleteNode(m_lexer->lastLineNumber(), expr, context.unaryTokenStackLastStart(tokenStackDepth), end, end);
+ break;
+ default:
+ // If we get here something has gone horribly horribly wrong
+ CRASH();
+ }
+ subExprStart = context.unaryTokenStackLastStart(tokenStackDepth);
+ context.unaryTokenStackRemoveLast(tokenStackDepth);
+ }
+ return expr;
+}
+
+// Instantiate the two flavors of Parser we need instead of putting most of this file in Parser.h
+template class Parser< Lexer<LChar> >;
+template class Parser< Lexer<UChar> >;
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
new file mode 100644
index 000000000..ef176f014
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Parser_h
+#define Parser_h
+
+#include "Debugger.h"
+#include "ExceptionHelpers.h"
+#include "Executable.h"
+#include "JSGlobalObject.h"
+#include "Lexer.h"
+#include "Nodes.h"
+#include "ParserArena.h"
+#include "ParserTokens.h"
+#include "SourceProvider.h"
+#include "SourceProviderCacheItem.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+class ExecState;
+class FunctionBodyNode;
+class FunctionParameters;
+class Identifier;
+class JSGlobalData;
+class ProgramNode;
+class SourceCode;
+class UString;
+
+#define fail() do { if (!m_error) updateErrorMessage(); return 0; } while (0)
+#define failWithToken(tok) do { if (!m_error) updateErrorMessage(tok); return 0; } while (0)
+#define failWithMessage(msg) do { if (!m_error) updateErrorMessage(msg); return 0; } while (0)
+#define failWithNameAndMessage(before, name, after) do { if (!m_error) updateErrorWithNameAndMessage(before, name, after); return 0; } while (0)
+#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
+#define failIfFalseWithMessage(cond, msg) do { if (!(cond)) failWithMessage(msg); } while (0)
+#define failIfFalseWithNameAndMessage(cond, before, name, msg) do { if (!(cond)) failWithNameAndMessage(before, name, msg); } while (0)
+#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
+#define failIfTrueWithMessage(cond, msg) do { if ((cond)) failWithMessage(msg); } while (0)
+#define failIfTrueWithNameAndMessage(cond, before, name, msg) do { if ((cond)) failWithNameAndMessage(before, name, msg); } while (0)
+#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
+#define failIfTrueIfStrictWithMessage(cond, msg) do { if ((cond) && strictMode()) failWithMessage(msg); } while (0)
+#define failIfTrueIfStrictWithNameAndMessage(cond, before, name, after) do { if ((cond) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
+#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
+#define failIfFalseIfStrictWithMessage(cond, msg) do { if ((!(cond)) && strictMode()) failWithMessage(msg); } while (0)
+#define failIfFalseIfStrictWithNameAndMessage(cond, before, name, after) do { if ((!(cond)) && strictMode()) failWithNameAndMessage(before, name, after); } while (0)
+#define consumeOrFail(tokenType) do { if (!consume(tokenType)) failWithToken(tokenType); } while (0)
+#define consumeOrFailWithFlags(tokenType, flags) do { if (!consume(tokenType, flags)) failWithToken(tokenType); } while (0)
+#define matchOrFail(tokenType) do { if (!match(tokenType)) failWithToken(tokenType); } while (0)
+#define failIfStackOverflow() do { failIfFalseWithMessage(canRecurse(), "Code nested too deeply."); } while (0)
+
+ // Macros to make the more common TreeBuilder types a little less verbose
+#define TreeStatement typename TreeBuilder::Statement
+#define TreeExpression typename TreeBuilder::Expression
+#define TreeFormalParameterList typename TreeBuilder::FormalParameterList
+#define TreeSourceElements typename TreeBuilder::SourceElements
+#define TreeClause typename TreeBuilder::Clause
+#define TreeClauseList typename TreeBuilder::ClauseList
+#define TreeConstDeclList typename TreeBuilder::ConstDeclList
+#define TreeArguments typename TreeBuilder::Arguments
+#define TreeArgumentsList typename TreeBuilder::ArgumentsList
+#define TreeFunctionBody typename TreeBuilder::FunctionBody
+#define TreeProperty typename TreeBuilder::Property
+#define TreePropertyList typename TreeBuilder::PropertyList
+
+COMPILE_ASSERT(LastUntaggedToken < 64, LessThan64UntaggedTokens);
+
+enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
+enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
+
+template <typename T> inline bool isEvalNode() { return false; }
+template <> inline bool isEvalNode<EvalNode>() { return true; }
+
+struct DepthManager {
+ DepthManager(int* depth)
+ : m_originalDepth(*depth)
+ , m_depth(depth)
+ {
+ }
+
+ ~DepthManager()
+ {
+ *m_depth = m_originalDepth;
+ }
+
+private:
+ int m_originalDepth;
+ int* m_depth;
+};
+
+struct ScopeLabelInfo {
+ ScopeLabelInfo(StringImpl* ident, bool isLoop)
+ : m_ident(ident)
+ , m_isLoop(isLoop)
+ {
+ }
+
+ StringImpl* m_ident;
+ bool m_isLoop;
+};
+
+struct Scope {
+ Scope(const JSGlobalData* globalData, bool isFunction, bool strictMode)
+ : m_globalData(globalData)
+ , m_shadowsArguments(false)
+ , m_usesEval(false)
+ , m_needsFullActivation(false)
+ , m_allowsNewDecls(true)
+ , m_strictMode(strictMode)
+ , m_isFunction(isFunction)
+ , m_isFunctionBoundary(false)
+ , m_isValidStrictMode(true)
+ , m_loopDepth(0)
+ , m_switchDepth(0)
+ {
+ }
+
+ Scope(const Scope& rhs)
+ : m_globalData(rhs.m_globalData)
+ , m_shadowsArguments(rhs.m_shadowsArguments)
+ , m_usesEval(rhs.m_usesEval)
+ , m_needsFullActivation(rhs.m_needsFullActivation)
+ , m_allowsNewDecls(rhs.m_allowsNewDecls)
+ , m_strictMode(rhs.m_strictMode)
+ , m_isFunction(rhs.m_isFunction)
+ , m_isFunctionBoundary(rhs.m_isFunctionBoundary)
+ , m_isValidStrictMode(rhs.m_isValidStrictMode)
+ , m_loopDepth(rhs.m_loopDepth)
+ , m_switchDepth(rhs.m_switchDepth)
+ {
+ if (rhs.m_labels) {
+ m_labels = adoptPtr(new LabelStack);
+
+ typedef LabelStack::const_iterator iterator;
+ iterator end = rhs.m_labels->end();
+ for (iterator it = rhs.m_labels->begin(); it != end; ++it)
+ m_labels->append(ScopeLabelInfo(it->m_ident, it->m_isLoop));
+ }
+ }
+
+ void startSwitch() { m_switchDepth++; }
+ void endSwitch() { m_switchDepth--; }
+ void startLoop() { m_loopDepth++; }
+ void endLoop() { ASSERT(m_loopDepth); m_loopDepth--; }
+ bool inLoop() { return !!m_loopDepth; }
+ bool breakIsValid() { return m_loopDepth || m_switchDepth; }
+ bool continueIsValid() { return m_loopDepth; }
+
+ void pushLabel(const Identifier* label, bool isLoop)
+ {
+ if (!m_labels)
+ m_labels = adoptPtr(new LabelStack);
+ m_labels->append(ScopeLabelInfo(label->impl(), isLoop));
+ }
+
+ void popLabel()
+ {
+ ASSERT(m_labels);
+ ASSERT(m_labels->size());
+ m_labels->removeLast();
+ }
+
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ if (!m_labels)
+ return 0;
+ for (int i = m_labels->size(); i > 0; i--) {
+ if (m_labels->at(i - 1).m_ident == label->impl())
+ return &m_labels->at(i - 1);
+ }
+ return 0;
+ }
+
+ void setIsFunction()
+ {
+ m_isFunction = true;
+ m_isFunctionBoundary = true;
+ }
+ bool isFunction() { return m_isFunction; }
+ bool isFunctionBoundary() { return m_isFunctionBoundary; }
+
+ bool declareVariable(const Identifier* ident)
+ {
+ bool isValidStrictMode = m_globalData->propertyNames->eval != *ident && m_globalData->propertyNames->arguments != *ident;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ m_declaredVariables.add(ident->ustring().impl());
+ return isValidStrictMode;
+ }
+
+ void declareWrite(const Identifier* ident)
+ {
+ ASSERT(m_strictMode);
+ m_writtenVariables.add(ident->impl());
+ }
+
+ void preventNewDecls() { m_allowsNewDecls = false; }
+ bool allowsNewDecls() const { return m_allowsNewDecls; }
+
+ bool declareParameter(const Identifier* ident)
+ {
+ bool isArguments = m_globalData->propertyNames->arguments == *ident;
+ bool isValidStrictMode = m_declaredVariables.add(ident->ustring().impl()).second && m_globalData->propertyNames->eval != *ident && !isArguments;
+ m_isValidStrictMode = m_isValidStrictMode && isValidStrictMode;
+ if (isArguments)
+ m_shadowsArguments = true;
+ return isValidStrictMode;
+ }
+
+ void useVariable(const Identifier* ident, bool isEval)
+ {
+ m_usesEval |= isEval;
+ m_usedVariables.add(ident->ustring().impl());
+ }
+
+ void setNeedsFullActivation() { m_needsFullActivation = true; }
+
+ bool collectFreeVariables(Scope* nestedScope, bool shouldTrackClosedVariables)
+ {
+ if (nestedScope->m_usesEval)
+ m_usesEval = true;
+ IdentifierSet::iterator end = nestedScope->m_usedVariables.end();
+ for (IdentifierSet::iterator ptr = nestedScope->m_usedVariables.begin(); ptr != end; ++ptr) {
+ if (nestedScope->m_declaredVariables.contains(*ptr))
+ continue;
+ m_usedVariables.add(*ptr);
+ if (shouldTrackClosedVariables)
+ m_closedVariables.add(*ptr);
+ }
+ if (nestedScope->m_writtenVariables.size()) {
+ IdentifierSet::iterator end = nestedScope->m_writtenVariables.end();
+ for (IdentifierSet::iterator ptr = nestedScope->m_writtenVariables.begin(); ptr != end; ++ptr) {
+ if (nestedScope->m_declaredVariables.contains(*ptr))
+ continue;
+ m_writtenVariables.add(*ptr);
+ }
+ }
+
+ return true;
+ }
+
+ void getUncapturedWrittenVariables(IdentifierSet& writtenVariables)
+ {
+ IdentifierSet::iterator end = m_writtenVariables.end();
+ for (IdentifierSet::iterator ptr = m_writtenVariables.begin(); ptr != end; ++ptr) {
+ if (!m_declaredVariables.contains(*ptr))
+ writtenVariables.add(*ptr);
+ }
+ }
+
+ void getCapturedVariables(IdentifierSet& capturedVariables)
+ {
+ if (m_needsFullActivation || m_usesEval) {
+ capturedVariables.swap(m_declaredVariables);
+ return;
+ }
+ for (IdentifierSet::iterator ptr = m_closedVariables.begin(); ptr != m_closedVariables.end(); ++ptr) {
+ if (!m_declaredVariables.contains(*ptr))
+ continue;
+ capturedVariables.add(*ptr);
+ }
+ }
+ void setStrictMode() { m_strictMode = true; }
+ bool strictMode() const { return m_strictMode; }
+ bool isValidStrictMode() const { return m_isValidStrictMode; }
+ bool shadowsArguments() const { return m_shadowsArguments; }
+
+ void copyCapturedVariablesToVector(const IdentifierSet& capturedVariables, Vector<RefPtr<StringImpl> >& vector)
+ {
+ IdentifierSet::iterator end = capturedVariables.end();
+ for (IdentifierSet::iterator it = capturedVariables.begin(); it != end; ++it) {
+ if (m_declaredVariables.contains(*it))
+ continue;
+ vector.append(*it);
+ }
+ vector.shrinkToFit();
+ }
+
+ void saveFunctionInfo(SourceProviderCacheItem* info)
+ {
+ ASSERT(m_isFunction);
+ info->usesEval = m_usesEval;
+ info->strictMode = m_strictMode;
+ info->needsFullActivation = m_needsFullActivation;
+ copyCapturedVariablesToVector(m_writtenVariables, info->writtenVariables);
+ copyCapturedVariablesToVector(m_usedVariables, info->usedVariables);
+ }
+
+ void restoreFunctionInfo(const SourceProviderCacheItem* info)
+ {
+ ASSERT(m_isFunction);
+ m_usesEval = info->usesEval;
+ m_strictMode = info->strictMode;
+ m_needsFullActivation = info->needsFullActivation;
+ unsigned size = info->usedVariables.size();
+ for (unsigned i = 0; i < size; ++i)
+ m_usedVariables.add(info->usedVariables[i]);
+ size = info->writtenVariables.size();
+ for (unsigned i = 0; i < size; ++i)
+ m_writtenVariables.add(info->writtenVariables[i]);
+ }
+
+private:
+ const JSGlobalData* m_globalData;
+ bool m_shadowsArguments : 1;
+ bool m_usesEval : 1;
+ bool m_needsFullActivation : 1;
+ bool m_allowsNewDecls : 1;
+ bool m_strictMode : 1;
+ bool m_isFunction : 1;
+ bool m_isFunctionBoundary : 1;
+ bool m_isValidStrictMode : 1;
+ int m_loopDepth;
+ int m_switchDepth;
+
+ typedef Vector<ScopeLabelInfo, 2> LabelStack;
+ OwnPtr<LabelStack> m_labels;
+ IdentifierSet m_declaredVariables;
+ IdentifierSet m_usedVariables;
+ IdentifierSet m_closedVariables;
+ IdentifierSet m_writtenVariables;
+};
+
+typedef Vector<Scope, 10> ScopeStack;
+
+struct ScopeRef {
+ ScopeRef(ScopeStack* scopeStack, unsigned index)
+ : m_scopeStack(scopeStack)
+ , m_index(index)
+ {
+ }
+ Scope* operator->() { return &m_scopeStack->at(m_index); }
+ unsigned index() const { return m_index; }
+
+ bool hasContainingScope()
+ {
+ return m_index && !m_scopeStack->at(m_index).isFunctionBoundary();
+ }
+
+ ScopeRef containingScope()
+ {
+ ASSERT(hasContainingScope());
+ return ScopeRef(m_scopeStack, m_index - 1);
+ }
+
+private:
+ ScopeStack* m_scopeStack;
+ unsigned m_index;
+};
+
+template <typename LexerType>
+class Parser {
+ WTF_MAKE_NONCOPYABLE(Parser);
+ WTF_MAKE_FAST_ALLOCATED;
+
+public:
+ Parser(JSGlobalData*, const SourceCode&, FunctionParameters*, JSParserStrictness, JSParserMode);
+ ~Parser();
+
+ template <class ParsedNode>
+ PassRefPtr<ParsedNode> parse(JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, JSObject**);
+
+private:
+ struct AllowInOverride {
+ AllowInOverride(Parser* parser)
+ : m_parser(parser)
+ , m_oldAllowsIn(parser->m_allowsIn)
+ {
+ parser->m_allowsIn = true;
+ }
+ ~AllowInOverride()
+ {
+ m_parser->m_allowsIn = m_oldAllowsIn;
+ }
+ Parser* m_parser;
+ bool m_oldAllowsIn;
+ };
+
+ struct AutoPopScopeRef : public ScopeRef {
+ AutoPopScopeRef(Parser* parser, ScopeRef scope)
+ : ScopeRef(scope)
+ , m_parser(parser)
+ {
+ }
+
+ ~AutoPopScopeRef()
+ {
+ if (m_parser)
+ m_parser->popScope(*this, false);
+ }
+
+ void setPopped()
+ {
+ m_parser = 0;
+ }
+
+ private:
+ Parser* m_parser;
+ };
+
+ ScopeRef currentScope()
+ {
+ return ScopeRef(&m_scopeStack, m_scopeStack.size() - 1);
+ }
+
+ ScopeRef pushScope()
+ {
+ bool isFunction = false;
+ bool isStrict = false;
+ if (!m_scopeStack.isEmpty()) {
+ isStrict = m_scopeStack.last().strictMode();
+ isFunction = m_scopeStack.last().isFunction();
+ }
+ m_scopeStack.append(Scope(m_globalData, isFunction, isStrict));
+ return currentScope();
+ }
+
+ bool popScopeInternal(ScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ ASSERT_UNUSED(scope, scope.index() == m_scopeStack.size() - 1);
+ ASSERT(m_scopeStack.size() > 1);
+ bool result = m_scopeStack[m_scopeStack.size() - 2].collectFreeVariables(&m_scopeStack.last(), shouldTrackClosedVariables);
+ m_scopeStack.removeLast();
+ return result;
+ }
+
+ bool popScope(ScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ return popScopeInternal(scope, shouldTrackClosedVariables);
+ }
+
+ bool popScope(AutoPopScopeRef& scope, bool shouldTrackClosedVariables)
+ {
+ scope.setPopped();
+ return popScopeInternal(scope, shouldTrackClosedVariables);
+ }
+
+ bool declareVariable(const Identifier* ident)
+ {
+ unsigned i = m_scopeStack.size() - 1;
+ ASSERT(i < m_scopeStack.size());
+ while (!m_scopeStack[i].allowsNewDecls()) {
+ i--;
+ ASSERT(i < m_scopeStack.size());
+ }
+ return m_scopeStack[i].declareVariable(ident);
+ }
+
+ void declareWrite(const Identifier* ident)
+ {
+ if (!m_syntaxAlreadyValidated)
+ m_scopeStack.last().declareWrite(ident);
+ }
+
+ ScopeStack m_scopeStack;
+
+ const SourceProviderCacheItem* findCachedFunctionInfo(int openBracePos)
+ {
+ return m_functionCache ? m_functionCache->get(openBracePos) : 0;
+ }
+
+ Parser();
+ UString parseInner();
+
+ void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*,
+ ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures,
+ int, int, IdentifierSet&);
+
+ // Used to determine type of error to report.
+ bool isFunctionBodyNode(ScopeNode*) { return false; }
+ bool isFunctionBodyNode(FunctionBodyNode*) { return true; }
+
+
+ ALWAYS_INLINE void next(unsigned lexerFlags = 0)
+ {
+ m_lastLine = m_token.m_info.line;
+ m_lastTokenEnd = m_token.m_info.endOffset;
+ m_lexer->setLastLineNumber(m_lastLine);
+ m_token.m_type = m_lexer->lex(&m_token.m_data, &m_token.m_info, lexerFlags, strictMode());
+ }
+
+ ALWAYS_INLINE void nextExpectIdentifier(unsigned lexerFlags = 0)
+ {
+ m_lastLine = m_token.m_info.line;
+ m_lastTokenEnd = m_token.m_info.endOffset;
+ m_lexer->setLastLineNumber(m_lastLine);
+ m_token.m_type = m_lexer->lexExpectIdentifier(&m_token.m_data, &m_token.m_info, lexerFlags, strictMode());
+ }
+
+ ALWAYS_INLINE bool nextTokenIsColon()
+ {
+ return m_lexer->nextTokenIsColon();
+ }
+
+ ALWAYS_INLINE bool consume(JSTokenType expected, unsigned flags = 0)
+ {
+ bool result = m_token.m_type == expected;
+ if (result)
+ next(flags);
+ return result;
+ }
+
+ ALWAYS_INLINE UString getToken() {
+ SourceProvider* sourceProvider = m_source->provider();
+ return UString(sourceProvider->getRange(tokenStart(), tokenEnd()).impl());
+ }
+
+ ALWAYS_INLINE bool match(JSTokenType expected)
+ {
+ return m_token.m_type == expected;
+ }
+
+ ALWAYS_INLINE int tokenStart()
+ {
+ return m_token.m_info.startOffset;
+ }
+
+ ALWAYS_INLINE int tokenLine()
+ {
+ return m_token.m_info.line;
+ }
+
+ ALWAYS_INLINE int tokenEnd()
+ {
+ return m_token.m_info.endOffset;
+ }
+
+ const char* getTokenName(JSTokenType tok)
+ {
+ switch (tok) {
+ case NULLTOKEN:
+ return "null";
+ case TRUETOKEN:
+ return "true";
+ case FALSETOKEN:
+ return "false";
+ case BREAK:
+ return "break";
+ case CASE:
+ return "case";
+ case DEFAULT:
+ return "defualt";
+ case FOR:
+ return "for";
+ case NEW:
+ return "new";
+ case VAR:
+ return "var";
+ case CONSTTOKEN:
+ return "const";
+ case CONTINUE:
+ return "continue";
+ case FUNCTION:
+ return "function";
+ case IF:
+ return "if";
+ case THISTOKEN:
+ return "this";
+ case DO:
+ return "do";
+ case WHILE:
+ return "while";
+ case SWITCH:
+ return "switch";
+ case WITH:
+ return "with";
+ case THROW:
+ return "throw";
+ case TRY:
+ return "try";
+ case CATCH:
+ return "catch";
+ case FINALLY:
+ return "finally";
+ case DEBUGGER:
+ return "debugger";
+ case ELSE:
+ return "else";
+ case OPENBRACE:
+ return "{";
+ case CLOSEBRACE:
+ return "}";
+ case OPENPAREN:
+ return "(";
+ case CLOSEPAREN:
+ return ")";
+ case OPENBRACKET:
+ return "[";
+ case CLOSEBRACKET:
+ return "]";
+ case COMMA:
+ return ",";
+ case QUESTION:
+ return "?";
+ case SEMICOLON:
+ return ";";
+ case COLON:
+ return ":";
+ case DOT:
+ return ".";
+ case EQUAL:
+ return "=";
+ case PLUSEQUAL:
+ return "+=";
+ case MINUSEQUAL:
+ return "-=";
+ case MULTEQUAL:
+ return "*=";
+ case DIVEQUAL:
+ return "/=";
+ case LSHIFTEQUAL:
+ return "<<=";
+ case RSHIFTEQUAL:
+ return ">>=";
+ case URSHIFTEQUAL:
+ return ">>>=";
+ case ANDEQUAL:
+ return "&=";
+ case MODEQUAL:
+ return "%=";
+ case XOREQUAL:
+ return "^=";
+ case OREQUAL:
+ return "|=";
+ case AUTOPLUSPLUS:
+ case PLUSPLUS:
+ return "++";
+ case AUTOMINUSMINUS:
+ case MINUSMINUS:
+ return "--";
+ case EXCLAMATION:
+ return "!";
+ case TILDE:
+ return "~";
+ case TYPEOF:
+ return "typeof";
+ case VOIDTOKEN:
+ return "void";
+ case DELETETOKEN:
+ return "delete";
+ case OR:
+ return "||";
+ case AND:
+ return "&&";
+ case BITOR:
+ return "|";
+ case BITXOR:
+ return "^";
+ case BITAND:
+ return "&";
+ case EQEQ:
+ return "==";
+ case NE:
+ return "!=";
+ case STREQ:
+ return "===";
+ case STRNEQ:
+ return "!==";
+ case LT:
+ return "<";
+ case GT:
+ return ">";
+ case LE:
+ return "<=";
+ case GE:
+ return ">=";
+ case INSTANCEOF:
+ return "instanceof";
+ case INTOKEN:
+ return "in";
+ case LSHIFT:
+ return "<<";
+ case RSHIFT:
+ return ">>";
+ case URSHIFT:
+ return ">>>";
+ case PLUS:
+ return "+";
+ case MINUS:
+ return "-";
+ case TIMES:
+ return "*";
+ case DIVIDE:
+ return "/";
+ case MOD:
+ return "%";
+ case RETURN:
+ case RESERVED_IF_STRICT:
+ case RESERVED:
+ case NUMBER:
+ case IDENT:
+ case STRING:
+ case ERRORTOK:
+ case EOFTOK:
+ return 0;
+ case LastUntaggedToken:
+ break;
+ }
+ ASSERT_NOT_REACHED();
+ return "internal error";
+ }
+
+ ALWAYS_INLINE void updateErrorMessageSpecialCase(JSTokenType expectedToken)
+ {
+ String errorMessage;
+ switch (expectedToken) {
+ case RESERVED_IF_STRICT:
+ errorMessage = "Use of reserved word '";
+ errorMessage += getToken().impl();
+ errorMessage += "' in strict mode";
+ m_errorMessage = errorMessage.impl();
+ return;
+ case RESERVED:
+ errorMessage = "Use of reserved word '";
+ errorMessage += getToken().impl();
+ errorMessage += "'";
+ m_errorMessage = errorMessage.impl();
+ return;
+ case NUMBER:
+ errorMessage = "Unexpected number '";
+ errorMessage += getToken().impl();
+ errorMessage += "'";
+ m_errorMessage = errorMessage.impl();
+ return;
+ case IDENT:
+ errorMessage = "Expected an identifier but found '";
+ errorMessage += getToken().impl();
+ errorMessage += "' instead";
+ m_errorMessage = errorMessage.impl();
+ return;
+ case STRING:
+ errorMessage = "Unexpected string ";
+ errorMessage += getToken().impl();
+ m_errorMessage = errorMessage.impl();
+ return;
+ case ERRORTOK:
+ errorMessage = "Unrecognized token '";
+ errorMessage += getToken().impl();
+ errorMessage += "'";
+ m_errorMessage = errorMessage.impl();
+ return;
+ case EOFTOK:
+ m_errorMessage = "Unexpected EOF";
+ return;
+ case RETURN:
+ m_errorMessage = "Return statements are only valid inside functions";
+ return;
+ default:
+ ASSERT_NOT_REACHED();
+ m_errorMessage = "internal error";
+ return;
+ }
+ }
+
+ NEVER_INLINE void updateErrorMessage()
+ {
+ m_error = true;
+ const char* name = getTokenName(m_token.m_type);
+ if (!name)
+ updateErrorMessageSpecialCase(m_token.m_type);
+ else
+ m_errorMessage = UString(String::format("Unexpected token '%s'", name).impl());
+ }
+
+ NEVER_INLINE void updateErrorMessage(JSTokenType expectedToken)
+ {
+ m_error = true;
+ const char* name = getTokenName(expectedToken);
+ if (name)
+ m_errorMessage = UString(String::format("Expected token '%s'", name).impl());
+ else {
+ if (!getTokenName(m_token.m_type))
+ updateErrorMessageSpecialCase(m_token.m_type);
+ else
+ updateErrorMessageSpecialCase(expectedToken);
+ }
+ }
+
+ NEVER_INLINE void updateErrorWithNameAndMessage(const char* beforeMsg, UString name, const char* afterMsg)
+ {
+ m_error = true;
+ String prefix(beforeMsg);
+ String postfix(afterMsg);
+ prefix += " '";
+ prefix += name.impl();
+ prefix += "' ";
+ prefix += postfix;
+ m_errorMessage = prefix.impl();
+ }
+
+ NEVER_INLINE void updateErrorMessage(const char* msg)
+ {
+ m_error = true;
+ m_errorMessage = UString(msg);
+ }
+
+ void startLoop() { currentScope()->startLoop(); }
+ void endLoop() { currentScope()->endLoop(); }
+ void startSwitch() { currentScope()->startSwitch(); }
+ void endSwitch() { currentScope()->endSwitch(); }
+ void setStrictMode() { currentScope()->setStrictMode(); }
+ bool strictMode() { return currentScope()->strictMode(); }
+ bool isValidStrictMode() { return currentScope()->isValidStrictMode(); }
+ bool declareParameter(const Identifier* ident) { return currentScope()->declareParameter(ident); }
+ bool breakIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->breakIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ bool continueIsValid()
+ {
+ ScopeRef current = currentScope();
+ while (!current->continueIsValid()) {
+ if (!current.hasContainingScope())
+ return false;
+ current = current.containingScope();
+ }
+ return true;
+ }
+ void pushLabel(const Identifier* label, bool isLoop) { currentScope()->pushLabel(label, isLoop); }
+ void popLabel() { currentScope()->popLabel(); }
+ ScopeLabelInfo* getLabel(const Identifier* label)
+ {
+ ScopeRef current = currentScope();
+ ScopeLabelInfo* result = 0;
+ while (!(result = current->getLabel(label))) {
+ if (!current.hasContainingScope())
+ return 0;
+ current = current.containingScope();
+ }
+ return result;
+ }
+
+ template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive, unsigned* directiveLiteralLength = 0);
+ template <class TreeBuilder> TreeStatement parseFunctionDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseVarDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseConstDeclaration(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDoWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWhileStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseForStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseBreakStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseContinueStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseReturnStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseThrowStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseWithStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseSwitchStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeClauseList parseSwitchClauses(TreeBuilder&);
+ template <class TreeBuilder> TreeClause parseSwitchDefaultClause(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseTryStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseDebuggerStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseExpressionOrLabelStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseIfStatement(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeStatement parseBlockStatement(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseAssignmentExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseConditionalExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseBinaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseUnaryExpression(TreeBuilder&);
+ template <class TreeBuilder> TreeExpression parseMemberExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parsePrimaryExpression(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseArrayLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseObjectLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseStrictObjectLiteral(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeArguments parseArguments(TreeBuilder&);
+ template <bool strict, class TreeBuilder> ALWAYS_INLINE TreeProperty parseProperty(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFunctionBody parseFunctionBody(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeFormalParameterList parseFormalParameters(TreeBuilder&);
+ template <class TreeBuilder> ALWAYS_INLINE TreeExpression parseVarDeclarationList(TreeBuilder&, int& declarations, const Identifier*& lastIdent, TreeExpression& lastInitializer, int& identStart, int& initStart, int& initEnd);
+ template <class TreeBuilder> ALWAYS_INLINE TreeConstDeclList parseConstDeclarationList(TreeBuilder& context);
+ template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
+ ALWAYS_INLINE int isBinaryOperator(JSTokenType);
+ bool allowAutomaticSemicolon();
+
+ bool autoSemiColon()
+ {
+ if (m_token.m_type == SEMICOLON) {
+ next();
+ return true;
+ }
+ return allowAutomaticSemicolon();
+ }
+
+ bool canRecurse()
+ {
+ return m_stack.recursionCheck();
+ }
+
+ int lastTokenEnd() const
+ {
+ return m_lastTokenEnd;
+ }
+
+ mutable const JSGlobalData* m_globalData;
+ const SourceCode* m_source;
+ ParserArena* m_arena;
+ OwnPtr<LexerType> m_lexer;
+
+ StackBounds m_stack;
+ bool m_error;
+ UString m_errorMessage;
+ JSToken m_token;
+ bool m_allowsIn;
+ int m_lastLine;
+ int m_lastTokenEnd;
+ int m_assignmentCount;
+ int m_nonLHSCount;
+ bool m_syntaxAlreadyValidated;
+ int m_statementDepth;
+ int m_nonTrivialExpressionCount;
+ const Identifier* m_lastIdentifier;
+ SourceProviderCache* m_functionCache;
+ SourceElements* m_sourceElements;
+ ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ IdentifierSet m_capturedVariables;
+ CodeFeatures m_features;
+ int m_numConstants;
+
+ struct DepthManager {
+ DepthManager(int* depth)
+ : m_originalDepth(*depth)
+ , m_depth(depth)
+ {
+ }
+
+ ~DepthManager()
+ {
+ *m_depth = m_originalDepth;
+ }
+
+ private:
+ int m_originalDepth;
+ int* m_depth;
+ };
+};
+
+template <typename LexerType>
+template <class ParsedNode>
+PassRefPtr<ParsedNode> Parser<LexerType>::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, JSObject** exception)
+{
+ ASSERT(lexicalGlobalObject);
+ ASSERT(exception && !*exception);
+ int errLine;
+ UString errMsg;
+
+ if (ParsedNode::scopeIsFunction)
+ m_lexer->setIsReparsing();
+
+ m_sourceElements = 0;
+
+ errLine = -1;
+ errMsg = UString();
+
+ UString parseError = parseInner();
+
+ int lineNumber = m_lexer->lineNumber();
+ bool lexError = m_lexer->sawError();
+ UString lexErrorMessage = lexError ? m_lexer->getErrorMessage() : UString();
+ ASSERT(lexErrorMessage.isNull() != lexError);
+ m_lexer->clear();
+
+ if (!parseError.isNull() || lexError) {
+ errLine = lineNumber;
+ errMsg = !lexErrorMessage.isNull() ? lexErrorMessage : parseError;
+ m_sourceElements = 0;
+ }
+
+ RefPtr<ParsedNode> result;
+ if (m_sourceElements) {
+ result = ParsedNode::create(&lexicalGlobalObject->globalData(),
+ m_lexer->lastLineNumber(),
+ m_sourceElements,
+ m_varDeclarations ? &m_varDeclarations->data : 0,
+ m_funcDeclarations ? &m_funcDeclarations->data : 0,
+ m_capturedVariables,
+ *m_source,
+ m_features,
+ m_numConstants);
+ result->setLoc(m_source->firstLine(), m_lastLine);
+ } else if (lexicalGlobalObject) {
+ // We can never see a syntax error when reparsing a function, since we should have
+ // reported the error when parsing the containing program or eval code. So if we're
+ // parsing a function body node, we assume that what actually happened here is that
+ // we ran out of stack while parsing. If we see an error while parsing eval or program
+ // code we assume that it was a syntax error since running out of stack is much less
+ // likely, and we are currently unable to distinguish between the two cases.
+ if (isFunctionBodyNode(static_cast<ParsedNode*>(0)))
+ *exception = createStackOverflowError(lexicalGlobalObject);
+ else if (isEvalNode<ParsedNode>())
+ *exception = createSyntaxError(lexicalGlobalObject, errMsg);
+ else
+ *exception = addErrorInfo(&lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, *m_source);
+ }
+
+ if (debugger && !ParsedNode::scopeIsFunction)
+ debugger->sourceParsed(debuggerExecState, m_source->provider(), errLine, errMsg);
+
+ m_arena->reset();
+
+ return result.release();
+}
+
+template <class ParsedNode>
+PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, JSGlobalObject* lexicalGlobalObject, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, Debugger* debugger, ExecState* execState, JSObject** exception)
+{
+ SamplingRegion samplingRegion("Parsing");
+
+ ASSERT(source.provider()->data());
+
+ if (source.provider()->data()->is8Bit()) {
+ Parser< Lexer<LChar> > parser(globalData, source, parameters, strictness, parserMode);
+ return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
+ }
+ Parser< Lexer<UChar> > parser(globalData, source, parameters, strictness, parserMode);
+ return parser.parse<ParsedNode>(lexicalGlobalObject, debugger, execState, exception);
+}
+
+} // namespace
+#endif
diff --git a/Source/JavaScriptCore/parser/ParserArena.cpp b/Source/JavaScriptCore/parser/ParserArena.cpp
new file mode 100644
index 000000000..56c58dacf
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserArena.cpp
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ParserArena.h"
+
+#include "Nodes.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+ParserArena::ParserArena()
+ : m_freeableMemory(0)
+ , m_freeablePoolEnd(0)
+ , m_identifierArena(adoptPtr(new IdentifierArena))
+{
+}
+
+inline void* ParserArena::freeablePool()
+{
+ ASSERT(m_freeablePoolEnd);
+ return m_freeablePoolEnd - freeablePoolSize;
+}
+
+inline void ParserArena::deallocateObjects()
+{
+ size_t size = m_deletableObjects.size();
+ for (size_t i = 0; i < size; ++i)
+ m_deletableObjects[i]->~ParserArenaDeletable();
+
+ if (m_freeablePoolEnd)
+ fastFree(freeablePool());
+
+ size = m_freeablePools.size();
+ for (size_t i = 0; i < size; ++i)
+ fastFree(m_freeablePools[i]);
+}
+
+ParserArena::~ParserArena()
+{
+ deallocateObjects();
+}
+
+bool ParserArena::contains(ParserArenaRefCounted* object) const
+{
+ return m_refCountedObjects.find(object) != notFound;
+}
+
+ParserArenaRefCounted* ParserArena::last() const
+{
+ return m_refCountedObjects.last().get();
+}
+
+void ParserArena::removeLast()
+{
+ m_refCountedObjects.removeLast();
+}
+
+void ParserArena::reset()
+{
+ // Since this code path is used only when parsing fails, it's not bothering to reuse
+ // any of the memory the arena allocated. We could improve that later if we want to
+ // efficiently reuse the same arena.
+
+ deallocateObjects();
+
+ m_freeableMemory = 0;
+ m_freeablePoolEnd = 0;
+ m_identifierArena->clear();
+ m_freeablePools.clear();
+ m_deletableObjects.clear();
+ m_refCountedObjects.clear();
+}
+
+void ParserArena::allocateFreeablePool()
+{
+ if (m_freeablePoolEnd)
+ m_freeablePools.append(freeablePool());
+
+ char* pool = static_cast<char*>(fastMalloc(freeablePoolSize));
+ m_freeableMemory = pool;
+ m_freeablePoolEnd = pool + freeablePoolSize;
+ ASSERT(freeablePool() == pool);
+}
+
+bool ParserArena::isEmpty() const
+{
+ return !m_freeablePoolEnd
+ && m_identifierArena->isEmpty()
+ && m_freeablePools.isEmpty()
+ && m_deletableObjects.isEmpty()
+ && m_refCountedObjects.isEmpty();
+}
+
+void ParserArena::derefWithArena(PassRefPtr<ParserArenaRefCounted> object)
+{
+ m_refCountedObjects.append(object);
+}
+
+}
diff --git a/Source/JavaScriptCore/parser/ParserArena.h b/Source/JavaScriptCore/parser/ParserArena.h
new file mode 100644
index 000000000..35674b604
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserArena.h
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParserArena_h
+#define ParserArena_h
+
+#include "Identifier.h"
+#include <wtf/SegmentedVector.h>
+
+namespace JSC {
+
+ class ParserArenaDeletable;
+ class ParserArenaRefCounted;
+
+ class IdentifierArena {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ IdentifierArena()
+ {
+ clear();
+ }
+
+ template <typename T>
+ ALWAYS_INLINE const Identifier& makeIdentifier(JSGlobalData*, const T* characters, size_t length);
+ ALWAYS_INLINE const Identifier& makeIdentifierLCharFromUChar(JSGlobalData*, const UChar* characters, size_t length);
+
+ const Identifier& makeNumericIdentifier(JSGlobalData*, double number);
+
+ bool isEmpty() const { return m_identifiers.isEmpty(); }
+
+ public:
+ static const int MaximumCachableCharacter = 128;
+ typedef SegmentedVector<Identifier, 64> IdentifierVector;
+ void clear()
+ {
+ m_identifiers.clear();
+ for (int i = 0; i < MaximumCachableCharacter; i++)
+ m_shortIdentifiers[i] = 0;
+ for (int i = 0; i < MaximumCachableCharacter; i++)
+ m_recentIdentifiers[i] = 0;
+ }
+
+ private:
+ IdentifierVector m_identifiers;
+ FixedArray<Identifier*, MaximumCachableCharacter> m_shortIdentifiers;
+ FixedArray<Identifier*, MaximumCachableCharacter> m_recentIdentifiers;
+ };
+
+ template <typename T>
+ ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifier(JSGlobalData* globalData, const T* characters, size_t length)
+ {
+ if (characters[0] >= MaximumCachableCharacter) {
+ m_identifiers.append(Identifier(globalData, characters, length));
+ return m_identifiers.last();
+ }
+ if (length == 1) {
+ if (Identifier* ident = m_shortIdentifiers[characters[0]])
+ return *ident;
+ m_identifiers.append(Identifier(globalData, characters, length));
+ m_shortIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+ Identifier* ident = m_recentIdentifiers[characters[0]];
+ if (ident && Identifier::equal(ident->impl(), characters, length))
+ return *ident;
+ m_identifiers.append(Identifier(globalData, characters, length));
+ m_recentIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+
+ ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifierLCharFromUChar(JSGlobalData* globalData, const UChar* characters, size_t length)
+ {
+ if (characters[0] >= MaximumCachableCharacter) {
+ m_identifiers.append(Identifier::createLCharFromUChar(globalData, characters, length));
+ return m_identifiers.last();
+ }
+ if (length == 1) {
+ if (Identifier* ident = m_shortIdentifiers[characters[0]])
+ return *ident;
+ m_identifiers.append(Identifier(globalData, characters, length));
+ m_shortIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+ Identifier* ident = m_recentIdentifiers[characters[0]];
+ if (ident && Identifier::equal(ident->impl(), characters, length))
+ return *ident;
+ m_identifiers.append(Identifier::createLCharFromUChar(globalData, characters, length));
+ m_recentIdentifiers[characters[0]] = &m_identifiers.last();
+ return m_identifiers.last();
+ }
+
+ inline const Identifier& IdentifierArena::makeNumericIdentifier(JSGlobalData* globalData, double number)
+ {
+ m_identifiers.append(Identifier(globalData, UString::number(number)));
+ return m_identifiers.last();
+ }
+
+ class ParserArena {
+ WTF_MAKE_NONCOPYABLE(ParserArena);
+ public:
+ ParserArena();
+ ~ParserArena();
+
+ void swap(ParserArena& otherArena)
+ {
+ std::swap(m_freeableMemory, otherArena.m_freeableMemory);
+ std::swap(m_freeablePoolEnd, otherArena.m_freeablePoolEnd);
+ m_identifierArena.swap(otherArena.m_identifierArena);
+ m_freeablePools.swap(otherArena.m_freeablePools);
+ m_deletableObjects.swap(otherArena.m_deletableObjects);
+ m_refCountedObjects.swap(otherArena.m_refCountedObjects);
+ }
+
+ void* allocateFreeable(size_t size)
+ {
+ ASSERT(size);
+ ASSERT(size <= freeablePoolSize);
+ size_t alignedSize = alignSize(size);
+ ASSERT(alignedSize <= freeablePoolSize);
+ if (UNLIKELY(static_cast<size_t>(m_freeablePoolEnd - m_freeableMemory) < alignedSize))
+ allocateFreeablePool();
+ void* block = m_freeableMemory;
+ m_freeableMemory += alignedSize;
+ return block;
+ }
+
+ void* allocateDeletable(size_t size)
+ {
+ ParserArenaDeletable* deletable = static_cast<ParserArenaDeletable*>(allocateFreeable(size));
+ m_deletableObjects.append(deletable);
+ return deletable;
+ }
+
+ void derefWithArena(PassRefPtr<ParserArenaRefCounted>);
+ bool contains(ParserArenaRefCounted*) const;
+ ParserArenaRefCounted* last() const;
+ void removeLast();
+
+ bool isEmpty() const;
+ void reset();
+
+ IdentifierArena& identifierArena() { return *m_identifierArena; }
+
+ private:
+ static const size_t freeablePoolSize = 8000;
+
+ static size_t alignSize(size_t size)
+ {
+ return (size + sizeof(WTF::AllocAlignmentInteger) - 1) & ~(sizeof(WTF::AllocAlignmentInteger) - 1);
+ }
+
+ void* freeablePool();
+ void allocateFreeablePool();
+ void deallocateObjects();
+
+ char* m_freeableMemory;
+ char* m_freeablePoolEnd;
+
+ OwnPtr<IdentifierArena> m_identifierArena;
+ Vector<void*> m_freeablePools;
+ Vector<ParserArenaDeletable*> m_deletableObjects;
+ Vector<RefPtr<ParserArenaRefCounted> > m_refCountedObjects;
+ };
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/parser/ParserTokens.h b/Source/JavaScriptCore/parser/ParserTokens.h
new file mode 100644
index 000000000..a1ea751ac
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserTokens.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ParserTokens_h
+#define ParserTokens_h
+
+namespace JSC {
+
+class Identifier;
+
+enum {
+ UnaryOpTokenFlag = 64,
+ KeywordTokenFlag = 128,
+ BinaryOpTokenPrecedenceShift = 8,
+ BinaryOpTokenAllowsInPrecedenceAdditionalShift = 4,
+ BinaryOpTokenPrecedenceMask = 15 << BinaryOpTokenPrecedenceShift,
+};
+
+#define BINARY_OP_PRECEDENCE(prec) (((prec) << BinaryOpTokenPrecedenceShift) | ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift)))
+#define IN_OP_PRECEDENCE(prec) ((prec) << (BinaryOpTokenPrecedenceShift + BinaryOpTokenAllowsInPrecedenceAdditionalShift))
+
+enum JSTokenType {
+ NULLTOKEN = KeywordTokenFlag,
+ TRUETOKEN,
+ FALSETOKEN,
+ BREAK,
+ CASE,
+ DEFAULT,
+ FOR,
+ NEW,
+ VAR,
+ CONSTTOKEN,
+ CONTINUE,
+ FUNCTION,
+ RETURN,
+ IF,
+ THISTOKEN,
+ DO,
+ WHILE,
+ SWITCH,
+ WITH,
+ RESERVED,
+ RESERVED_IF_STRICT,
+ THROW,
+ TRY,
+ CATCH,
+ FINALLY,
+ DEBUGGER,
+ ELSE,
+ OPENBRACE = 0,
+ CLOSEBRACE,
+ OPENPAREN,
+ CLOSEPAREN,
+ OPENBRACKET,
+ CLOSEBRACKET,
+ COMMA,
+ QUESTION,
+ NUMBER,
+ IDENT,
+ STRING,
+ SEMICOLON,
+ COLON,
+ DOT,
+ ERRORTOK,
+ EOFTOK,
+ EQUAL,
+ PLUSEQUAL,
+ MINUSEQUAL,
+ MULTEQUAL,
+ DIVEQUAL,
+ LSHIFTEQUAL,
+ RSHIFTEQUAL,
+ URSHIFTEQUAL,
+ ANDEQUAL,
+ MODEQUAL,
+ XOREQUAL,
+ OREQUAL,
+ LastUntaggedToken,
+
+ // Begin tagged tokens
+ PLUSPLUS = 0 | UnaryOpTokenFlag,
+ MINUSMINUS = 1 | UnaryOpTokenFlag,
+ EXCLAMATION = 2 | UnaryOpTokenFlag,
+ TILDE = 3 | UnaryOpTokenFlag,
+ AUTOPLUSPLUS = 4 | UnaryOpTokenFlag,
+ AUTOMINUSMINUS = 5 | UnaryOpTokenFlag,
+ TYPEOF = 6 | UnaryOpTokenFlag | KeywordTokenFlag,
+ VOIDTOKEN = 7 | UnaryOpTokenFlag | KeywordTokenFlag,
+ DELETETOKEN = 8 | UnaryOpTokenFlag | KeywordTokenFlag,
+ OR = 0 | BINARY_OP_PRECEDENCE(1),
+ AND = 1 | BINARY_OP_PRECEDENCE(2),
+ BITOR = 2 | BINARY_OP_PRECEDENCE(3),
+ BITXOR = 3 | BINARY_OP_PRECEDENCE(4),
+ BITAND = 4 | BINARY_OP_PRECEDENCE(5),
+ EQEQ = 5 | BINARY_OP_PRECEDENCE(6),
+ NE = 6 | BINARY_OP_PRECEDENCE(6),
+ STREQ = 7 | BINARY_OP_PRECEDENCE(6),
+ STRNEQ = 8 | BINARY_OP_PRECEDENCE(6),
+ LT = 9 | BINARY_OP_PRECEDENCE(7),
+ GT = 10 | BINARY_OP_PRECEDENCE(7),
+ LE = 11 | BINARY_OP_PRECEDENCE(7),
+ GE = 12 | BINARY_OP_PRECEDENCE(7),
+ INSTANCEOF = 13 | BINARY_OP_PRECEDENCE(7) | KeywordTokenFlag,
+ INTOKEN = 14 | IN_OP_PRECEDENCE(7) | KeywordTokenFlag,
+ LSHIFT = 15 | BINARY_OP_PRECEDENCE(8),
+ RSHIFT = 16 | BINARY_OP_PRECEDENCE(8),
+ URSHIFT = 17 | BINARY_OP_PRECEDENCE(8),
+ PLUS = 18 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag,
+ MINUS = 19 | BINARY_OP_PRECEDENCE(9) | UnaryOpTokenFlag,
+ TIMES = 20 | BINARY_OP_PRECEDENCE(10),
+ DIVIDE = 21 | BINARY_OP_PRECEDENCE(10),
+ MOD = 22 | BINARY_OP_PRECEDENCE(10)
+};
+
+union JSTokenData {
+ int intValue;
+ double doubleValue;
+ const Identifier* ident;
+};
+
+struct JSTokenInfo {
+ JSTokenInfo() : line(0) { }
+ int line;
+ int startOffset;
+ int endOffset;
+};
+
+struct JSToken {
+ JSTokenType m_type;
+ JSTokenData m_data;
+ JSTokenInfo m_info;
+};
+
+enum JSParserStrictness { JSParseNormal, JSParseStrict };
+enum JSParserMode { JSParseProgramCode, JSParseFunctionCode };
+
+}
+
+
+#endif // ParserTokens_h
diff --git a/Source/JavaScriptCore/parser/ResultType.h b/Source/JavaScriptCore/parser/ResultType.h
new file mode 100644
index 000000000..27b8112a0
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ResultType.h
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ResultType_h
+#define ResultType_h
+
+namespace JSC {
+
+ struct ResultType {
+ friend struct OperandTypes;
+
+ typedef char Type;
+ static const Type TypeReusable = 1;
+ static const Type TypeInt32 = 2;
+
+ static const Type TypeMaybeNumber = 0x04;
+ static const Type TypeMaybeString = 0x08;
+ static const Type TypeMaybeNull = 0x10;
+ static const Type TypeMaybeBool = 0x20;
+ static const Type TypeMaybeOther = 0x40;
+
+ static const Type TypeBits = TypeMaybeNumber | TypeMaybeString | TypeMaybeNull | TypeMaybeBool | TypeMaybeOther;
+
+ explicit ResultType(Type type)
+ : m_type(type)
+ {
+ }
+
+ bool isReusable()
+ {
+ return m_type & TypeReusable;
+ }
+
+ bool isInt32()
+ {
+ return m_type & TypeInt32;
+ }
+
+ bool definitelyIsNumber()
+ {
+ return (m_type & TypeBits) == TypeMaybeNumber;
+ }
+
+ bool definitelyIsString()
+ {
+ return (m_type & TypeBits) == TypeMaybeString;
+ }
+
+ bool mightBeNumber()
+ {
+ return m_type & TypeMaybeNumber;
+ }
+
+ bool isNotNumber()
+ {
+ return !mightBeNumber();
+ }
+
+ static ResultType nullType()
+ {
+ return ResultType(TypeMaybeNull);
+ }
+
+ static ResultType booleanType()
+ {
+ return ResultType(TypeMaybeBool);
+ }
+
+ static ResultType numberType()
+ {
+ return ResultType(TypeMaybeNumber);
+ }
+
+ static ResultType numberTypeCanReuse()
+ {
+ return ResultType(TypeReusable | TypeMaybeNumber);
+ }
+
+ static ResultType numberTypeCanReuseIsInt32()
+ {
+ return ResultType(TypeReusable | TypeInt32 | TypeMaybeNumber);
+ }
+
+ static ResultType stringOrNumberTypeCanReuse()
+ {
+ return ResultType(TypeReusable | TypeMaybeNumber | TypeMaybeString);
+ }
+
+ static ResultType stringType()
+ {
+ return ResultType(TypeMaybeString);
+ }
+
+ static ResultType unknownType()
+ {
+ return ResultType(TypeBits);
+ }
+
+ static ResultType forAdd(ResultType op1, ResultType op2)
+ {
+ if (op1.definitelyIsNumber() && op2.definitelyIsNumber())
+ return numberTypeCanReuse();
+ if (op1.definitelyIsString() || op2.definitelyIsString())
+ return stringType();
+ return stringOrNumberTypeCanReuse();
+ }
+
+ static ResultType forBitOp()
+ {
+ return numberTypeCanReuseIsInt32();
+ }
+
+ private:
+ Type m_type;
+ };
+
+ struct OperandTypes
+ {
+ OperandTypes(ResultType first = ResultType::unknownType(), ResultType second = ResultType::unknownType())
+ {
+ // We have to initialize one of the int to ensure that
+ // the entire struct is initialized.
+ m_u.i = 0;
+ m_u.rds.first = first.m_type;
+ m_u.rds.second = second.m_type;
+ }
+
+ union {
+ struct {
+ ResultType::Type first;
+ ResultType::Type second;
+ } rds;
+ int i;
+ } m_u;
+
+ ResultType first()
+ {
+ return ResultType(m_u.rds.first);
+ }
+
+ ResultType second()
+ {
+ return ResultType(m_u.rds.second);
+ }
+
+ int toInt()
+ {
+ return m_u.i;
+ }
+ static OperandTypes fromInt(int value)
+ {
+ OperandTypes types;
+ types.m_u.i = value;
+ return types;
+ }
+ };
+
+} // namespace JSC
+
+#endif // ResultType_h
diff --git a/Source/JavaScriptCore/parser/SourceCode.h b/Source/JavaScriptCore/parser/SourceCode.h
new file mode 100644
index 000000000..2a162b90f
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceCode.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceCode_h
+#define SourceCode_h
+
+#include "SourceProvider.h"
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ class SourceCode {
+ public:
+ SourceCode()
+ : m_provider(0)
+ , m_startChar(0)
+ , m_endChar(0)
+ , m_firstLine(0)
+ {
+ }
+
+ SourceCode(PassRefPtr<SourceProvider> provider, int firstLine = 1)
+ : m_provider(provider)
+ , m_startChar(0)
+ , m_endChar(m_provider->length())
+ , m_firstLine(std::max(firstLine, 1))
+ {
+ }
+
+ SourceCode(PassRefPtr<SourceProvider> provider, int start, int end, int firstLine)
+ : m_provider(provider)
+ , m_startChar(start)
+ , m_endChar(end)
+ , m_firstLine(std::max(firstLine, 1))
+ {
+ }
+
+ UString toString() const
+ {
+ if (!m_provider)
+ return UString();
+ return m_provider->getRange(m_startChar, m_endChar);
+ }
+
+ bool isNull() const { return !m_provider; }
+ SourceProvider* provider() const { return m_provider.get(); }
+ int firstLine() const { return m_firstLine; }
+ int startOffset() const { return m_startChar; }
+ int endOffset() const { return m_endChar; }
+ const UChar* data() const
+ {
+ ASSERT(m_provider->data());
+ return m_provider->data()->characters16() + m_startChar;
+ }
+ int length() const { return m_endChar - m_startChar; }
+
+ SourceCode subExpression(unsigned openBrace, unsigned closeBrace, int firstLine);
+
+ private:
+ RefPtr<SourceProvider> m_provider;
+ int m_startChar;
+ int m_endChar;
+ int m_firstLine;
+ };
+
+ inline SourceCode makeSource(const UString& source, const UString& url = UString(), const TextPosition& startPosition = TextPosition::minimumPosition())
+ {
+ return SourceCode(UStringSourceProvider::create(source, url, startPosition), startPosition.m_line.oneBasedInt());
+ }
+
+ inline SourceCode SourceCode::subExpression(unsigned openBrace, unsigned closeBrace, int firstLine)
+ {
+ ASSERT((*provider()->data())[openBrace] == '{');
+ ASSERT((*provider()->data())[closeBrace] == '}');
+ return SourceCode(provider(), openBrace, closeBrace + 1, firstLine);
+ }
+
+} // namespace JSC
+
+#endif // SourceCode_h
diff --git a/Source/JavaScriptCore/parser/SourceProvider.h b/Source/JavaScriptCore/parser/SourceProvider.h
new file mode 100644
index 000000000..dfc8d88e2
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProvider.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceProvider_h
+#define SourceProvider_h
+
+#include "SourceProviderCache.h"
+#include "UString.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/UnusedParam.h>
+#include <wtf/text/TextPosition.h>
+
+namespace JSC {
+
+ class SourceProvider : public RefCounted<SourceProvider> {
+ public:
+ SourceProvider(const UString& url, const TextPosition& startPosition, SourceProviderCache* cache = 0)
+ : m_url(url)
+ , m_startPosition(startPosition)
+ , m_validated(false)
+ , m_cache(cache ? cache : new SourceProviderCache)
+ , m_cacheOwned(!cache)
+ {
+ deprecatedTurnOffVerifier();
+ }
+ virtual ~SourceProvider()
+ {
+ if (m_cacheOwned)
+ delete m_cache;
+ }
+
+ virtual UString getRange(int start, int end) const = 0;
+ virtual const StringImpl* data() const = 0;
+ virtual int length() const = 0;
+
+ const UString& url() { return m_url; }
+ TextPosition startPosition() const { return m_startPosition; }
+ intptr_t asID() { return reinterpret_cast<intptr_t>(this); }
+
+ bool isValid() const { return m_validated; }
+ void setValid() { m_validated = true; }
+
+ SourceProviderCache* cache() const { return m_cache; }
+ void notifyCacheSizeChanged(int delta) { if (!m_cacheOwned) cacheSizeChanged(delta); }
+
+ private:
+ virtual void cacheSizeChanged(int delta) { UNUSED_PARAM(delta); }
+
+ UString m_url;
+ TextPosition m_startPosition;
+ bool m_validated;
+ SourceProviderCache* m_cache;
+ bool m_cacheOwned;
+ };
+
+ class UStringSourceProvider : public SourceProvider {
+ public:
+ static PassRefPtr<UStringSourceProvider> create(const UString& source, const UString& url, const TextPosition& startPosition = TextPosition::minimumPosition())
+ {
+ return adoptRef(new UStringSourceProvider(source, url, startPosition));
+ }
+
+ UString getRange(int start, int end) const
+ {
+ return m_source.substringSharingImpl(start, end - start);
+ }
+ const StringImpl* data() const { return m_source.impl(); }
+ int length() const { return m_source.length(); }
+
+ private:
+ UStringSourceProvider(const UString& source, const UString& url, const TextPosition& startPosition)
+ : SourceProvider(url, startPosition)
+ , m_source(source)
+ {
+ }
+
+ UString m_source;
+ };
+
+} // namespace JSC
+
+#endif // SourceProvider_h
diff --git a/Source/JavaScriptCore/parser/SourceProviderCache.cpp b/Source/JavaScriptCore/parser/SourceProviderCache.cpp
new file mode 100644
index 000000000..afeec5283
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProviderCache.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "SourceProviderCache.h"
+
+#include "SourceProviderCacheItem.h"
+
+namespace JSC {
+
+SourceProviderCache::~SourceProviderCache()
+{
+ clear();
+}
+
+void SourceProviderCache::clear()
+{
+ deleteAllValues(m_map);
+ m_map.clear();
+ m_contentByteSize = 0;
+}
+
+unsigned SourceProviderCache::byteSize() const
+{
+ return m_contentByteSize + sizeof(*this) + m_map.capacity() * sizeof(SourceProviderCacheItem*);
+}
+
+void SourceProviderCache::add(int sourcePosition, PassOwnPtr<SourceProviderCacheItem> item, unsigned size)
+{
+ m_map.add(sourcePosition, item.leakPtr());
+ m_contentByteSize += size;
+}
+
+}
diff --git a/Source/JavaScriptCore/parser/SourceProviderCache.h b/Source/JavaScriptCore/parser/SourceProviderCache.h
new file mode 100644
index 000000000..c7f332d38
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProviderCache.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceProviderCache_h
+#define SourceProviderCache_h
+
+#include <wtf/HashMap.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+class SourceProviderCacheItem;
+
+class SourceProviderCache {
+public:
+ SourceProviderCache() : m_contentByteSize(0) {}
+ JS_EXPORT_PRIVATE ~SourceProviderCache();
+
+ JS_EXPORT_PRIVATE void clear();
+ JS_EXPORT_PRIVATE unsigned byteSize() const;
+ void add(int sourcePosition, PassOwnPtr<SourceProviderCacheItem>, unsigned size);
+ const SourceProviderCacheItem* get(int sourcePosition) const { return m_map.get(sourcePosition); }
+
+private:
+ HashMap<int, SourceProviderCacheItem*> m_map;
+ unsigned m_contentByteSize;
+};
+
+}
+
+#endif // SourceProviderCache_h
diff --git a/Source/JavaScriptCore/parser/SourceProviderCacheItem.h b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h
new file mode 100644
index 000000000..3662367a0
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProviderCacheItem.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceProviderCacheItem_h
+#define SourceProviderCacheItem_h
+
+#include "ParserTokens.h"
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+namespace JSC {
+
+class SourceProviderCacheItem {
+public:
+ SourceProviderCacheItem(int closeBraceLine, int closeBracePos)
+ : closeBraceLine(closeBraceLine)
+ , closeBracePos(closeBracePos)
+ {
+ }
+ unsigned approximateByteSize() const
+ {
+ // The identifiers are uniqued strings so most likely there are few names that actually use any additional memory.
+ static const unsigned assummedAverageIdentifierSize = sizeof(RefPtr<StringImpl>) + 2;
+ unsigned size = sizeof(*this);
+ size += usedVariables.size() * assummedAverageIdentifierSize;
+ size += writtenVariables.size() * assummedAverageIdentifierSize;
+ return size;
+ }
+ JSToken closeBraceToken() const
+ {
+ JSToken token;
+ token.m_type = CLOSEBRACE;
+ token.m_data.intValue = closeBracePos;
+ token.m_info.startOffset = closeBracePos;
+ token.m_info.endOffset = closeBracePos + 1;
+ token.m_info.line = closeBraceLine;
+ return token;
+ }
+
+ int closeBraceLine;
+ int closeBracePos;
+ bool usesEval;
+ bool strictMode;
+ bool needsFullActivation;
+ Vector<RefPtr<StringImpl> > usedVariables;
+ Vector<RefPtr<StringImpl> > writtenVariables;
+};
+
+}
+
+#endif // SourceProviderCacheItem_h
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
new file mode 100644
index 000000000..270c82385
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SyntaxChecker_h
+#define SyntaxChecker_h
+
+#include "Lexer.h"
+#include <yarr/YarrSyntaxChecker.h>
+
+namespace JSC {
+
+class SyntaxChecker {
+public:
+ struct BinaryExprContext {
+ BinaryExprContext(SyntaxChecker& context)
+ : m_context(&context)
+ {
+ m_context->m_topBinaryExprs.append(m_context->m_topBinaryExpr);
+ m_context->m_topBinaryExpr = 0;
+ }
+ ~BinaryExprContext()
+ {
+ m_context->m_topBinaryExpr = m_context->m_topBinaryExprs.last();
+ m_context->m_topBinaryExprs.removeLast();
+ }
+ private:
+ SyntaxChecker* m_context;
+ };
+ struct UnaryExprContext {
+ UnaryExprContext(SyntaxChecker& context)
+ : m_context(&context)
+ {
+ m_context->m_topUnaryTokens.append(m_context->m_topUnaryToken);
+ m_context->m_topUnaryToken = 0;
+ }
+ ~UnaryExprContext()
+ {
+ m_context->m_topUnaryToken = m_context->m_topUnaryTokens.last();
+ m_context->m_topUnaryTokens.removeLast();
+ }
+ private:
+ SyntaxChecker* m_context;
+ };
+
+ SyntaxChecker(JSGlobalData* , void*)
+ {
+ }
+
+ typedef SyntaxChecker FunctionBodyBuilder;
+ enum { NoneExpr = 0,
+ ResolveEvalExpr, ResolveExpr, NumberExpr, StringExpr,
+ ThisExpr, NullExpr, BoolExpr, RegExpExpr, ObjectLiteralExpr,
+ FunctionExpr, BracketExpr, DotExpr, CallExpr,
+ NewExpr, PreExpr, PostExpr, UnaryExpr, BinaryExpr,
+ ConditionalExpr, AssignmentExpr, TypeofExpr,
+ DeleteExpr, ArrayLiteralExpr };
+ typedef int ExpressionType;
+
+ typedef ExpressionType Expression;
+ typedef int SourceElements;
+ typedef int Arguments;
+ typedef ExpressionType Comma;
+ struct Property {
+ ALWAYS_INLINE Property(void* = 0)
+ : type((PropertyNode::Type)0)
+ {
+ }
+ ALWAYS_INLINE Property(const Identifier* ident, PropertyNode::Type ty)
+ : name(ident)
+ , type(ty)
+ {
+ }
+ ALWAYS_INLINE Property(PropertyNode::Type ty)
+ : name(0)
+ , type(ty)
+ {
+ }
+ ALWAYS_INLINE bool operator!() { return !type; }
+ const Identifier* name;
+ PropertyNode::Type type;
+ };
+ typedef int PropertyList;
+ typedef int ElementList;
+ typedef int ArgumentsList;
+ typedef int FormalParameterList;
+ typedef int FunctionBody;
+ typedef int Statement;
+ typedef int ClauseList;
+ typedef int Clause;
+ typedef int ConstDeclList;
+ typedef int BinaryOperand;
+
+ static const bool CreatesAST = false;
+ static const bool NeedsFreeVariableInfo = false;
+ static const bool CanUseFunctionCache = true;
+ static const unsigned DontBuildKeywords = LexexFlagsDontBuildKeywords;
+ static const unsigned DontBuildStrings = LexerFlagsDontBuildStrings;
+
+ int createSourceElements() { return 1; }
+ ExpressionType makeFunctionCallNode(int, int, int, int, int, int) { return CallExpr; }
+ void appendToComma(ExpressionType& base, ExpressionType right) { base = right; }
+ ExpressionType createCommaExpr(int, ExpressionType, ExpressionType right) { return right; }
+ ExpressionType makeAssignNode(int, ExpressionType, Operator, ExpressionType, bool, bool, int, int, int) { return AssignmentExpr; }
+ ExpressionType makePrefixNode(int, ExpressionType, Operator, int, int, int) { return PreExpr; }
+ ExpressionType makePostfixNode(int, ExpressionType, Operator, int, int, int) { return PostExpr; }
+ ExpressionType makeTypeOfNode(int, ExpressionType) { return TypeofExpr; }
+ ExpressionType makeDeleteNode(int, ExpressionType, int, int, int) { return DeleteExpr; }
+ ExpressionType makeNegateNode(int, ExpressionType) { return UnaryExpr; }
+ ExpressionType makeBitwiseNotNode(int, ExpressionType) { return UnaryExpr; }
+ ExpressionType createLogicalNot(int, ExpressionType) { return UnaryExpr; }
+ ExpressionType createUnaryPlus(int, ExpressionType) { return UnaryExpr; }
+ ExpressionType createVoid(int, ExpressionType) { return UnaryExpr; }
+ ExpressionType thisExpr(int) { return ThisExpr; }
+ ExpressionType createResolve(int, const Identifier*, int) { return ResolveExpr; }
+ ExpressionType createObjectLiteral(int) { return ObjectLiteralExpr; }
+ ExpressionType createObjectLiteral(int, int) { return ObjectLiteralExpr; }
+ ExpressionType createArray(int, int) { return ArrayLiteralExpr; }
+ ExpressionType createArray(int, int, int) { return ArrayLiteralExpr; }
+ ExpressionType createNumberExpr(int, double) { return NumberExpr; }
+ ExpressionType createString(int, const Identifier*) { return StringExpr; }
+ ExpressionType createBoolean(int, bool) { return BoolExpr; }
+ ExpressionType createNull(int) { return NullExpr; }
+ ExpressionType createBracketAccess(int, ExpressionType, ExpressionType, bool, int, int, int) { return BracketExpr; }
+ ExpressionType createDotAccess(int, ExpressionType, const Identifier*, int, int, int) { return DotExpr; }
+ ExpressionType createRegExp(int, const Identifier& pattern, const Identifier&, int) { return Yarr::checkSyntax(pattern.ustring()) ? 0 : RegExpExpr; }
+ ExpressionType createNewExpr(int, ExpressionType, int, int, int, int) { return NewExpr; }
+ ExpressionType createNewExpr(int, ExpressionType, int, int) { return NewExpr; }
+ ExpressionType createConditionalExpr(int, ExpressionType, ExpressionType, ExpressionType) { return ConditionalExpr; }
+ ExpressionType createAssignResolve(int, const Identifier&, ExpressionType, bool, int, int, int) { return AssignmentExpr; }
+ ExpressionType createFunctionExpr(int, const Identifier*, int, int, int, int, int, int) { return FunctionExpr; }
+ int createFunctionBody(int, bool) { return 1; }
+ int createArguments() { return 1; }
+ int createArguments(int) { return 1; }
+ int createArgumentsList(int, int) { return 1; }
+ int createArgumentsList(int, int, int) { return 1; }
+ template <bool complete> Property createProperty(const Identifier* name, int, PropertyNode::Type type)
+ {
+ if (!complete)
+ return Property(type);
+ ASSERT(name);
+ return Property(name, type);
+ }
+ template <bool complete> Property createProperty(JSGlobalData* globalData, double name, int, PropertyNode::Type type)
+ {
+ if (!complete)
+ return Property(type);
+ return Property(&globalData->parserArena->identifierArena().makeNumericIdentifier(globalData, name), type);
+ }
+ int createPropertyList(int, Property) { return 1; }
+ int createPropertyList(int, Property, int) { return 1; }
+ int createElementList(int, int) { return 1; }
+ int createElementList(int, int, int) { return 1; }
+ int createFormalParameterList(const Identifier&) { return 1; }
+ int createFormalParameterList(int, const Identifier&) { return 1; }
+ int createClause(int, int) { return 1; }
+ int createClauseList(int) { return 1; }
+ int createClauseList(int, int) { return 1; }
+ void setUsesArguments(int) { }
+ int createFuncDeclStatement(int, const Identifier*, int, int, int, int, int, int) { return 1; }
+ int createBlockStatement(int, int, int, int) { return 1; }
+ int createExprStatement(int, int, int, int) { return 1; }
+ int createIfStatement(int, int, int, int, int) { return 1; }
+ int createIfStatement(int, int, int, int, int, int) { return 1; }
+ int createForLoop(int, int, int, int, int, bool, int, int) { return 1; }
+ int createForInLoop(int, const Identifier*, int, int, int, int, int, int, int, int, int, int) { return 1; }
+ int createForInLoop(int, int, int, int, int, int, int, int, int) { return 1; }
+ int createEmptyStatement(int) { return 1; }
+ int createVarStatement(int, int, int, int) { return 1; }
+ int createReturnStatement(int, int, int, int, int, int) { return 1; }
+ int createBreakStatement(int, int, int, int, int) { return 1; }
+ int createBreakStatement(int, const Identifier*, int, int, int, int) { return 1; }
+ int createContinueStatement(int, int, int, int, int) { return 1; }
+ int createContinueStatement(int, const Identifier*, int, int, int, int) { return 1; }
+ int createTryStatement(int, int, const Identifier*, bool, int, int, int, int) { return 1; }
+ int createSwitchStatement(int, int, int, int, int, int, int) { return 1; }
+ int createWhileStatement(int, int, int, int, int) { return 1; }
+ int createWithStatement(int, int, int, int, int, int, int) { return 1; }
+ int createDoWhileStatement(int, int, int, int, int) { return 1; }
+ int createLabelStatement(int, const Identifier*, int, int, int) { return 1; }
+ int createThrowStatement(int, int, int, int, int, int) { return 1; }
+ int createDebugger(int, int, int) { return 1; }
+ int createConstStatement(int, int, int, int) { return 1; }
+ int appendConstDecl(int, int, const Identifier*, int) { return 1; }
+ template <bool strict> Property createGetterOrSetterProperty(int, PropertyNode::Type type, const Identifier* name, int, int, int, int, int, int)
+ {
+ ASSERT(name);
+ if (!strict)
+ return Property(type);
+ return Property(name, type);
+ }
+
+ void appendStatement(int, int) { }
+ void addVar(const Identifier*, bool) { }
+ int combineCommaNodes(int, int, int) { return 1; }
+ int evalCount() const { return 0; }
+ void appendBinaryExpressionInfo(int& operandStackDepth, int expr, int, int, int, bool)
+ {
+ if (!m_topBinaryExpr)
+ m_topBinaryExpr = expr;
+ else
+ m_topBinaryExpr = BinaryExpr;
+ operandStackDepth++;
+ }
+
+ // Logic to handle datastructures used during parsing of binary expressions
+ void operatorStackPop(int& operatorStackDepth) { operatorStackDepth--; }
+ bool operatorStackHasHigherPrecedence(int&, int) { return true; }
+ BinaryOperand getFromOperandStack(int) { return m_topBinaryExpr; }
+ void shrinkOperandStackBy(int& operandStackDepth, int amount) { operandStackDepth -= amount; }
+ void appendBinaryOperation(int, int& operandStackDepth, int&, BinaryOperand, BinaryOperand) { operandStackDepth++; }
+ void operatorStackAppend(int& operatorStackDepth, int, int) { operatorStackDepth++; }
+ int popOperandStack(int&) { int res = m_topBinaryExpr; m_topBinaryExpr = 0; return res; }
+
+ void appendUnaryToken(int& stackDepth, int tok, int) { stackDepth = 1; m_topUnaryToken = tok; }
+ int unaryTokenStackLastType(int&) { return m_topUnaryToken; }
+ int unaryTokenStackLastStart(int&) { return 0; }
+ void unaryTokenStackRemoveLast(int& stackDepth) { stackDepth = 0; }
+
+ void assignmentStackAppend(int, int, int, int, int, Operator) { }
+ int createAssignment(int, int, int, int, int, int) { ASSERT_NOT_REACHED(); return 1; }
+ const Identifier& getName(const Property& property) const { ASSERT(property.name); return *property.name; }
+ PropertyNode::Type getType(const Property& property) const { return property.type; }
+ bool isResolve(ExpressionType expr) const { return expr == ResolveExpr || expr == ResolveEvalExpr; }
+
+private:
+ int m_topBinaryExpr;
+ int m_topUnaryToken;
+ Vector<int, 8> m_topBinaryExprs;
+ Vector<int, 8> m_topUnaryTokens;
+};
+
+}
+
+#endif