summaryrefslogtreecommitdiffstats
path: root/Source/JavaScriptCore/parser
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/parser')
-rw-r--r--Source/JavaScriptCore/parser/ASTBuilder.h967
-rw-r--r--Source/JavaScriptCore/parser/JSParser.cpp1907
-rw-r--r--Source/JavaScriptCore/parser/JSParser.h164
-rw-r--r--Source/JavaScriptCore/parser/Keywords.table72
-rw-r--r--Source/JavaScriptCore/parser/Lexer.cpp1196
-rw-r--r--Source/JavaScriptCore/parser/Lexer.h158
-rw-r--r--Source/JavaScriptCore/parser/NodeConstructors.h908
-rw-r--r--Source/JavaScriptCore/parser/NodeInfo.h63
-rw-r--r--Source/JavaScriptCore/parser/Nodes.cpp196
-rw-r--r--Source/JavaScriptCore/parser/Nodes.h1617
-rw-r--r--Source/JavaScriptCore/parser/Parser.cpp85
-rw-r--r--Source/JavaScriptCore/parser/Parser.h128
-rw-r--r--Source/JavaScriptCore/parser/ParserArena.cpp125
-rw-r--r--Source/JavaScriptCore/parser/ParserArena.h130
-rw-r--r--Source/JavaScriptCore/parser/ResultType.h182
-rw-r--r--Source/JavaScriptCore/parser/SourceCode.h92
-rw-r--r--Source/JavaScriptCore/parser/SourceProvider.h87
-rw-r--r--Source/JavaScriptCore/parser/SyntaxChecker.h217
18 files changed, 8294 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/parser/ASTBuilder.h b/Source/JavaScriptCore/parser/ASTBuilder.h
new file mode 100644
index 0000000..04cf272
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ASTBuilder.h
@@ -0,0 +1,967 @@
+/*
+ * 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, Lexer* lexer)
+ : m_globalData(globalData)
+ , m_lexer(lexer)
+ , m_evalCount(0)
+ {
+ m_scopes.append(Scope(globalData));
+ }
+
+ 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;
+
+ ExpressionNode* makeBinaryNode(int token, std::pair<ExpressionNode*, BinaryOpInfo>, std::pair<ExpressionNode*, BinaryOpInfo>);
+ ExpressionNode* makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end);
+
+ JSC::SourceElements* createSourceElements() { return new (m_globalData) JSC::SourceElements(m_globalData); }
+
+ ParserArenaData<DeclarationStacks::VarStack>* varDeclarations() { return m_scopes.last().m_varDeclarations; }
+ ParserArenaData<DeclarationStacks::FunctionStack>* funcDeclarations() { return m_scopes.last().m_funcDeclarations; }
+ int features() const { return m_scopes.last().m_features; }
+ int numConstants() const { return m_scopes.last().m_numConstants; }
+
+ void appendToComma(CommaNode* commaNode, ExpressionNode* expr) { commaNode->append(expr); }
+
+ CommaNode* createCommaExpr(ExpressionNode* lhs, ExpressionNode* rhs) { return new (m_globalData) CommaNode(m_globalData, lhs, rhs); }
+
+ ExpressionNode* makeAssignNode(ExpressionNode* left, Operator, ExpressionNode* right, bool leftHasAssignments, bool rightHasAssignments, int start, int divot, int end);
+ ExpressionNode* makePrefixNode(ExpressionNode*, Operator, int start, int divot, int end);
+ ExpressionNode* makePostfixNode(ExpressionNode*, Operator, int start, int divot, int end);
+ ExpressionNode* makeTypeOfNode(ExpressionNode*);
+ ExpressionNode* makeDeleteNode(ExpressionNode*, int start, int divot, int end);
+ ExpressionNode* makeNegateNode(ExpressionNode*);
+ ExpressionNode* makeBitwiseNotNode(ExpressionNode*);
+ ExpressionNode* makeMultNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeDivNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeModNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeAddNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeSubNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitXOrNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitAndNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeBitOrNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeLeftShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeRightShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+ ExpressionNode* makeURightShiftNode(ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments);
+
+ ExpressionNode* createLogicalNot(ExpressionNode* expr) { return new (m_globalData) LogicalNotNode(m_globalData, expr); }
+ ExpressionNode* createUnaryPlus(ExpressionNode* expr) { return new (m_globalData) UnaryPlusNode(m_globalData, expr); }
+ ExpressionNode* createVoid(ExpressionNode* expr)
+ {
+ incConstants();
+ return new (m_globalData) VoidNode(m_globalData, expr);
+ }
+ ExpressionNode* thisExpr()
+ {
+ usesThis();
+ return new (m_globalData) ThisNode(m_globalData);
+ }
+ ExpressionNode* createResolve(const Identifier* ident, int start)
+ {
+ if (m_globalData->propertyNames->arguments == *ident)
+ usesArguments();
+ return new (m_globalData) ResolveNode(m_globalData, *ident, start);
+ }
+ ExpressionNode* createObjectLiteral() { return new (m_globalData) ObjectLiteralNode(m_globalData); }
+ ExpressionNode* createObjectLiteral(PropertyListNode* properties) { return new (m_globalData) ObjectLiteralNode(m_globalData, properties); }
+
+ ExpressionNode* createArray(int elisions)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_globalData) ArrayNode(m_globalData, elisions);
+ }
+
+ ExpressionNode* createArray(ElementNode* elems) { return new (m_globalData) ArrayNode(m_globalData, elems); }
+ ExpressionNode* createArray(int elisions, ElementNode* elems)
+ {
+ if (elisions)
+ incConstants();
+ return new (m_globalData) ArrayNode(m_globalData, elisions, elems);
+ }
+ ExpressionNode* createNumberExpr(double d)
+ {
+ incConstants();
+ return new (m_globalData) NumberNode(m_globalData, d);
+ }
+
+ ExpressionNode* createString(const Identifier* string)
+ {
+ incConstants();
+ return new (m_globalData) StringNode(m_globalData, *string);
+ }
+
+ ExpressionNode* createBoolean(bool b)
+ {
+ incConstants();
+ return new (m_globalData) BooleanNode(m_globalData, b);
+ }
+
+ ExpressionNode* createNull()
+ {
+ incConstants();
+ return new (m_globalData) NullNode(m_globalData);
+ }
+
+ ExpressionNode* createBracketAccess(ExpressionNode* base, ExpressionNode* property, bool propertyHasAssignments, int start, int divot, int end)
+ {
+ BracketAccessorNode* node = new (m_globalData) BracketAccessorNode(m_globalData, base, property, propertyHasAssignments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createDotAccess(ExpressionNode* base, const Identifier& property, int start, int divot, int end)
+ {
+ DotAccessorNode* node = new (m_globalData) DotAccessorNode(m_globalData, base, property);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createRegex(const Identifier& pattern, const Identifier& flags, int start)
+ {
+ RegExpNode* node = new (m_globalData) RegExpNode(m_globalData, pattern, flags);
+ int size = pattern.length() + 2; // + 2 for the two /'s
+ setExceptionLocation(node, start, start + size, start + size);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(ExpressionNode* expr, ArgumentsNode* arguments, int start, int divot, int end)
+ {
+ NewExprNode* node = new (m_globalData) NewExprNode(m_globalData, expr, arguments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createNewExpr(ExpressionNode* expr, int start, int end)
+ {
+ NewExprNode* node = new (m_globalData) NewExprNode(m_globalData, expr);
+ setExceptionLocation(node, start, end, end);
+ return node;
+ }
+
+ ExpressionNode* createConditionalExpr(ExpressionNode* condition, ExpressionNode* lhs, ExpressionNode* rhs)
+ {
+ return new (m_globalData) ConditionalNode(m_globalData, condition, lhs, rhs);
+ }
+
+ ExpressionNode* createAssignResolve(const Identifier& ident, ExpressionNode* rhs, bool rhsHasAssignment, int start, int divot, int end)
+ {
+ AssignResolveNode* node = new (m_globalData) AssignResolveNode(m_globalData, ident, rhs, rhsHasAssignment);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+
+ ExpressionNode* createFunctionExpr(const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ FuncExprNode* result = new (m_globalData) FuncExprNode(m_globalData, *name, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), parameters);
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return result;
+ }
+
+ FunctionBodyNode* createFunctionBody(bool inStrictContext)
+ {
+ usesClosures();
+ return FunctionBodyNode::create(m_globalData, inStrictContext);
+ }
+
+ template <bool> PropertyNode* createGetterOrSetterProperty(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(m_globalData, m_globalData->propertyNames->nullIdentifier, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), params), type);
+ }
+
+
+ ArgumentsNode* createArguments() { return new (m_globalData) ArgumentsNode(m_globalData); }
+ ArgumentsNode* createArguments(ArgumentListNode* args) { return new (m_globalData) ArgumentsNode(m_globalData, args); }
+ ArgumentListNode* createArgumentsList(ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, arg); }
+ ArgumentListNode* createArgumentsList(ArgumentListNode* args, ExpressionNode* arg) { return new (m_globalData) ArgumentListNode(m_globalData, 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(PropertyNode* property) { return new (m_globalData) PropertyListNode(m_globalData, property); }
+ PropertyListNode* createPropertyList(PropertyNode* property, PropertyListNode* tail) { return new (m_globalData) PropertyListNode(m_globalData, property, tail); }
+
+ ElementNode* createElementList(int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(m_globalData, elisions, expr); }
+ ElementNode* createElementList(ElementNode* elems, int elisions, ExpressionNode* expr) { return new (m_globalData) ElementNode(m_globalData, elems, elisions, expr); }
+
+ ParameterNode* createFormalParameterList(const Identifier& ident) { return new (m_globalData) ParameterNode(m_globalData, ident); }
+ ParameterNode* createFormalParameterList(ParameterNode* list, const Identifier& ident) { return new (m_globalData) ParameterNode(m_globalData, list, ident); }
+
+ CaseClauseNode* createClause(ExpressionNode* expr, JSC::SourceElements* statements) { return new (m_globalData) CaseClauseNode(m_globalData, expr, statements); }
+ ClauseListNode* createClauseList(CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(m_globalData, clause); }
+ ClauseListNode* createClauseList(ClauseListNode* tail, CaseClauseNode* clause) { return new (m_globalData) ClauseListNode(m_globalData, tail, clause); }
+
+ void setUsesArguments(FunctionBodyNode* node) { node->setUsesArguments(); }
+
+ StatementNode* createFuncDeclStatement(const Identifier* name, FunctionBodyNode* body, ParameterNode* parameters, int openBracePos, int closeBracePos, int bodyStartLine, int bodyEndLine)
+ {
+ FuncDeclNode* decl = new (m_globalData) FuncDeclNode(m_globalData, *name, body, m_lexer->sourceCode(openBracePos, closeBracePos, bodyStartLine), parameters);
+ if (*name == m_globalData->propertyNames->arguments)
+ usesArguments();
+ m_scopes.last().m_funcDeclarations->data.append(decl->body());
+ body->setLoc(bodyStartLine, bodyEndLine);
+ return decl;
+ }
+
+ StatementNode* createBlockStatement(JSC::SourceElements* elements, int startLine, int endLine)
+ {
+ BlockNode* block = new (m_globalData) BlockNode(m_globalData, elements);
+ block->setLoc(startLine, endLine);
+ return block;
+ }
+
+ StatementNode* createExprStatement(ExpressionNode* expr, int start, int end)
+ {
+ ExprStatementNode* result = new (m_globalData) ExprStatementNode(m_globalData, expr);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createIfStatement(ExpressionNode* condition, StatementNode* trueBlock, int start, int end)
+ {
+ IfNode* result = new (m_globalData) IfNode(m_globalData, condition, trueBlock);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createIfStatement(ExpressionNode* condition, StatementNode* trueBlock, StatementNode* falseBlock, int start, int end)
+ {
+ IfNode* result = new (m_globalData) IfElseNode(m_globalData, condition, trueBlock, falseBlock);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createForLoop(ExpressionNode* initializer, ExpressionNode* condition, ExpressionNode* iter, StatementNode* statements, bool b, int start, int end)
+ {
+ ForNode* result = new (m_globalData) ForNode(m_globalData, initializer, condition, iter, statements, b);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createForInLoop(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, *ident, initializer, iter, statements, initStart, initStart - start, initEnd - initStart);
+ result->setLoc(startLine, endLine);
+ setExceptionLocation(result, start, divot + 1, end);
+ return result;
+ }
+
+ StatementNode* createForInLoop(ExpressionNode* lhs, ExpressionNode* iter, StatementNode* statements, int eStart, int eDivot, int eEnd, int start, int end)
+ {
+ ForInNode* result = new (m_globalData) ForInNode(m_globalData, lhs, iter, statements);
+ result->setLoc(start, end);
+ setExceptionLocation(result, eStart, eDivot, eEnd);
+ return result;
+ }
+
+ StatementNode* createEmptyStatement() { return new (m_globalData) EmptyStatementNode(m_globalData); }
+
+ StatementNode* createVarStatement(ExpressionNode* expr, int start, int end)
+ {
+ StatementNode* result;
+ if (!expr)
+ result = new (m_globalData) EmptyStatementNode(m_globalData);
+ else
+ result = new (m_globalData) VarStatementNode(m_globalData, expr);
+ result->setLoc(start, end);
+ return result;
+ }
+
+ StatementNode* createReturnStatement(ExpressionNode* expression, int eStart, int eEnd, int startLine, int endLine)
+ {
+ ReturnNode* result = new (m_globalData) ReturnNode(m_globalData, expression);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createBreakStatement(int eStart, int eEnd, int startLine, int endLine)
+ {
+ BreakNode* result = new (m_globalData) BreakNode(m_globalData);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createBreakStatement(const Identifier* ident, int eStart, int eEnd, int startLine, int endLine)
+ {
+ BreakNode* result = new (m_globalData) BreakNode(m_globalData, *ident);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createContinueStatement(int eStart, int eEnd, int startLine, int endLine)
+ {
+ ContinueNode* result = new (m_globalData) ContinueNode(m_globalData);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createContinueStatement(const Identifier* ident, int eStart, int eEnd, int startLine, int endLine)
+ {
+ ContinueNode* result = new (m_globalData) ContinueNode(m_globalData, *ident);
+ setExceptionLocation(result, eStart, eEnd, eEnd);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createTryStatement(StatementNode* tryBlock, const Identifier* ident, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock, int startLine, int endLine)
+ {
+ TryNode* result = new (m_globalData) TryNode(m_globalData, tryBlock, *ident, catchHasEval, catchBlock, finallyBlock);
+ if (catchBlock)
+ usesCatch();
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createSwitchStatement(ExpressionNode* expr, ClauseListNode* firstClauses, CaseClauseNode* defaultClause, ClauseListNode* secondClauses, int startLine, int endLine)
+ {
+ CaseBlockNode* cases = new (m_globalData) CaseBlockNode(m_globalData, firstClauses, defaultClause, secondClauses);
+ SwitchNode* result = new (m_globalData) SwitchNode(m_globalData, expr, cases);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createWhileStatement(ExpressionNode* expr, StatementNode* statement, int startLine, int endLine)
+ {
+ WhileNode* result = new (m_globalData) WhileNode(m_globalData, expr, statement);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createDoWhileStatement(StatementNode* statement, ExpressionNode* expr, int startLine, int endLine)
+ {
+ DoWhileNode* result = new (m_globalData) DoWhileNode(m_globalData, statement, expr);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createLabelStatement(const Identifier* ident, StatementNode* statement, int start, int end)
+ {
+ LabelNode* result = new (m_globalData) LabelNode(m_globalData, *ident, statement);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createWithStatement(ExpressionNode* expr, StatementNode* statement, int start, int end, int startLine, int endLine)
+ {
+ usesWith();
+ WithNode* result = new (m_globalData) WithNode(m_globalData, expr, statement, end, end - start);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createThrowStatement(ExpressionNode* expr, int start, int end, int startLine, int endLine)
+ {
+ ThrowNode* result = new (m_globalData) ThrowNode(m_globalData, expr);
+ result->setLoc(startLine, endLine);
+ setExceptionLocation(result, start, end, end);
+ return result;
+ }
+
+ StatementNode* createDebugger(int startLine, int endLine)
+ {
+ DebuggerStatementNode* result = new (m_globalData) DebuggerStatementNode(m_globalData);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ StatementNode* createConstStatement(ConstDeclNode* decls, int startLine, int endLine)
+ {
+ ConstStatementNode* result = new (m_globalData) ConstStatementNode(m_globalData, decls);
+ result->setLoc(startLine, endLine);
+ return result;
+ }
+
+ ConstDeclNode* appendConstDecl(ConstDeclNode* tail, const Identifier* name, ExpressionNode* initializer)
+ {
+ ConstDeclNode* result = new (m_globalData) ConstDeclNode(m_globalData, *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_scopes.last().m_varDeclarations->data.append(std::make_pair(ident, attrs));
+ }
+
+ ExpressionNode* combineCommaNodes(ExpressionNode* list, ExpressionNode* init)
+ {
+ if (!list)
+ return init;
+ if (list->isCommaNode()) {
+ static_cast<CommaNode*>(list)->append(init);
+ return list;
+ }
+ return new (m_globalData) CommaNode(m_globalData, 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& operandStackDepth, int&, const BinaryOperand& lhs, const BinaryOperand& rhs)
+ {
+ operandStackDepth++;
+ m_binaryOperandStack.append(std::make_pair(makeBinaryNode(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& assignmentStackDepth, ExpressionNode* rhs, int initialAssignmentCount, int currentAssignmentCount, int lastTokenEnd)
+ {
+ ExpressionNode* result = makeAssignNode(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_scopes.last().m_numConstants++; }
+ void usesThis() { m_scopes.last().m_features |= ThisFeature; }
+ void usesCatch() { m_scopes.last().m_features |= CatchFeature; }
+ void usesClosures() { m_scopes.last().m_features |= ClosureFeature; }
+ void usesArguments() { m_scopes.last().m_features |= ArgumentsFeature; }
+ void usesAssignment() { m_scopes.last().m_features |= AssignFeature; }
+ void usesWith() { m_scopes.last().m_features |= WithFeature; }
+ void usesEval()
+ {
+ m_evalCount++;
+ m_scopes.last().m_features |= EvalFeature;
+ }
+ ExpressionNode* createNumber(double d)
+ {
+ return new (m_globalData) NumberNode(m_globalData, d);
+ }
+
+ JSGlobalData* m_globalData;
+ Lexer* m_lexer;
+ Vector<Scope> m_scopes;
+ 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(ExpressionNode* expr)
+{
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) TypeOfResolveNode(m_globalData, resolve->identifier());
+ }
+ return new (m_globalData) TypeOfValueNode(m_globalData, expr);
+}
+
+ExpressionNode* ASTBuilder::makeDeleteNode(ExpressionNode* expr, int start, int divot, int end)
+{
+ if (!expr->isLocation())
+ return new (m_globalData) DeleteValueNode(m_globalData, expr);
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) DeleteResolveNode(m_globalData, resolve->identifier(), divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ return new (m_globalData) DeleteBracketNode(m_globalData, bracket->base(), bracket->subscript(), divot, divot - start, end - divot);
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ return new (m_globalData) DeleteDotNode(m_globalData, dot->base(), dot->identifier(), divot, divot - start, end - divot);
+}
+
+ExpressionNode* ASTBuilder::makeNegateNode(ExpressionNode* n)
+{
+ if (n->isNumber()) {
+ NumberNode* numberNode = static_cast<NumberNode*>(n);
+ numberNode->setValue(-numberNode->value());
+ return numberNode;
+ }
+
+ return new (m_globalData) NegateNode(m_globalData, n);
+}
+
+ExpressionNode* ASTBuilder::makeBitwiseNotNode(ExpressionNode* expr)
+{
+ if (expr->isNumber())
+ return createNumber(~toInt32(static_cast<NumberNode*>(expr)->value()));
+ return new (m_globalData) BitwiseNotNode(m_globalData, expr);
+}
+
+ExpressionNode* ASTBuilder::makeMultNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
+
+ if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
+ return new (m_globalData) UnaryPlusNode(m_globalData, expr2);
+
+ if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
+ return new (m_globalData) UnaryPlusNode(m_globalData, expr1);
+
+ return new (m_globalData) MultNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeDivNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) DivNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeModNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(fmod(static_cast<NumberNode*>(expr1)->value(), static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) ModNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeAddNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) AddNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeSubNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value());
+ return new (m_globalData) SubNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeLeftShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) LeftShiftNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeRightShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) RightShiftNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeURightShiftNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toUInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new (m_globalData) UnsignedRightShiftNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitOrNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) | toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitOrNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitAndNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) & toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitAndNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeBitXOrNode(ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return createNumber(toInt32(static_cast<NumberNode*>(expr1)->value()) ^ toInt32(static_cast<NumberNode*>(expr2)->value()));
+ return new (m_globalData) BitXOrNode(m_globalData, expr1, expr2, rightHasAssignments);
+}
+
+ExpressionNode* ASTBuilder::makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args, int start, int divot, int end)
+{
+ if (!func->isLocation())
+ return new (m_globalData) FunctionCallValueNode(m_globalData, 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(m_globalData, args, divot, divot - start, end - divot);
+ }
+ return new (m_globalData) FunctionCallResolveNode(m_globalData, identifier, args, divot, divot - start, end - divot);
+ }
+ if (func->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func);
+ FunctionCallBracketNode* node = new (m_globalData) FunctionCallBracketNode(m_globalData, 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(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ else if (dot->identifier() == m_globalData->propertyNames->apply)
+ node = new (m_globalData) ApplyFunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ else
+ node = new (m_globalData) FunctionCallDotNode(m_globalData, dot->base(), dot->identifier(), args, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makeBinaryNode(int token, pair<ExpressionNode*, BinaryOpInfo> lhs, pair<ExpressionNode*, BinaryOpInfo> rhs)
+{
+ switch (token) {
+ case OR:
+ return new (m_globalData) LogicalOpNode(m_globalData, lhs.first, rhs.first, OpLogicalOr);
+
+ case AND:
+ return new (m_globalData) LogicalOpNode(m_globalData, lhs.first, rhs.first, OpLogicalAnd);
+
+ case BITOR:
+ return makeBitOrNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITXOR:
+ return makeBitXOrNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case BITAND:
+ return makeBitAndNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case EQEQ:
+ return new (m_globalData) EqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case NE:
+ return new (m_globalData) NotEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STREQ:
+ return new (m_globalData) StrictEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case STRNEQ:
+ return new (m_globalData) NotStrictEqualNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LT:
+ return new (m_globalData) LessNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GT:
+ return new (m_globalData) GreaterNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case LE:
+ return new (m_globalData) LessEqNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case GE:
+ return new (m_globalData) GreaterEqNode(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case INSTANCEOF: {
+ InstanceOfNode* node = new (m_globalData) InstanceOfNode(m_globalData, 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(m_globalData, lhs.first, rhs.first, rhs.second.hasAssignment);
+ setExceptionLocation(node, lhs.second.start, rhs.second.start, rhs.second.end);
+ return node;
+ }
+
+ case LSHIFT:
+ return makeLeftShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case RSHIFT:
+ return makeRightShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case URSHIFT:
+ return makeURightShiftNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case PLUS:
+ return makeAddNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MINUS:
+ return makeSubNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case TIMES:
+ return makeMultNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case DIVIDE:
+ return makeDivNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+
+ case MOD:
+ return makeModNode(lhs.first, rhs.first, rhs.second.hasAssignment);
+ }
+ CRASH();
+ return 0;
+}
+
+ExpressionNode* ASTBuilder::makeAssignNode(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(m_globalData, 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(m_globalData, resolve->identifier(), expr, exprHasAssignments);
+ setExceptionLocation(node, start, divot, end);
+ return node;
+ }
+ return new (m_globalData) ReadModifyResolveNode(m_globalData, 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(m_globalData, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot());
+ ReadModifyBracketNode* node = new (m_globalData) ReadModifyBracketNode(m_globalData, 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(m_globalData, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot());
+
+ ReadModifyDotNode* node = new (m_globalData) ReadModifyDotNode(m_globalData, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makePrefixNode(ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!expr->isLocation())
+ return new (m_globalData) PrefixErrorNode(m_globalData, expr, op, divot, divot - start, end - divot);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) PrefixResolveNode(m_globalData, resolve->identifier(), op, divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ PrefixBracketNode* node = new (m_globalData) PrefixBracketNode(m_globalData, 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(m_globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->startOffset());
+ return node;
+}
+
+ExpressionNode* ASTBuilder::makePostfixNode(ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
+ usesAssignment();
+ if (!expr->isLocation())
+ return new (m_globalData) PostfixErrorNode(m_globalData, expr, op, divot, divot - start, end - divot);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new (m_globalData) PostfixResolveNode(m_globalData, resolve->identifier(), op, divot, divot - start, end - divot);
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ PostfixBracketNode* node = new (m_globalData) PostfixBracketNode(m_globalData, 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(m_globalData, 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/JSParser.cpp b/Source/JavaScriptCore/parser/JSParser.cpp
new file mode 100644
index 0000000..4201555
--- /dev/null
+++ b/Source/JavaScriptCore/parser/JSParser.cpp
@@ -0,0 +1,1907 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+
+#include "JSParser.h"
+
+using namespace JSC;
+
+#include "CodeBlock.h"
+#include "JSGlobalData.h"
+#include "NodeInfo.h"
+#include "ASTBuilder.h"
+#include <wtf/HashFunctions.h>
+#include <wtf/WTFThreadData.h>
+#include <utility>
+
+using namespace std;
+
+namespace JSC {
+#define fail() do { m_error = true; return 0; } while (0)
+#define failIfFalse(cond) do { if (!(cond)) fail(); } while (0)
+#define failIfTrue(cond) do { if ((cond)) fail(); } while (0)
+#define failIfTrueIfStrict(cond) do { if ((cond) && strictMode()) fail(); } while (0)
+#define failIfFalseIfStrict(cond) do { if ((!(cond)) && strictMode()) fail(); } while (0)
+#define consumeOrFail(tokenType) do { if (!consume(tokenType)) fail(); } while (0)
+#define matchOrFail(tokenType) do { if (!match(tokenType)) fail(); } while (0)
+#define failIfStackOverflow() do { failIfFalse(canRecurse()); } 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);
+
+class JSParser {
+public:
+ JSParser(Lexer*, JSGlobalData*, FunctionParameters*, bool isStrictContext, bool isFunction, SourceProvider*);
+ bool parseProgram();
+private:
+ struct AllowInOverride {
+ AllowInOverride(JSParser* parser)
+ : m_parser(parser)
+ , m_oldAllowsIn(parser->m_allowsIn)
+ {
+ parser->m_allowsIn = true;
+ }
+ ~AllowInOverride()
+ {
+ m_parser->m_allowsIn = m_oldAllowsIn;
+ }
+ JSParser* m_parser;
+ bool m_oldAllowsIn;
+ };
+
+ void next(Lexer::LexType lexType = Lexer::IdentifyReservedWords)
+ {
+ 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, lexType, strictMode());
+ m_tokenCount++;
+ }
+
+ bool consume(JSTokenType expected)
+ {
+ bool result = m_token.m_type == expected;
+ failIfFalse(result);
+ next();
+ return result;
+ }
+
+ bool match(JSTokenType expected)
+ {
+ return m_token.m_type == expected;
+ }
+
+ int tokenStart()
+ {
+ return m_token.m_info.startOffset;
+ }
+
+ int tokenLine()
+ {
+ return m_token.m_info.line;
+ }
+
+ int tokenEnd()
+ {
+ return m_token.m_info.endOffset;
+ }
+
+ 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() { return currentScope()->breakIsValid(); }
+ void pushLabel(const Identifier* label) { currentScope()->pushLabel(label); }
+ void popLabel() { currentScope()->popLabel(); }
+ bool hasLabel(const Identifier* label) { return currentScope()->hasLabel(label); }
+
+ enum SourceElementsMode { CheckForStrictMode, DontCheckForStrictMode };
+ template <SourceElementsMode mode, class TreeBuilder> TreeSourceElements parseSourceElements(TreeBuilder&);
+ template <class TreeBuilder> TreeStatement parseStatement(TreeBuilder&, const Identifier*& directive);
+ 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);
+ enum FunctionRequirements { FunctionNoRequirements, FunctionNeedsName };
+ template <FunctionRequirements, bool nameIsInContainingScope, class TreeBuilder> bool parseFunctionInfo(TreeBuilder&, const Identifier*&, TreeFormalParameterList&, TreeFunctionBody&, int& openBrace, int& closeBrace, int& bodyStartLine);
+ ALWAYS_INLINE int isBinaryOperator(JSTokenType token);
+ 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;
+ }
+
+ ParserArena m_arena;
+ Lexer* m_lexer;
+ StackBounds m_stack;
+ bool m_error;
+ JSGlobalData* m_globalData;
+ JSToken m_token;
+ bool m_allowsIn;
+ int m_tokenCount;
+ 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;
+
+ struct DepthManager {
+ DepthManager(int* depth)
+ : m_originalDepth(*depth)
+ , m_depth(depth)
+ {
+ }
+
+ ~DepthManager()
+ {
+ *m_depth = m_originalDepth;
+ }
+
+ private:
+ int m_originalDepth;
+ int* m_depth;
+ };
+
+ struct Scope {
+ Scope(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_isValidStrictMode(true)
+ , m_loopDepth(0)
+ , m_switchDepth(0)
+ , m_labels(0)
+ {
+ }
+
+ 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; }
+
+ void pushLabel(const Identifier* label)
+ {
+ if (!m_labels)
+ m_labels = new LabelStack;
+ m_labels->append(label->impl());
+ }
+
+ void popLabel()
+ {
+ ASSERT(m_labels);
+ ASSERT(m_labels->size());
+ m_labels->removeLast();
+ }
+
+ bool hasLabel(const Identifier* label)
+ {
+ if (!m_labels)
+ return false;
+ for (int i = m_labels->size(); i > 0; i--) {
+ if (m_labels->at(i - 1) == label->impl())
+ return true;
+ }
+ return false;
+ }
+
+ void setIsFunction() { m_isFunction = true; }
+ bool isFunction() { return m_isFunction; }
+
+ 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; }
+
+ private:
+ 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_isValidStrictMode : 1;
+ int m_loopDepth;
+ int m_switchDepth;
+ typedef Vector<StringImpl*, 2> LabelStack;
+ 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; }
+ private:
+ ScopeStack* m_scopeStack;
+ unsigned m_index;
+ };
+
+ 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 popScope(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 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;
+};
+
+int jsParse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode parserMode, const SourceCode* source)
+{
+ JSParser parser(globalData->lexer, globalData, parameters, strictness == JSParseStrict, parserMode == JSParseFunctionCode, source->provider());
+ return parser.parseProgram();
+}
+
+JSParser::JSParser(Lexer* lexer, JSGlobalData* globalData, FunctionParameters* parameters, bool inStrictContext, bool isFunction, SourceProvider* provider)
+ : m_lexer(lexer)
+ , m_stack(globalData->stack())
+ , m_error(false)
+ , m_globalData(globalData)
+ , m_allowsIn(true)
+ , m_tokenCount(0)
+ , m_lastLine(0)
+ , m_lastTokenEnd(0)
+ , m_assignmentCount(0)
+ , m_nonLHSCount(0)
+ , m_syntaxAlreadyValidated(provider->isValid())
+ , m_statementDepth(0)
+ , m_nonTrivialExpressionCount(0)
+ , m_lastIdentifier(0)
+{
+ ScopeRef scope = pushScope();
+ if (isFunction)
+ scope->setIsFunction();
+ if (inStrictContext)
+ scope->setStrictMode();
+ if (parameters) {
+ for (unsigned i = 0; i < parameters->size(); i++)
+ scope->declareParameter(&parameters->at(i));
+ }
+ next();
+ m_lexer->setLastLineNumber(tokenLine());
+}
+
+bool JSParser::parseProgram()
+{
+ ASTBuilder context(m_globalData, m_lexer);
+ if (m_lexer->isReparsing())
+ m_statementDepth--;
+ ScopeRef scope = currentScope();
+ SourceElements* sourceElements = parseSourceElements<CheckForStrictMode>(context);
+ if (!sourceElements || !consume(EOFTOK))
+ return true;
+ IdentifierSet capturedVariables;
+ scope->getCapturedVariables(capturedVariables);
+ CodeFeatures features = context.features();
+ if (scope->strictMode())
+ features |= StrictModeFeature;
+ if (scope->shadowsArguments())
+ features |= ShadowsArgumentsFeature;
+
+ m_globalData->parser->didFinishParsing(sourceElements, context.varDeclarations(), context.funcDeclarations(), features,
+ m_lastLine, context.numConstants(), capturedVariables);
+ return false;
+}
+
+bool JSParser::allowAutomaticSemicolon()
+{
+ return match(CLOSEBRACE) || match(EOFTOK) || m_lexer->prevTerminator();
+}
+
+template <JSParser::SourceElementsMode mode, class TreeBuilder> TreeSourceElements JSParser::parseSourceElements(TreeBuilder& context)
+{
+ TreeSourceElements sourceElements = context.createSourceElements();
+ bool seenNonDirective = false;
+ const Identifier* directive = 0;
+ unsigned startOffset = m_token.m_info.startOffset;
+ bool hasSetStrict = false;
+ while (TreeStatement statement = parseStatement(context, directive)) {
+ if (mode == CheckForStrictMode && !seenNonDirective) {
+ if (directive) {
+ if (!hasSetStrict && m_globalData->propertyNames->useStrictIdentifier == *directive) {
+ setStrictMode();
+ hasSetStrict = true;
+ failIfFalse(isValidStrictMode());
+ m_lexer->setOffset(startOffset);
+ next();
+ failIfTrue(m_error);
+ continue;
+ }
+ } else
+ seenNonDirective = true;
+ }
+ context.appendStatement(sourceElements, statement);
+ }
+
+ if (m_error)
+ fail();
+ return sourceElements;
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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(varDecls, start, end);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseConstDeclaration(TreeBuilder& context)
+{
+ ASSERT(match(CONSTTOKEN));
+ int start = tokenLine();
+ int end = 0;
+ TreeConstDeclList constDecls = parseConstDeclarationList(context);
+ failIfTrue(m_error);
+ failIfFalse(autoSemiColon());
+
+ return context.createConstStatement(constDecls, start, end);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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(statement, expr, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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(expr, statement, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::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);
+ failIfFalseIfStrict(declareVariable(name));
+ context.addVar(name, (hasInitializer || (!m_allowsIn && match(INTOKEN))) ? DeclarationStacks::HasInitializer : 0);
+ if (hasInitializer) {
+ int varDivot = tokenStart() + 1;
+ initStart = tokenStart();
+ next(); // consume '='
+ int initialAssignments = m_assignmentCount;
+ TreeExpression initializer = parseAssignmentExpression(context);
+ initEnd = lastTokenEnd();
+ lastInitializer = initializer;
+ failIfFalse(initializer);
+
+ TreeExpression node = context.createAssignResolve(*name, initializer, initialAssignments != m_assignmentCount, varStart, varDivot, lastTokenEnd());
+ if (!varDecls)
+ varDecls = node;
+ else
+ varDecls = context.combineCommaNodes(varDecls, node);
+ }
+ } while (match(COMMA));
+ return varDecls;
+}
+
+template <class TreeBuilder> TreeConstDeclList JSParser::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(); // consume '='
+ initializer = parseAssignmentExpression(context);
+ }
+ tail = context.appendConstDecl(tail, name, initializer);
+ if (!constDecls)
+ constDecls = tail;
+ } while (match(COMMA));
+ return constDecls;
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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 (declarations > 1 || match(SEMICOLON))
+ goto standardForLoop;
+
+ // Handle for-in with var declaration
+ int inLocation = tokenStart();
+ if (!consume(INTOKEN))
+ fail();
+
+ 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(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(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(decls, expr, statement, declsStart, declsEnd, exprEnd, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseBreakStatement(TreeBuilder& context)
+{
+ ASSERT(match(BREAK));
+ int startCol = tokenStart();
+ int endCol = tokenEnd();
+ int startLine = tokenLine();
+ int endLine = tokenLine();
+ next();
+
+ if (autoSemiColon()) {
+ failIfFalseIfStrict(breakIsValid());
+ return context.createBreakStatement(startCol, endCol, startLine, endLine);
+ }
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ failIfFalseIfStrict(hasLabel(ident));
+ endCol = tokenEnd();
+ endLine = tokenLine();
+ next();
+ failIfFalse(autoSemiColon());
+ return context.createBreakStatement(ident, startCol, endCol, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseContinueStatement(TreeBuilder& context)
+{
+ ASSERT(match(CONTINUE));
+ int startCol = tokenStart();
+ int endCol = tokenEnd();
+ int startLine = tokenLine();
+ int endLine = tokenLine();
+ next();
+
+ if (autoSemiColon()) {
+ failIfFalseIfStrict(breakIsValid());
+ return context.createContinueStatement(startCol, endCol, startLine, endLine);
+ }
+ matchOrFail(IDENT);
+ const Identifier* ident = m_token.m_data.ident;
+ failIfFalseIfStrict(hasLabel(ident));
+ endCol = tokenEnd();
+ endLine = tokenLine();
+ next();
+ failIfFalse(autoSemiColon());
+ return context.createContinueStatement(ident, startCol, endCol, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseReturnStatement(TreeBuilder& context)
+{
+ ASSERT(match(RETURN));
+ failIfFalseIfStrict(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(0, start, end, startLine, endLine);
+ TreeExpression expr = parseExpression(context);
+ failIfFalse(expr);
+ end = lastTokenEnd();
+ if (match(SEMICOLON))
+ endLine = tokenLine();
+ failIfFalse(autoSemiColon());
+ return context.createReturnStatement(expr, start, end, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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(expr, eStart, eEnd, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseWithStatement(TreeBuilder& context)
+{
+ ASSERT(match(WITH));
+ failIfTrue(strictMode());
+ 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(expr, statement, start, end, startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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(expr, firstClauses, defaultClause, secondClauses, startLine, endLine);
+
+}
+
+template <class TreeBuilder> TreeClauseList JSParser::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 <class TreeBuilder> TreeClause JSParser::parseSwitchDefaultClause(TreeBuilder& context)
+{
+ if (!match(DEFAULT))
+ return 0;
+ next();
+ consumeOrFail(COLON);
+ TreeSourceElements statements = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(statements);
+ return context.createClause(0, statements);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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();
+ ScopeRef catchScope = pushScope();
+ failIfFalseIfStrict(catchScope->declareVariable(ident));
+ catchScope->preventNewDecls();
+ consumeOrFail(CLOSEPAREN);
+ matchOrFail(OPENBRACE);
+ int initialEvalCount = context.evalCount();
+ catchBlock = parseBlockStatement(context);
+ failIfFalse(catchBlock);
+ 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(tryBlock, ident, catchHasEval, catchBlock, finallyBlock, firstLine, lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseDebuggerStatement(TreeBuilder& context)
+{
+ ASSERT(match(DEBUGGER));
+ int startLine = tokenLine();
+ int endLine = startLine;
+ next();
+ if (match(SEMICOLON))
+ startLine = tokenLine();
+ failIfFalse(autoSemiColon());
+ return context.createDebugger(startLine, endLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseBlockStatement(TreeBuilder& context)
+{
+ ASSERT(match(OPENBRACE));
+ int start = tokenLine();
+ next();
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createBlockStatement(0, start, m_lastLine);
+ }
+ TreeSourceElements subtree = parseSourceElements<DontCheckForStrictMode>(context);
+ failIfFalse(subtree);
+ matchOrFail(CLOSEBRACE);
+ next();
+ return context.createBlockStatement(subtree, start, m_lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseStatement(TreeBuilder& context, const Identifier*& directive)
+{
+ 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:
+ failIfFalseIfStrict(m_statementDepth == 1);
+ return parseFunctionDeclaration(context);
+ case SEMICOLON:
+ next();
+ return context.createEmptyStatement();
+ 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;
+ nonTrivialExpressionCount = m_nonTrivialExpressionCount;
+ default:
+ TreeStatement exprStatement = parseExpressionStatement(context);
+ if (directive && nonTrivialExpressionCount != m_nonTrivialExpressionCount)
+ directive = 0;
+ return exprStatement;
+ }
+}
+
+template <class TreeBuilder> TreeFormalParameterList JSParser::parseFormalParameters(TreeBuilder& context)
+{
+ matchOrFail(IDENT);
+ failIfFalseIfStrict(declareParameter(m_token.m_data.ident));
+ 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;
+ failIfFalseIfStrict(declareParameter(ident));
+ next();
+ tail = context.createFormalParameterList(tail, *ident);
+ }
+ return list;
+}
+
+template <class TreeBuilder> TreeFunctionBody JSParser::parseFunctionBody(TreeBuilder& context)
+{
+ if (match(CLOSEBRACE))
+ return context.createFunctionBody(strictMode());
+ DepthManager statementDepth(&m_statementDepth);
+ m_statementDepth = 0;
+ typename TreeBuilder::FunctionBodyBuilder bodyBuilder(m_globalData, m_lexer);
+ failIfFalse(parseSourceElements<CheckForStrictMode>(bodyBuilder));
+ return context.createFunctionBody(strictMode());
+}
+
+template <JSParser::FunctionRequirements requirements, bool nameIsInContainingScope, class TreeBuilder> bool JSParser::parseFunctionInfo(TreeBuilder& context, const Identifier*& name, TreeFormalParameterList& parameters, TreeFunctionBody& body, int& openBracePos, int& closeBracePos, int& bodyStartLine)
+{
+ ScopeRef functionScope = pushScope();
+ functionScope->setIsFunction();
+ if (match(IDENT)) {
+ name = m_token.m_data.ident;
+ 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();
+ next();
+
+ body = parseFunctionBody(context);
+ failIfFalse(body);
+ if (functionScope->strictMode() && name) {
+ failIfTrue(m_globalData->propertyNames->arguments == *name);
+ failIfTrue(m_globalData->propertyNames->eval == *name);
+ }
+ failIfFalse(popScope(functionScope, TreeBuilder::NeedsFreeVariableInfo));
+ matchOrFail(CLOSEBRACE);
+ closeBracePos = m_token.m_data.intValue;
+ next();
+ return true;
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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(name, body, parameters, openBracePos, closeBracePos, bodyStartLine, m_lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseExpressionOrLabelStatement(TreeBuilder& context)
+{
+
+ /* Expression and Label statements are ambiguous at LL(1), to avoid
+ * the cost of having a token buffer to support LL(2) we simply assume
+ * we have an expression statement, and then only look for a label if that
+ * parse fails.
+ */
+ int start = tokenStart();
+ int startLine = tokenLine();
+ const Identifier* ident = m_token.m_data.ident;
+ int currentToken = m_tokenCount;
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression);
+ if (autoSemiColon())
+ return context.createExprStatement(expression, startLine, m_lastLine);
+ failIfFalse(currentToken + 1 == m_tokenCount);
+ int end = tokenEnd();
+ consumeOrFail(COLON);
+ const Identifier* unused = 0;
+ if (strictMode() && !m_syntaxAlreadyValidated)
+ pushLabel(ident);
+ TreeStatement statement = parseStatement(context, unused);
+ if (strictMode() && !m_syntaxAlreadyValidated)
+ popLabel();
+ failIfFalse(statement);
+ return context.createLabelStatement(ident, statement, start, end);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::parseExpressionStatement(TreeBuilder& context)
+{
+ int startLine = tokenLine();
+ TreeExpression expression = parseExpression(context);
+ failIfFalse(expression);
+ failIfFalse(autoSemiColon());
+ return context.createExprStatement(expression, startLine, m_lastLine);
+}
+
+template <class TreeBuilder> TreeStatement JSParser::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(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(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(condition, trueBlock, falseBlock, pos.first, pos.second));
+ }
+
+ return context.createIfStatement(condition, trueBlock, statementStack.last(), start, end);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::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(node, right);
+ while (match(COMMA)) {
+ next();
+ right = parseAssignmentExpression(context);
+ failIfFalse(right);
+ context.appendToComma(commaNode, right);
+ }
+ return commaNode;
+}
+
+
+template <typename TreeBuilder> TreeExpression JSParser::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();
+ if (strictMode() && m_lastIdentifier && context.isResolve(lhs)) {
+ failIfTrueIfStrict(m_globalData->propertyNames->eval == *m_lastIdentifier);
+ 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(assignmentStack, lhs, initialAssignmentCount, m_assignmentCount, lastTokenEnd());
+
+ return lhs;
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseConditionalExpression(TreeBuilder& context)
+{
+ TreeExpression cond = parseBinaryExpression(context);
+ failIfFalse(cond);
+ if (!match(QUESTION))
+ return cond;
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ next();
+ TreeExpression lhs = parseAssignmentExpression(context);
+ consumeOrFail(COLON);
+
+ TreeExpression rhs = parseAssignmentExpression(context);
+ failIfFalse(rhs);
+ return context.createConditionalExpr(cond, lhs, rhs);
+}
+
+ALWAYS_INLINE static bool isUnaryOp(JSTokenType token)
+{
+ return token & UnaryOpTokenFlag;
+}
+
+int JSParser::isBinaryOperator(JSTokenType token)
+{
+ if (m_allowsIn)
+ return token & (BinaryOpTokenPrecedenceMask << BinaryOpTokenAllowsInPrecedenceAdditionalShift);
+ return token & BinaryOpTokenPrecedenceMask;
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseBinaryExpression(TreeBuilder& context)
+{
+
+ int operandStackDepth = 0;
+ int operatorStackDepth = 0;
+ 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();
+
+ 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(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(operandStackDepth, operatorStackDepth, lhs, rhs);
+ context.operatorStackPop(operatorStackDepth);
+ }
+ return context.popOperandStack(operandStackDepth);
+}
+
+
+template <bool complete, class TreeBuilder> TreeProperty JSParser::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;
+ next(Lexer::IgnoreReservedWords);
+ 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>(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>(m_globalData, propertyName, node, PropertyNode::Constant);
+ }
+ default:
+ failIfFalse(m_token.m_type & KeywordTokenFlag);
+ goto namedProperty;
+ }
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseObjectLiteral(TreeBuilder& context)
+{
+ int startOffset = m_token.m_data.intValue;
+ consumeOrFail(OPENBRACE);
+
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral();
+ }
+
+ 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(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<false>(context);
+ failIfFalse(property);
+ if (!m_syntaxAlreadyValidated && context.getType(property) != PropertyNode::Constant) {
+ m_lexer->setOffset(startOffset);
+ next();
+ return parseStrictObjectLiteral(context);
+ }
+ tail = context.createPropertyList(property, tail);
+ }
+
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createObjectLiteral(propertyList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseStrictObjectLiteral(TreeBuilder& context)
+{
+ consumeOrFail(OPENBRACE);
+
+ if (match(CLOSEBRACE)) {
+ next();
+ return context.createObjectLiteral();
+ }
+
+ 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(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(strictMode());
+ if ((context.getType(property) & propertyEntryIter.first->second) != PropertyNode::Constant) {
+ // Can't have multiple getters or setters with the same name, nor can we define
+ // a property as both an accessor and a constant value
+ failIfTrue(context.getType(property) & propertyEntryIter.first->second);
+ failIfTrue((context.getType(property) | propertyEntryIter.first->second) & PropertyNode::Constant);
+ }
+ }
+ }
+ tail = context.createPropertyList(property, tail);
+ }
+
+ consumeOrFail(CLOSEBRACE);
+
+ return context.createObjectLiteral(propertyList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseArrayLiteral(TreeBuilder& context)
+{
+ consumeOrFail(OPENBRACKET);
+
+ int elisions = 0;
+ while (match(COMMA)) {
+ next();
+ elisions++;
+ }
+ if (match(CLOSEBRACKET)) {
+ next();
+ return context.createArray(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();
+ elisions = 0;
+
+ while (match(COMMA)) {
+ next();
+ elisions++;
+ }
+
+ if (match(CLOSEBRACKET)) {
+ next();
+ return context.createArray(elisions, elementList);
+ }
+ TreeExpression elem = parseAssignmentExpression(context);
+ failIfFalse(elem);
+ tail = context.createElementList(tail, elisions, elem);
+ }
+
+ consumeOrFail(CLOSEBRACKET);
+
+ return context.createArray(elementList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parsePrimaryExpression(TreeBuilder& context)
+{
+ 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();
+ }
+ 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(ident, start);
+ }
+ case STRING: {
+ const Identifier* ident = m_token.m_data.ident;
+ next();
+ return context.createString(ident);
+ }
+ case NUMBER: {
+ double d = m_token.m_data.doubleValue;
+ next();
+ return context.createNumberExpr(d);
+ }
+ case NULLTOKEN: {
+ next();
+ return context.createNull();
+ }
+ case TRUETOKEN: {
+ next();
+ return context.createBoolean(true);
+ }
+ case FALSETOKEN: {
+ next();
+ return context.createBoolean(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();
+ return context.createRegex(*pattern, *flags, start);
+ }
+ default:
+ fail();
+ }
+}
+
+template <class TreeBuilder> TreeArguments JSParser::parseArguments(TreeBuilder& context)
+{
+ consumeOrFail(OPENPAREN);
+ if (match(CLOSEPAREN)) {
+ next();
+ return context.createArguments();
+ }
+ TreeExpression firstArg = parseAssignmentExpression(context);
+ failIfFalse(firstArg);
+
+ TreeArgumentsList argList = context.createArgumentsList(firstArg);
+ TreeArgumentsList tail = argList;
+ while (match(COMMA)) {
+ next();
+ TreeExpression arg = parseAssignmentExpression(context);
+ failIfFalse(arg);
+ tail = context.createArgumentsList(tail, arg);
+ }
+ consumeOrFail(CLOSEPAREN);
+ return context.createArguments(argList);
+}
+
+template <class TreeBuilder> TreeExpression JSParser::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(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(base, property, initialAssignments != m_assignmentCount, expressionStart, expressionEnd, tokenEnd());
+ if (!consume(CLOSEBRACKET))
+ fail();
+ 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(base, arguments, start, exprEnd, lastTokenEnd());
+ } else
+ base = context.createNewExpr(base, start, lastTokenEnd());
+ } else {
+ int nonLHSCount = m_nonLHSCount;
+ int expressionEnd = lastTokenEnd();
+ TreeArguments arguments = parseArguments(context);
+ failIfFalse(arguments);
+ base = context.makeFunctionCallNode(base, arguments, expressionStart, expressionEnd, lastTokenEnd());
+ m_nonLHSCount = nonLHSCount;
+ }
+ break;
+ }
+ case DOT: {
+ m_nonTrivialExpressionCount++;
+ int expressionEnd = lastTokenEnd();
+ next(Lexer::IgnoreReservedWords);
+ matchOrFail(IDENT);
+ base = context.createDotAccess(base, *m_token.m_data.ident, expressionStart, expressionEnd, tokenEnd());
+ next();
+ break;
+ }
+ default:
+ goto endMemberExpression;
+ }
+ }
+endMemberExpression:
+ while (newCount--)
+ base = context.createNewExpr(base, start, lastTokenEnd());
+ return base;
+}
+
+template <class TreeBuilder> TreeExpression JSParser::parseUnaryExpression(TreeBuilder& 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_globalData->propertyNames->eval == *m_lastIdentifier;
+ if (!isEvalOrArguments && currentScope()->isFunction())
+ isEvalOrArguments = m_globalData->propertyNames->arguments == *m_lastIdentifier;
+ }
+ }
+ failIfTrueIfStrict(isEvalOrArguments && modifiesExpr);
+ switch (m_token.m_type) {
+ case PLUSPLUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(expr, OpPlusPlus, subExprStart, lastTokenEnd(), tokenEnd());
+ m_assignmentCount++;
+ failIfTrueIfStrict(isEvalOrArguments);
+ failIfTrueIfStrict(requiresLExpr);
+ next();
+ break;
+ case MINUSMINUS:
+ m_nonTrivialExpressionCount++;
+ m_nonLHSCount++;
+ expr = context.makePostfixNode(expr, OpMinusMinus, subExprStart, lastTokenEnd(), tokenEnd());
+ m_assignmentCount++;
+ failIfTrueIfStrict(isEvalOrArguments);
+ 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(expr);
+ break;
+ case TILDE:
+ expr = context.makeBitwiseNotNode(expr);
+ break;
+ case MINUS:
+ expr = context.makeNegateNode(expr);
+ break;
+ case PLUS:
+ expr = context.createUnaryPlus(expr);
+ break;
+ case PLUSPLUS:
+ case AUTOPLUSPLUS:
+ expr = context.makePrefixNode(expr, OpPlusPlus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case MINUSMINUS:
+ case AUTOMINUSMINUS:
+ expr = context.makePrefixNode(expr, OpMinusMinus, context.unaryTokenStackLastStart(tokenStackDepth), subExprStart + 1, end);
+ m_assignmentCount++;
+ break;
+ case TYPEOF:
+ expr = context.makeTypeOfNode(expr);
+ break;
+ case VOIDTOKEN:
+ expr = context.createVoid(expr);
+ break;
+ case DELETETOKEN:
+ failIfTrueIfStrict(context.isResolve(expr));
+ expr = context.makeDeleteNode(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;
+}
+
+}
diff --git a/Source/JavaScriptCore/parser/JSParser.h b/Source/JavaScriptCore/parser/JSParser.h
new file mode 100644
index 0000000..0676b41
--- /dev/null
+++ b/Source/JavaScriptCore/parser/JSParser.h
@@ -0,0 +1,164 @@
+/*
+ * 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 JSParser_h
+#define JSParser_h
+
+namespace JSC {
+
+class ExecState;
+class FunctionParameters;
+class Identifier;
+class JSGlobalData;
+class SourceCode;
+
+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,
+ 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 };
+
+int jsParse(JSGlobalData*, FunctionParameters*, JSParserStrictness, JSParserMode, const SourceCode*);
+}
+#endif // JSParser_h
diff --git a/Source/JavaScriptCore/parser/Keywords.table b/Source/JavaScriptCore/parser/Keywords.table
new file mode 100644
index 0000000..490c1cc
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Keywords.table
@@ -0,0 +1,72 @@
+# main keywords
+@begin mainTable 41
+
+# 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
+
+# these words are reserved for future use in the ECMA spec, but not in WinIE
+# (see http://bugs.webkit.org/show_bug.cgi?id=6179)
+# abstract RESERVED
+# boolean RESERVED
+# byte RESERVED
+# char RESERVED
+# double RESERVED
+# final RESERVED
+# float RESERVED
+# goto RESERVED
+# implements RESERVED
+# int RESERVED
+# interface RESERVED
+# long RESERVED
+# native RESERVED
+# package RESERVED
+# private RESERVED
+# protected RESERVED
+# public RESERVED
+# short RESERVED
+# static RESERVED
+# synchronized RESERVED
+# throws RESERVED
+# transient RESERVED
+# volatile RESERVED
+@end
+
diff --git a/Source/JavaScriptCore/parser/Lexer.cpp b/Source/JavaScriptCore/parser/Lexer.cpp
new file mode 100644
index 0000000..ff7079f
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Lexer.cpp
@@ -0,0 +1,1196 @@
+/*
+ * 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 "JSParser.h"
+#include "Lookup.h"
+#include "Lexer.lut.h"
+
+namespace JSC {
+
+
+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,
+};
+
+Lexer::Lexer(JSGlobalData* globalData)
+ : m_isReparsing(false)
+ , m_globalData(globalData)
+ , m_keywordTable(JSC::mainTable)
+{
+}
+
+Lexer::~Lexer()
+{
+ m_keywordTable.deleteTable();
+}
+
+ALWAYS_INLINE const UChar* Lexer::currentCharacter() const
+{
+ ASSERT(m_code <= m_codeEnd);
+ return m_code;
+}
+
+ALWAYS_INLINE int Lexer::currentOffset() const
+{
+ return currentCharacter() - m_codeStart;
+}
+
+void Lexer::setCode(const SourceCode& source, ParserArena& arena)
+{
+ m_arena = &arena.identifierArena();
+
+ m_lineNumber = source.firstLine();
+ m_delimited = false;
+ m_lastToken = -1;
+
+ const UChar* data = source.provider()->data();
+
+ m_source = &source;
+ m_codeStart = data;
+ m_code = data + source.startOffset();
+ m_codeEnd = data + source.endOffset();
+ m_error = false;
+ m_atLineStart = true;
+
+ 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());
+}
+
+ALWAYS_INLINE void Lexer::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;
+}
+
+ALWAYS_INLINE int Lexer::peek(int offset)
+{
+ // Only use if necessary
+ ASSERT(offset > 0 && offset < 5);
+ const UChar* code = m_code + offset;
+ return (code < m_codeEnd) ? *code : -1;
+}
+
+int Lexer::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;
+}
+
+void Lexer::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;
+}
+
+ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length)
+{
+ return &m_arena->makeIdentifier(m_globalData, characters, length);
+}
+
+ALWAYS_INLINE bool Lexer::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 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;
+ }
+}
+
+inline void Lexer::record8(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= 0xFF);
+ m_buffer8.append(static_cast<char>(c));
+}
+
+inline void Lexer::record16(UChar c)
+{
+ m_buffer16.append(c);
+}
+
+inline void Lexer::record16(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= USHRT_MAX);
+ record16(UChar(static_cast<unsigned short>(c)));
+}
+
+ALWAYS_INLINE JSTokenType Lexer::parseIdentifier(JSTokenData* lvalp, LexType lexType)
+{
+ bool bufferRequired = false;
+ const UChar* identifierStart = currentCharacter();
+ int identifierLength;
+
+ 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;
+ record16(character);
+ identifierStart = currentCharacter();
+ }
+
+ if (!bufferRequired)
+ identifierLength = currentCharacter() - identifierStart;
+ else {
+ if (identifierStart != currentCharacter())
+ m_buffer16.append(identifierStart, currentCharacter() - identifierStart);
+ identifierStart = m_buffer16.data();
+ identifierLength = m_buffer16.size();
+ }
+
+ const Identifier* ident = makeIdentifier(identifierStart, identifierLength);
+ lvalp->ident = ident;
+ m_delimited = false;
+
+ if (LIKELY(!bufferRequired && lexType == IdentifyReservedWords)) {
+ // Keywords must not be recognized if there was an \uXXXX in the identifier.
+ const HashEntry* entry = m_keywordTable.entry(m_globalData, *ident);
+ return entry ? static_cast<JSTokenType>(entry->lexerValue()) : IDENT;
+ }
+
+ m_buffer16.resize(0);
+ return IDENT;
+}
+
+ALWAYS_INLINE bool Lexer::parseString(JSTokenData* lvalp, bool strictMode)
+{
+ int stringQuoteCharacter = m_current;
+ shift();
+
+ const UChar* stringStart = currentCharacter();
+
+ while (m_current != stringQuoteCharacter) {
+ if (UNLIKELY(m_current == '\\')) {
+ if (stringStart != currentCharacter())
+ m_buffer16.append(stringStart, currentCharacter() - stringStart);
+ shift();
+
+ int escape = singleEscape(m_current);
+
+ // Most common escape sequences first
+ if (escape) {
+ 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();
+ record16(convertHex(prev, m_current));
+ shift();
+ } else
+ record16('x');
+ } else if (m_current == 'u') {
+ shift();
+ int character = getUnicodeCharacter();
+ if (character != -1)
+ record16(character);
+ else if (m_current == stringQuoteCharacter)
+ record16('u');
+ else // Only stringQuoteCharacter allowed after \u
+ 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))
+ return false;
+ 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)) {
+ record16((character1 - '0') * 64 + (character2 - '0') * 8 + m_current - '0');
+ shift();
+ } else
+ record16((character1 - '0') * 8 + character2 - '0');
+ } else
+ record16(character1 - '0');
+ } else if (m_current != -1) {
+ record16(m_current);
+ shift();
+ } else
+ 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))
+ return false;
+ // Anything else is just a normal character
+ }
+ shift();
+ }
+
+ if (currentCharacter() != stringStart)
+ m_buffer16.append(stringStart, currentCharacter() - stringStart);
+ lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size());
+ m_buffer16.resize(0);
+ return true;
+}
+
+ALWAYS_INLINE void Lexer::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);
+}
+
+ALWAYS_INLINE bool Lexer::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.
+ char 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;
+}
+
+ALWAYS_INLINE bool Lexer::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.
+ char 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;
+}
+
+ALWAYS_INLINE void Lexer::parseNumberAfterDecimalPoint()
+{
+ record8('.');
+ while (isASCIIDigit(m_current)) {
+ record8(m_current);
+ shift();
+ }
+}
+
+ALWAYS_INLINE bool Lexer::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;
+}
+
+ALWAYS_INLINE bool Lexer::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();
+ else
+ shift();
+ }
+}
+
+JSTokenType Lexer::lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType lexType, 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;
+ 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:
+ lvalp->intValue = currentOffset();
+ shift();
+ token = OPENBRACE;
+ break;
+ case CharacterCloseBrace:
+ lvalp->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(lvalp->doubleValue);
+ token = NUMBER;
+ } else {
+ record8('0');
+ if (isASCIIOctalDigit(m_current)) {
+ if (parseOctal(lvalp->doubleValue)) {
+ if (strictMode)
+ goto returnError;
+ token = NUMBER;
+ }
+ }
+ }
+ // Fall through into CharacterNumber
+ case CharacterNumber:
+ if (LIKELY(token != NUMBER)) {
+ if (!parseDecimal(lvalp->doubleValue)) {
+ if (m_current == '.') {
+ shift();
+inNumberAfterDecimalPoint:
+ parseNumberAfterDecimalPoint();
+ }
+ if ((m_current | 0x20) == 'e')
+ if (!parseNumberAfterExponentIndicator())
+ goto returnError;
+ // Null-terminate string for strtod.
+ m_buffer8.append('\0');
+ lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0);
+ }
+ token = NUMBER;
+ }
+
+ // No identifiers allowed directly after numeric literal, e.g. "3in" is bad.
+ if (UNLIKELY(isIdentStart(m_current)))
+ goto returnError;
+ m_buffer8.resize(0);
+ m_delimited = false;
+ break;
+ case CharacterQuote:
+ if (UNLIKELY(!parseString(lvalp, strictMode)))
+ goto returnError;
+ shift();
+ m_delimited = false;
+ token = STRING;
+ break;
+ case CharacterIdentifierStart:
+ ASSERT(isIdentStart(m_current));
+ // Fall through into CharacterBackSlash.
+ case CharacterBackSlash:
+ token = parseIdentifier(lvalp, lexType);
+ break;
+ case CharacterLineTerminator:
+ ASSERT(isLineTerminator(m_current));
+ shiftLineTerminator();
+ m_atLineStart = true;
+ m_terminator = true;
+ goto start;
+ case CharacterInvalid:
+ goto returnError;
+ default:
+ ASSERT_NOT_REACHED();
+ 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:
+ llocp->line = m_lineNumber;
+ llocp->startOffset = startOffset;
+ llocp->endOffset = currentOffset();
+ m_lastToken = token;
+ return token;
+
+returnError:
+ m_error = true;
+ return ERRORTOK;
+}
+
+bool Lexer::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;
+}
+
+bool Lexer::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;
+}
+
+void Lexer::clear()
+{
+ m_arena = 0;
+
+ Vector<char> newBuffer8;
+ m_buffer8.swap(newBuffer8);
+
+ Vector<UChar> newBuffer16;
+ m_buffer16.swap(newBuffer16);
+
+ m_isReparsing = false;
+}
+
+SourceCode Lexer::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);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Lexer.h b/Source/JavaScriptCore/parser/Lexer.h
new file mode 100644
index 0000000..4d2513d
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Lexer.h
@@ -0,0 +1,158 @@
+/*
+ * 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 "JSParser.h"
+#include "Lookup.h"
+#include "ParserArena.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 RegExp;
+
+ class Lexer : public Noncopyable {
+ public:
+ // 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; }
+
+ // Functions for the parser itself.
+ enum LexType { IdentifyReservedWords, IgnoreReservedWords };
+ JSTokenType lex(JSTokenData* lvalp, JSTokenInfo* llocp, LexType, bool strictMode);
+ 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; }
+ void clear();
+ int currentOffset() { return m_code - m_codeStart; }
+ void setOffset(int offset)
+ {
+ m_code = m_codeStart + offset;
+ m_current = *m_code;
+ }
+
+ private:
+ friend class JSGlobalData;
+
+ Lexer(JSGlobalData*);
+ ~Lexer();
+
+ void record8(int);
+ void record16(int);
+ void record16(UChar);
+
+ void copyCodeWithoutBOMs();
+
+ ALWAYS_INLINE void shift();
+ ALWAYS_INLINE int peek(int offset);
+ int getUnicodeCharacter();
+ void shiftLineTerminator();
+
+ ALWAYS_INLINE const UChar* currentCharacter() const;
+ ALWAYS_INLINE int currentOffset() const;
+
+ ALWAYS_INLINE const Identifier* makeIdentifier(const UChar* characters, size_t length);
+
+ ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
+
+ ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, LexType);
+ ALWAYS_INLINE bool parseString(JSTokenData* lvalp, 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<char> 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 UChar* m_code;
+ const UChar* m_codeStart;
+ const UChar* m_codeEnd;
+ bool m_isReparsing;
+ bool m_atLineStart;
+ bool m_error;
+
+ // current and following unicode characters (int to allow for -1 for end-of-file marker)
+ int m_current;
+
+ IdentifierArena* m_arena;
+
+ JSGlobalData* m_globalData;
+
+ const HashTable m_keywordTable;
+ };
+
+ inline bool Lexer::isWhiteSpace(int ch)
+ {
+ return isASCII(ch) ? (ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC) : (WTF::Unicode::isSeparatorSpace(ch) || ch == 0xFEFF);
+ }
+
+ inline bool Lexer::isLineTerminator(int ch)
+ {
+ return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028;
+ }
+
+ inline unsigned char Lexer::convertHex(int c1, int c2)
+ {
+ return (toASCIIHexValue(c1) << 4) | toASCIIHexValue(c2);
+ }
+
+ inline UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4)
+ {
+ return (convertHex(c1, c2) << 8) | convertHex(c3, c4);
+ }
+
+} // namespace JSC
+
+#endif // Lexer_h
diff --git a/Source/JavaScriptCore/parser/NodeConstructors.h b/Source/JavaScriptCore/parser/NodeConstructors.h
new file mode 100644
index 0000000..4e094b6
--- /dev/null
+++ b/Source/JavaScriptCore/parser/NodeConstructors.h
@@ -0,0 +1,908 @@
+/*
+ * 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->parser->arena().allocateFreeable(size);
+ }
+
+ inline void* ParserArenaDeletable::operator new(size_t size, JSGlobalData* globalData)
+ {
+ return globalData->parser->arena().allocateDeletable(size);
+ }
+
+ inline ParserArenaRefCounted::ParserArenaRefCounted(JSGlobalData* globalData)
+ {
+ globalData->parser->arena().derefWithArena(adoptRef(this));
+ }
+
+ inline Node::Node(JSGlobalData* globalData)
+ : m_line(globalData->lexer->lastLineNumber())
+ {
+ }
+
+ inline ExpressionNode::ExpressionNode(JSGlobalData* globalData, ResultType resultType)
+ : Node(globalData)
+ , m_resultType(resultType)
+ {
+ }
+
+ inline StatementNode::StatementNode(JSGlobalData* globalData)
+ : Node(globalData)
+ , m_lastLine(-1)
+ {
+ }
+
+ inline NullNode::NullNode(JSGlobalData* globalData)
+ : ExpressionNode(globalData, ResultType::nullType())
+ {
+ }
+
+ inline BooleanNode::BooleanNode(JSGlobalData* globalData, bool value)
+ : ExpressionNode(globalData, ResultType::booleanType())
+ , m_value(value)
+ {
+ }
+
+ inline NumberNode::NumberNode(JSGlobalData* globalData, double value)
+ : ExpressionNode(globalData, ResultType::numberType())
+ , m_value(value)
+ {
+ }
+
+ inline StringNode::StringNode(JSGlobalData* globalData, const Identifier& value)
+ : ExpressionNode(globalData, ResultType::stringType())
+ , m_value(value)
+ {
+ }
+
+ inline RegExpNode::RegExpNode(JSGlobalData* globalData, const Identifier& pattern, const Identifier& flags)
+ : ExpressionNode(globalData)
+ , m_pattern(pattern)
+ , m_flags(flags)
+ {
+ }
+
+ inline ThisNode::ThisNode(JSGlobalData* globalData)
+ : ExpressionNode(globalData)
+ {
+ }
+
+ inline ResolveNode::ResolveNode(JSGlobalData* globalData, const Identifier& ident, int startOffset)
+ : ExpressionNode(globalData)
+ , m_ident(ident)
+ , m_startOffset(startOffset)
+ {
+ }
+
+ inline ElementNode::ElementNode(JSGlobalData*, int elision, ExpressionNode* node)
+ : m_next(0)
+ , m_elision(elision)
+ , m_node(node)
+ {
+ }
+
+ inline ElementNode::ElementNode(JSGlobalData*, ElementNode* l, int elision, ExpressionNode* node)
+ : m_next(0)
+ , m_elision(elision)
+ , m_node(node)
+ {
+ l->m_next = this;
+ }
+
+ inline ArrayNode::ArrayNode(JSGlobalData* globalData, int elision)
+ : ExpressionNode(globalData)
+ , m_element(0)
+ , m_elision(elision)
+ , m_optional(true)
+ {
+ }
+
+ inline ArrayNode::ArrayNode(JSGlobalData* globalData, ElementNode* element)
+ : ExpressionNode(globalData)
+ , m_element(element)
+ , m_elision(0)
+ , m_optional(false)
+ {
+ }
+
+ inline ArrayNode::ArrayNode(JSGlobalData* globalData, int elision, ElementNode* element)
+ : ExpressionNode(globalData)
+ , 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->parser->arena().identifierArena().makeNumericIdentifier(globalData, name))
+ , m_assign(assign)
+ , m_type(type)
+ {
+ }
+
+ inline PropertyListNode::PropertyListNode(JSGlobalData* globalData, PropertyNode* node)
+ : Node(globalData)
+ , m_node(node)
+ , m_next(0)
+ {
+ }
+
+ inline PropertyListNode::PropertyListNode(JSGlobalData* globalData, PropertyNode* node, PropertyListNode* list)
+ : Node(globalData)
+ , m_node(node)
+ , m_next(0)
+ {
+ list->m_next = this;
+ }
+
+ inline ObjectLiteralNode::ObjectLiteralNode(JSGlobalData* globalData)
+ : ExpressionNode(globalData)
+ , m_list(0)
+ {
+ }
+
+ inline ObjectLiteralNode::ObjectLiteralNode(JSGlobalData* globalData, PropertyListNode* list)
+ : ExpressionNode(globalData)
+ , m_list(list)
+ {
+ }
+
+ inline BracketAccessorNode::BracketAccessorNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments)
+ : ExpressionNode(globalData)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ {
+ }
+
+ inline DotAccessorNode::DotAccessorNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident)
+ : ExpressionNode(globalData)
+ , m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ inline ArgumentListNode::ArgumentListNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : Node(globalData)
+ , m_next(0)
+ , m_expr(expr)
+ {
+ }
+
+ inline ArgumentListNode::ArgumentListNode(JSGlobalData* globalData, ArgumentListNode* listNode, ExpressionNode* expr)
+ : Node(globalData)
+ , m_next(0)
+ , m_expr(expr)
+ {
+ listNode->m_next = this;
+ }
+
+ inline ArgumentsNode::ArgumentsNode(JSGlobalData*)
+ : m_listNode(0)
+ {
+ }
+
+ inline ArgumentsNode::ArgumentsNode(JSGlobalData*, ArgumentListNode* listNode)
+ : m_listNode(listNode)
+ {
+ }
+
+ inline NewExprNode::NewExprNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : ExpressionNode(globalData)
+ , m_expr(expr)
+ , m_args(0)
+ {
+ }
+
+ inline NewExprNode::NewExprNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args)
+ : ExpressionNode(globalData)
+ , m_expr(expr)
+ , m_args(args)
+ {
+ }
+
+ inline EvalFunctionCallNode::EvalFunctionCallNode(JSGlobalData* globalData, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallValueNode::FunctionCallValueNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallResolveNode::FunctionCallResolveNode(JSGlobalData* globalData, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallBracketNode::FunctionCallBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_args(args)
+ {
+ }
+
+ inline FunctionCallDotNode::FunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ inline CallFunctionCallDotNode::CallFunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : FunctionCallDotNode(globalData, base, ident, args, divot, startOffset, endOffset)
+ {
+ }
+
+ inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : FunctionCallDotNode(globalData, base, ident, args, divot, startOffset, endOffset)
+ {
+ }
+
+ inline PrePostResolveNode::PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData, ResultType::numberType()) // could be reusable for pre?
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ {
+ }
+
+ inline PostfixResolveNode::PostfixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset)
+ , m_operator(oper)
+ {
+ }
+
+ inline PostfixBracketNode::PostfixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_operator(oper)
+ {
+ }
+
+ inline PostfixDotNode::PostfixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_operator(oper)
+ {
+ }
+
+ inline PostfixErrorNode::PostfixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
+ , m_operator(oper)
+ {
+ }
+
+ inline DeleteResolveNode::DeleteResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ {
+ }
+
+ inline DeleteBracketNode::DeleteBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ {
+ }
+
+ inline DeleteDotNode::DeleteDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ inline DeleteValueNode::DeleteValueNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : ExpressionNode(globalData)
+ , m_expr(expr)
+ {
+ }
+
+ inline VoidNode::VoidNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : ExpressionNode(globalData)
+ , m_expr(expr)
+ {
+ }
+
+ inline TypeOfResolveNode::TypeOfResolveNode(JSGlobalData* globalData, const Identifier& ident)
+ : ExpressionNode(globalData, ResultType::stringType())
+ , m_ident(ident)
+ {
+ }
+
+ inline TypeOfValueNode::TypeOfValueNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : ExpressionNode(globalData, ResultType::stringType())
+ , m_expr(expr)
+ {
+ }
+
+ inline PrefixResolveNode::PrefixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset)
+ , m_operator(oper)
+ {
+ }
+
+ inline PrefixBracketNode::PrefixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_operator(oper)
+ {
+ }
+
+ inline PrefixDotNode::PrefixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_operator(oper)
+ {
+ }
+
+ inline PrefixErrorNode::PrefixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
+ , m_operator(oper)
+ {
+ }
+
+ inline UnaryOpNode::UnaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr, OpcodeID opcodeID)
+ : ExpressionNode(globalData, type)
+ , m_expr(expr)
+ , m_opcodeID(opcodeID)
+ {
+ }
+
+ inline UnaryPlusNode::UnaryPlusNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : UnaryOpNode(globalData, ResultType::numberType(), expr, op_to_jsnumber)
+ {
+ }
+
+ inline NegateNode::NegateNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : UnaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr, op_negate)
+ {
+ }
+
+ inline BitwiseNotNode::BitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : UnaryOpNode(globalData, ResultType::forBitOp(), expr, op_bitnot)
+ {
+ }
+
+ inline LogicalNotNode::LogicalNotNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : UnaryOpNode(globalData, ResultType::booleanType(), expr, op_not)
+ {
+ }
+
+ inline BinaryOpNode::BinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : ExpressionNode(globalData)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_opcodeID(opcodeID)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline BinaryOpNode::BinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : ExpressionNode(globalData, type)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_opcodeID(opcodeID)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline ReverseBinaryOpNode::ReverseBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(globalData, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline ReverseBinaryOpNode::ReverseBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(globalData, type, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline MultNode::MultNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_mul, rightHasAssignments)
+ {
+ }
+
+ inline DivNode::DivNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_div, rightHasAssignments)
+ {
+ }
+
+
+ inline ModNode::ModNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_mod, rightHasAssignments)
+ {
+ }
+
+ inline AddNode::AddNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_add, rightHasAssignments)
+ {
+ }
+
+ inline SubNode::SubNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_sub, rightHasAssignments)
+ {
+ }
+
+ inline LeftShiftNode::LeftShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_lshift, rightHasAssignments)
+ {
+ }
+
+ inline RightShiftNode::RightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_rshift, rightHasAssignments)
+ {
+ }
+
+ inline UnsignedRightShiftNode::UnsignedRightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_urshift, rightHasAssignments)
+ {
+ }
+
+ inline LessNode::LessNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_less, rightHasAssignments)
+ {
+ }
+
+ inline GreaterNode::GreaterNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ReverseBinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_less, rightHasAssignments)
+ {
+ }
+
+ inline LessEqNode::LessEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_lesseq, rightHasAssignments)
+ {
+ }
+
+ inline GreaterEqNode::GreaterEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ReverseBinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_lesseq, rightHasAssignments)
+ {
+ }
+
+ inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(globalData, type, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments)
+ : BinaryOpNode(globalData, expr1, expr2, opcodeID, rightHasAssignments)
+ {
+ }
+
+ inline InstanceOfNode::InstanceOfNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ThrowableBinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_instanceof, rightHasAssignments)
+ {
+ }
+
+ inline InNode::InNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ThrowableBinaryOpNode(globalData, expr1, expr2, op_in, rightHasAssignments)
+ {
+ }
+
+ inline EqualNode::EqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_eq, rightHasAssignments)
+ {
+ }
+
+ inline NotEqualNode::NotEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_neq, rightHasAssignments)
+ {
+ }
+
+ inline StrictEqualNode::StrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_stricteq, rightHasAssignments)
+ {
+ }
+
+ inline NotStrictEqualNode::NotStrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_nstricteq, rightHasAssignments)
+ {
+ }
+
+ inline BitAndNode::BitAndNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_bitand, rightHasAssignments)
+ {
+ }
+
+ inline BitOrNode::BitOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_bitor, rightHasAssignments)
+ {
+ }
+
+ inline BitXOrNode::BitXOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_bitxor, rightHasAssignments)
+ {
+ }
+
+ inline LogicalOpNode::LogicalOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper)
+ : ExpressionNode(globalData, ResultType::booleanType())
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_operator(oper)
+ {
+ }
+
+ inline ConditionalNode::ConditionalNode(JSGlobalData* globalData, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2)
+ : ExpressionNode(globalData)
+ , m_logical(logical)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ inline ReadModifyResolveNode::ReadModifyResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignResolveNode::AssignResolveNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments)
+ : ExpressionNode(globalData)
+ , m_ident(ident)
+ , m_right(right)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline ReadModifyBracketNode::ReadModifyBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , 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(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_subscript(subscript)
+ , m_right(right)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignDotNode::AssignDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline ReadModifyDotNode::ReadModifyDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
+
+ inline AssignErrorNode::AssignErrorNode(JSGlobalData* globalData, ExpressionNode* left, Operator oper, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_left(left)
+ , m_operator(oper)
+ , m_right(right)
+ {
+ }
+
+ inline CommaNode::CommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2)
+ : ExpressionNode(globalData)
+ {
+ m_expressions.append(expr1);
+ m_expressions.append(expr2);
+ }
+
+ inline ConstStatementNode::ConstStatementNode(JSGlobalData* globalData, ConstDeclNode* next)
+ : StatementNode(globalData)
+ , m_next(next)
+ {
+ }
+
+ inline SourceElements::SourceElements(JSGlobalData*)
+ {
+ }
+
+ inline EmptyStatementNode::EmptyStatementNode(JSGlobalData* globalData)
+ : StatementNode(globalData)
+ {
+ }
+
+ inline DebuggerStatementNode::DebuggerStatementNode(JSGlobalData* globalData)
+ : StatementNode(globalData)
+ {
+ }
+
+ inline ExprStatementNode::ExprStatementNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : StatementNode(globalData)
+ , m_expr(expr)
+ {
+ }
+
+ inline VarStatementNode::VarStatementNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : StatementNode(globalData)
+ , m_expr(expr)
+ {
+ }
+
+ inline IfNode::IfNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock)
+ : StatementNode(globalData)
+ , m_condition(condition)
+ , m_ifBlock(ifBlock)
+ {
+ }
+
+ inline IfElseNode::IfElseNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock)
+ : IfNode(globalData, condition, ifBlock)
+ , m_elseBlock(elseBlock)
+ {
+ }
+
+ inline DoWhileNode::DoWhileNode(JSGlobalData* globalData, StatementNode* statement, ExpressionNode* expr)
+ : StatementNode(globalData)
+ , m_statement(statement)
+ , m_expr(expr)
+ {
+ }
+
+ inline WhileNode::WhileNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement)
+ : StatementNode(globalData)
+ , m_expr(expr)
+ , m_statement(statement)
+ {
+ }
+
+ inline ForNode::ForNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl)
+ : StatementNode(globalData)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_expr3(expr3)
+ , m_statement(statement)
+ , m_expr1WasVarDecl(expr1 && expr1WasVarDecl)
+ {
+ ASSERT(statement);
+ }
+
+ inline ContinueNode::ContinueNode(JSGlobalData* globalData)
+ : StatementNode(globalData)
+ , m_ident(globalData->propertyNames->nullIdentifier)
+ {
+ }
+
+ inline ContinueNode::ContinueNode(JSGlobalData* globalData, const Identifier& ident)
+ : StatementNode(globalData)
+ , m_ident(ident)
+ {
+ }
+
+ inline BreakNode::BreakNode(JSGlobalData* globalData)
+ : StatementNode(globalData)
+ , m_ident(globalData->propertyNames->nullIdentifier)
+ {
+ }
+
+ inline BreakNode::BreakNode(JSGlobalData* globalData, const Identifier& ident)
+ : StatementNode(globalData)
+ , m_ident(ident)
+ {
+ }
+
+ inline ReturnNode::ReturnNode(JSGlobalData* globalData, ExpressionNode* value)
+ : StatementNode(globalData)
+ , m_value(value)
+ {
+ }
+
+ inline WithNode::WithNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement, uint32_t divot, uint32_t expressionLength)
+ : StatementNode(globalData)
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_divot(divot)
+ , m_expressionLength(expressionLength)
+ {
+ }
+
+ inline LabelNode::LabelNode(JSGlobalData* globalData, const Identifier& name, StatementNode* statement)
+ : StatementNode(globalData)
+ , m_name(name)
+ , m_statement(statement)
+ {
+ }
+
+ inline ThrowNode::ThrowNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : StatementNode(globalData)
+ , m_expr(expr)
+ {
+ }
+
+ inline TryNode::TryNode(JSGlobalData* globalData, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock)
+ : StatementNode(globalData)
+ , m_tryBlock(tryBlock)
+ , m_exceptionIdent(exceptionIdent)
+ , m_catchBlock(catchBlock)
+ , m_finallyBlock(finallyBlock)
+ , m_catchHasEval(catchHasEval)
+ {
+ }
+
+ inline ParameterNode::ParameterNode(JSGlobalData*, const Identifier& ident)
+ : m_ident(ident)
+ , m_next(0)
+ {
+ }
+
+ inline ParameterNode::ParameterNode(JSGlobalData*, ParameterNode* l, const Identifier& ident)
+ : m_ident(ident)
+ , m_next(0)
+ {
+ l->m_next = this;
+ }
+
+ inline FuncExprNode::FuncExprNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter)
+ : ExpressionNode(globalData)
+ , m_body(body)
+ {
+ m_body->finishParsing(source, parameter, ident);
+ }
+
+ inline FuncDeclNode::FuncDeclNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter)
+ : StatementNode(globalData)
+ , m_body(body)
+ {
+ m_body->finishParsing(source, parameter, ident);
+ }
+
+ inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr, SourceElements* statements)
+ : m_expr(expr)
+ , m_statements(statements)
+ {
+ }
+
+ inline ClauseListNode::ClauseListNode(JSGlobalData*, CaseClauseNode* clause)
+ : m_clause(clause)
+ , m_next(0)
+ {
+ }
+
+ inline ClauseListNode::ClauseListNode(JSGlobalData*, ClauseListNode* clauseList, CaseClauseNode* clause)
+ : m_clause(clause)
+ , m_next(0)
+ {
+ clauseList->m_next = this;
+ }
+
+ inline CaseBlockNode::CaseBlockNode(JSGlobalData*, ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2)
+ : m_list1(list1)
+ , m_defaultClause(defaultClause)
+ , m_list2(list2)
+ {
+ }
+
+ inline SwitchNode::SwitchNode(JSGlobalData* globalData, ExpressionNode* expr, CaseBlockNode* block)
+ : StatementNode(globalData)
+ , m_expr(expr)
+ , m_block(block)
+ {
+ }
+
+ inline ConstDeclNode::ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* init)
+ : ExpressionNode(globalData)
+ , m_ident(ident)
+ , m_next(0)
+ , m_init(init)
+ {
+ }
+
+ inline BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* statements)
+ : StatementNode(globalData)
+ , m_statements(statements)
+ {
+ }
+
+ inline ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
+ : StatementNode(globalData)
+ , 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, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement, int divot, int startOffset, int endOffset)
+ : StatementNode(globalData)
+ , m_ident(ident)
+ , m_init(0)
+ , m_lexpr(new (globalData) ResolveNode(globalData, ident, divot - startOffset))
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_identIsVarDecl(true)
+ {
+ if (in) {
+ AssignResolveNode* node = new (globalData) AssignResolveNode(globalData, 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 0000000..7f4deff
--- /dev/null
+++ b/Source/JavaScriptCore/parser/NodeInfo.h
@@ -0,0 +1,63 @@
+/*
+ * 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"
+#include "Parser.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 0000000..34aa674
--- /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_line = 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, bool inStrictContext)
+ : StatementNode(globalData)
+ , ParserArenaRefCounted(globalData)
+ , m_features(inStrictContext ? StrictModeFeature : NoFeatures)
+{
+}
+
+ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, CodeFeatures features, int numConstants)
+ : StatementNode(globalData)
+ , ParserArenaRefCounted(globalData)
+ , m_data(adoptPtr(new ScopeNodeData(globalData->parser->arena(), 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, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, source, children, varStack, funcStack, capturedVariables, features, numConstants)
+{
+}
+
+PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+{
+ RefPtr<ProgramNode> node = new ProgramNode(globalData, 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, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, source, children, varStack, funcStack, capturedVariables, features, numConstants)
+{
+}
+
+PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& source, CodeFeatures features, int numConstants)
+{
+ RefPtr<EvalNode> node = new EvalNode(globalData, 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, bool inStrictContext)
+ : ScopeNode(globalData, inStrictContext)
+{
+}
+
+inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, 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, bool inStrictContext)
+{
+ return new FunctionBodyNode(globalData, inStrictContext);
+}
+
+PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, IdentifierSet& capturedVariables, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+{
+ RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, 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 0000000..b8e9cdf
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Nodes.h
@@ -0,0 +1,1617 @@
+/*
+ * 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*);
+ };
+
+ class ParserArenaRefCounted : public RefCounted<ParserArenaRefCounted> {
+ protected:
+ ParserArenaRefCounted(JSGlobalData*);
+
+ public:
+ virtual ~ParserArenaRefCounted()
+ {
+ ASSERT(deletionHasBegun());
+ }
+ };
+
+ class Node : public ParserArenaFreeable {
+ protected:
+ Node(JSGlobalData*);
+
+ public:
+ virtual ~Node() { }
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* destination = 0) = 0;
+
+ int lineNo() const { return m_line; }
+
+ protected:
+ int m_line;
+ };
+
+ class ExpressionNode : public Node {
+ protected:
+ ExpressionNode(JSGlobalData*, 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(JSGlobalData*);
+
+ 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(JSGlobalData*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isNull() const { return true; }
+ };
+
+ class BooleanNode : public ExpressionNode {
+ public:
+ BooleanNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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);
+ RegisterID* emitThrowSyntaxError(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(JSGlobalData*, 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(JSGlobalData*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ResolveNode : public ExpressionNode {
+ public:
+ ResolveNode(JSGlobalData*, 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(JSGlobalData*, int elision, ExpressionNode*);
+ ElementNode(JSGlobalData*, 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(JSGlobalData*, int elision);
+ ArrayNode(JSGlobalData*, ElementNode*);
+ ArrayNode(JSGlobalData*, int elision, ElementNode*);
+
+ ArgumentListNode* toArgumentList(JSGlobalData*) 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& name, ExpressionNode* value, Type);
+ PropertyNode(JSGlobalData*, double name, ExpressionNode* value, 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(JSGlobalData*, PropertyNode*);
+ PropertyListNode(JSGlobalData*, PropertyNode*, PropertyListNode*);
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ private:
+ PropertyNode* m_node;
+ PropertyListNode* m_next;
+ };
+
+ class ObjectLiteralNode : public ExpressionNode {
+ public:
+ ObjectLiteralNode(JSGlobalData*);
+ ObjectLiteralNode(JSGlobalData*, PropertyListNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ PropertyListNode* m_list;
+ };
+
+ class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ BracketAccessorNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, ExpressionNode*);
+ ArgumentListNode(JSGlobalData*, ArgumentListNode*, ExpressionNode*);
+
+ ArgumentListNode* m_next;
+ ExpressionNode* m_expr;
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ArgumentsNode : public ParserArenaFreeable {
+ public:
+ ArgumentsNode(JSGlobalData*);
+ ArgumentsNode(JSGlobalData*, ArgumentListNode*);
+
+ ArgumentListNode* m_listNode;
+ };
+
+ class NewExprNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ NewExprNode(JSGlobalData*, ExpressionNode*);
+ NewExprNode(JSGlobalData*, ExpressionNode*, ArgumentsNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ ArgumentsNode* m_args;
+ };
+
+ class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ EvalFunctionCallNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, ExpressionNode* base, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ApplyFunctionCallDotNode : public FunctionCallDotNode {
+ public:
+ ApplyFunctionCallDotNode(JSGlobalData*, 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(JSGlobalData*, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset);
+
+ protected:
+ const Identifier& m_ident;
+ };
+
+ class PostfixResolveNode : public PrePostResolveNode {
+ public:
+ PostfixResolveNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class VoidNode : public ExpressionNode {
+ public:
+ VoidNode(JSGlobalData*, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class TypeOfResolveNode : public ExpressionNode {
+ public:
+ TypeOfResolveNode(JSGlobalData*, 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(JSGlobalData*, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class PrefixResolveNode : public PrePostResolveNode {
+ public:
+ PrefixResolveNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, ExpressionNode*);
+
+ private:
+ virtual ExpressionNode* stripUnaryPlus() { return expr(); }
+ };
+
+ class NegateNode : public UnaryOpNode {
+ public:
+ NegateNode(JSGlobalData*, ExpressionNode*);
+ };
+
+ class BitwiseNotNode : public UnaryOpNode {
+ public:
+ BitwiseNotNode(JSGlobalData*, ExpressionNode*);
+ };
+
+ class LogicalNotNode : public UnaryOpNode {
+ public:
+ LogicalNotNode(JSGlobalData*, ExpressionNode*);
+ private:
+ void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue);
+ virtual bool hasConditionContextCodegen() const { return expr()->hasConditionContextCodegen(); }
+ };
+
+ class BinaryOpNode : public ExpressionNode {
+ public:
+ BinaryOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+ BinaryOpNode(JSGlobalData*, 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 ReverseBinaryOpNode : public BinaryOpNode {
+ public:
+ ReverseBinaryOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+ ReverseBinaryOpNode(JSGlobalData*, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class MultNode : public BinaryOpNode {
+ public:
+ MultNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class DivNode : public BinaryOpNode {
+ public:
+ DivNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class ModNode : public BinaryOpNode {
+ public:
+ ModNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class AddNode : public BinaryOpNode {
+ public:
+ AddNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ virtual bool isAdd() const { return true; }
+ };
+
+ class SubNode : public BinaryOpNode {
+ public:
+ SubNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ virtual bool isSubtract() const { return true; }
+ };
+
+ class LeftShiftNode : public BinaryOpNode {
+ public:
+ LeftShiftNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class RightShiftNode : public BinaryOpNode {
+ public:
+ RightShiftNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class UnsignedRightShiftNode : public BinaryOpNode {
+ public:
+ UnsignedRightShiftNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class LessNode : public BinaryOpNode {
+ public:
+ LessNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class GreaterNode : public ReverseBinaryOpNode {
+ public:
+ GreaterNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class LessEqNode : public BinaryOpNode {
+ public:
+ LessEqNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class GreaterEqNode : public ReverseBinaryOpNode {
+ public:
+ GreaterEqNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData {
+ public:
+ ThrowableBinaryOpNode(JSGlobalData*, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+ ThrowableBinaryOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class InstanceOfNode : public ThrowableBinaryOpNode {
+ public:
+ InstanceOfNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class InNode : public ThrowableBinaryOpNode {
+ public:
+ InNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class EqualNode : public BinaryOpNode {
+ public:
+ EqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class NotEqualNode : public BinaryOpNode {
+ public:
+ NotEqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class StrictEqualNode : public BinaryOpNode {
+ public:
+ StrictEqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class NotStrictEqualNode : public BinaryOpNode {
+ public:
+ NotStrictEqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitAndNode : public BinaryOpNode {
+ public:
+ BitAndNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitOrNode : public BinaryOpNode {
+ public:
+ BitOrNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ class BitXOrNode : public BinaryOpNode {
+ public:
+ BitXOrNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments);
+ };
+
+ // m_expr1 && m_expr2, m_expr1 || m_expr2
+ class LogicalOpNode : public ExpressionNode {
+ public:
+ LogicalOpNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, ConstDeclNode* next);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ConstDeclNode* m_next;
+ };
+
+ class SourceElements : public ParserArenaDeletable {
+ public:
+ SourceElements(JSGlobalData*);
+
+ 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(JSGlobalData*, 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(JSGlobalData*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ virtual bool isEmptyStatement() const { return true; }
+ };
+
+ class DebuggerStatementNode : public StatementNode {
+ public:
+ DebuggerStatementNode(JSGlobalData*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class ExprStatementNode : public StatementNode {
+ public:
+ ExprStatementNode(JSGlobalData*, 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(JSGlobalData*, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class IfNode : public StatementNode {
+ public:
+ IfNode(JSGlobalData*, ExpressionNode* condition, StatementNode* ifBlock);
+
+ protected:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_condition;
+ StatementNode* m_ifBlock;
+ };
+
+ class IfElseNode : public IfNode {
+ public:
+ IfElseNode(JSGlobalData*, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ StatementNode* m_elseBlock;
+ };
+
+ class DoWhileNode : public StatementNode {
+ public:
+ DoWhileNode(JSGlobalData*, StatementNode* statement, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ StatementNode* m_statement;
+ ExpressionNode* m_expr;
+ };
+
+ class WhileNode : public StatementNode {
+ public:
+ WhileNode(JSGlobalData*, ExpressionNode*, StatementNode* statement);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ StatementNode* m_statement;
+ };
+
+ class ForNode : public StatementNode {
+ public:
+ ForNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, 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*, ExpressionNode*, ExpressionNode*, StatementNode*);
+ ForInNode(JSGlobalData*, 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*);
+ ContinueNode(JSGlobalData*, const Identifier&);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ };
+
+ class BreakNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ BreakNode(JSGlobalData*);
+ BreakNode(JSGlobalData*, const Identifier&);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ const Identifier& m_ident;
+ };
+
+ class ReturnNode : public StatementNode, public ThrowableExpressionData {
+ public:
+ ReturnNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, ExpressionNode*);
+
+ private:
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+
+ ExpressionNode* m_expr;
+ };
+
+ class TryNode : public StatementNode {
+ public:
+ TryNode(JSGlobalData*, 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(JSGlobalData*, const Identifier&);
+ ParameterNode(JSGlobalData*, 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 : FastAllocBase {
+ 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*, bool inStrictContext);
+ ScopeNode(JSGlobalData*, 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*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ static const bool scopeIsFunction = false;
+
+ private:
+ ProgramNode(JSGlobalData*, 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*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ static const bool scopeIsFunction = false;
+
+ private:
+ EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0);
+ };
+
+ class FunctionParameters : public Vector<Identifier>, public RefCounted<FunctionParameters> {
+ 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*, bool isStrictMode);
+ static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, 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*, bool inStrictContext);
+ FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, IdentifierSet&, const SourceCode&, CodeFeatures, int numConstants);
+
+ Identifier m_ident;
+ RefPtr<FunctionParameters> m_parameters;
+ };
+
+ class FuncExprNode : public ExpressionNode {
+ public:
+ FuncExprNode(JSGlobalData*, const Identifier&, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 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(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, CaseClauseNode*);
+ ClauseListNode(JSGlobalData*, 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(JSGlobalData*, 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(JSGlobalData*, 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 0000000..b203b21
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Parser.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "Debugger.h"
+#include "JSParser.h"
+#include "Lexer.h"
+
+#ifdef ANDROID_INSTRUMENT
+#include "TimeCounter.h"
+#endif
+
+namespace JSC {
+
+void Parser::parse(JSGlobalData* globalData, FunctionParameters* parameters, JSParserStrictness strictness, JSParserMode mode, int* errLine, UString* errMsg)
+{
+#ifdef ANDROID_INSTRUMENT
+ android::TimeCounter::start(android::TimeCounter::JavaScriptParseTimeCounter);
+#endif
+ ASSERT(globalData);
+ m_sourceElements = 0;
+
+ int defaultErrLine;
+ UString defaultErrMsg;
+
+ if (!errLine)
+ errLine = &defaultErrLine;
+ if (!errMsg)
+ errMsg = &defaultErrMsg;
+
+ *errLine = -1;
+ *errMsg = UString();
+
+ Lexer& lexer = *globalData->lexer;
+ lexer.setCode(*m_source, m_arena);
+
+ int parseError = jsParse(globalData, parameters, strictness, mode, m_source);
+ int lineNumber = lexer.lineNumber();
+ bool lexError = lexer.sawError();
+ lexer.clear();
+
+ if (parseError || lexError) {
+ *errLine = lineNumber;
+ *errMsg = "Parse error";
+ m_sourceElements = 0;
+ }
+#ifdef ANDROID_INSTRUMENT
+ android::TimeCounter::record(android::TimeCounter::JavaScriptParseTimeCounter, __FUNCTION__);
+#endif
+}
+
+void Parser::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;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/parser/Parser.h b/Source/JavaScriptCore/parser/Parser.h
new file mode 100644
index 0000000..213827b
--- /dev/null
+++ b/Source/JavaScriptCore/parser/Parser.h
@@ -0,0 +1,128 @@
+/*
+ * 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 "SourceProvider.h"
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ class FunctionBodyNode;
+
+ class ProgramNode;
+ class UString;
+
+ template <typename T> struct ParserArenaData : ParserArenaDeletable { T data; };
+
+ class Parser : public Noncopyable {
+ public:
+ template <class ParsedNode>
+ PassRefPtr<ParsedNode> parse(JSGlobalObject* lexicalGlobalObject, Debugger*, ExecState*, const SourceCode& source, FunctionParameters*, JSParserStrictness strictness, JSObject** exception);
+
+ void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*,
+ ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features,
+ int lastLine, int numConstants, IdentifierSet&);
+
+ ParserArena& arena() { return m_arena; }
+
+ private:
+ void parse(JSGlobalData*, FunctionParameters*, JSParserStrictness strictness, JSParserMode mode, int* errLine, UString* errMsg);
+
+ // Used to determine type of error to report.
+ bool isFunctionBodyNode(ScopeNode*) { return false; }
+ bool isFunctionBodyNode(FunctionBodyNode*) { return true; }
+
+ ParserArena m_arena;
+ const SourceCode* m_source;
+ SourceElements* m_sourceElements;
+ ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ IdentifierSet m_capturedVariables;
+ CodeFeatures m_features;
+ int m_lastLine;
+ int m_numConstants;
+ };
+
+ template <class ParsedNode>
+ PassRefPtr<ParsedNode> Parser::parse(JSGlobalObject* lexicalGlobalObject, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, FunctionParameters* parameters, JSParserStrictness strictness, JSObject** exception)
+ {
+ ASSERT(lexicalGlobalObject);
+ ASSERT(exception && !*exception);
+ int errLine;
+ UString errMsg;
+
+ m_source = &source;
+ if (ParsedNode::scopeIsFunction)
+ lexicalGlobalObject->globalData().lexer->setIsReparsing();
+ parse(&lexicalGlobalObject->globalData(), parameters, strictness, ParsedNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, &errLine, &errMsg);
+
+ RefPtr<ParsedNode> result;
+ if (m_sourceElements) {
+ result = ParsedNode::create(&lexicalGlobalObject->globalData(),
+ m_sourceElements,
+ m_varDeclarations ? &m_varDeclarations->data : 0,
+ m_funcDeclarations ? &m_funcDeclarations->data : 0,
+ m_capturedVariables,
+ 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
+ *exception = addErrorInfo(&lexicalGlobalObject->globalData(), createSyntaxError(lexicalGlobalObject, errMsg), errLine, source);
+ }
+
+ m_arena.reset();
+
+ m_source = 0;
+ m_sourceElements = 0;
+ m_varDeclarations = 0;
+ m_funcDeclarations = 0;
+
+ if (debugger && !ParsedNode::scopeIsFunction)
+ debugger->sourceParsed(debuggerExecState, source, errLine, errMsg);
+ return result.release();
+ }
+
+} // namespace JSC
+
+#endif // Parser_h
diff --git a/Source/JavaScriptCore/parser/ParserArena.cpp b/Source/JavaScriptCore/parser/ParserArena.cpp
new file mode 100644
index 0000000..9c96de7
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserArena.cpp
@@ -0,0 +1,125 @@
+/*
+ * 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()
+{
+ if (m_freeablePoolEnd)
+ fastFree(freeablePool());
+
+ size_t size = m_freeablePools.size();
+ for (size_t i = 0; i < size; ++i)
+ fastFree(m_freeablePools[i]);
+
+ size = m_deletableObjects.size();
+ for (size_t i = 0; i < size; ++i) {
+ ParserArenaDeletable* object = m_deletableObjects[i];
+ object->~ParserArenaDeletable();
+ fastFree(object);
+ }
+}
+
+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 0000000..7c1809e
--- /dev/null
+++ b/Source/JavaScriptCore/parser/ParserArena.h
@@ -0,0 +1,130 @@
+/*
+ * 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 : public FastAllocBase {
+ public:
+ ALWAYS_INLINE const Identifier& makeIdentifier(JSGlobalData*, const UChar* characters, size_t length);
+ const Identifier& makeNumericIdentifier(JSGlobalData*, double number);
+
+ void clear() { m_identifiers.clear(); }
+ bool isEmpty() const { return m_identifiers.isEmpty(); }
+
+ private:
+ typedef SegmentedVector<Identifier, 64> IdentifierVector;
+ IdentifierVector m_identifiers;
+ };
+
+ ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifier(JSGlobalData* globalData, const UChar* characters, size_t length)
+ {
+ m_identifiers.append(Identifier(globalData, characters, length));
+ 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 : Noncopyable {
+ 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*>(fastMalloc(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/ResultType.h b/Source/JavaScriptCore/parser/ResultType.h
new file mode 100644
index 0000000..27b8112
--- /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 0000000..9ba4da3
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceCode.h
@@ -0,0 +1,92 @@
+/*
+ * 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 { return m_provider->data() + m_startChar; }
+ int length() const { return m_endChar - m_startChar; }
+
+ private:
+ RefPtr<SourceProvider> m_provider;
+ int m_startChar;
+ int m_endChar;
+ int m_firstLine;
+ };
+
+ inline SourceCode makeSource(const UString& source, const UString& url = UString(), int firstLine = 1)
+ {
+ return SourceCode(UStringSourceProvider::create(source, url), 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 0000000..5ff1d14
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SourceProvider.h
@@ -0,0 +1,87 @@
+/*
+ * 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 "UString.h"
+#include <wtf/RefCounted.h>
+
+namespace JSC {
+
+ class SourceProvider : public RefCounted<SourceProvider> {
+ public:
+ SourceProvider(const UString& url)
+ : m_url(url)
+ , m_validated(false)
+ {
+ }
+ virtual ~SourceProvider() { }
+
+ virtual UString getRange(int start, int end) const = 0;
+ virtual const UChar* data() const = 0;
+ virtual int length() const = 0;
+
+ const UString& url() { return m_url; }
+ intptr_t asID() { return reinterpret_cast<intptr_t>(this); }
+
+ bool isValid() const { return m_validated; }
+ void setValid() { m_validated = true; }
+
+ private:
+ UString m_url;
+ bool m_validated;
+ };
+
+ class UStringSourceProvider : public SourceProvider {
+ public:
+ static PassRefPtr<UStringSourceProvider> create(const UString& source, const UString& url)
+ {
+ return adoptRef(new UStringSourceProvider(source, url));
+ }
+
+ UString getRange(int start, int end) const
+ {
+ return m_source.substringSharingImpl(start, end - start);
+ }
+ const UChar* data() const { return m_source.characters(); }
+ int length() const { return m_source.length(); }
+
+ private:
+ UStringSourceProvider(const UString& source, const UString& url)
+ : SourceProvider(url)
+ , m_source(source)
+ {
+ }
+
+ UString m_source;
+ };
+
+} // namespace JSC
+
+#endif // SourceProvider_h
diff --git a/Source/JavaScriptCore/parser/SyntaxChecker.h b/Source/JavaScriptCore/parser/SyntaxChecker.h
new file mode 100644
index 0000000..b00e710
--- /dev/null
+++ b/Source/JavaScriptCore/parser/SyntaxChecker.h
@@ -0,0 +1,217 @@
+/*
+ * 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
+
+namespace JSC {
+class SyntaxChecker {
+public:
+ SyntaxChecker(JSGlobalData* , Lexer*)
+ : m_topBinaryExpr(0)
+ {
+ }
+
+ 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;
+
+ int createSourceElements() { return 1; }
+ ExpressionType makeFunctionCallNode(int, int, int, int, int) { return CallExpr; }
+ void appendToComma(ExpressionType& base, ExpressionType right) { base = right; }
+ ExpressionType createCommaExpr(ExpressionType, ExpressionType right) { return right; }
+ ExpressionType makeAssignNode(ExpressionType, Operator, ExpressionType, bool, bool, int, int, int) { return AssignmentExpr; }
+ ExpressionType makePrefixNode(ExpressionType, Operator, int, int, int) { return PreExpr; }
+ ExpressionType makePostfixNode(ExpressionType, Operator, int, int, int) { return PostExpr; }
+ ExpressionType makeTypeOfNode(ExpressionType) { return TypeofExpr; }
+ ExpressionType makeDeleteNode(ExpressionType, int, int, int) { return DeleteExpr; }
+ ExpressionType makeNegateNode(ExpressionType) { return UnaryExpr; }
+ ExpressionType makeBitwiseNotNode(ExpressionType) { return UnaryExpr; }
+ ExpressionType createLogicalNot(ExpressionType) { return UnaryExpr; }
+ ExpressionType createUnaryPlus(ExpressionType) { return UnaryExpr; }
+ ExpressionType createVoid(ExpressionType) { return UnaryExpr; }
+ ExpressionType thisExpr() { return ThisExpr; }
+ ExpressionType createResolve(const Identifier*, int) { return ResolveExpr; }
+ ExpressionType createObjectLiteral() { return ObjectLiteralExpr; }
+ ExpressionType createObjectLiteral(int) { return ObjectLiteralExpr; }
+ ExpressionType createArray(int) { return ArrayLiteralExpr; }
+ ExpressionType createArray(int, int) { return ArrayLiteralExpr; }
+ ExpressionType createNumberExpr(double) { return NumberExpr; }
+ ExpressionType createString(const Identifier*) { return StringExpr; }
+ ExpressionType createBoolean(bool) { return BoolExpr; }
+ ExpressionType createNull() { return NullExpr; }
+ ExpressionType createBracketAccess(ExpressionType, ExpressionType, bool, int, int, int) { return BracketExpr; }
+ ExpressionType createDotAccess(ExpressionType, const Identifier&, int, int, int) { return DotExpr; }
+ ExpressionType createRegex(const Identifier&, const Identifier&, int) { return RegExpExpr; }
+ ExpressionType createNewExpr(ExpressionType, int, int, int, int) { return NewExpr; }
+ ExpressionType createNewExpr(ExpressionType, int, int) { return NewExpr; }
+ ExpressionType createConditionalExpr(ExpressionType, ExpressionType, ExpressionType) { return ConditionalExpr; }
+ ExpressionType createAssignResolve(const Identifier&, ExpressionType, bool, int, int, int) { return AssignmentExpr; }
+ ExpressionType createFunctionExpr(const Identifier*, int, int, int, int, int, int) { return FunctionExpr; }
+ int createFunctionBody(bool) { return 1; }
+ int createArguments() { return 1; }
+ int createArguments(int) { return 1; }
+ int createArgumentsList(int) { return 1; }
+ int createArgumentsList(int, int) { return 1; }
+ template <bool complete> Property createProperty(const Identifier* name, int, PropertyNode::Type type)
+ {
+ ASSERT(name);
+ if (!complete)
+ return Property(type);
+ 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->parser->arena().identifierArena().makeNumericIdentifier(globalData, name), type);
+ }
+ int createPropertyList(Property) { return 1; }
+ int createPropertyList(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(const Identifier*, int, int, int, int, int, int) { return 1; }
+ int createBlockStatement(int, int, int) { return 1; }
+ int createExprStatement(int, int, int) { return 1; }
+ int createIfStatement(int, int, int, int) { return 1; }
+ int createIfStatement(int, int, int, int, int) { return 1; }
+ int createForLoop(int, int, int, int, bool, int, int) { return 1; }
+ int createForInLoop(const Identifier*, int, int, int, int, int, int, int, int, int, int) { return 1; }
+ int createForInLoop(int, int, int, int, int, int, int, int) { return 1; }
+ int createEmptyStatement() { return 1; }
+ int createVarStatement(int, int, int) { return 1; }
+ int createReturnStatement(int, int, int, int, int) { return 1; }
+ int createBreakStatement(int, int, int, int) { return 1; }
+ int createBreakStatement(const Identifier*, int, int, int, int) { return 1; }
+ int createContinueStatement(int, int, int, int) { return 1; }
+ int createContinueStatement(const Identifier*, int, int, int, int) { return 1; }
+ int createTryStatement(int, const Identifier*, bool, int, int, int, int) { return 1; }
+ int createSwitchStatement(int, int, int, int, int, int) { return 1; }
+ int createWhileStatement(int, int, int, int) { return 1; }
+ int createWithStatement(int, int, int, int, int, int) { return 1; }
+ int createDoWhileStatement(int, int, int, int) { return 1; }
+ int createLabelStatement(const Identifier*, int, int, int) { return 1; }
+ int createThrowStatement(int, int, int, int, int) { return 1; }
+ int createDebugger(int, int) { return 1; }
+ int createConstStatement(int, int, int) { return 1; }
+ int appendConstDecl(int, const Identifier*, int) { return 1; }
+ template <bool strict> Property createGetterOrSetterProperty(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) { 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& 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) { 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;
+};
+
+}
+
+#endif