diff options
Diffstat (limited to 'Source/JavaScriptCore/parser')
-rw-r--r-- | Source/JavaScriptCore/parser/ASTBuilder.h | 967 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/JSParser.cpp | 1907 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/JSParser.h | 164 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/Keywords.table | 72 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/Lexer.cpp | 1196 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/Lexer.h | 158 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/NodeConstructors.h | 908 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/NodeInfo.h | 63 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/Nodes.cpp | 196 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/Nodes.h | 1617 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/Parser.cpp | 85 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/Parser.h | 128 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/ParserArena.cpp | 125 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/ParserArena.h | 130 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/ResultType.h | 182 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/SourceCode.h | 92 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/SourceProvider.h | 87 | ||||
-rw-r--r-- | Source/JavaScriptCore/parser/SyntaxChecker.h | 217 |
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(¶meters->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 |