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