diff options
author | Alexis Menard <alexis.menard@nokia.com> | 2009-04-17 10:40:52 (GMT) |
---|---|---|
committer | Alexis Menard <alexis.menard@nokia.com> | 2009-04-17 10:40:52 (GMT) |
commit | bb2e4df9bee3148e819c98410aa36e22dad95d7a (patch) | |
tree | a6e6e8c070a72378d4b2e5f39ad3cc9c368b61ab /src/3rdparty/webkit/JavaScriptCore/parser | |
download | Qt-bb2e4df9bee3148e819c98410aa36e22dad95d7a.zip Qt-bb2e4df9bee3148e819c98410aa36e22dad95d7a.tar.gz Qt-bb2e4df9bee3148e819c98410aa36e22dad95d7a.tar.bz2 |
Initial import of kinetic-animations branch from the old kinetic
repository to the new repository
Diffstat (limited to 'src/3rdparty/webkit/JavaScriptCore/parser')
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Grammar.y | 2084 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Keywords.table | 72 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Lexer.cpp | 900 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Lexer.h | 171 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/NodeInfo.h | 63 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Nodes.cpp | 2721 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Nodes.h | 2418 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Parser.cpp | 104 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/Parser.h | 123 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/ResultType.h | 159 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/SourceCode.h | 91 | ||||
-rw-r--r-- | src/3rdparty/webkit/JavaScriptCore/parser/SourceProvider.h | 79 |
12 files changed, 8985 insertions, 0 deletions
diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/Grammar.y b/src/3rdparty/webkit/JavaScriptCore/parser/Grammar.y new file mode 100644 index 0000000..ae787f6 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Grammar.y @@ -0,0 +1,2084 @@ +%pure_parser + +%{ + +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * 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 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 + * + */ + +#include "config.h" + +#include <string.h> +#include <stdlib.h> +#include "JSValue.h" +#include "JSObject.h" +#include "Nodes.h" +#include "Lexer.h" +#include "JSString.h" +#include "JSGlobalData.h" +#include "CommonIdentifiers.h" +#include "NodeInfo.h" +#include "Parser.h" +#include <wtf/MathExtras.h> + +#define YYMAXDEPTH 10000 +#define YYENABLE_NLS 0 + +/* default values for bison */ +#define YYDEBUG 0 // Set to 1 to debug a parse error. +#define jscyydebug 0 // Set to 1 to debug a parse error. +#if !PLATFORM(DARWIN) + // avoid triggering warnings in older bison +#define YYERROR_VERBOSE +#endif + +int jscyylex(void* lvalp, void* llocp, void* globalPtr); +int jscyyerror(const char*); +static inline bool allowAutomaticSemicolon(JSC::Lexer&, int); + +#define GLOBAL_DATA static_cast<JSGlobalData*>(globalPtr) +#define LEXER (GLOBAL_DATA->lexer) + +#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon(*LEXER, yychar)) YYABORT; } while (0) +#define SET_EXCEPTION_LOCATION(node, start, divot, end) node->setExceptionSourceCode((divot), (divot) - (start), (end) - (divot)) +#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line) + +using namespace JSC; +using namespace std; + +static ExpressionNode* makeAssignNode(void*, ExpressionNode* loc, Operator, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end); +static ExpressionNode* makePrefixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end); +static ExpressionNode* makePostfixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end); +static PropertyNode* makeGetterOrSetterPropertyNode(void*, const Identifier &getOrSet, const Identifier& name, ParameterNode*, FunctionBodyNode*, const SourceCode&); +static ExpressionNodeInfo makeFunctionCallNode(void*, ExpressionNodeInfo func, ArgumentsNodeInfo, int start, int divot, int end); +static ExpressionNode* makeTypeOfNode(void*, ExpressionNode*); +static ExpressionNode* makeDeleteNode(void*, ExpressionNode*, int start, int divot, int end); +static ExpressionNode* makeNegateNode(void*, ExpressionNode*); +static NumberNode* makeNumberNode(void*, double); +static ExpressionNode* makeBitwiseNotNode(void*, ExpressionNode*); +static ExpressionNode* makeMultNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); +static ExpressionNode* makeDivNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); +static ExpressionNode* makeAddNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); +static ExpressionNode* makeSubNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); +static ExpressionNode* makeLeftShiftNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); +static ExpressionNode* makeRightShiftNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments); +static StatementNode* makeVarStatementNode(void*, ExpressionNode*); +static ExpressionNode* combineVarInitializers(void*, ExpressionNode* list, AssignResolveNode* init); + +#if COMPILER(MSVC) + +#pragma warning(disable: 4065) +#pragma warning(disable: 4244) +#pragma warning(disable: 4702) + +// At least some of the time, the declarations of malloc and free that bison +// generates are causing warnings. A way to avoid this is to explicitly define +// the macros so that bison doesn't try to declare malloc and free. +#define YYMALLOC malloc +#define YYFREE free + +#endif + +#define YYPARSE_PARAM globalPtr +#define YYLEX_PARAM globalPtr + +template <typename T> NodeDeclarationInfo<T> createNodeDeclarationInfo(T node, ParserRefCountedData<DeclarationStacks::VarStack>* varDecls, + ParserRefCountedData<DeclarationStacks::FunctionStack>* funcDecls, + CodeFeatures info, + int numConstants) +{ + ASSERT((info & ~AllFeatures) == 0); + NodeDeclarationInfo<T> result = {node, varDecls, funcDecls, info, numConstants}; + return result; +} + +template <typename T> NodeInfo<T> createNodeInfo(T node, CodeFeatures info, int numConstants) +{ + ASSERT((info & ~AllFeatures) == 0); + NodeInfo<T> result = {node, info, numConstants}; + return result; +} + +template <typename T> T mergeDeclarationLists(T decls1, T decls2) +{ + // decls1 or both are null + if (!decls1) + return decls2; + // only decls1 is non-null + if (!decls2) + return decls1; + + // Both are non-null + decls1->data.append(decls2->data); + + // We manually release the declaration lists to avoid accumulating many many + // unused heap allocated vectors + decls2->ref(); + decls2->deref(); + return decls1; +} + +static void appendToVarDeclarationList(void* globalPtr, ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs) +{ + if (!varDecls) + varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); + + varDecls->data.append(make_pair(ident, attrs)); + +} + +static inline void appendToVarDeclarationList(void* globalPtr, ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl) +{ + unsigned attrs = DeclarationStacks::IsConstant; + if (decl->m_init) + attrs |= DeclarationStacks::HasInitializer; + appendToVarDeclarationList(globalPtr, varDecls, decl->m_ident, attrs); +} + +%} + +%union { + int intValue; + double doubleValue; + Identifier* ident; + + // expression subtrees + ExpressionNodeInfo expressionNode; + FuncDeclNodeInfo funcDeclNode; + PropertyNodeInfo propertyNode; + ArgumentsNodeInfo argumentsNode; + ConstDeclNodeInfo constDeclNode; + CaseBlockNodeInfo caseBlockNode; + CaseClauseNodeInfo caseClauseNode; + FuncExprNodeInfo funcExprNode; + + // statement nodes + StatementNodeInfo statementNode; + FunctionBodyNode* functionBodyNode; + ProgramNode* programNode; + + SourceElementsInfo sourceElements; + PropertyListInfo propertyList; + ArgumentListInfo argumentList; + VarDeclListInfo varDeclList; + ConstDeclListInfo constDeclList; + ClauseListInfo clauseList; + ElementListInfo elementList; + ParameterListInfo parameterList; + + Operator op; +} + +%start Program + +/* literals */ +%token NULLTOKEN TRUETOKEN FALSETOKEN + +/* keywords */ +%token BREAK CASE DEFAULT FOR NEW VAR CONSTTOKEN CONTINUE +%token FUNCTION RETURN VOIDTOKEN DELETETOKEN +%token IF THISTOKEN DO WHILE INTOKEN INSTANCEOF TYPEOF +%token SWITCH WITH RESERVED +%token THROW TRY CATCH FINALLY +%token DEBUGGER + +/* give an if without an else higher precedence than an else to resolve the ambiguity */ +%nonassoc IF_WITHOUT_ELSE +%nonassoc ELSE + +/* punctuators */ +%token EQEQ NE /* == and != */ +%token STREQ STRNEQ /* === and !== */ +%token LE GE /* < and > */ +%token OR AND /* || and && */ +%token PLUSPLUS MINUSMINUS /* ++ and -- */ +%token LSHIFT /* << */ +%token RSHIFT URSHIFT /* >> and >>> */ +%token PLUSEQUAL MINUSEQUAL /* += and -= */ +%token MULTEQUAL DIVEQUAL /* *= and /= */ +%token LSHIFTEQUAL /* <<= */ +%token RSHIFTEQUAL URSHIFTEQUAL /* >>= and >>>= */ +%token ANDEQUAL MODEQUAL /* &= and %= */ +%token XOREQUAL OREQUAL /* ^= and |= */ +%token <intValue> OPENBRACE /* { (with char offset) */ +%token <intValue> CLOSEBRACE /* { (with char offset) */ + +/* terminal types */ +%token <doubleValue> NUMBER +%token <ident> IDENT STRING + +/* automatically inserted semicolon */ +%token AUTOPLUSPLUS AUTOMINUSMINUS + +/* non-terminal types */ +%type <expressionNode> Literal ArrayLiteral + +%type <expressionNode> PrimaryExpr PrimaryExprNoBrace +%type <expressionNode> MemberExpr MemberExprNoBF /* BF => brace or function */ +%type <expressionNode> NewExpr NewExprNoBF +%type <expressionNode> CallExpr CallExprNoBF +%type <expressionNode> LeftHandSideExpr LeftHandSideExprNoBF +%type <expressionNode> PostfixExpr PostfixExprNoBF +%type <expressionNode> UnaryExpr UnaryExprNoBF UnaryExprCommon +%type <expressionNode> MultiplicativeExpr MultiplicativeExprNoBF +%type <expressionNode> AdditiveExpr AdditiveExprNoBF +%type <expressionNode> ShiftExpr ShiftExprNoBF +%type <expressionNode> RelationalExpr RelationalExprNoIn RelationalExprNoBF +%type <expressionNode> EqualityExpr EqualityExprNoIn EqualityExprNoBF +%type <expressionNode> BitwiseANDExpr BitwiseANDExprNoIn BitwiseANDExprNoBF +%type <expressionNode> BitwiseXORExpr BitwiseXORExprNoIn BitwiseXORExprNoBF +%type <expressionNode> BitwiseORExpr BitwiseORExprNoIn BitwiseORExprNoBF +%type <expressionNode> LogicalANDExpr LogicalANDExprNoIn LogicalANDExprNoBF +%type <expressionNode> LogicalORExpr LogicalORExprNoIn LogicalORExprNoBF +%type <expressionNode> ConditionalExpr ConditionalExprNoIn ConditionalExprNoBF +%type <expressionNode> AssignmentExpr AssignmentExprNoIn AssignmentExprNoBF +%type <expressionNode> Expr ExprNoIn ExprNoBF + +%type <expressionNode> ExprOpt ExprNoInOpt + +%type <statementNode> Statement Block +%type <statementNode> VariableStatement ConstStatement EmptyStatement ExprStatement +%type <statementNode> IfStatement IterationStatement ContinueStatement +%type <statementNode> BreakStatement ReturnStatement WithStatement +%type <statementNode> SwitchStatement LabelledStatement +%type <statementNode> ThrowStatement TryStatement +%type <statementNode> DebuggerStatement + +%type <expressionNode> Initializer InitializerNoIn +%type <statementNode> FunctionDeclaration +%type <funcExprNode> FunctionExpr +%type <functionBodyNode> FunctionBody +%type <sourceElements> SourceElements +%type <parameterList> FormalParameterList +%type <op> AssignmentOperator +%type <argumentsNode> Arguments +%type <argumentList> ArgumentList +%type <varDeclList> VariableDeclarationList VariableDeclarationListNoIn +%type <constDeclList> ConstDeclarationList +%type <constDeclNode> ConstDeclaration +%type <caseBlockNode> CaseBlock +%type <caseClauseNode> CaseClause DefaultClause +%type <clauseList> CaseClauses CaseClausesOpt +%type <intValue> Elision ElisionOpt +%type <elementList> ElementList +%type <propertyNode> Property +%type <propertyList> PropertyList +%% + +// FIXME: There are currently two versions of the grammar in this file, the normal one, and the NoNodes version used for +// lazy recompilation of FunctionBodyNodes. We should move to generating the two versions from a script to avoid bugs. +// In the mean time, make sure to make any changes to the grammar in both versions. + +Literal: + NULLTOKEN { $$ = createNodeInfo<ExpressionNode*>(new NullNode(GLOBAL_DATA), 0, 1); } + | TRUETOKEN { $$ = createNodeInfo<ExpressionNode*>(new BooleanNode(GLOBAL_DATA, true), 0, 1); } + | FALSETOKEN { $$ = createNodeInfo<ExpressionNode*>(new BooleanNode(GLOBAL_DATA, false), 0, 1); } + | NUMBER { $$ = createNodeInfo<ExpressionNode*>(makeNumberNode(GLOBAL_DATA, $1), 0, 1); } + | STRING { $$ = createNodeInfo<ExpressionNode*>(new StringNode(GLOBAL_DATA, *$1), 0, 1); } + | '/' /* regexp */ { + Lexer& l = *LEXER; + if (!l.scanRegExp()) + YYABORT; + RegExpNode* node = new RegExpNode(GLOBAL_DATA, l.pattern(), l.flags()); + int size = l.pattern().size() + 2; // + 2 for the two /'s + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size); + $$ = createNodeInfo<ExpressionNode*>(node, 0, 0); + } + | DIVEQUAL /* regexp with /= */ { + Lexer& l = *LEXER; + if (!l.scanRegExp()) + YYABORT; + RegExpNode* node = new RegExpNode(GLOBAL_DATA, "=" + l.pattern(), l.flags()); + int size = l.pattern().size() + 2; // + 2 for the two /'s + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size); + $$ = createNodeInfo<ExpressionNode*>(node, 0, 0); + } +; + +Property: + IDENT ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } + | STRING ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } + | NUMBER ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, Identifier(GLOBAL_DATA, UString::from($1)), $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } + | IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, 0, $6, LEXER->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); DBG($6, @5, @7); if (!$$.m_node) YYABORT; } + | IDENT IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE + { + $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, $4.m_node.head, $7, LEXER->sourceCode($6, $8, @6.first_line)), $4.m_features | ClosureFeature, 0); + if ($4.m_features & ArgumentsFeature) + $7->setUsesArguments(); + DBG($7, @6, @8); + if (!$$.m_node) + YYABORT; + } +; + +PropertyList: + Property { $$.m_node.head = new PropertyListNode(GLOBAL_DATA, $1.m_node); + $$.m_node.tail = $$.m_node.head; + $$.m_features = $1.m_features; + $$.m_numConstants = $1.m_numConstants; } + | PropertyList ',' Property { $$.m_node.head = $1.m_node.head; + $$.m_node.tail = new PropertyListNode(GLOBAL_DATA, $3.m_node, $1.m_node.tail); + $$.m_features = $1.m_features | $3.m_features; + $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; } +; + +PrimaryExpr: + PrimaryExprNoBrace + | OPENBRACE CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA), 0, 0); } + | OPENBRACE PropertyList CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } + /* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */ + | OPENBRACE PropertyList ',' CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } +; + +PrimaryExprNoBrace: + THISTOKEN { $$ = createNodeInfo<ExpressionNode*>(new ThisNode(GLOBAL_DATA), ThisFeature, 0); } + | Literal + | ArrayLiteral + | IDENT { $$ = createNodeInfo<ExpressionNode*>(new ResolveNode(GLOBAL_DATA, *$1, @1.first_column), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); } + | '(' Expr ')' { $$ = $2; } +; + +ArrayLiteral: + '[' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $2), 0, $2 ? 1 : 0); } + | '[' ElementList ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } + | '[' ElementList ',' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $4, $2.m_node.head), $2.m_features, $4 ? $2.m_numConstants + 1 : $2.m_numConstants); } +; + +ElementList: + ElisionOpt AssignmentExpr { $$.m_node.head = new ElementNode(GLOBAL_DATA, $1, $2.m_node); + $$.m_node.tail = $$.m_node.head; + $$.m_features = $2.m_features; + $$.m_numConstants = $2.m_numConstants; } + | ElementList ',' ElisionOpt AssignmentExpr + { $$.m_node.head = $1.m_node.head; + $$.m_node.tail = new ElementNode(GLOBAL_DATA, $1.m_node.tail, $3, $4.m_node); + $$.m_features = $1.m_features | $4.m_features; + $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; } +; + +ElisionOpt: + /* nothing */ { $$ = 0; } + | Elision +; + +Elision: + ',' { $$ = 1; } + | Elision ',' { $$ = $1 + 1; } +; + +MemberExpr: + PrimaryExpr + | FunctionExpr { $$ = createNodeInfo<ExpressionNode*>($1.m_node, $1.m_features, $1.m_numConstants); } + | MemberExpr '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); + } + | MemberExpr '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); + } + | NEW MemberExpr Arguments { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants); + } +; + +MemberExprNoBF: + PrimaryExprNoBrace + | MemberExprNoBF '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); + } + | MemberExprNoBF '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); + } + | NEW MemberExpr Arguments { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants); + } +; + +NewExpr: + MemberExpr + | NEW NewExpr { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants); + } +; + +NewExprNoBF: + MemberExprNoBF + | NEW NewExpr { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants); + } +; + +CallExpr: + MemberExpr Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } + | CallExpr Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } + | CallExpr '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); + } + | CallExpr '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); } +; + +CallExprNoBF: + MemberExprNoBF Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } + | CallExprNoBF Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); } + | CallExprNoBF '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); + } + | CallExprNoBF '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); + } +; + +Arguments: + '(' ')' { $$ = createNodeInfo<ArgumentsNode*>(new ArgumentsNode(GLOBAL_DATA), 0, 0); } + | '(' ArgumentList ')' { $$ = createNodeInfo<ArgumentsNode*>(new ArgumentsNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } +; + +ArgumentList: + AssignmentExpr { $$.m_node.head = new ArgumentListNode(GLOBAL_DATA, $1.m_node); + $$.m_node.tail = $$.m_node.head; + $$.m_features = $1.m_features; + $$.m_numConstants = $1.m_numConstants; } + | ArgumentList ',' AssignmentExpr { $$.m_node.head = $1.m_node.head; + $$.m_node.tail = new ArgumentListNode(GLOBAL_DATA, $1.m_node.tail, $3.m_node); + $$.m_features = $1.m_features | $3.m_features; + $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; } +; + +LeftHandSideExpr: + NewExpr + | CallExpr +; + +LeftHandSideExprNoBF: + NewExprNoBF + | CallExprNoBF +; + +PostfixExpr: + LeftHandSideExpr + | LeftHandSideExpr PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } + | LeftHandSideExpr MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } +; + +PostfixExprNoBF: + LeftHandSideExprNoBF + | LeftHandSideExprNoBF PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } + | LeftHandSideExprNoBF MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); } +; + +UnaryExprCommon: + DELETETOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDeleteNode(GLOBAL_DATA, $2.m_node, @1.first_column, @2.last_column, @2.last_column), $2.m_features, $2.m_numConstants); } + | VOIDTOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new VoidNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants + 1); } + | TYPEOF UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeTypeOfNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } + | PLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } + | AUTOPLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } + | MINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } + | AUTOMINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); } + | '+' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new UnaryPlusNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } + | '-' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeNegateNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } + | '~' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeBitwiseNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } + | '!' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); } + +UnaryExpr: + PostfixExpr + | UnaryExprCommon +; + +UnaryExprNoBF: + PostfixExprNoBF + | UnaryExprCommon +; + +MultiplicativeExpr: + UnaryExpr + | MultiplicativeExpr '*' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | MultiplicativeExpr '/' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | MultiplicativeExpr '%' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +MultiplicativeExprNoBF: + UnaryExprNoBF + | MultiplicativeExprNoBF '*' UnaryExpr + { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | MultiplicativeExprNoBF '/' UnaryExpr + { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | MultiplicativeExprNoBF '%' UnaryExpr + { $$ = createNodeInfo<ExpressionNode*>(new ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +AdditiveExpr: + MultiplicativeExpr + | AdditiveExpr '+' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | AdditiveExpr '-' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +AdditiveExprNoBF: + MultiplicativeExprNoBF + | AdditiveExprNoBF '+' MultiplicativeExpr + { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | AdditiveExprNoBF '-' MultiplicativeExpr + { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +ShiftExpr: + AdditiveExpr + | ShiftExpr LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | ShiftExpr RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | ShiftExpr URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +ShiftExprNoBF: + AdditiveExprNoBF + | ShiftExprNoBF LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | ShiftExprNoBF RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | ShiftExprNoBF URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +RelationalExpr: + ShiftExpr + | RelationalExpr '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExpr '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExpr LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExpr GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExpr INSTANCEOF ShiftExpr { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExpr INTOKEN ShiftExpr { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +RelationalExprNoIn: + ShiftExpr + | RelationalExprNoIn '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoIn '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoIn LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoIn GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoIn INSTANCEOF ShiftExpr + { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +RelationalExprNoBF: + ShiftExprNoBF + | RelationalExprNoBF '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoBF '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoBF LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoBF GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoBF INSTANCEOF ShiftExpr + { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | RelationalExprNoBF INTOKEN ShiftExpr + { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column); + $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +EqualityExpr: + RelationalExpr + | EqualityExpr EQEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExpr NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExpr STREQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExpr STRNEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +EqualityExprNoIn: + RelationalExprNoIn + | EqualityExprNoIn EQEQ RelationalExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExprNoIn NE RelationalExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExprNoIn STREQ RelationalExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExprNoIn STRNEQ RelationalExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +EqualityExprNoBF: + RelationalExprNoBF + | EqualityExprNoBF EQEQ RelationalExpr + { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExprNoBF NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExprNoBF STREQ RelationalExpr + { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } + | EqualityExprNoBF STRNEQ RelationalExpr + { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseANDExpr: + EqualityExpr + | BitwiseANDExpr '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseANDExprNoIn: + EqualityExprNoIn + | BitwiseANDExprNoIn '&' EqualityExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseANDExprNoBF: + EqualityExprNoBF + | BitwiseANDExprNoBF '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseXORExpr: + BitwiseANDExpr + | BitwiseXORExpr '^' BitwiseANDExpr { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseXORExprNoIn: + BitwiseANDExprNoIn + | BitwiseXORExprNoIn '^' BitwiseANDExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseXORExprNoBF: + BitwiseANDExprNoBF + | BitwiseXORExprNoBF '^' BitwiseANDExpr + { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseORExpr: + BitwiseXORExpr + | BitwiseORExpr '|' BitwiseXORExpr { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseORExprNoIn: + BitwiseXORExprNoIn + | BitwiseORExprNoIn '|' BitwiseXORExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +BitwiseORExprNoBF: + BitwiseXORExprNoBF + | BitwiseORExprNoBF '|' BitwiseXORExpr + { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +LogicalANDExpr: + BitwiseORExpr + | LogicalANDExpr AND BitwiseORExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +LogicalANDExprNoIn: + BitwiseORExprNoIn + | LogicalANDExprNoIn AND BitwiseORExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +LogicalANDExprNoBF: + BitwiseORExprNoBF + | LogicalANDExprNoBF AND BitwiseORExpr + { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +LogicalORExpr: + LogicalANDExpr + | LogicalORExpr OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +LogicalORExprNoIn: + LogicalANDExprNoIn + | LogicalORExprNoIn OR LogicalANDExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +LogicalORExprNoBF: + LogicalANDExprNoBF + | LogicalORExprNoBF OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +ConditionalExpr: + LogicalORExpr + | LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr + { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); } +; + +ConditionalExprNoIn: + LogicalORExprNoIn + | LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); } +; + +ConditionalExprNoBF: + LogicalORExprNoBF + | LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr + { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); } +; + +AssignmentExpr: + ConditionalExpr + | LeftHandSideExpr AssignmentOperator AssignmentExpr + { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature, + @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants); + } +; + +AssignmentExprNoIn: + ConditionalExprNoIn + | LeftHandSideExpr AssignmentOperator AssignmentExprNoIn + { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature, + @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants); + } +; + +AssignmentExprNoBF: + ConditionalExprNoBF + | LeftHandSideExprNoBF AssignmentOperator AssignmentExpr + { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature, + @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants); + } +; + +AssignmentOperator: + '=' { $$ = OpEqual; } + | PLUSEQUAL { $$ = OpPlusEq; } + | MINUSEQUAL { $$ = OpMinusEq; } + | MULTEQUAL { $$ = OpMultEq; } + | DIVEQUAL { $$ = OpDivEq; } + | LSHIFTEQUAL { $$ = OpLShift; } + | RSHIFTEQUAL { $$ = OpRShift; } + | URSHIFTEQUAL { $$ = OpURShift; } + | ANDEQUAL { $$ = OpAndEq; } + | XOREQUAL { $$ = OpXOrEq; } + | OREQUAL { $$ = OpOrEq; } + | MODEQUAL { $$ = OpModEq; } +; + +Expr: + AssignmentExpr + | Expr ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +ExprNoIn: + AssignmentExprNoIn + | ExprNoIn ',' AssignmentExprNoIn { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +ExprNoBF: + AssignmentExprNoBF + | ExprNoBF ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); } +; + +Statement: + Block + | VariableStatement + | ConstStatement + | FunctionDeclaration + | EmptyStatement + | ExprStatement + | IfStatement + | IterationStatement + | ContinueStatement + | BreakStatement + | ReturnStatement + | WithStatement + | SwitchStatement + | LabelledStatement + | ThrowStatement + | TryStatement + | DebuggerStatement +; + +Block: + OPENBRACE CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new BlockNode(GLOBAL_DATA, 0), 0, 0, 0, 0); + DBG($$.m_node, @1, @2); } + | OPENBRACE SourceElements CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new BlockNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); + DBG($$.m_node, @1, @3); } +; + +VariableStatement: + VAR VariableDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); + DBG($$.m_node, @1, @3); } + | VAR VariableDeclarationList error { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); + DBG($$.m_node, @1, @2); + AUTO_SEMICOLON; } +; + +VariableDeclarationList: + IDENT { $$.m_node = 0; + $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0); + $$.m_funcDeclarations = 0; + $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0; + $$.m_numConstants = 0; + } + | IDENT Initializer { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column); + $$.m_node = node; + $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer); + $$.m_funcDeclarations = 0; + $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features; + $$.m_numConstants = $2.m_numConstants; + } + | VariableDeclarationList ',' IDENT + { $$.m_node = $1.m_node; + $$.m_varDeclarations = $1.m_varDeclarations; + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0); + $$.m_funcDeclarations = 0; + $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0); + $$.m_numConstants = $1.m_numConstants; + } + | VariableDeclarationList ',' IDENT Initializer + { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column); + $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node); + $$.m_varDeclarations = $1.m_varDeclarations; + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer); + $$.m_funcDeclarations = 0; + $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features; + $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; + } +; + +VariableDeclarationListNoIn: + IDENT { $$.m_node = 0; + $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0); + $$.m_funcDeclarations = 0; + $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0; + $$.m_numConstants = 0; + } + | IDENT InitializerNoIn { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column); + $$.m_node = node; + $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer); + $$.m_funcDeclarations = 0; + $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features; + $$.m_numConstants = $2.m_numConstants; + } + | VariableDeclarationListNoIn ',' IDENT + { $$.m_node = $1.m_node; + $$.m_varDeclarations = $1.m_varDeclarations; + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0); + $$.m_funcDeclarations = 0; + $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0); + $$.m_numConstants = $1.m_numConstants; + } + | VariableDeclarationListNoIn ',' IDENT InitializerNoIn + { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature); + SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column); + $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node); + $$.m_varDeclarations = $1.m_varDeclarations; + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer); + $$.m_funcDeclarations = 0; + $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features; + $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; + } +; + +ConstStatement: + CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); + DBG($$.m_node, @1, @3); } + | CONSTTOKEN ConstDeclarationList error + { $$ = createNodeDeclarationInfo<StatementNode*>(new ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); + DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } +; + +ConstDeclarationList: + ConstDeclaration { $$.m_node.head = $1.m_node; + $$.m_node.tail = $$.m_node.head; + $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA); + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $1.m_node); + $$.m_funcDeclarations = 0; + $$.m_features = $1.m_features; + $$.m_numConstants = $1.m_numConstants; + } + | ConstDeclarationList ',' ConstDeclaration + { $$.m_node.head = $1.m_node.head; + $1.m_node.tail->m_next = $3.m_node; + $$.m_node.tail = $3.m_node; + $$.m_varDeclarations = $1.m_varDeclarations; + appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $3.m_node); + $$.m_funcDeclarations = 0; + $$.m_features = $1.m_features | $3.m_features; + $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; } +; + +ConstDeclaration: + IDENT { $$ = createNodeInfo<ConstDeclNode*>(new ConstDeclNode(GLOBAL_DATA, *$1, 0), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); } + | IDENT Initializer { $$ = createNodeInfo<ConstDeclNode*>(new ConstDeclNode(GLOBAL_DATA, *$1, $2.m_node), ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features, $2.m_numConstants); } +; + +Initializer: + '=' AssignmentExpr { $$ = $2; } +; + +InitializerNoIn: + '=' AssignmentExprNoIn { $$ = $2; } +; + +EmptyStatement: + ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new EmptyStatementNode(GLOBAL_DATA), 0, 0, 0, 0); } +; + +ExprStatement: + ExprNoBF ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants); + DBG($$.m_node, @1, @2); } + | ExprNoBF error { $$ = createNodeDeclarationInfo<StatementNode*>(new ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants); + DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } +; + +IfStatement: + IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE + { $$ = createNodeDeclarationInfo<StatementNode*>(new IfNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants); + DBG($$.m_node, @1, @4); } + | IF '(' Expr ')' Statement ELSE Statement + { $$ = createNodeDeclarationInfo<StatementNode*>(new IfElseNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node), + mergeDeclarationLists($5.m_varDeclarations, $7.m_varDeclarations), mergeDeclarationLists($5.m_funcDeclarations, $7.m_funcDeclarations), + $3.m_features | $5.m_features | $7.m_features, + $3.m_numConstants + $5.m_numConstants + $7.m_numConstants); + DBG($$.m_node, @1, @4); } +; + +IterationStatement: + DO Statement WHILE '(' Expr ')' ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants); + DBG($$.m_node, @1, @3); } + | DO Statement WHILE '(' Expr ')' error { $$ = createNodeDeclarationInfo<StatementNode*>(new DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants); + DBG($$.m_node, @1, @3); } // Always performs automatic semicolon insertion. + | WHILE '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new WhileNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants); + DBG($$.m_node, @1, @4); } + | FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement + { $$ = createNodeDeclarationInfo<StatementNode*>(new ForNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node, $9.m_node, false), $9.m_varDeclarations, $9.m_funcDeclarations, + $3.m_features | $5.m_features | $7.m_features | $9.m_features, + $3.m_numConstants + $5.m_numConstants + $7.m_numConstants + $9.m_numConstants); + DBG($$.m_node, @1, @8); + } + | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement + { $$ = createNodeDeclarationInfo<StatementNode*>(new ForNode(GLOBAL_DATA, $4.m_node, $6.m_node, $8.m_node, $10.m_node, true), + mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations), + mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations), + $4.m_features | $6.m_features | $8.m_features | $10.m_features, + $4.m_numConstants + $6.m_numConstants + $8.m_numConstants + $10.m_numConstants); + DBG($$.m_node, @1, @9); } + | FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement + { + ForInNode* node = new ForInNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node); + SET_EXCEPTION_LOCATION(node, @3.first_column, @3.last_column, @5.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, $7.m_varDeclarations, $7.m_funcDeclarations, + $3.m_features | $5.m_features | $7.m_features, + $3.m_numConstants + $5.m_numConstants + $7.m_numConstants); + DBG($$.m_node, @1, @6); + } + | FOR '(' VAR IDENT INTOKEN Expr ')' Statement + { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, 0, $6.m_node, $8.m_node, @5.first_column, @5.first_column - @4.first_column, @6.last_column - @5.first_column); + SET_EXCEPTION_LOCATION(forIn, @4.first_column, @5.first_column + 1, @6.last_column); + appendToVarDeclarationList(GLOBAL_DATA, $8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer); + $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations, ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $6.m_features | $8.m_features, $6.m_numConstants + $8.m_numConstants); + DBG($$.m_node, @1, @7); } + | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement + { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, $5.m_node, $7.m_node, $9.m_node, @5.first_column, @5.first_column - @4.first_column, @5.last_column - @5.first_column); + SET_EXCEPTION_LOCATION(forIn, @4.first_column, @6.first_column + 1, @7.last_column); + appendToVarDeclarationList(GLOBAL_DATA, $9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer); + $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations, + ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $5.m_features | $7.m_features | $9.m_features, + $5.m_numConstants + $7.m_numConstants + $9.m_numConstants); + DBG($$.m_node, @1, @8); } +; + +ExprOpt: + /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); } + | Expr +; + +ExprNoInOpt: + /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); } + | ExprNoIn +; + +ContinueStatement: + CONTINUE ';' { ContinueNode* node = new ContinueNode(GLOBAL_DATA); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); + DBG($$.m_node, @1, @2); } + | CONTINUE error { ContinueNode* node = new ContinueNode(GLOBAL_DATA); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); + DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + | CONTINUE IDENT ';' { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); + DBG($$.m_node, @1, @3); } + | CONTINUE IDENT error { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); + DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } +; + +BreakStatement: + BREAK ';' { BreakNode* node = new BreakNode(GLOBAL_DATA); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @2); } + | BREAK error { BreakNode* node = new BreakNode(GLOBAL_DATA); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA), 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + | BREAK IDENT ';' { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @3); } + | BREAK IDENT error { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA, *$2), 0, 0, 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } +; + +ReturnStatement: + RETURN ';' { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @2); } + | RETURN error { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + | RETURN Expr ';' { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @3); } + | RETURN Expr error { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } +; + +WithStatement: + WITH '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new WithNode(GLOBAL_DATA, $3.m_node, $5.m_node, @3.last_column, @3.last_column - @3.first_column), + $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features | WithFeature, $3.m_numConstants + $5.m_numConstants); + DBG($$.m_node, @1, @4); } +; + +SwitchStatement: + SWITCH '(' Expr ')' CaseBlock { $$ = createNodeDeclarationInfo<StatementNode*>(new SwitchNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, + $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants); + DBG($$.m_node, @1, @4); } +; + +CaseBlock: + OPENBRACE CaseClausesOpt CLOSEBRACE { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new CaseBlockNode(GLOBAL_DATA, $2.m_node.head, 0, 0), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); } + | OPENBRACE CaseClausesOpt DefaultClause CaseClausesOpt CLOSEBRACE + { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new CaseBlockNode(GLOBAL_DATA, $2.m_node.head, $3.m_node, $4.m_node.head), + mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $3.m_varDeclarations), $4.m_varDeclarations), + mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $3.m_funcDeclarations), $4.m_funcDeclarations), + $2.m_features | $3.m_features | $4.m_features, + $2.m_numConstants + $3.m_numConstants + $4.m_numConstants); } +; + +CaseClausesOpt: +/* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; $$.m_features = 0; $$.m_numConstants = 0; } + | CaseClauses +; + +CaseClauses: + CaseClause { $$.m_node.head = new ClauseListNode(GLOBAL_DATA, $1.m_node); + $$.m_node.tail = $$.m_node.head; + $$.m_varDeclarations = $1.m_varDeclarations; + $$.m_funcDeclarations = $1.m_funcDeclarations; + $$.m_features = $1.m_features; + $$.m_numConstants = $1.m_numConstants; } + | CaseClauses CaseClause { $$.m_node.head = $1.m_node.head; + $$.m_node.tail = new ClauseListNode(GLOBAL_DATA, $1.m_node.tail, $2.m_node); + $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations); + $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations); + $$.m_features = $1.m_features | $2.m_features; + $$.m_numConstants = $1.m_numConstants + $2.m_numConstants; + } +; + +CaseClause: + CASE Expr ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_features, $2.m_numConstants); } + | CASE Expr ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, $2.m_node, $4.m_node), $4.m_varDeclarations, $4.m_funcDeclarations, $2.m_features | $4.m_features, $2.m_numConstants + $4.m_numConstants); } +; + +DefaultClause: + DEFAULT ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, 0), 0, 0, 0, 0); } + | DEFAULT ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, 0, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); } +; + +LabelledStatement: + IDENT ':' Statement { LabelNode* node = new LabelNode(GLOBAL_DATA, *$1, $3.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); } +; + +ThrowStatement: + THROW Expr ';' { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @2); + } + | THROW Expr error { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; + } +; + +TryStatement: + TRY Block FINALLY Block { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, GLOBAL_DATA->propertyNames->nullIdentifier, false, 0, $4.m_node), + mergeDeclarationLists($2.m_varDeclarations, $4.m_varDeclarations), + mergeDeclarationLists($2.m_funcDeclarations, $4.m_funcDeclarations), + $2.m_features | $4.m_features, + $2.m_numConstants + $4.m_numConstants); + DBG($$.m_node, @1, @2); } + | TRY Block CATCH '(' IDENT ')' Block { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, *$5, ($7.m_features & EvalFeature) != 0, $7.m_node, 0), + mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations), + mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations), + $2.m_features | $7.m_features | CatchFeature, + $2.m_numConstants + $7.m_numConstants); + DBG($$.m_node, @1, @2); } + | TRY Block CATCH '(' IDENT ')' Block FINALLY Block + { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, *$5, ($7.m_features & EvalFeature) != 0, $7.m_node, $9.m_node), + mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations), $9.m_varDeclarations), + mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations), $9.m_funcDeclarations), + $2.m_features | $7.m_features | $9.m_features | CatchFeature, + $2.m_numConstants + $7.m_numConstants + $9.m_numConstants); + DBG($$.m_node, @1, @2); } +; + +DebuggerStatement: + DEBUGGER ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0); + DBG($$.m_node, @1, @2); } + | DEBUGGER error { $$ = createNodeDeclarationInfo<StatementNode*>(new DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0); + DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } +; + +FunctionDeclaration: + FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new FuncDeclNode(GLOBAL_DATA, *$2, $6, LEXER->sourceCode($5, $7, @5.first_line)), 0, new ParserRefCountedData<DeclarationStacks::FunctionStack>(GLOBAL_DATA), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); DBG($6, @5, @7); $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)); } + | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE + { + $$ = createNodeDeclarationInfo<StatementNode*>(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceCode($6, $8, @6.first_line), $4.m_node.head), 0, new ParserRefCountedData<DeclarationStacks::FunctionStack>(GLOBAL_DATA), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features | ClosureFeature, 0); + if ($4.m_features & ArgumentsFeature) + $7->setUsesArguments(); + DBG($7, @6, @8); + $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)); + } +; + +FunctionExpr: + FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $5, LEXER->sourceCode($4, $6, @4.first_line)), ClosureFeature, 0); DBG($5, @4, @6); } + | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE + { + $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, LEXER->sourceCode($5, $7, @5.first_line), $3.m_node.head), $3.m_features | ClosureFeature, 0); + if ($3.m_features & ArgumentsFeature) + $6->setUsesArguments(); + DBG($6, @5, @7); + } + | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, *$2, $6, LEXER->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); DBG($6, @5, @7); } + | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE + { + $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, *$2, $7, LEXER->sourceCode($6, $8, @6.first_line), $4.m_node.head), $4.m_features | ClosureFeature, 0); + if ($4.m_features & ArgumentsFeature) + $7->setUsesArguments(); + DBG($7, @6, @8); + } +; + +FormalParameterList: + IDENT { $$.m_node.head = new ParameterNode(GLOBAL_DATA, *$1); + $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0; + $$.m_node.tail = $$.m_node.head; } + | FormalParameterList ',' IDENT { $$.m_node.head = $1.m_node.head; + $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0); + $$.m_node.tail = new ParameterNode(GLOBAL_DATA, $1.m_node.tail, *$3); } +; + +FunctionBody: + /* not in spec */ { $$ = FunctionBodyNode::create(GLOBAL_DATA); } + | SourceElements_NoNode { $$ = FunctionBodyNode::create(GLOBAL_DATA); } +; + +Program: + /* not in spec */ { GLOBAL_DATA->parser->didFinishParsing(new SourceElements(GLOBAL_DATA), 0, 0, NoFeatures, @0.last_line, 0); } + | SourceElements { GLOBAL_DATA->parser->didFinishParsing($1.m_node, $1.m_varDeclarations, $1.m_funcDeclarations, $1.m_features, + @1.last_line, $1.m_numConstants); } +; + +SourceElements: + Statement { $$.m_node = new SourceElements(GLOBAL_DATA); + $$.m_node->append($1.m_node); + $$.m_varDeclarations = $1.m_varDeclarations; + $$.m_funcDeclarations = $1.m_funcDeclarations; + $$.m_features = $1.m_features; + $$.m_numConstants = $1.m_numConstants; + } + | SourceElements Statement { $$.m_node->append($2.m_node); + $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations); + $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations); + $$.m_features = $1.m_features | $2.m_features; + $$.m_numConstants = $1.m_numConstants + $2.m_numConstants; + } +; + +// Start NoNodes + +Literal_NoNode: + NULLTOKEN + | TRUETOKEN + | FALSETOKEN + | NUMBER { } + | STRING { } + | '/' /* regexp */ { Lexer& l = *LEXER; if (!l.scanRegExp()) YYABORT; } + | DIVEQUAL /* regexp with /= */ { Lexer& l = *LEXER; if (!l.scanRegExp()) YYABORT; } +; + +Property_NoNode: + IDENT ':' AssignmentExpr_NoNode { } + | STRING ':' AssignmentExpr_NoNode { } + | NUMBER ':' AssignmentExpr_NoNode { } + | IDENT IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE { if (*$1 != "get" && *$1 != "set") YYABORT; } + | IDENT IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE { if (*$1 != "get" && *$1 != "set") YYABORT; } +; + +PropertyList_NoNode: + Property_NoNode + | PropertyList_NoNode ',' Property_NoNode +; + +PrimaryExpr_NoNode: + PrimaryExprNoBrace_NoNode + | OPENBRACE CLOSEBRACE { } + | OPENBRACE PropertyList_NoNode CLOSEBRACE { } + /* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */ + | OPENBRACE PropertyList_NoNode ',' CLOSEBRACE { } +; + +PrimaryExprNoBrace_NoNode: + THISTOKEN + | Literal_NoNode + | ArrayLiteral_NoNode + | IDENT { } + | '(' Expr_NoNode ')' +; + +ArrayLiteral_NoNode: + '[' ElisionOpt_NoNode ']' + | '[' ElementList_NoNode ']' + | '[' ElementList_NoNode ',' ElisionOpt_NoNode ']' +; + +ElementList_NoNode: + ElisionOpt_NoNode AssignmentExpr_NoNode + | ElementList_NoNode ',' ElisionOpt_NoNode AssignmentExpr_NoNode +; + +ElisionOpt_NoNode: + /* nothing */ + | Elision_NoNode +; + +Elision_NoNode: + ',' + | Elision_NoNode ',' +; + +MemberExpr_NoNode: + PrimaryExpr_NoNode + | FunctionExpr_NoNode + | MemberExpr_NoNode '[' Expr_NoNode ']' + | MemberExpr_NoNode '.' IDENT + | NEW MemberExpr_NoNode Arguments_NoNode +; + +MemberExprNoBF_NoNode: + PrimaryExprNoBrace_NoNode + | MemberExprNoBF_NoNode '[' Expr_NoNode ']' + | MemberExprNoBF_NoNode '.' IDENT + | NEW MemberExpr_NoNode Arguments_NoNode +; + +NewExpr_NoNode: + MemberExpr_NoNode + | NEW NewExpr_NoNode +; + +NewExprNoBF_NoNode: + MemberExprNoBF_NoNode + | NEW NewExpr_NoNode +; + +CallExpr_NoNode: + MemberExpr_NoNode Arguments_NoNode + | CallExpr_NoNode Arguments_NoNode + | CallExpr_NoNode '[' Expr_NoNode ']' + | CallExpr_NoNode '.' IDENT +; + +CallExprNoBF_NoNode: + MemberExprNoBF_NoNode Arguments_NoNode + | CallExprNoBF_NoNode Arguments_NoNode + | CallExprNoBF_NoNode '[' Expr_NoNode ']' + | CallExprNoBF_NoNode '.' IDENT +; + +Arguments_NoNode: + '(' ')' + | '(' ArgumentList_NoNode ')' +; + +ArgumentList_NoNode: + AssignmentExpr_NoNode + | ArgumentList_NoNode ',' AssignmentExpr_NoNode +; + +LeftHandSideExpr_NoNode: + NewExpr_NoNode + | CallExpr_NoNode +; + +LeftHandSideExprNoBF_NoNode: + NewExprNoBF_NoNode + | CallExprNoBF_NoNode +; + +PostfixExpr_NoNode: + LeftHandSideExpr_NoNode + | LeftHandSideExpr_NoNode PLUSPLUS + | LeftHandSideExpr_NoNode MINUSMINUS +; + +PostfixExprNoBF_NoNode: + LeftHandSideExprNoBF_NoNode + | LeftHandSideExprNoBF_NoNode PLUSPLUS + | LeftHandSideExprNoBF_NoNode MINUSMINUS +; + +UnaryExprCommon_NoNode: + DELETETOKEN UnaryExpr_NoNode + | VOIDTOKEN UnaryExpr_NoNode + | TYPEOF UnaryExpr_NoNode + | PLUSPLUS UnaryExpr_NoNode + | AUTOPLUSPLUS UnaryExpr_NoNode + | MINUSMINUS UnaryExpr_NoNode + | AUTOMINUSMINUS UnaryExpr_NoNode + | '+' UnaryExpr_NoNode + | '-' UnaryExpr_NoNode + | '~' UnaryExpr_NoNode + | '!' UnaryExpr_NoNode + +UnaryExpr_NoNode: + PostfixExpr_NoNode + | UnaryExprCommon_NoNode +; + +UnaryExprNoBF_NoNode: + PostfixExprNoBF_NoNode + | UnaryExprCommon_NoNode +; + +MultiplicativeExpr_NoNode: + UnaryExpr_NoNode + | MultiplicativeExpr_NoNode '*' UnaryExpr_NoNode + | MultiplicativeExpr_NoNode '/' UnaryExpr_NoNode + | MultiplicativeExpr_NoNode '%' UnaryExpr_NoNode +; + +MultiplicativeExprNoBF_NoNode: + UnaryExprNoBF_NoNode + | MultiplicativeExprNoBF_NoNode '*' UnaryExpr_NoNode + | MultiplicativeExprNoBF_NoNode '/' UnaryExpr_NoNode + | MultiplicativeExprNoBF_NoNode '%' UnaryExpr_NoNode +; + +AdditiveExpr_NoNode: + MultiplicativeExpr_NoNode + | AdditiveExpr_NoNode '+' MultiplicativeExpr_NoNode + | AdditiveExpr_NoNode '-' MultiplicativeExpr_NoNode +; + +AdditiveExprNoBF_NoNode: + MultiplicativeExprNoBF_NoNode + | AdditiveExprNoBF_NoNode '+' MultiplicativeExpr_NoNode + | AdditiveExprNoBF_NoNode '-' MultiplicativeExpr_NoNode +; + +ShiftExpr_NoNode: + AdditiveExpr_NoNode + | ShiftExpr_NoNode LSHIFT AdditiveExpr_NoNode + | ShiftExpr_NoNode RSHIFT AdditiveExpr_NoNode + | ShiftExpr_NoNode URSHIFT AdditiveExpr_NoNode +; + +ShiftExprNoBF_NoNode: + AdditiveExprNoBF_NoNode + | ShiftExprNoBF_NoNode LSHIFT AdditiveExpr_NoNode + | ShiftExprNoBF_NoNode RSHIFT AdditiveExpr_NoNode + | ShiftExprNoBF_NoNode URSHIFT AdditiveExpr_NoNode +; + +RelationalExpr_NoNode: + ShiftExpr_NoNode + | RelationalExpr_NoNode '<' ShiftExpr_NoNode + | RelationalExpr_NoNode '>' ShiftExpr_NoNode + | RelationalExpr_NoNode LE ShiftExpr_NoNode + | RelationalExpr_NoNode GE ShiftExpr_NoNode + | RelationalExpr_NoNode INSTANCEOF ShiftExpr_NoNode + | RelationalExpr_NoNode INTOKEN ShiftExpr_NoNode +; + +RelationalExprNoIn_NoNode: + ShiftExpr_NoNode + | RelationalExprNoIn_NoNode '<' ShiftExpr_NoNode + | RelationalExprNoIn_NoNode '>' ShiftExpr_NoNode + | RelationalExprNoIn_NoNode LE ShiftExpr_NoNode + | RelationalExprNoIn_NoNode GE ShiftExpr_NoNode + | RelationalExprNoIn_NoNode INSTANCEOF ShiftExpr_NoNode +; + +RelationalExprNoBF_NoNode: + ShiftExprNoBF_NoNode + | RelationalExprNoBF_NoNode '<' ShiftExpr_NoNode + | RelationalExprNoBF_NoNode '>' ShiftExpr_NoNode + | RelationalExprNoBF_NoNode LE ShiftExpr_NoNode + | RelationalExprNoBF_NoNode GE ShiftExpr_NoNode + | RelationalExprNoBF_NoNode INSTANCEOF ShiftExpr_NoNode + | RelationalExprNoBF_NoNode INTOKEN ShiftExpr_NoNode +; + +EqualityExpr_NoNode: + RelationalExpr_NoNode + | EqualityExpr_NoNode EQEQ RelationalExpr_NoNode + | EqualityExpr_NoNode NE RelationalExpr_NoNode + | EqualityExpr_NoNode STREQ RelationalExpr_NoNode + | EqualityExpr_NoNode STRNEQ RelationalExpr_NoNode +; + +EqualityExprNoIn_NoNode: + RelationalExprNoIn_NoNode + | EqualityExprNoIn_NoNode EQEQ RelationalExprNoIn_NoNode + | EqualityExprNoIn_NoNode NE RelationalExprNoIn_NoNode + | EqualityExprNoIn_NoNode STREQ RelationalExprNoIn_NoNode + | EqualityExprNoIn_NoNode STRNEQ RelationalExprNoIn_NoNode +; + +EqualityExprNoBF_NoNode: + RelationalExprNoBF_NoNode + | EqualityExprNoBF_NoNode EQEQ RelationalExpr_NoNode + | EqualityExprNoBF_NoNode NE RelationalExpr_NoNode + | EqualityExprNoBF_NoNode STREQ RelationalExpr_NoNode + | EqualityExprNoBF_NoNode STRNEQ RelationalExpr_NoNode +; + +BitwiseANDExpr_NoNode: + EqualityExpr_NoNode + | BitwiseANDExpr_NoNode '&' EqualityExpr_NoNode +; + +BitwiseANDExprNoIn_NoNode: + EqualityExprNoIn_NoNode + | BitwiseANDExprNoIn_NoNode '&' EqualityExprNoIn_NoNode +; + +BitwiseANDExprNoBF_NoNode: + EqualityExprNoBF_NoNode + | BitwiseANDExprNoBF_NoNode '&' EqualityExpr_NoNode +; + +BitwiseXORExpr_NoNode: + BitwiseANDExpr_NoNode + | BitwiseXORExpr_NoNode '^' BitwiseANDExpr_NoNode +; + +BitwiseXORExprNoIn_NoNode: + BitwiseANDExprNoIn_NoNode + | BitwiseXORExprNoIn_NoNode '^' BitwiseANDExprNoIn_NoNode +; + +BitwiseXORExprNoBF_NoNode: + BitwiseANDExprNoBF_NoNode + | BitwiseXORExprNoBF_NoNode '^' BitwiseANDExpr_NoNode +; + +BitwiseORExpr_NoNode: + BitwiseXORExpr_NoNode + | BitwiseORExpr_NoNode '|' BitwiseXORExpr_NoNode +; + +BitwiseORExprNoIn_NoNode: + BitwiseXORExprNoIn_NoNode + | BitwiseORExprNoIn_NoNode '|' BitwiseXORExprNoIn_NoNode +; + +BitwiseORExprNoBF_NoNode: + BitwiseXORExprNoBF_NoNode + | BitwiseORExprNoBF_NoNode '|' BitwiseXORExpr_NoNode +; + +LogicalANDExpr_NoNode: + BitwiseORExpr_NoNode + | LogicalANDExpr_NoNode AND BitwiseORExpr_NoNode +; + +LogicalANDExprNoIn_NoNode: + BitwiseORExprNoIn_NoNode + | LogicalANDExprNoIn_NoNode AND BitwiseORExprNoIn_NoNode +; + +LogicalANDExprNoBF_NoNode: + BitwiseORExprNoBF_NoNode + | LogicalANDExprNoBF_NoNode AND BitwiseORExpr_NoNode +; + +LogicalORExpr_NoNode: + LogicalANDExpr_NoNode + | LogicalORExpr_NoNode OR LogicalANDExpr_NoNode +; + +LogicalORExprNoIn_NoNode: + LogicalANDExprNoIn_NoNode + | LogicalORExprNoIn_NoNode OR LogicalANDExprNoIn_NoNode +; + +LogicalORExprNoBF_NoNode: + LogicalANDExprNoBF_NoNode + | LogicalORExprNoBF_NoNode OR LogicalANDExpr_NoNode +; + +ConditionalExpr_NoNode: + LogicalORExpr_NoNode + | LogicalORExpr_NoNode '?' AssignmentExpr_NoNode ':' AssignmentExpr_NoNode +; + +ConditionalExprNoIn_NoNode: + LogicalORExprNoIn_NoNode + | LogicalORExprNoIn_NoNode '?' AssignmentExprNoIn_NoNode ':' AssignmentExprNoIn_NoNode +; + +ConditionalExprNoBF_NoNode: + LogicalORExprNoBF_NoNode + | LogicalORExprNoBF_NoNode '?' AssignmentExpr_NoNode ':' AssignmentExpr_NoNode +; + +AssignmentExpr_NoNode: + ConditionalExpr_NoNode + | LeftHandSideExpr_NoNode AssignmentOperator_NoNode AssignmentExpr_NoNode +; + +AssignmentExprNoIn_NoNode: + ConditionalExprNoIn_NoNode + | LeftHandSideExpr_NoNode AssignmentOperator_NoNode AssignmentExprNoIn_NoNode +; + +AssignmentExprNoBF_NoNode: + ConditionalExprNoBF_NoNode + | LeftHandSideExprNoBF_NoNode AssignmentOperator_NoNode AssignmentExpr_NoNode +; + +AssignmentOperator_NoNode: + '=' + | PLUSEQUAL + | MINUSEQUAL + | MULTEQUAL + | DIVEQUAL + | LSHIFTEQUAL + | RSHIFTEQUAL + | URSHIFTEQUAL + | ANDEQUAL + | XOREQUAL + | OREQUAL + | MODEQUAL +; + +Expr_NoNode: + AssignmentExpr_NoNode + | Expr_NoNode ',' AssignmentExpr_NoNode +; + +ExprNoIn_NoNode: + AssignmentExprNoIn_NoNode + | ExprNoIn_NoNode ',' AssignmentExprNoIn_NoNode +; + +ExprNoBF_NoNode: + AssignmentExprNoBF_NoNode + | ExprNoBF_NoNode ',' AssignmentExpr_NoNode +; + +Statement_NoNode: + Block_NoNode + | VariableStatement_NoNode + | ConstStatement_NoNode + | FunctionDeclaration_NoNode + | EmptyStatement_NoNode + | ExprStatement_NoNode + | IfStatement_NoNode + | IterationStatement_NoNode + | ContinueStatement_NoNode + | BreakStatement_NoNode + | ReturnStatement_NoNode + | WithStatement_NoNode + | SwitchStatement_NoNode + | LabelledStatement_NoNode + | ThrowStatement_NoNode + | TryStatement_NoNode + | DebuggerStatement_NoNode +; + +Block_NoNode: + OPENBRACE CLOSEBRACE { } + | OPENBRACE SourceElements_NoNode CLOSEBRACE { } +; + +VariableStatement_NoNode: + VAR VariableDeclarationList_NoNode ';' + | VAR VariableDeclarationList_NoNode error { AUTO_SEMICOLON; } +; + +VariableDeclarationList_NoNode: + IDENT { } + | IDENT Initializer_NoNode { } + | VariableDeclarationList_NoNode ',' IDENT + | VariableDeclarationList_NoNode ',' IDENT Initializer_NoNode +; + +VariableDeclarationListNoIn_NoNode: + IDENT { } + | IDENT InitializerNoIn_NoNode { } + | VariableDeclarationListNoIn_NoNode ',' IDENT + | VariableDeclarationListNoIn_NoNode ',' IDENT InitializerNoIn_NoNode +; + +ConstStatement_NoNode: + CONSTTOKEN ConstDeclarationList_NoNode ';' + | CONSTTOKEN ConstDeclarationList_NoNode error { AUTO_SEMICOLON; } +; + +ConstDeclarationList_NoNode: + ConstDeclaration_NoNode + | ConstDeclarationList_NoNode ',' ConstDeclaration_NoNode +; + +ConstDeclaration_NoNode: + IDENT { } + | IDENT Initializer_NoNode { } +; + +Initializer_NoNode: + '=' AssignmentExpr_NoNode +; + +InitializerNoIn_NoNode: + '=' AssignmentExprNoIn_NoNode +; + +EmptyStatement_NoNode: + ';' +; + +ExprStatement_NoNode: + ExprNoBF_NoNode ';' + | ExprNoBF_NoNode error { AUTO_SEMICOLON; } +; + +IfStatement_NoNode: + IF '(' Expr_NoNode ')' Statement_NoNode %prec IF_WITHOUT_ELSE + | IF '(' Expr_NoNode ')' Statement_NoNode ELSE Statement_NoNode +; + +IterationStatement_NoNode: + DO Statement_NoNode WHILE '(' Expr_NoNode ')' ';' + | DO Statement_NoNode WHILE '(' Expr_NoNode ')' error // Always performs automatic semicolon insertion + | WHILE '(' Expr_NoNode ')' Statement_NoNode + | FOR '(' ExprNoInOpt_NoNode ';' ExprOpt_NoNode ';' ExprOpt_NoNode ')' Statement_NoNode + | FOR '(' VAR VariableDeclarationListNoIn_NoNode ';' ExprOpt_NoNode ';' ExprOpt_NoNode ')' Statement_NoNode + | FOR '(' LeftHandSideExpr_NoNode INTOKEN Expr_NoNode ')' Statement_NoNode + | FOR '(' VAR IDENT INTOKEN Expr_NoNode ')' Statement_NoNode + | FOR '(' VAR IDENT InitializerNoIn_NoNode INTOKEN Expr_NoNode ')' Statement_NoNode +; + +ExprOpt_NoNode: + /* nothing */ + | Expr_NoNode +; + +ExprNoInOpt_NoNode: + /* nothing */ + | ExprNoIn_NoNode +; + +ContinueStatement_NoNode: + CONTINUE ';' + | CONTINUE error { AUTO_SEMICOLON; } + | CONTINUE IDENT ';' + | CONTINUE IDENT error { AUTO_SEMICOLON; } +; + +BreakStatement_NoNode: + BREAK ';' + | BREAK error { AUTO_SEMICOLON; } + | BREAK IDENT ';' + | BREAK IDENT error { AUTO_SEMICOLON; } +; + +ReturnStatement_NoNode: + RETURN ';' + | RETURN error { AUTO_SEMICOLON; } + | RETURN Expr_NoNode ';' + | RETURN Expr_NoNode error { AUTO_SEMICOLON; } +; + +WithStatement_NoNode: + WITH '(' Expr_NoNode ')' Statement_NoNode +; + +SwitchStatement_NoNode: + SWITCH '(' Expr_NoNode ')' CaseBlock_NoNode +; + +CaseBlock_NoNode: + OPENBRACE CaseClausesOpt_NoNode CLOSEBRACE { } + | OPENBRACE CaseClausesOpt_NoNode DefaultClause_NoNode CaseClausesOpt_NoNode CLOSEBRACE { } +; + +CaseClausesOpt_NoNode: + /* nothing */ + | CaseClauses_NoNode +; + +CaseClauses_NoNode: + CaseClause_NoNode + | CaseClauses_NoNode CaseClause_NoNode +; + +CaseClause_NoNode: + CASE Expr_NoNode ':' + | CASE Expr_NoNode ':' SourceElements_NoNode +; + +DefaultClause_NoNode: + DEFAULT ':' + | DEFAULT ':' SourceElements_NoNode +; + +LabelledStatement_NoNode: + IDENT ':' Statement_NoNode { } +; + +ThrowStatement_NoNode: + THROW Expr_NoNode ';' + | THROW Expr_NoNode error { AUTO_SEMICOLON; } +; + +TryStatement_NoNode: + TRY Block_NoNode FINALLY Block_NoNode + | TRY Block_NoNode CATCH '(' IDENT ')' Block_NoNode + | TRY Block_NoNode CATCH '(' IDENT ')' Block_NoNode FINALLY Block_NoNode +; + +DebuggerStatement_NoNode: + DEBUGGER ';' + | DEBUGGER error { AUTO_SEMICOLON; } +; + +FunctionDeclaration_NoNode: + FUNCTION IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE + | FUNCTION IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE +; + +FunctionExpr_NoNode: + FUNCTION '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE + | FUNCTION '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE + | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE + | FUNCTION IDENT '(' FormalParameterList_NoNode ')' OPENBRACE FunctionBody_NoNode CLOSEBRACE +; + +FormalParameterList_NoNode: + IDENT { } + | FormalParameterList_NoNode ',' IDENT +; + +FunctionBody_NoNode: + /* not in spec */ + | SourceElements_NoNode +; + +SourceElements_NoNode: + Statement_NoNode + | SourceElements_NoNode Statement_NoNode +; + +// End NoNodes + +%% + +static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end) +{ + if (!loc->isLocation()) + return new AssignErrorNode(GLOBAL_DATA, loc, op, expr, divot, divot - start, end - divot); + + if (loc->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(loc); + if (op == OpEqual) { + AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, resolve->identifier(), expr, exprHasAssignments); + SET_EXCEPTION_LOCATION(node, start, divot, end); + return node; + } else + return new ReadModifyResolveNode(GLOBAL_DATA, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); + } + if (loc->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc); + if (op == OpEqual) + return new AssignBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot()); + else { + ReadModifyBracketNode* node = new ReadModifyBracketNode(GLOBAL_DATA, 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 AssignDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot()); + + ReadModifyDotNode* node = new ReadModifyDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->endOffset()); + return node; +} + +static ExpressionNode* makePrefixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end) +{ + if (!expr->isLocation()) + return new PrefixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); + + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new PrefixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + PrefixBracketNode* node = new PrefixBracketNode(GLOBAL_DATA, 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 PrefixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->startOffset()); + return node; +} + +static ExpressionNode* makePostfixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end) +{ + if (!expr->isLocation()) + return new PostfixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); + + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new PostfixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + PostfixBracketNode* node = new PostfixBracketNode(GLOBAL_DATA, 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 PostfixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->endOffset()); + return node; +} + +static ExpressionNodeInfo makeFunctionCallNode(void* globalPtr, ExpressionNodeInfo func, ArgumentsNodeInfo args, int start, int divot, int end) +{ + CodeFeatures features = func.m_features | args.m_features; + int numConstants = func.m_numConstants + args.m_numConstants; + if (!func.m_node->isLocation()) + return createNodeInfo<ExpressionNode*>(new FunctionCallValueNode(GLOBAL_DATA, func.m_node, args.m_node, divot, divot - start, end - divot), features, numConstants); + if (func.m_node->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(func.m_node); + const Identifier& identifier = resolve->identifier(); + if (identifier == GLOBAL_DATA->propertyNames->eval) + return createNodeInfo<ExpressionNode*>(new EvalFunctionCallNode(GLOBAL_DATA, args.m_node, divot, divot - start, end - divot), EvalFeature | features, numConstants); + return createNodeInfo<ExpressionNode*>(new FunctionCallResolveNode(GLOBAL_DATA, identifier, args.m_node, divot, divot - start, end - divot), features, numConstants); + } + if (func.m_node->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func.m_node); + FunctionCallBracketNode* node = new FunctionCallBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), args.m_node, divot, divot - start, end - divot); + node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); + return createNodeInfo<ExpressionNode*>(node, features, numConstants); + } + ASSERT(func.m_node->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(func.m_node); + FunctionCallDotNode* node = new FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); + node->setSubexpressionInfo(dot->divot(), dot->endOffset()); + return createNodeInfo<ExpressionNode*>(node, features, numConstants); +} + +static ExpressionNode* makeTypeOfNode(void* globalPtr, ExpressionNode* expr) +{ + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new TypeOfResolveNode(GLOBAL_DATA, resolve->identifier()); + } + return new TypeOfValueNode(GLOBAL_DATA, expr); +} + +static ExpressionNode* makeDeleteNode(void* globalPtr, ExpressionNode* expr, int start, int divot, int end) +{ + if (!expr->isLocation()) + return new DeleteValueNode(GLOBAL_DATA, expr); + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new DeleteResolveNode(GLOBAL_DATA, resolve->identifier(), divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + return new DeleteBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), divot, divot - start, end - divot); + } + ASSERT(expr->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); + return new DeleteDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), divot, divot - start, end - divot); +} + +static PropertyNode* makeGetterOrSetterPropertyNode(void* globalPtr, const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body, const SourceCode& source) +{ + PropertyNode::Type type; + if (getOrSet == "get") + type = PropertyNode::Getter; + else if (getOrSet == "set") + type = PropertyNode::Setter; + else + return 0; + return new PropertyNode(GLOBAL_DATA, name, new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, body, source, params), type); +} + +static ExpressionNode* makeNegateNode(void* globalPtr, ExpressionNode* n) +{ + if (n->isNumber()) { + NumberNode* number = static_cast<NumberNode*>(n); + + if (number->value() > 0.0) { + number->setValue(-number->value()); + return number; + } + } + + return new NegateNode(GLOBAL_DATA, n); +} + +static NumberNode* makeNumberNode(void* globalPtr, double d) +{ + return new NumberNode(GLOBAL_DATA, d); +} + +static ExpressionNode* makeBitwiseNotNode(void* globalPtr, ExpressionNode* expr) +{ + if (expr->isNumber()) + return makeNumberNode(globalPtr, ~toInt32(static_cast<NumberNode*>(expr)->value())); + return new BitwiseNotNode(GLOBAL_DATA, expr); +} + +static ExpressionNode* makeMultNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + expr1 = expr1->stripUnaryPlus(); + expr2 = expr2->stripUnaryPlus(); + + if (expr1->isNumber() && expr2->isNumber()) + return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value()); + + if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1) + return new UnaryPlusNode(GLOBAL_DATA, expr2); + + if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1) + return new UnaryPlusNode(GLOBAL_DATA, expr1); + + return new MultNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); +} + +static ExpressionNode* makeDivNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + expr1 = expr1->stripUnaryPlus(); + expr2 = expr2->stripUnaryPlus(); + + if (expr1->isNumber() && expr2->isNumber()) + return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value()); + return new DivNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); +} + +static ExpressionNode* makeAddNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + if (expr1->isNumber() && expr2->isNumber()) + return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value()); + return new AddNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); +} + +static ExpressionNode* makeSubNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + expr1 = expr1->stripUnaryPlus(); + expr2 = expr2->stripUnaryPlus(); + + if (expr1->isNumber() && expr2->isNumber()) + return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value()); + return new SubNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); +} + +static ExpressionNode* makeLeftShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + if (expr1->isNumber() && expr2->isNumber()) + return makeNumberNode(globalPtr, toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); + return new LeftShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); +} + +static ExpressionNode* makeRightShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +{ + if (expr1->isNumber() && expr2->isNumber()) + return makeNumberNode(globalPtr, toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); + return new RightShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); +} + +/* called by yyparse on error */ +int yyerror(const char *) +{ + return 1; +} + +/* may we automatically insert a semicolon ? */ +static bool allowAutomaticSemicolon(Lexer& lexer, int yychar) +{ + return yychar == CLOSEBRACE || yychar == 0 || lexer.prevTerminator(); +} + +static ExpressionNode* combineVarInitializers(void* globalPtr, ExpressionNode* list, AssignResolveNode* init) +{ + if (!list) + return init; + return new VarDeclCommaNode(GLOBAL_DATA, list, init); +} + +// We turn variable declarations into either assignments or empty +// statements (which later get stripped out), because the actual +// declaration work is hoisted up to the start of the function body +static StatementNode* makeVarStatementNode(void* globalPtr, ExpressionNode* expr) +{ + if (!expr) + return new EmptyStatementNode(GLOBAL_DATA); + return new VarStatementNode(GLOBAL_DATA, expr); +} + +#undef GLOBAL_DATA diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/Keywords.table b/src/3rdparty/webkit/JavaScriptCore/parser/Keywords.table new file mode 100644 index 0000000..490c1cc --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Keywords.table @@ -0,0 +1,72 @@ +# main keywords +@begin mainTable 41 + +# types +null NULLTOKEN +true TRUETOKEN +false FALSETOKEN + +# keywords +break BREAK +case CASE +catch CATCH +const CONSTTOKEN +default DEFAULT +finally FINALLY +for FOR +instanceof INSTANCEOF +new NEW +var VAR +continue CONTINUE +function FUNCTION +return RETURN +void VOIDTOKEN +delete DELETETOKEN +if IF +this THISTOKEN +do DO +while WHILE +else ELSE +in INTOKEN +switch SWITCH +throw THROW +try TRY +typeof TYPEOF +with WITH +debugger DEBUGGER + +# reserved for future use +class RESERVED +enum RESERVED +export RESERVED +extends RESERVED +import RESERVED +super RESERVED + +# these words are reserved for future use in the ECMA spec, but not in WinIE +# (see http://bugs.webkit.org/show_bug.cgi?id=6179) +# abstract RESERVED +# boolean RESERVED +# byte RESERVED +# char RESERVED +# double RESERVED +# final RESERVED +# float RESERVED +# goto RESERVED +# implements RESERVED +# int RESERVED +# interface RESERVED +# long RESERVED +# native RESERVED +# package RESERVED +# private RESERVED +# protected RESERVED +# public RESERVED +# short RESERVED +# static RESERVED +# synchronized RESERVED +# throws RESERVED +# transient RESERVED +# volatile RESERVED +@end + diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/Lexer.cpp b/src/3rdparty/webkit/JavaScriptCore/parser/Lexer.cpp new file mode 100644 index 0000000..0bacb22 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Lexer.cpp @@ -0,0 +1,900 @@ +/* + * 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) + * + * 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 "NodeInfo.h" +#include "Nodes.h" +#include "dtoa.h" +#include <ctype.h> +#include <limits.h> +#include <string.h> +#include <wtf/ASCIICType.h> +#include <wtf/Assertions.h> +#include <wtf/unicode/Unicode.h> + +using namespace WTF; +using namespace Unicode; + +// we can't specify the namespace in yacc's C output, so do it here +using namespace JSC; + +#ifndef KDE_USE_FINAL +#include "Grammar.h" +#endif + +#include "Lookup.h" +#include "Lexer.lut.h" + +// a bridge for yacc from the C world to C++ +int jscyylex(void* lvalp, void* llocp, void* globalData) +{ + return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp); +} + +namespace JSC { + +static bool isDecimalDigit(int); + +Lexer::Lexer(JSGlobalData* globalData) + : yylineno(1) + , m_restrKeyword(false) + , m_eatNextIdentifier(false) + , m_stackToken(-1) + , m_lastToken(-1) + , m_position(0) + , m_code(0) + , m_length(0) + , m_isReparsing(false) + , m_atLineStart(true) + , m_current(0) + , m_next1(0) + , m_next2(0) + , m_next3(0) + , m_currentOffset(0) + , m_nextOffset1(0) + , m_nextOffset2(0) + , m_nextOffset3(0) + , m_globalData(globalData) + , m_mainTable(JSC::mainTable) +{ + m_buffer8.reserveCapacity(initialReadBufferCapacity); + m_buffer16.reserveCapacity(initialReadBufferCapacity); +} + +Lexer::~Lexer() +{ + m_mainTable.deleteTable(); +} + +void Lexer::setCode(const SourceCode& source) +{ + yylineno = source.firstLine(); + m_restrKeyword = false; + m_delimited = false; + m_eatNextIdentifier = false; + m_stackToken = -1; + m_lastToken = -1; + + m_position = source.startOffset(); + m_source = &source; + m_code = source.provider()->data(); + m_length = source.endOffset(); + m_skipLF = false; + m_skipCR = false; + m_error = false; + m_atLineStart = true; + + // read first characters + shift(4); +} + +void Lexer::shift(unsigned p) +{ + // ECMA-262 calls for stripping Cf characters here, but we only do this for BOM, + // see <https://bugs.webkit.org/show_bug.cgi?id=4931>. + + while (p--) { + m_current = m_next1; + m_next1 = m_next2; + m_next2 = m_next3; + m_currentOffset = m_nextOffset1; + m_nextOffset1 = m_nextOffset2; + m_nextOffset2 = m_nextOffset3; + do { + if (m_position >= m_length) { + m_nextOffset3 = m_position; + m_position++; + m_next3 = -1; + break; + } + m_nextOffset3 = m_position; + m_next3 = m_code[m_position++]; + } while (m_next3 == 0xFEFF); + } +} + +// called on each new line +void Lexer::nextLine() +{ + yylineno++; + m_atLineStart = true; +} + +void Lexer::setDone(State s) +{ + m_state = s; + m_done = true; +} + +int Lexer::lex(void* p1, void* p2) +{ + YYSTYPE* lvalp = static_cast<YYSTYPE*>(p1); + YYLTYPE* llocp = static_cast<YYLTYPE*>(p2); + int token = 0; + m_state = Start; + unsigned short stringType = 0; // either single or double quotes + m_buffer8.clear(); + m_buffer16.clear(); + m_done = false; + m_terminator = false; + m_skipLF = false; + m_skipCR = false; + + // did we push a token on the stack previously ? + // (after an automatic semicolon insertion) + if (m_stackToken >= 0) { + setDone(Other); + token = m_stackToken; + m_stackToken = 0; + } + int startOffset = m_currentOffset; + while (!m_done) { + if (m_skipLF && m_current != '\n') // found \r but not \n afterwards + m_skipLF = false; + if (m_skipCR && m_current != '\r') // found \n but not \r afterwards + m_skipCR = false; + if (m_skipLF || m_skipCR) { // found \r\n or \n\r -> eat the second one + m_skipLF = false; + m_skipCR = false; + shift(1); + } + switch (m_state) { + case Start: + startOffset = m_currentOffset; + if (isWhiteSpace()) { + // do nothing + } else if (m_current == '/' && m_next1 == '/') { + shift(1); + m_state = InSingleLineComment; + } else if (m_current == '/' && m_next1 == '*') { + shift(1); + m_state = InMultiLineComment; + } else if (m_current == -1) { + if (!m_terminator && !m_delimited && !m_isReparsing) { + // automatic semicolon insertion if program incomplete + token = ';'; + m_stackToken = 0; + setDone(Other); + } else + setDone(Eof); + } else if (isLineTerminator()) { + nextLine(); + m_terminator = true; + if (m_restrKeyword) { + token = ';'; + setDone(Other); + } + } else if (m_current == '"' || m_current == '\'') { + m_state = InString; + stringType = static_cast<unsigned short>(m_current); + } else if (isIdentStart(m_current)) { + record16(m_current); + m_state = InIdentifierOrKeyword; + } else if (m_current == '\\') + m_state = InIdentifierStartUnicodeEscapeStart; + else if (m_current == '0') { + record8(m_current); + m_state = InNum0; + } else if (isDecimalDigit(m_current)) { + record8(m_current); + m_state = InNum; + } else if (m_current == '.' && isDecimalDigit(m_next1)) { + record8(m_current); + m_state = InDecimal; + // <!-- marks the beginning of a line comment (for www usage) + } else if (m_current == '<' && m_next1 == '!' && m_next2 == '-' && m_next3 == '-') { + shift(3); + m_state = InSingleLineComment; + // same for --> + } else if (m_atLineStart && m_current == '-' && m_next1 == '-' && m_next2 == '>') { + shift(2); + m_state = InSingleLineComment; + } else { + token = matchPunctuator(lvalp->intValue, m_current, m_next1, m_next2, m_next3); + if (token != -1) + setDone(Other); + else + setDone(Bad); + } + break; + case InString: + if (m_current == stringType) { + shift(1); + setDone(String); + } else if (isLineTerminator() || m_current == -1) + setDone(Bad); + else if (m_current == '\\') + m_state = InEscapeSequence; + else + record16(m_current); + break; + // Escape Sequences inside of strings + case InEscapeSequence: + if (isOctalDigit(m_current)) { + if (m_current >= '0' && m_current <= '3' && + isOctalDigit(m_next1) && isOctalDigit(m_next2)) { + record16(convertOctal(m_current, m_next1, m_next2)); + shift(2); + m_state = InString; + } else if (isOctalDigit(m_current) && isOctalDigit(m_next1)) { + record16(convertOctal('0', m_current, m_next1)); + shift(1); + m_state = InString; + } else if (isOctalDigit(m_current)) { + record16(convertOctal('0', '0', m_current)); + m_state = InString; + } else + setDone(Bad); + } else if (m_current == 'x') + m_state = InHexEscape; + else if (m_current == 'u') + m_state = InUnicodeEscape; + else if (isLineTerminator()) { + nextLine(); + m_state = InString; + } else { + record16(singleEscape(static_cast<unsigned short>(m_current))); + m_state = InString; + } + break; + case InHexEscape: + if (isHexDigit(m_current) && isHexDigit(m_next1)) { + m_state = InString; + record16(convertHex(m_current, m_next1)); + shift(1); + } else if (m_current == stringType) { + record16('x'); + shift(1); + setDone(String); + } else { + record16('x'); + record16(m_current); + m_state = InString; + } + break; + case InUnicodeEscape: + if (isHexDigit(m_current) && isHexDigit(m_next1) && isHexDigit(m_next2) && isHexDigit(m_next3)) { + record16(convertUnicode(m_current, m_next1, m_next2, m_next3)); + shift(3); + m_state = InString; + } else if (m_current == stringType) { + record16('u'); + shift(1); + setDone(String); + } else + setDone(Bad); + break; + case InSingleLineComment: + if (isLineTerminator()) { + nextLine(); + m_terminator = true; + if (m_restrKeyword) { + token = ';'; + setDone(Other); + } else + m_state = Start; + } else if (m_current == -1) + setDone(Eof); + break; + case InMultiLineComment: + if (m_current == -1) + setDone(Bad); + else if (isLineTerminator()) + nextLine(); + else if (m_current == '*' && m_next1 == '/') { + m_state = Start; + shift(1); + } + break; + case InIdentifierOrKeyword: + case InIdentifier: + if (isIdentPart(m_current)) + record16(m_current); + else if (m_current == '\\') + m_state = InIdentifierPartUnicodeEscapeStart; + else + setDone(m_state == InIdentifierOrKeyword ? IdentifierOrKeyword : Identifier); + break; + case InNum0: + if (m_current == 'x' || m_current == 'X') { + record8(m_current); + m_state = InHex; + } else if (m_current == '.') { + record8(m_current); + m_state = InDecimal; + } else if (m_current == 'e' || m_current == 'E') { + record8(m_current); + m_state = InExponentIndicator; + } else if (isOctalDigit(m_current)) { + record8(m_current); + m_state = InOctal; + } else if (isDecimalDigit(m_current)) { + record8(m_current); + m_state = InDecimal; + } else + setDone(Number); + break; + case InHex: + if (isHexDigit(m_current)) + record8(m_current); + else + setDone(Hex); + break; + case InOctal: + if (isOctalDigit(m_current)) + record8(m_current); + else if (isDecimalDigit(m_current)) { + record8(m_current); + m_state = InDecimal; + } else + setDone(Octal); + break; + case InNum: + if (isDecimalDigit(m_current)) + record8(m_current); + else if (m_current == '.') { + record8(m_current); + m_state = InDecimal; + } else if (m_current == 'e' || m_current == 'E') { + record8(m_current); + m_state = InExponentIndicator; + } else + setDone(Number); + break; + case InDecimal: + if (isDecimalDigit(m_current)) + record8(m_current); + else if (m_current == 'e' || m_current == 'E') { + record8(m_current); + m_state = InExponentIndicator; + } else + setDone(Number); + break; + case InExponentIndicator: + if (m_current == '+' || m_current == '-') + record8(m_current); + else if (isDecimalDigit(m_current)) { + record8(m_current); + m_state = InExponent; + } else + setDone(Bad); + break; + case InExponent: + if (isDecimalDigit(m_current)) + record8(m_current); + else + setDone(Number); + break; + case InIdentifierStartUnicodeEscapeStart: + if (m_current == 'u') + m_state = InIdentifierStartUnicodeEscape; + else + setDone(Bad); + break; + case InIdentifierPartUnicodeEscapeStart: + if (m_current == 'u') + m_state = InIdentifierPartUnicodeEscape; + else + setDone(Bad); + break; + case InIdentifierStartUnicodeEscape: + if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) { + setDone(Bad); + break; + } + token = convertUnicode(m_current, m_next1, m_next2, m_next3); + shift(3); + if (!isIdentStart(token)) { + setDone(Bad); + break; + } + record16(token); + m_state = InIdentifier; + break; + case InIdentifierPartUnicodeEscape: + if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) { + setDone(Bad); + break; + } + token = convertUnicode(m_current, m_next1, m_next2, m_next3); + shift(3); + if (!isIdentPart(token)) { + setDone(Bad); + break; + } + record16(token); + m_state = InIdentifier; + break; + default: + ASSERT(!"Unhandled state in switch statement"); + } + + // move on to the next character + if (!m_done) + shift(1); + if (m_state != Start && m_state != InSingleLineComment) + m_atLineStart = false; + } + + // no identifiers allowed directly after numeric literal, e.g. "3in" is bad + if ((m_state == Number || m_state == Octal || m_state == Hex) && isIdentStart(m_current)) + m_state = Bad; + + // terminate string + m_buffer8.append('\0'); + +#ifdef JSC_DEBUG_LEX + fprintf(stderr, "line: %d ", lineNo()); + fprintf(stderr, "yytext (%x): ", m_buffer8[0]); + fprintf(stderr, "%s ", m_buffer8.data()); +#endif + + double dval = 0; + if (m_state == Number) + dval = WTF::strtod(m_buffer8.data(), 0L); + else if (m_state == Hex) { // scan hex numbers + const char* p = m_buffer8.data() + 2; + while (char c = *p++) { + dval *= 16; + dval += convertHex(c); + } + + if (dval >= mantissaOverflowLowerBound) + dval = parseIntOverflow(m_buffer8.data() + 2, p - (m_buffer8.data() + 3), 16); + + m_state = Number; + } else if (m_state == Octal) { // scan octal number + const char* p = m_buffer8.data() + 1; + while (char c = *p++) { + dval *= 8; + dval += c - '0'; + } + + if (dval >= mantissaOverflowLowerBound) + dval = parseIntOverflow(m_buffer8.data() + 1, p - (m_buffer8.data() + 2), 8); + + m_state = Number; + } + +#ifdef JSC_DEBUG_LEX + switch (m_state) { + case Eof: + printf("(EOF)\n"); + break; + case Other: + printf("(Other)\n"); + break; + case Identifier: + printf("(Identifier)/(Keyword)\n"); + break; + case String: + printf("(String)\n"); + break; + case Number: + printf("(Number)\n"); + break; + default: + printf("(unknown)"); + } +#endif + + if (m_state != Identifier) + m_eatNextIdentifier = false; + + m_restrKeyword = false; + m_delimited = false; + llocp->first_line = yylineno; + llocp->last_line = yylineno; + llocp->first_column = startOffset; + llocp->last_column = m_currentOffset; + switch (m_state) { + case Eof: + token = 0; + break; + case Other: + if (token == '}' || token == ';') + m_delimited = true; + break; + case Identifier: + // Apply anonymous-function hack below (eat the identifier). + if (m_eatNextIdentifier) { + m_eatNextIdentifier = false; + token = lex(lvalp, llocp); + break; + } + lvalp->ident = makeIdentifier(m_buffer16); + token = IDENT; + break; + case IdentifierOrKeyword: { + lvalp->ident = makeIdentifier(m_buffer16); + const HashEntry* entry = m_mainTable.entry(m_globalData, *lvalp->ident); + if (!entry) { + // Lookup for keyword failed, means this is an identifier. + token = IDENT; + break; + } + token = entry->lexerValue(); + // Hack for "f = function somename() { ... }"; too hard to get into the grammar. + m_eatNextIdentifier = token == FUNCTION && m_lastToken == '='; + if (token == CONTINUE || token == BREAK || token == RETURN || token == THROW) + m_restrKeyword = true; + break; + } + case String: + // Atomize constant strings in case they're later used in property lookup. + lvalp->ident = makeIdentifier(m_buffer16); + token = STRING; + break; + case Number: + lvalp->doubleValue = dval; + token = NUMBER; + break; + case Bad: +#ifdef JSC_DEBUG_LEX + fprintf(stderr, "yylex: ERROR.\n"); +#endif + m_error = true; + return -1; + default: + ASSERT(!"unhandled numeration value in switch"); + m_error = true; + return -1; + } + m_lastToken = token; + return token; +} + +bool Lexer::isWhiteSpace() const +{ + return m_current == '\t' || m_current == 0x0b || m_current == 0x0c || isSeparatorSpace(m_current); +} + +bool Lexer::isLineTerminator() +{ + bool cr = (m_current == '\r'); + bool lf = (m_current == '\n'); + if (cr) + m_skipLF = true; + else if (lf) + m_skipCR = true; + return cr || lf || m_current == 0x2028 || m_current == 0x2029; +} + +bool Lexer::isIdentStart(int c) +{ + return isASCIIAlpha(c) || c == '$' || c == '_' || (!isASCII(c) && (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other))); +} + +bool Lexer::isIdentPart(int c) +{ + return isASCIIAlphanumeric(c) || c == '$' || c == '_' || (!isASCII(c) && (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other + | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector))); +} + +static bool isDecimalDigit(int c) +{ + return isASCIIDigit(c); +} + +bool Lexer::isHexDigit(int c) +{ + return isASCIIHexDigit(c); +} + +bool Lexer::isOctalDigit(int c) +{ + return isASCIIOctalDigit(c); +} + +int Lexer::matchPunctuator(int& charPos, int c1, int c2, int c3, int c4) +{ + if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') { + shift(4); + return URSHIFTEQUAL; + } + if (c1 == '=' && c2 == '=' && c3 == '=') { + shift(3); + return STREQ; + } + if (c1 == '!' && c2 == '=' && c3 == '=') { + shift(3); + return STRNEQ; + } + if (c1 == '>' && c2 == '>' && c3 == '>') { + shift(3); + return URSHIFT; + } + if (c1 == '<' && c2 == '<' && c3 == '=') { + shift(3); + return LSHIFTEQUAL; + } + if (c1 == '>' && c2 == '>' && c3 == '=') { + shift(3); + return RSHIFTEQUAL; + } + if (c1 == '<' && c2 == '=') { + shift(2); + return LE; + } + if (c1 == '>' && c2 == '=') { + shift(2); + return GE; + } + if (c1 == '!' && c2 == '=') { + shift(2); + return NE; + } + if (c1 == '+' && c2 == '+') { + shift(2); + if (m_terminator) + return AUTOPLUSPLUS; + return PLUSPLUS; + } + if (c1 == '-' && c2 == '-') { + shift(2); + if (m_terminator) + return AUTOMINUSMINUS; + return MINUSMINUS; + } + if (c1 == '=' && c2 == '=') { + shift(2); + return EQEQ; + } + if (c1 == '+' && c2 == '=') { + shift(2); + return PLUSEQUAL; + } + if (c1 == '-' && c2 == '=') { + shift(2); + return MINUSEQUAL; + } + if (c1 == '*' && c2 == '=') { + shift(2); + return MULTEQUAL; + } + if (c1 == '/' && c2 == '=') { + shift(2); + return DIVEQUAL; + } + if (c1 == '&' && c2 == '=') { + shift(2); + return ANDEQUAL; + } + if (c1 == '^' && c2 == '=') { + shift(2); + return XOREQUAL; + } + if (c1 == '%' && c2 == '=') { + shift(2); + return MODEQUAL; + } + if (c1 == '|' && c2 == '=') { + shift(2); + return OREQUAL; + } + if (c1 == '<' && c2 == '<') { + shift(2); + return LSHIFT; + } + if (c1 == '>' && c2 == '>') { + shift(2); + return RSHIFT; + } + if (c1 == '&' && c2 == '&') { + shift(2); + return AND; + } + if (c1 == '|' && c2 == '|') { + shift(2); + return OR; + } + + switch (c1) { + case '=': + case '>': + case '<': + case ',': + case '!': + case '~': + case '?': + case ':': + case '.': + case '+': + case '-': + case '*': + case '/': + case '&': + case '|': + case '^': + case '%': + case '(': + case ')': + case '[': + case ']': + case ';': + shift(1); + return static_cast<int>(c1); + case '{': + charPos = m_position - 4; + shift(1); + return OPENBRACE; + case '}': + charPos = m_position - 4; + shift(1); + return CLOSEBRACE; + default: + return -1; + } +} + +unsigned short Lexer::singleEscape(unsigned short 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 0x22; + case '\'': + return 0x27; + case '\\': + return 0x5C; + default: + return c; + } +} + +unsigned short Lexer::convertOctal(int c1, int c2, int c3) +{ + return static_cast<unsigned short>((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0'); +} + +unsigned char Lexer::convertHex(int c) +{ + if (c >= '0' && c <= '9') + return static_cast<unsigned char>(c - '0'); + if (c >= 'a' && c <= 'f') + return static_cast<unsigned char>(c - 'a' + 10); + return static_cast<unsigned char>(c - 'A' + 10); +} + +unsigned char Lexer::convertHex(int c1, int c2) +{ + return ((convertHex(c1) << 4) + convertHex(c2)); +} + +UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4) +{ + unsigned char highByte = (convertHex(c1) << 4) + convertHex(c2); + unsigned char lowByte = (convertHex(c3) << 4) + convertHex(c4); + return (highByte << 8 | lowByte); +} + +void Lexer::record8(int c) +{ + ASSERT(c >= 0); + ASSERT(c <= 0xff); + m_buffer8.append(static_cast<char>(c)); +} + +void Lexer::record16(int c) +{ + ASSERT(c >= 0); + ASSERT(c <= USHRT_MAX); + record16(UChar(static_cast<unsigned short>(c))); +} + +void Lexer::record16(UChar c) +{ + m_buffer16.append(c); +} + +bool Lexer::scanRegExp() +{ + m_buffer16.clear(); + bool lastWasEscape = false; + bool inBrackets = false; + + while (1) { + if (isLineTerminator() || m_current == -1) + return false; + else if (m_current != '/' || lastWasEscape == true || inBrackets == true) { + // keep track of '[' and ']' + if (!lastWasEscape) { + if ( m_current == '[' && !inBrackets ) + inBrackets = true; + if ( m_current == ']' && inBrackets ) + inBrackets = false; + } + record16(m_current); + lastWasEscape = + !lastWasEscape && (m_current == '\\'); + } else { // end of regexp + m_pattern = UString(m_buffer16); + m_buffer16.clear(); + shift(1); + break; + } + shift(1); + } + + while (isIdentPart(m_current)) { + record16(m_current); + shift(1); + } + m_flags = UString(m_buffer16); + + return true; +} + +void Lexer::clear() +{ + m_identifiers.clear(); + + Vector<char> newBuffer8; + newBuffer8.reserveCapacity(initialReadBufferCapacity); + m_buffer8.swap(newBuffer8); + + Vector<UChar> newBuffer16; + newBuffer16.reserveCapacity(initialReadBufferCapacity); + m_buffer16.swap(newBuffer16); + + m_isReparsing = false; + + m_pattern = 0; + m_flags = 0; +} + +} // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/Lexer.h b/src/3rdparty/webkit/JavaScriptCore/parser/Lexer.h new file mode 100644 index 0000000..cb553af --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Lexer.h @@ -0,0 +1,171 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008 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 Lexer_h +#define Lexer_h + +#include "Identifier.h" +#include "Lookup.h" +#include "SegmentedVector.h" +#include "SourceCode.h" +#include <wtf/Vector.h> + +namespace JSC { + + class RegExp; + + class Lexer : Noncopyable { + public: + void setCode(const SourceCode&); + void setIsReparsing() { m_isReparsing = true; } + int lex(void* lvalp, void* llocp); + + int lineNo() const { return yylineno; } + + bool prevTerminator() const { return m_terminator; } + + enum State { + Start, + IdentifierOrKeyword, + Identifier, + InIdentifierOrKeyword, + InIdentifier, + InIdentifierStartUnicodeEscapeStart, + InIdentifierStartUnicodeEscape, + InIdentifierPartUnicodeEscapeStart, + InIdentifierPartUnicodeEscape, + InSingleLineComment, + InMultiLineComment, + InNum, + InNum0, + InHex, + InOctal, + InDecimal, + InExponentIndicator, + InExponent, + Hex, + Octal, + Number, + String, + Eof, + InString, + InEscapeSequence, + InHexEscape, + InUnicodeEscape, + Other, + Bad + }; + + bool scanRegExp(); + const UString& pattern() const { return m_pattern; } + const UString& flags() const { return m_flags; } + + static unsigned char convertHex(int); + static unsigned char convertHex(int c1, int c2); + static UChar convertUnicode(int c1, int c2, int c3, int c4); + static bool isIdentStart(int); + static bool isIdentPart(int); + static bool isHexDigit(int); + + bool sawError() const { return m_error; } + + void clear(); + SourceCode sourceCode(int openBrace, int closeBrace, int firstLine) { return SourceCode(m_source->provider(), openBrace + 1, closeBrace, firstLine); } + + private: + friend class JSGlobalData; + Lexer(JSGlobalData*); + ~Lexer(); + + void setDone(State); + void shift(unsigned int p); + void nextLine(); + int lookupKeyword(const char *); + + bool isWhiteSpace() const; + bool isLineTerminator(); + static bool isOctalDigit(int); + + int matchPunctuator(int& charPos, int c1, int c2, int c3, int c4); + static unsigned short singleEscape(unsigned short); + static unsigned short convertOctal(int c1, int c2, int c3); + + void record8(int); + void record16(int); + void record16(UChar); + + JSC::Identifier* makeIdentifier(const Vector<UChar>& buffer) + { + m_identifiers.append(JSC::Identifier(m_globalData, buffer.data(), buffer.size())); + return &m_identifiers.last(); + } + + static const size_t initialReadBufferCapacity = 32; + static const size_t initialIdentifierTableCapacity = 64; + + int yylineno; + int yycolumn; + + bool m_done; + Vector<char> m_buffer8; + Vector<UChar> m_buffer16; + bool m_terminator; + bool m_restrKeyword; + bool m_delimited; // encountered delimiter like "'" and "}" on last run + bool m_skipLF; + bool m_skipCR; + bool m_eatNextIdentifier; + int m_stackToken; + int m_lastToken; + + State m_state; + unsigned int m_position; + const SourceCode* m_source; + const UChar* m_code; + unsigned int m_length; + bool m_isReparsing; + int m_atLineStart; + bool m_error; + + // current and following unicode characters (int to allow for -1 for end-of-file marker) + int m_current; + int m_next1; + int m_next2; + int m_next3; + + int m_currentOffset; + int m_nextOffset1; + int m_nextOffset2; + int m_nextOffset3; + + SegmentedVector<JSC::Identifier, initialIdentifierTableCapacity> m_identifiers; + + JSGlobalData* m_globalData; + + UString m_pattern; + UString m_flags; + + const HashTable m_mainTable; + }; + +} // namespace JSC + +#endif // Lexer_h diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/NodeInfo.h b/src/3rdparty/webkit/JavaScriptCore/parser/NodeInfo.h new file mode 100644 index 0000000..a518b23 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/NodeInfo.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef NodeInfo_h +#define NodeInfo_h + +#include "Nodes.h" +#include "Parser.h" + +namespace JSC { + + template <typename T> struct NodeInfo { + T m_node; + CodeFeatures m_features; + int m_numConstants; + }; + + typedef NodeInfo<FuncDeclNode*> FuncDeclNodeInfo; + typedef NodeInfo<FuncExprNode*> FuncExprNodeInfo; + typedef NodeInfo<ExpressionNode*> ExpressionNodeInfo; + typedef NodeInfo<ArgumentsNode*> ArgumentsNodeInfo; + typedef NodeInfo<ConstDeclNode*> ConstDeclNodeInfo; + typedef NodeInfo<PropertyNode*> PropertyNodeInfo; + typedef NodeInfo<PropertyList> PropertyListInfo; + typedef NodeInfo<ElementList> ElementListInfo; + typedef NodeInfo<ArgumentList> ArgumentListInfo; + + template <typename T> struct NodeDeclarationInfo { + T m_node; + ParserRefCountedData<DeclarationStacks::VarStack>* m_varDeclarations; + ParserRefCountedData<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/src/3rdparty/webkit/JavaScriptCore/parser/Nodes.cpp b/src/3rdparty/webkit/JavaScriptCore/parser/Nodes.cpp new file mode 100644 index 0000000..bdc5d2f --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Nodes.cpp @@ -0,0 +1,2721 @@ +/* +* 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 "BytecodeGenerator.h" +#include "CallFrame.h" +#include "JSGlobalObject.h" +#include "JSStaticScopeObject.h" +#include "LabelScope.h" +#include "Parser.h" +#include "PropertyNameArray.h" +#include "RegExpObject.h" +#include "SamplingTool.h" +#include "Debugger.h" +#include "Lexer.h" +#include "Operations.h" +#include <math.h> +#include <wtf/Assertions.h> +#include <wtf/HashCountedSet.h> +#include <wtf/HashSet.h> +#include <wtf/MathExtras.h> +#include <wtf/RefCountedLeakCounter.h> +#include <wtf/Threading.h> + +using namespace WTF; + +namespace JSC { + +static void substitute(UString& string, const UString& substring) JSC_FAST_CALL; + +// ------------------------------ NodeReleaser -------------------------------- + +class NodeReleaser : Noncopyable { +public: + // Call this function inside the destructor of a class derived from Node. + // This will traverse the tree below this node, destroying all of those nodes, + // but without relying on recursion. + static void releaseAllNodes(ParserRefCounted* root); + + // Call this on each node in a the releaseNodes virtual function. + // It gives the node to the NodeReleaser, which will then release the + // node later at the end of the releaseAllNodes process. + template <typename T> void release(RefPtr<T>& node) { if (node) adopt(node.release()); } + void release(RefPtr<FunctionBodyNode>& node) { if (node) adoptFunctionBodyNode(node); } + +private: + NodeReleaser() { } + ~NodeReleaser() { } + + void adopt(PassRefPtr<ParserRefCounted>); + void adoptFunctionBodyNode(RefPtr<FunctionBodyNode>&); + + typedef Vector<RefPtr<ParserRefCounted> > NodeReleaseVector; + OwnPtr<NodeReleaseVector> m_vector; +}; + +void NodeReleaser::releaseAllNodes(ParserRefCounted* root) +{ + ASSERT(root); + NodeReleaser releaser; + root->releaseNodes(releaser); + if (!releaser.m_vector) + return; + // Note: The call to release.m_vector->size() is intentionally inside + // the loop, since calls to releaseNodes are expected to increase the size. + for (size_t i = 0; i < releaser.m_vector->size(); ++i) { + ParserRefCounted* node = (*releaser.m_vector)[i].get(); + if (node->hasOneRef()) + node->releaseNodes(releaser); + } +} + +void NodeReleaser::adopt(PassRefPtr<ParserRefCounted> node) +{ + ASSERT(node); + if (!node->hasOneRef()) + return; + if (!m_vector) + m_vector.set(new NodeReleaseVector); + m_vector->append(node); +} + +void NodeReleaser::adoptFunctionBodyNode(RefPtr<FunctionBodyNode>& functionBodyNode) +{ + // This sidesteps a problem where if you assign a PassRefPtr<FunctionBodyNode> + // to a PassRefPtr<Node> we leave the two reference counts (FunctionBodyNode + // and ParserRefCounted) unbalanced. It would be nice to fix this problem in + // a cleaner way -- perhaps we could remove the FunctionBodyNode reference + // count at some point. + RefPtr<Node> node = functionBodyNode; + functionBodyNode = 0; + adopt(node.release()); +} + +// ------------------------------ ParserRefCounted ----------------------------------------- + +#ifndef NDEBUG +static RefCountedLeakCounter parserRefCountedCounter("JSC::Node"); +#endif + +ParserRefCounted::ParserRefCounted(JSGlobalData* globalData) + : m_globalData(globalData) +{ +#ifndef NDEBUG + parserRefCountedCounter.increment(); +#endif + if (!m_globalData->newParserObjects) + m_globalData->newParserObjects = new HashSet<ParserRefCounted*>; + m_globalData->newParserObjects->add(this); + ASSERT(m_globalData->newParserObjects->contains(this)); +} + +ParserRefCounted::~ParserRefCounted() +{ +#ifndef NDEBUG + parserRefCountedCounter.decrement(); +#endif +} + +void ParserRefCounted::releaseNodes(NodeReleaser&) +{ +} + +void ParserRefCounted::ref() +{ + // bumping from 0 to 1 is just removing from the new nodes set + if (m_globalData->newParserObjects) { + HashSet<ParserRefCounted*>::iterator it = m_globalData->newParserObjects->find(this); + if (it != m_globalData->newParserObjects->end()) { + m_globalData->newParserObjects->remove(it); + ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this)); + return; + } + } + + ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); + + if (!m_globalData->parserObjectExtraRefCounts) + m_globalData->parserObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>; + m_globalData->parserObjectExtraRefCounts->add(this); +} + +void ParserRefCounted::deref() +{ + ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); + + if (!m_globalData->parserObjectExtraRefCounts) { + delete this; + return; + } + + HashCountedSet<ParserRefCounted*>::iterator it = m_globalData->parserObjectExtraRefCounts->find(this); + if (it == m_globalData->parserObjectExtraRefCounts->end()) + delete this; + else + m_globalData->parserObjectExtraRefCounts->remove(it); +} + +bool ParserRefCounted::hasOneRef() +{ + if (m_globalData->newParserObjects && m_globalData->newParserObjects->contains(this)) { + ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this)); + return false; + } + + ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this)); + + if (!m_globalData->parserObjectExtraRefCounts) + return true; + + return !m_globalData->parserObjectExtraRefCounts->contains(this); +} + +void ParserRefCounted::deleteNewObjects(JSGlobalData* globalData) +{ + if (!globalData->newParserObjects) + return; + +#ifndef NDEBUG + HashSet<ParserRefCounted*>::iterator end = globalData->newParserObjects->end(); + for (HashSet<ParserRefCounted*>::iterator it = globalData->newParserObjects->begin(); it != end; ++it) + ASSERT(!globalData->parserObjectExtraRefCounts || !globalData->parserObjectExtraRefCounts->contains(*it)); +#endif + deleteAllValues(*globalData->newParserObjects); + delete globalData->newParserObjects; + globalData->newParserObjects = 0; +} + +// ------------------------------ Node -------------------------------- + +Node::Node(JSGlobalData* globalData) + : ParserRefCounted(globalData) +{ + m_line = globalData->lexer->lineNo(); +} + +// ------------------------------ ThrowableExpressionData -------------------------------- + +static void substitute(UString& string, const UString& substring) +{ + int position = string.find("%s"); + ASSERT(position != -1); + UString newString = string.substr(0, position); + newString.append(substring); + newString.append(string.substr(position + 2)); + string = newString; +} + +RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg) +{ + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), msg)); + generator.emitThrow(exception); + return exception; +} + +RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label) +{ + UString message = msg; + substitute(message, label.ustring()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), message)); + generator.emitThrow(exception); + return exception; +} + +// ------------------------------ StatementNode -------------------------------- + +StatementNode::StatementNode(JSGlobalData* globalData) + : Node(globalData) + , m_lastLine(-1) +{ +} + +void StatementNode::setLoc(int firstLine, int lastLine) +{ + m_line = firstLine; + m_lastLine = lastLine; +} + +// ------------------------------ SourceElements -------------------------------- + +void SourceElements::append(PassRefPtr<StatementNode> statement) +{ + if (statement->isEmptyStatement()) + return; + + m_statements.append(statement); +} + +// ------------------------------ NullNode ------------------------------------- + +RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, jsNull()); +} + +// ------------------------------ BooleanNode ---------------------------------- + +RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_value); +} + +// ------------------------------ NumberNode ----------------------------------- + +RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_double); +} + +// ------------------------------ StringNode ----------------------------------- + +RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_value); +} + +// ------------------------------ RegExpNode ----------------------------------- + +RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern, m_flags); + if (!regExp->isValid()) + return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(regExp->errorMessage())).UTF8String().c_str()); + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); +} + +// ------------------------------ ThisNode ------------------------------------- + +RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); +} + +// ------------------------------ ResolveNode ---------------------------------- + +bool ResolveNode::isPure(BytecodeGenerator& generator) const +{ + return generator.isLocal(m_ident); +} + +RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.moveToDestinationIfNeeded(dst, local); + } + + generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0); + return generator.emitResolve(generator.finalDestination(dst), m_ident); +} + +// ------------------------------ ElementNode ------------------------------------ + +ElementNode::~ElementNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ElementNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_next); + releaser.release(m_node); +} + +// ------------------------------ ArrayNode ------------------------------------ + +ArrayNode::~ArrayNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ArrayNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_element); +} + +RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + // FIXME: Should we put all of this code into emitNewArray? + + unsigned length = 0; + ElementNode* firstPutElement; + for (firstPutElement = m_element.get(); firstPutElement; firstPutElement = firstPutElement->next()) { + if (firstPutElement->elision()) + break; + ++length; + } + + if (!firstPutElement && !m_elision) + return generator.emitNewArray(generator.finalDestination(dst), m_element.get()); + + RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element.get()); + + for (ElementNode* n = firstPutElement; n; n = n->next()) { + RegisterID* value = generator.emitNode(n->value()); + length += n->elision(); + generator.emitPutByIndex(array.get(), length++, value); + } + + if (m_elision) { + RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); + generator.emitPutById(array.get(), generator.propertyNames().length, value); + } + + return generator.moveToDestinationIfNeeded(dst, array.get()); +} + +// ------------------------------ PropertyNode ---------------------------- + +PropertyNode::~PropertyNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PropertyNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_assign); +} + +// ------------------------------ ObjectLiteralNode ---------------------------- + +ObjectLiteralNode::~ObjectLiteralNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ObjectLiteralNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_list); +} + +RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (!m_list) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewObject(generator.finalDestination(dst)); + } + return generator.emitNode(dst, m_list.get()); +} + +// ------------------------------ PropertyListNode ----------------------------- + +PropertyListNode::~PropertyListNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PropertyListNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_node); + releaser.release(m_next); +} + +RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> newObj = generator.tempDestination(dst); + + generator.emitNewObject(newObj.get()); + + for (PropertyListNode* p = this; p; p = p->m_next.get()) { + RegisterID* value = generator.emitNode(p->m_node->m_assign.get()); + + switch (p->m_node->m_type) { + case PropertyNode::Constant: { + generator.emitPutById(newObj.get(), p->m_node->name(), value); + break; + } + case PropertyNode::Getter: { + generator.emitPutGetter(newObj.get(), p->m_node->name(), value); + break; + } + case PropertyNode::Setter: { + generator.emitPutSetter(newObj.get(), p->m_node->name(), value); + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + return generator.moveToDestinationIfNeeded(dst, newObj.get()); +} + +// ------------------------------ BracketAccessorNode -------------------------------- + +BracketAccessorNode::~BracketAccessorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void BracketAccessorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments, m_subscript->isPure(generator)); + RegisterID* property = generator.emitNode(m_subscript.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); +} + +// ------------------------------ DotAccessorNode -------------------------------- + +DotAccessorNode::~DotAccessorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DotAccessorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* base = generator.emitNode(m_base.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetById(generator.finalDestination(dst), base, m_ident); +} + +// ------------------------------ ArgumentListNode ----------------------------- + +ArgumentListNode::~ArgumentListNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ArgumentListNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_next); + releaser.release(m_expr); +} + +RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expr); + return generator.emitNode(dst, m_expr.get()); +} + +// ------------------------------ ArgumentsNode ----------------------------- + +ArgumentsNode::~ArgumentsNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ArgumentsNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_listNode); +} + +// ------------------------------ NewExprNode ---------------------------------- + +NewExprNode::~NewExprNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void NewExprNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); + releaser.release(m_args); +} + +RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.emitNode(m_expr.get()); + return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ EvalFunctionCallNode ---------------------------------- + +EvalFunctionCallNode::~EvalFunctionCallNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void EvalFunctionCallNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_args); +} + +RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.tempDestination(dst); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); + generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallValueNode ---------------------------------- + +FunctionCallValueNode::~FunctionCallValueNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallValueNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); + releaser.release(m_args); +} + +RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.emitNode(m_expr.get()); + RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallResolveNode ---------------------------------- + +FunctionCallResolveNode::~FunctionCallResolveNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallResolveNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_args); +} + +RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { + RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, thisRegister.get()), local.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { + RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); + RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); + } + + RefPtr<RegisterID> func = generator.tempDestination(dst); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + int identifierStart = divot() - startOffset(); + generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); + generator.emitResolveFunction(thisRegister.get(), func.get(), m_ident); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallBracketNode ---------------------------------- + +FunctionCallBracketNode::~FunctionCallBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); + releaser.release(m_args); +} + +RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base.get()); + RegisterID* property = generator.emitNode(m_subscript.get()); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property); + RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallDotNode ---------------------------------- + +FunctionCallDotNode::~FunctionCallDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FunctionCallDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_args); +} + +RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base.get()); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args.get(), divot(), startOffset(), endOffset()); +} + +// ------------------------------ PostfixResolveNode ---------------------------------- + +static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) +{ + return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst); +} + +static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) +{ + return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst); +} + +RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitToJSNumber(generator.finalDestination(dst), local); + } + + if (dst == generator.ignoredResult()) + return emitPreIncOrDec(generator, local, m_operator); + return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + emitPreIncOrDec(generator, value.get(), m_operator); + } else { + oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); + } + generator.emitPutScopedVar(depth, index, value.get(), globalObject); + return oldValue; + } + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RefPtr<RegisterID> value = generator.newTemporary(); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + emitPreIncOrDec(generator, value.get(), m_operator); + } else { + oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator); + } + generator.emitPutById(base.get(), m_ident, value.get()); + return oldValue; +} + +// ------------------------------ PostfixBracketNode ---------------------------------- + +PostfixBracketNode::~PostfixBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PostfixBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base.get()); + RefPtr<RegisterID> property = generator.emitNode(m_subscript.get()); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + if (m_operator == OpPlusPlus) + generator.emitPreInc(value.get()); + else + generator.emitPreDec(value.get()); + } else { + oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); + } + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), value.get()); + return oldValue; +} + +// ------------------------------ PostfixDotNode ---------------------------------- + +PostfixDotNode::~PostfixDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PostfixDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base.get()); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); + RegisterID* oldValue; + if (dst == generator.ignoredResult()) { + oldValue = 0; + if (m_operator == OpPlusPlus) + generator.emitPreInc(value.get()); + else + generator.emitPreDec(value.get()); + } else { + oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get()); + } + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, value.get()); + return oldValue; +} + +// ------------------------------ PostfixErrorNode ----------------------------------- + +PostfixErrorNode::~PostfixErrorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PostfixErrorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference."); +} + +// ------------------------------ DeleteResolveNode ----------------------------------- + +RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (generator.registerFor(m_ident)) + return generator.emitUnexpectedLoad(generator.finalDestination(dst), false); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); +} + +// ------------------------------ DeleteBracketNode ----------------------------------- + +DeleteBracketNode::~DeleteBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DeleteBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> r0 = generator.emitNode(m_base.get()); + RegisterID* r1 = generator.emitNode(m_subscript.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); +} + +// ------------------------------ DeleteDotNode ----------------------------------- + +DeleteDotNode::~DeleteDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DeleteDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* r0 = generator.emitNode(m_base.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); +} + +// ------------------------------ DeleteValueNode ----------------------------------- + +DeleteValueNode::~DeleteValueNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DeleteValueNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitNode(generator.ignoredResult(), m_expr.get()); + + // delete on a non-location expression ignores the value and returns true + return generator.emitUnexpectedLoad(generator.finalDestination(dst), true); +} + +// ------------------------------ VoidNode ------------------------------------- + +VoidNode::~VoidNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void VoidNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr.get()); + return 0; + } + RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get()); + return generator.emitLoad(dst, jsUndefined()); +} + +// ------------------------------ TypeOfValueNode ----------------------------------- + +RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitTypeOf(generator.finalDestination(dst), local); + } + + RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + generator.emitGetById(scratch.get(), scratch.get(), m_ident); + if (dst == generator.ignoredResult()) + return 0; + return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); +} + +// ------------------------------ TypeOfValueNode ----------------------------------- + +TypeOfValueNode::~TypeOfValueNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void TypeOfValueNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr.get()); + return 0; + } + RefPtr<RegisterID> src = generator.emitNode(m_expr.get()); + return generator.emitTypeOf(generator.finalDestination(dst), src.get()); +} + +// ------------------------------ PrefixResolveNode ---------------------------------- + +RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + RefPtr<RegisterID> r0 = generator.emitUnexpectedLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); + return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); + } + + emitPreIncOrDec(generator, local, m_operator); + return generator.moveToDestinationIfNeeded(dst, local); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) { + RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); + emitPreIncOrDec(generator, propDst.get(), m_operator); + generator.emitPutScopedVar(depth, index, propDst.get(), globalObject); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); + } + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RefPtr<RegisterID> propDst = generator.tempDestination(dst); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident); + emitPreIncOrDec(generator, propDst.get(), m_operator); + generator.emitPutById(base.get(), m_ident, propDst.get()); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixBracketNode ---------------------------------- + +PrefixBracketNode::~PrefixBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PrefixBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); +} + +RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base.get()); + RefPtr<RegisterID> property = generator.emitNode(m_subscript.get()); + RefPtr<RegisterID> propDst = generator.tempDestination(dst); + + generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); + RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get()); + if (m_operator == OpPlusPlus) + generator.emitPreInc(value); + else + generator.emitPreDec(value); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), value); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixDotNode ---------------------------------- + +PrefixDotNode::~PrefixDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PrefixDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); +} + +RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base.get()); + RefPtr<RegisterID> propDst = generator.tempDestination(dst); + + generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, endOffset() - m_subexpressionDivotOffset); + RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident); + if (m_operator == OpPlusPlus) + generator.emitPreInc(value); + else + generator.emitPreDec(value); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, value); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixErrorNode ----------------------------------- + +PrefixErrorNode::~PrefixErrorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void PrefixErrorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference."); +} + +// ------------------------------ Unary Operation Nodes ----------------------------------- + +UnaryOpNode::~UnaryOpNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void UnaryOpNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* src = generator.emitNode(m_expr.get()); + return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); +} + +// ------------------------------ Binary Operation Nodes ----------------------------------- + +BinaryOpNode::~BinaryOpNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void BinaryOpNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr1); + releaser.release(m_expr2); +} + +RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + OpcodeID opcodeID = this->opcodeID(); + if (opcodeID == op_neq) { + if (m_expr1->isNull() || m_expr2->isNull()) { + RefPtr<RegisterID> src = generator.tempDestination(dst); + generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2.get() : m_expr1.get()); + return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); + } + } + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); +} + +RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (m_expr1->isNull() || m_expr2->isNull()) { + RefPtr<RegisterID> src = generator.tempDestination(dst); + generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2.get() : m_expr1.get()); + return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); + } + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2); +} + +RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); +} + +RegisterID* ReverseBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor())); +} + +RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); +} + +RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator)); + RefPtr<RegisterID> src2 = generator.emitNode(m_expr2.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitGetByIdExceptionInfo(op_instanceof); + RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); +} + +// ------------------------------ LogicalOpNode ---------------------------- + +LogicalOpNode::~LogicalOpNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void LogicalOpNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr1); + releaser.release(m_expr2); +} + +RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> temp = generator.tempDestination(dst); + RefPtr<Label> target = generator.newLabel(); + + generator.emitNode(temp.get(), m_expr1.get()); + if (m_operator == OpLogicalAnd) + generator.emitJumpIfFalse(temp.get(), target.get()); + else + generator.emitJumpIfTrue(temp.get(), target.get()); + generator.emitNode(temp.get(), m_expr2.get()); + generator.emitLabel(target.get()); + + return generator.moveToDestinationIfNeeded(dst, temp.get()); +} + +// ------------------------------ ConditionalNode ------------------------------ + +ConditionalNode::~ConditionalNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ConditionalNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_logical); + releaser.release(m_expr1); + releaser.release(m_expr2); +} + +RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> newDst = generator.finalDestination(dst); + RefPtr<Label> beforeElse = generator.newLabel(); + RefPtr<Label> afterElse = generator.newLabel(); + + RegisterID* cond = generator.emitNode(m_logical.get()); + generator.emitJumpIfFalse(cond, beforeElse.get()); + + generator.emitNode(newDst.get(), m_expr1.get()); + generator.emitJump(afterElse.get()); + + generator.emitLabel(beforeElse.get()); + generator.emitNode(newDst.get(), m_expr2.get()); + + generator.emitLabel(afterElse.get()); + + return newDst.get(); +} + +// ------------------------------ ReadModifyResolveNode ----------------------------------- + +ReadModifyResolveNode::~ReadModifyResolveNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ReadModifyResolveNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_right); +} + +// FIXME: should this be moved to be a method on BytecodeGenerator? +static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, RegisterID* src2, Operator oper, OperandTypes types) +{ + OpcodeID opcodeID; + switch (oper) { + case OpMultEq: + opcodeID = op_mul; + break; + case OpDivEq: + opcodeID = op_div; + break; + case OpPlusEq: + opcodeID = op_add; + break; + case OpMinusEq: + opcodeID = op_sub; + break; + case OpLShift: + opcodeID = op_lshift; + break; + case OpRShift: + opcodeID = op_rshift; + break; + case OpURShift: + opcodeID = op_urshift; + break; + case OpAndEq: + opcodeID = op_bitand; + break; + case OpXOrEq: + opcodeID = op_bitxor; + break; + case OpOrEq: + opcodeID = op_bitor; + break; + case OpModEq: + opcodeID = op_mod; + break; + default: + ASSERT_NOT_REACHED(); + return dst; + } + + return generator.emitBinaryOp(opcodeID, dst, src1, src2, types); +} + +RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + RegisterID* src2 = generator.emitNode(m_right.get()); + return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); + } + + if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { + RefPtr<RegisterID> result = generator.newTemporary(); + generator.emitMove(result.get(), local); + RegisterID* src2 = generator.emitNode(m_right.get()); + emitReadModifyAssignment(generator, result.get(), result.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); + generator.emitMove(local, result.get()); + return generator.moveToDestinationIfNeeded(dst, result.get()); + } + + RegisterID* src2 = generator.emitNode(m_right.get()); + RegisterID* result = emitReadModifyAssignment(generator, local, local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); + return generator.moveToDestinationIfNeeded(dst, result); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject); + RegisterID* src2 = generator.emitNode(m_right.get()); + RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); + generator.emitPutScopedVar(depth, index, result, globalObject); + return result; + } + + RefPtr<RegisterID> src1 = generator.tempDestination(dst); + generator.emitExpressionInfo(divot() - startOffset() + m_ident.size(), m_ident.size(), 0); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); + RegisterID* src2 = generator.emitNode(m_right.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); + return generator.emitPutById(base.get(), m_ident, result); +} + +// ------------------------------ AssignResolveNode ----------------------------------- + +AssignResolveNode::~AssignResolveNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void AssignResolveNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_right); +} + +RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) + return generator.emitNode(dst, m_right.get()); + + RegisterID* result = generator.emitNode(local, m_right.get()); + return generator.moveToDestinationIfNeeded(dst, result); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + if (dst == generator.ignoredResult()) + dst = 0; + RegisterID* value = generator.emitNode(dst, m_right.get()); + generator.emitPutScopedVar(depth, index, value, globalObject); + return value; + } + + RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); + if (dst == generator.ignoredResult()) + dst = 0; + RegisterID* value = generator.emitNode(dst, m_right.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitPutById(base.get(), m_ident, value); +} + +// ------------------------------ AssignDotNode ----------------------------------- + +AssignDotNode::~AssignDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void AssignDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_right); +} + +RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator)); + RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); + RegisterID* result = generator.emitNode(value.get(), m_right.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, result); + return generator.moveToDestinationIfNeeded(dst, result); +} + +// ------------------------------ ReadModifyDotNode ----------------------------------- + +ReadModifyDotNode::~ReadModifyDotNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ReadModifyDotNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_right); +} + +RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator)); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RegisterID* change = generator.emitNode(m_right.get()); + RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitPutById(base.get(), m_ident, updatedValue); +} + +// ------------------------------ AssignErrorNode ----------------------------------- + +AssignErrorNode::~AssignErrorNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void AssignErrorNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_left); + releaser.release(m_right); +} + +RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference."); +} + +// ------------------------------ AssignBracketNode ----------------------------------- + +AssignBracketNode::~AssignBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void AssignBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); + releaser.release(m_right); +} + +RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); + RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator)); + RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); + RegisterID* result = generator.emitNode(value.get(), m_right.get()); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), result); + return generator.moveToDestinationIfNeeded(dst, result); +} + +// ------------------------------ ReadModifyBracketNode ----------------------------------- + +ReadModifyBracketNode::~ReadModifyBracketNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ReadModifyBracketNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_base); + releaser.release(m_subscript); + releaser.release(m_right); +} + +RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); + RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator)); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); + RegisterID* change = generator.emitNode(m_right.get()); + RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor())); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), updatedValue); + + return updatedValue; +} + +// ------------------------------ CommaNode ------------------------------------ + +CommaNode::~CommaNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void CommaNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr1); + releaser.release(m_expr2); +} + +RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitNode(generator.ignoredResult(), m_expr1.get()); + return generator.emitNode(dst, m_expr2.get()); +} + +// ------------------------------ ConstDeclNode ------------------------------------ + +ConstDeclNode::~ConstDeclNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ConstDeclNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_next); + releaser.release(m_init); +} + +ConstDeclNode::ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* init) + : ExpressionNode(globalData) + , m_ident(ident) + , m_init(init) +{ +} + +RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) +{ + if (RegisterID* local = generator.constRegisterFor(m_ident)) { + if (!m_init) + return local; + + return generator.emitNode(local, m_init.get()); + } + + // FIXME: While this code should only be hit in eval code, it will potentially + // assign to the wrong base if m_ident exists in an intervening dynamic scope. + RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); + RegisterID* value = m_init ? generator.emitNode(m_init.get()) : generator.emitLoad(0, jsUndefined()); + return generator.emitPutById(base.get(), m_ident, value); +} + +RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + RegisterID* result = 0; + for (ConstDeclNode* n = this; n; n = n->m_next.get()) + result = n->emitCodeSingle(generator); + + return result; +} + +// ------------------------------ ConstStatementNode ----------------------------- + +ConstStatementNode::~ConstStatementNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ConstStatementNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_next); +} + +RegisterID* ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return generator.emitNode(m_next.get()); +} + +// ------------------------------ Helper functions for handling Vectors of StatementNode ------------------------------- + +static inline RegisterID* statementListEmitCode(const StatementVector& statements, BytecodeGenerator& generator, RegisterID* dst) +{ + StatementVector::const_iterator end = statements.end(); + for (StatementVector::const_iterator it = statements.begin(); it != end; ++it) { + StatementNode* n = it->get(); + if (!n->isLoop()) + generator.emitDebugHook(WillExecuteStatement, n->firstLine(), n->lastLine()); + generator.emitNode(dst, n); + } + return 0; +} + +// ------------------------------ BlockNode ------------------------------------ + +BlockNode::~BlockNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void BlockNode::releaseNodes(NodeReleaser& releaser) +{ + size_t size = m_children.size(); + for (size_t i = 0; i < size; ++i) + releaser.release(m_children[i]); +} + +BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* children) + : StatementNode(globalData) +{ + if (children) + children->releaseContentsIntoVector(m_children); +} + +RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + return statementListEmitCode(m_children, generator, dst); +} + +// ------------------------------ EmptyStatementNode --------------------------- + +RegisterID* EmptyStatementNode::emitBytecode(BytecodeGenerator&, RegisterID* dst) +{ + return dst; +} + +// ------------------------------ DebuggerStatementNode --------------------------- + +RegisterID* DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine()); + return dst; +} + +// ------------------------------ ExprStatementNode ---------------------------- + +RegisterID* ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expr); + return generator.emitNode(dst, m_expr.get()); +} + +// ------------------------------ VarStatementNode ---------------------------- + +VarStatementNode::~VarStatementNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void VarStatementNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + ASSERT(m_expr); + return generator.emitNode(m_expr.get()); +} + +// ------------------------------ IfNode --------------------------------------- + +IfNode::~IfNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void IfNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_condition); + releaser.release(m_ifBlock); +} + +RegisterID* IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<Label> afterThen = generator.newLabel(); + + RegisterID* cond = generator.emitNode(m_condition.get()); + generator.emitJumpIfFalse(cond, afterThen.get()); + + if (!m_ifBlock->isBlock()) + generator.emitDebugHook(WillExecuteStatement, m_ifBlock->firstLine(), m_ifBlock->lastLine()); + + generator.emitNode(dst, m_ifBlock.get()); + generator.emitLabel(afterThen.get()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion. + return 0; +} + +// ------------------------------ IfElseNode --------------------------------------- + +IfElseNode::~IfElseNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void IfElseNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_elseBlock); + IfNode::releaseNodes(releaser); +} + +RegisterID* IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<Label> beforeElse = generator.newLabel(); + RefPtr<Label> afterElse = generator.newLabel(); + + RegisterID* cond = generator.emitNode(m_condition.get()); + generator.emitJumpIfFalse(cond, beforeElse.get()); + + if (!m_ifBlock->isBlock()) + generator.emitDebugHook(WillExecuteStatement, m_ifBlock->firstLine(), m_ifBlock->lastLine()); + + generator.emitNode(dst, m_ifBlock.get()); + generator.emitJump(afterElse.get()); + + generator.emitLabel(beforeElse.get()); + + if (!m_elseBlock->isBlock()) + generator.emitDebugHook(WillExecuteStatement, m_elseBlock->firstLine(), m_elseBlock->lastLine()); + + generator.emitNode(dst, m_elseBlock.get()); + + generator.emitLabel(afterElse.get()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion. + return 0; +} + +// ------------------------------ DoWhileNode ---------------------------------- + +DoWhileNode::~DoWhileNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void DoWhileNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_statement); + releaser.release(m_expr); +} + +RegisterID* DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + if (!m_statement->isBlock()) + generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); + + RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get()); + + generator.emitLabel(scope->continueTarget()); + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); + RegisterID* cond = generator.emitNode(m_expr.get()); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + + generator.emitLabel(scope->breakTarget()); + return result.get(); +} + +// ------------------------------ WhileNode ------------------------------------ + +WhileNode::~WhileNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void WhileNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); + releaser.release(m_statement); +} + +RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + generator.emitJump(scope->continueTarget()); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + if (!m_statement->isBlock()) + generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); + + generator.emitNode(dst, m_statement.get()); + + generator.emitLabel(scope->continueTarget()); + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); + RegisterID* cond = generator.emitNode(m_expr.get()); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + + generator.emitLabel(scope->breakTarget()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion + return 0; +} + +// ------------------------------ ForNode -------------------------------------- + +ForNode::~ForNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ForNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr1); + releaser.release(m_expr2); + releaser.release(m_expr3); + releaser.release(m_statement); +} + +RegisterID* ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + dst = 0; + + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + if (m_expr1) + generator.emitNode(generator.ignoredResult(), m_expr1.get()); + + RefPtr<Label> condition = generator.newLabel(); + generator.emitJump(condition.get()); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + if (!m_statement->isBlock()) + generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); + RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get()); + + generator.emitLabel(scope->continueTarget()); + if (m_expr3) + generator.emitNode(generator.ignoredResult(), m_expr3.get()); + + generator.emitLabel(condition.get()); + if (m_expr2) { + RegisterID* cond = generator.emitNode(m_expr2.get()); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + } else + generator.emitJump(topOfLoop.get()); + + generator.emitLabel(scope->breakTarget()); + return result.get(); +} + +// ------------------------------ ForInNode ------------------------------------ + +ForInNode::~ForInNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ForInNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_init); + releaser.release(m_lexpr); + releaser.release(m_expr); + releaser.release(m_statement); +} + +ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement) + : StatementNode(globalData) + , m_init(0L) + , m_lexpr(l) + , m_expr(expr) + , m_statement(statement) + , m_identIsVarDecl(false) +{ +} + +ForInNode::ForInNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement, int divot, int startOffset, int endOffset) + : StatementNode(globalData) + , m_ident(ident) + , m_lexpr(new ResolveNode(globalData, ident, divot - startOffset)) + , m_expr(expr) + , m_statement(statement) + , m_identIsVarDecl(true) +{ + if (in) { + AssignResolveNode* node = new AssignResolveNode(globalData, ident, in, true); + node->setExceptionSourceCode(divot, divot - startOffset, endOffset - divot); + m_init = node; + } + // for( var foo = bar in baz ) +} + +RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + if (!m_lexpr->isLocation()) + return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference."); + + RefPtr<Label> continueTarget = generator.newLabel(); + + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + if (m_init) + generator.emitNode(generator.ignoredResult(), m_init.get()); + RegisterID* forInBase = generator.emitNode(m_expr.get()); + RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase); + generator.emitJump(scope->continueTarget()); + + RefPtr<Label> loopStart = generator.newLabel(); + generator.emitLabel(loopStart.get()); + + RegisterID* propertyName; + if (m_lexpr->isResolveNode()) { + const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier(); + propertyName = generator.registerFor(ident); + if (!propertyName) { + propertyName = generator.newTemporary(); + RefPtr<RegisterID> protect = propertyName; + RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base, ident, propertyName); + } + } else if (m_lexpr->isDotAccessorNode()) { + DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr.get()); + const Identifier& ident = assignNode->identifier(); + propertyName = generator.newTemporary(); + RefPtr<RegisterID> protect = propertyName; + RegisterID* base = generator.emitNode(assignNode->base()); + + generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); + generator.emitPutById(base, ident, propertyName); + } else { + ASSERT(m_lexpr->isBracketAccessorNode()); + BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr.get()); + propertyName = generator.newTemporary(); + RefPtr<RegisterID> protect = propertyName; + RefPtr<RegisterID> base = generator.emitNode(assignNode->base()); + RegisterID* subscript = generator.emitNode(assignNode->subscript()); + + generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset()); + generator.emitPutByVal(base.get(), subscript, propertyName); + } + + if (!m_statement->isBlock()) + generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine()); + generator.emitNode(dst, m_statement.get()); + + generator.emitLabel(scope->continueTarget()); + generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get()); + generator.emitLabel(scope->breakTarget()); + return dst; +} + +// ------------------------------ ContinueNode --------------------------------- + +// ECMA 12.7 +RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + LabelScope* scope = generator.continueTarget(m_ident); + + if (!scope) + return m_ident.isEmpty() + ? emitThrowError(generator, SyntaxError, "Invalid continue statement.") + : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident); + + generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth()); + return dst; +} + +// ------------------------------ BreakNode ------------------------------------ + +// ECMA 12.8 +RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + LabelScope* scope = generator.breakTarget(m_ident); + + if (!scope) + return m_ident.isEmpty() + ? emitThrowError(generator, SyntaxError, "Invalid break statement.") + : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident); + + generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth()); + return dst; +} + +// ------------------------------ ReturnNode ----------------------------------- + +ReturnNode::~ReturnNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ReturnNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_value); +} + +RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (generator.codeType() != FunctionCode) + return emitThrowError(generator, SyntaxError, "Invalid return statement."); + + if (dst == generator.ignoredResult()) + dst = 0; + RegisterID* r0 = m_value ? generator.emitNode(dst, m_value.get()) : generator.emitLoad(dst, jsUndefined()); + if (generator.scopeDepth()) { + RefPtr<Label> l0 = generator.newLabel(); + generator.emitJumpScopes(l0.get(), 0); + generator.emitLabel(l0.get()); + } + generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); + return generator.emitReturn(r0); +} + +// ------------------------------ WithNode ------------------------------------- + +WithNode::~WithNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void WithNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); + releaser.release(m_statement); +} + +RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> scope = generator.newTemporary(); + generator.emitNode(scope.get(), m_expr.get()); // scope must be protected until popped + generator.emitExpressionInfo(m_divot, m_expressionLength, 0); + generator.emitPushScope(scope.get()); + RegisterID* result = generator.emitNode(dst, m_statement.get()); + generator.emitPopScope(); + return result; +} + +// ------------------------------ CaseClauseNode -------------------------------- + +CaseClauseNode::~CaseClauseNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void CaseClauseNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +// ------------------------------ ClauseListNode -------------------------------- + +ClauseListNode::~ClauseListNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ClauseListNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_clause); + releaser.release(m_next); +} + +// ------------------------------ CaseBlockNode -------------------------------- + +CaseBlockNode::~CaseBlockNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void CaseBlockNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_list1); + releaser.release(m_defaultClause); + releaser.release(m_list2); +} + +enum SwitchKind { + SwitchUnset = 0, + SwitchNumber = 1, + SwitchString = 2, + SwitchNeither = 3 +}; + +static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) +{ + for (; list; list = list->getNext()) { + ExpressionNode* clauseExpression = list->getClause()->expr(); + literalVector.append(clauseExpression); + if (clauseExpression->isNumber()) { + double value = static_cast<NumberNode*>(clauseExpression)->value(); + if ((typeForTable & ~SwitchNumber) || !JSImmediate::from(value)) { + typeForTable = SwitchNeither; + break; + } + int32_t intVal = static_cast<int32_t>(value); + ASSERT(intVal == value); + if (intVal < min_num) + min_num = intVal; + if (intVal > max_num) + max_num = intVal; + typeForTable = SwitchNumber; + continue; + } + if (clauseExpression->isString()) { + if (typeForTable & ~SwitchString) { + typeForTable = SwitchNeither; + break; + } + const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring(); + if (singleCharacterSwitch &= value.size() == 1) { + int32_t intVal = value.rep()->data()[0]; + if (intVal < min_num) + min_num = intVal; + if (intVal > max_num) + max_num = intVal; + } + typeForTable = SwitchString; + continue; + } + typeForTable = SwitchNeither; + break; + } +} + +SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) +{ + SwitchKind typeForTable = SwitchUnset; + bool singleCharacterSwitch = true; + + processClauseList(m_list1.get(), literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); + processClauseList(m_list2.get(), literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); + + if (typeForTable == SwitchUnset || typeForTable == SwitchNeither) + return SwitchInfo::SwitchNone; + + if (typeForTable == SwitchNumber) { + int32_t range = max_num - min_num; + if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) + return SwitchInfo::SwitchImmediate; + return SwitchInfo::SwitchNone; + } + + ASSERT(typeForTable == SwitchString); + + if (singleCharacterSwitch) { + int32_t range = max_num - min_num; + if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10) + return SwitchInfo::SwitchCharacter; + } + + return SwitchInfo::SwitchString; +} + +RegisterID* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) +{ + RefPtr<Label> defaultLabel; + Vector<RefPtr<Label>, 8> labelVector; + Vector<ExpressionNode*, 8> literalVector; + int32_t min_num = std::numeric_limits<int32_t>::max(); + int32_t max_num = std::numeric_limits<int32_t>::min(); + SwitchInfo::SwitchType switchType = tryOptimizedSwitch(literalVector, min_num, max_num); + + if (switchType != SwitchInfo::SwitchNone) { + // Prepare the various labels + for (uint32_t i = 0; i < literalVector.size(); i++) + labelVector.append(generator.newLabel()); + defaultLabel = generator.newLabel(); + generator.beginSwitch(switchExpression, switchType); + } else { + // Setup jumps + for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) { + RefPtr<RegisterID> clauseVal = generator.newTemporary(); + generator.emitNode(clauseVal.get(), list->getClause()->expr()); + generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); + labelVector.append(generator.newLabel()); + generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); + } + + for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) { + RefPtr<RegisterID> clauseVal = generator.newTemporary(); + generator.emitNode(clauseVal.get(), list->getClause()->expr()); + generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes()); + labelVector.append(generator.newLabel()); + generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get()); + } + defaultLabel = generator.newLabel(); + generator.emitJump(defaultLabel.get()); + } + + RegisterID* result = 0; + + size_t i = 0; + for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) { + generator.emitLabel(labelVector[i++].get()); + result = statementListEmitCode(list->getClause()->children(), generator, dst); + } + + if (m_defaultClause) { + generator.emitLabel(defaultLabel.get()); + result = statementListEmitCode(m_defaultClause->children(), generator, dst); + } + + for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) { + generator.emitLabel(labelVector[i++].get()); + result = statementListEmitCode(list->getClause()->children(), generator, dst); + } + if (!m_defaultClause) + generator.emitLabel(defaultLabel.get()); + + ASSERT(i == labelVector.size()); + if (switchType != SwitchInfo::SwitchNone) { + ASSERT(labelVector.size() == literalVector.size()); + generator.endSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get(), min_num, max_num); + } + return result; +} + +// ------------------------------ SwitchNode ----------------------------------- + +SwitchNode::~SwitchNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void SwitchNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); + releaser.release(m_block); +} + +RegisterID* SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); + + RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get()); + RegisterID* r1 = m_block->emitBytecodeForBlock(generator, r0.get(), dst); + + generator.emitLabel(scope->breakTarget()); + return r1; +} + +// ------------------------------ LabelNode ------------------------------------ + +LabelNode::~LabelNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void LabelNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_statement); +} + +RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (generator.breakTarget(m_name)) + return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", m_name); + + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); + RegisterID* r0 = generator.emitNode(dst, m_statement.get()); + + generator.emitLabel(scope->breakTarget()); + return r0; +} + +// ------------------------------ ThrowNode ------------------------------------ + +ThrowNode::~ThrowNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ThrowNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_expr); +} + +RegisterID* ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + dst = 0; + RefPtr<RegisterID> expr = generator.emitNode(dst, m_expr.get()); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitThrow(expr.get()); + return dst; +} + +// ------------------------------ TryNode -------------------------------------- + +TryNode::~TryNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void TryNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_tryBlock); + releaser.release(m_catchBlock); + releaser.release(m_finallyBlock); +} + +RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<Label> tryStartLabel = generator.newLabel(); + RefPtr<Label> tryEndLabel = generator.newLabel(); + RefPtr<Label> finallyStart; + RefPtr<RegisterID> finallyReturnAddr; + if (m_finallyBlock) { + finallyStart = generator.newLabel(); + finallyReturnAddr = generator.newTemporary(); + generator.pushFinallyContext(finallyStart.get(), finallyReturnAddr.get()); + } + generator.emitLabel(tryStartLabel.get()); + generator.emitNode(dst, m_tryBlock.get()); + generator.emitLabel(tryEndLabel.get()); + + if (m_catchBlock) { + RefPtr<Label> handlerEndLabel = generator.newLabel(); + generator.emitJump(handlerEndLabel.get()); + RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), tryEndLabel.get()); + if (m_catchHasEval) { + RefPtr<RegisterID> dynamicScopeObject = generator.emitNewObject(generator.newTemporary()); + generator.emitPutById(dynamicScopeObject.get(), m_exceptionIdent, exceptionRegister.get()); + generator.emitMove(exceptionRegister.get(), dynamicScopeObject.get()); + generator.emitPushScope(exceptionRegister.get()); + } else + generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); + generator.emitNode(dst, m_catchBlock.get()); + generator.emitPopScope(); + generator.emitLabel(handlerEndLabel.get()); + } + + if (m_finallyBlock) { + generator.popFinallyContext(); + // there may be important registers live at the time we jump + // to a finally block (such as for a return or throw) so we + // ref the highest register ever used as a conservative + // approach to not clobbering anything important + RefPtr<RegisterID> highestUsedRegister = generator.highestUsedRegister(); + RefPtr<Label> finallyEndLabel = generator.newLabel(); + generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); + // Use a label to record the subtle fact that sret will return to the + // next instruction. sret is the only way to jump without an explicit label. + generator.emitLabel(generator.newLabel().get()); + generator.emitJump(finallyEndLabel.get()); + + // Finally block for exception path + RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), generator.emitLabel(generator.newLabel().get()).get()); + generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); + // Use a label to record the subtle fact that sret will return to the + // next instruction. sret is the only way to jump without an explicit label. + generator.emitLabel(generator.newLabel().get()); + generator.emitThrow(tempExceptionRegister.get()); + + // emit the finally block itself + generator.emitLabel(finallyStart.get()); + generator.emitNode(dst, m_finallyBlock.get()); + generator.emitSubroutineReturn(finallyReturnAddr.get()); + + generator.emitLabel(finallyEndLabel.get()); + } + + return dst; +} + +// ------------------------------ ParameterNode ----------------------------- + +ParameterNode::~ParameterNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ParameterNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_next); +} + +// -----------------------------ScopeNodeData --------------------------- + +ScopeNodeData::ScopeNodeData(SourceElements* children, VarStack* varStack, FunctionStack* funcStack, int numConstants) + : m_numConstants(numConstants) +{ + if (varStack) + m_varStack = *varStack; + if (funcStack) + m_functionStack = *funcStack; + if (children) + children->releaseContentsIntoVector(m_children); +} + +// ------------------------------ ScopeNode ----------------------------- + +ScopeNode::ScopeNode(JSGlobalData* globalData) + : StatementNode(globalData) + , m_features(NoFeatures) +{ +#if ENABLE(OPCODE_SAMPLING) + globalData->interpreter->sampler()->notifyOfScope(this); +#endif +} + +ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants) + : StatementNode(globalData) + , m_data(new ScopeNodeData(children, varStack, funcStack, numConstants)) + , m_features(features) + , m_source(source) +{ +#if ENABLE(OPCODE_SAMPLING) + globalData->interpreter->sampler()->notifyOfScope(this); +#endif +} + +ScopeNode::~ScopeNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void ScopeNode::releaseNodes(NodeReleaser& releaser) +{ + if (!m_data) + return; + size_t size = m_data->m_children.size(); + for (size_t i = 0; i < size; ++i) + releaser.release(m_data->m_children[i]); +} + +// ------------------------------ ProgramNode ----------------------------- + +ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) + : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants) +{ +} + +ProgramNode* ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) +{ + return new ProgramNode(globalData, children, varStack, funcStack, source, features, numConstants); +} + +RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); + + RefPtr<RegisterID> dstRegister = generator.newTemporary(); + generator.emitLoad(dstRegister.get(), jsUndefined()); + statementListEmitCode(children(), generator, dstRegister.get()); + + generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); + generator.emitEnd(dstRegister.get()); + return 0; +} + +void ProgramNode::generateBytecode(ScopeChainNode* scopeChainNode) +{ + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + m_code.set(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider())); + + BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get()); + generator.generate(); + + destroyData(); +} + +// ------------------------------ EvalNode ----------------------------- + +EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) + : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants) +{ +} + +EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) +{ + return new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants); +} + +RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); + + RefPtr<RegisterID> dstRegister = generator.newTemporary(); + generator.emitLoad(dstRegister.get(), jsUndefined()); + statementListEmitCode(children(), generator, dstRegister.get()); + + generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); + generator.emitEnd(dstRegister.get()); + return 0; +} + +void EvalNode::generateBytecode(ScopeChainNode* scopeChainNode) +{ + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + m_code.set(new EvalCodeBlock(this, globalObject, source().provider())); + + BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get()); + generator.generate(); + + // Eval code needs to hang on to its declaration stacks to keep declaration info alive until Interpreter::execute time, + // so the entire ScopeNodeData cannot be destoyed. + children().clear(); +} + +EvalCodeBlock& EvalNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode) +{ + ASSERT(!m_code); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + m_code.set(new EvalCodeBlock(this, globalObject, source().provider())); + + BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get()); + generator.setRegeneratingForExceptionInfo(); + generator.generate(); + + return *m_code; +} + +// ------------------------------ FunctionBodyNode ----------------------------- + +FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData) + : ScopeNode(globalData) + , m_parameters(0) + , m_parameterCount(0) + , m_refCount(0) +{ +} + +FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants) + : ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants) + , m_parameters(0) + , m_parameterCount(0) + , m_refCount(0) +{ +} + +FunctionBodyNode::~FunctionBodyNode() +{ + ASSERT(!m_refCount); + fastFree(m_parameters); +} + +void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter) +{ + Vector<Identifier> parameters; + for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam()) + parameters.append(parameter->ident()); + size_t count = parameters.size(); + + setSource(source); + finishParsing(parameters.releaseBuffer(), count); +} + +void FunctionBodyNode::finishParsing(Identifier* parameters, size_t parameterCount) +{ + ASSERT(!source().isNull()); + m_parameters = parameters; + m_parameterCount = parameterCount; +} + +void FunctionBodyNode::mark() +{ + if (m_code) + m_code->mark(); +} + +FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData) +{ + return new FunctionBodyNode(globalData); +} + +FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants) +{ + return new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants); +} + +void FunctionBodyNode::generateBytecode(ScopeChainNode* scopeChainNode) +{ + // This branch is only necessary since you can still create a non-stub FunctionBodyNode by + // calling Parser::parse<FunctionBodyNode>(). + if (!data()) + scopeChainNode->globalData->parser->reparseInPlace(scopeChainNode->globalData, this); + ASSERT(data()); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset())); + + BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get()); + generator.generate(); + + destroyData(); +} + +CodeBlock& FunctionBodyNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode) +{ + ASSERT(!m_code); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset())); + + BytecodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get()); + generator.setRegeneratingForExceptionInfo(); + generator.generate(); + + return *m_code; +} + +RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine()); + statementListEmitCode(children(), generator, generator.ignoredResult()); + if (!children().size() || !children().last()->isReturnNode()) { + RegisterID* r0 = generator.emitLoad(0, jsUndefined()); + generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); + generator.emitReturn(r0); + } + return 0; +} + +UString FunctionBodyNode::paramString() const +{ + UString s(""); + for (size_t pos = 0; pos < m_parameterCount; ++pos) { + if (!s.isEmpty()) + s += ", "; + s += parameters()[pos].ustring(); + } + + return s; +} + +Identifier* FunctionBodyNode::copyParameters() +{ + Identifier* parameters = static_cast<Identifier*>(fastMalloc(m_parameterCount * sizeof(Identifier))); + VectorCopier<false, Identifier>::uninitializedCopy(m_parameters, m_parameters + m_parameterCount, parameters); + return parameters; +} + +// ------------------------------ FuncDeclNode --------------------------------- + +FuncDeclNode::~FuncDeclNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FuncDeclNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_parameter); + releaser.release(m_body); +} + +JSFunction* FuncDeclNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain) +{ + return new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain); +} + +RegisterID* FuncDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + dst = 0; + return dst; +} + +// ------------------------------ FuncExprNode --------------------------------- + +FuncExprNode::~FuncExprNode() +{ + NodeReleaser::releaseAllNodes(this); +} + +void FuncExprNode::releaseNodes(NodeReleaser& releaser) +{ + releaser.release(m_parameter); + releaser.release(m_body); +} + +RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); +} + +JSFunction* FuncExprNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain) +{ + JSFunction* func = new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain); + + /* + The Identifier in a FunctionExpression can be referenced from inside + the FunctionExpression's FunctionBody to allow the function to call + itself recursively. However, unlike in a FunctionDeclaration, the + Identifier in a FunctionExpression cannot be referenced from and + does not affect the scope enclosing the FunctionExpression. + */ + + if (!m_ident.isNull()) { + JSStaticScopeObject* functionScopeObject = new (exec) JSStaticScopeObject(exec, m_ident, func, ReadOnly | DontDelete); + func->scope().push(functionScopeObject); + } + + return func; +} + +} // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/Nodes.h b/src/3rdparty/webkit/JavaScriptCore/parser/Nodes.h new file mode 100644 index 0000000..f8512f7 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Nodes.h @@ -0,0 +1,2418 @@ +/* + * 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 "Opcode.h" +#include "ResultType.h" +#include "SourceCode.h" +#include "SymbolTable.h" +#include <wtf/MathExtras.h> +#include <wtf/OwnPtr.h> +#include <wtf/Vector.h> + +#if PLATFORM(X86) && COMPILER(GCC) +#define JSC_FAST_CALL __attribute__((regparm(3))) +#else +#define JSC_FAST_CALL +#endif + +namespace JSC { + + class CodeBlock; + class BytecodeGenerator; + class FuncDeclNode; + class EvalCodeBlock; + class JSFunction; + class NodeReleaser; + class ProgramCodeBlock; + class PropertyListNode; + class RegisterID; + class ScopeChainNode; + + 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 AllFeatures = EvalFeature | ClosureFeature | AssignFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature; + + enum Operator { + OpEqual, + OpPlusEq, + OpMinusEq, + OpMultEq, + OpDivEq, + OpPlusPlus, + OpMinusMinus, + OpAndEq, + OpXOrEq, + OpOrEq, + OpModEq, + OpLShift, + OpRShift, + OpURShift + }; + + enum LogicalOperator { + OpLogicalAnd, + OpLogicalOr + }; + + namespace DeclarationStacks { + enum VarAttrs { IsConstant = 1, HasInitializer = 2 }; + typedef Vector<std::pair<Identifier, unsigned> > VarStack; + typedef Vector<RefPtr<FuncDeclNode> > FunctionStack; + } + + struct SwitchInfo { + enum SwitchType { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString }; + uint32_t bytecodeOffset; + SwitchType switchType; + }; + + class ParserRefCounted : Noncopyable { + protected: + ParserRefCounted(JSGlobalData*) JSC_FAST_CALL; + + public: + virtual ~ParserRefCounted(); + + // Nonrecursive destruction. + virtual void releaseNodes(NodeReleaser&); + + void ref() JSC_FAST_CALL; + void deref() JSC_FAST_CALL; + bool hasOneRef() JSC_FAST_CALL; + + static void deleteNewObjects(JSGlobalData*) JSC_FAST_CALL; + + private: + JSGlobalData* m_globalData; + }; + + class Node : public ParserRefCounted { + public: + Node(JSGlobalData*) JSC_FAST_CALL; + + /* + Return value: The register holding the production's value. + dst: An optional parameter specifying the most efficient + destination at which to store the production's value. + The callee must honor dst. + + dst provides for a crude form of copy propagation. For example, + + x = 1 + + becomes + + load r[x], 1 + + instead of + + load r0, 1 + mov r[x], r0 + + because the assignment node, "x =", passes r[x] as dst to the number + node, "1". + */ + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* dst = 0) JSC_FAST_CALL = 0; + + int lineNo() const { return m_line; } + + protected: + int m_line; + }; + + class ExpressionNode : public Node { + public: + ExpressionNode(JSGlobalData* globalData, ResultType resultDesc = ResultType::unknown()) JSC_FAST_CALL + : Node(globalData) + , m_resultDesc(resultDesc) + { + } + + virtual bool isNumber() const JSC_FAST_CALL { return false; } + virtual bool isString() const JSC_FAST_CALL { return false; } + virtual bool isNull() const JSC_FAST_CALL { return false; } + virtual bool isPure(BytecodeGenerator&) const JSC_FAST_CALL { return false; } + virtual bool isLocation() const JSC_FAST_CALL { return false; } + virtual bool isResolveNode() const JSC_FAST_CALL { return false; } + virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return false; } + virtual bool isDotAccessorNode() const JSC_FAST_CALL { return false; } + virtual bool isFuncExprNode() const JSC_FAST_CALL { return false; } + + virtual ExpressionNode* stripUnaryPlus() { return this; } + + ResultType resultDescriptor() const JSC_FAST_CALL { return m_resultDesc; } + + // This needs to be in public in order to compile using GCC 3.x + typedef enum { EvalOperator, FunctionCall } CallerType; + + private: + ResultType m_resultDesc; + }; + + class StatementNode : public Node { + public: + StatementNode(JSGlobalData*) JSC_FAST_CALL; + void setLoc(int line0, int line1) JSC_FAST_CALL; + int firstLine() const JSC_FAST_CALL { return lineNo(); } + int lastLine() const JSC_FAST_CALL { return m_lastLine; } + + virtual bool isEmptyStatement() const JSC_FAST_CALL { return false; } + virtual bool isReturnNode() const JSC_FAST_CALL { return false; } + virtual bool isExprStatement() const JSC_FAST_CALL { return false; } + + virtual bool isBlock() const JSC_FAST_CALL { return false; } + virtual bool isLoop() const JSC_FAST_CALL { return false; } + + private: + int m_lastLine; + }; + + class NullNode : public ExpressionNode { + public: + NullNode(JSGlobalData* globalData) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::nullType()) + { + } + + virtual bool isNull() const JSC_FAST_CALL { return true; } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + }; + + class BooleanNode : public ExpressionNode { + public: + BooleanNode(JSGlobalData* globalData, bool value) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::boolean()) + , m_value(value) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isPure(BytecodeGenerator&) const JSC_FAST_CALL { return true; } + + private: + bool m_value; + }; + + class NumberNode : public ExpressionNode { + public: + NumberNode(JSGlobalData* globalData, double v) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::constNumber()) + , m_double(v) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isNumber() const JSC_FAST_CALL { return true; } + virtual bool isPure(BytecodeGenerator&) const JSC_FAST_CALL { return true; } + double value() const JSC_FAST_CALL { return m_double; } + void setValue(double d) JSC_FAST_CALL { m_double = d; } + + private: + double m_double; + }; + + class StringNode : public ExpressionNode { + public: + StringNode(JSGlobalData* globalData, const Identifier& v) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::string()) + , m_value(v) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isString() const JSC_FAST_CALL { return true; } + const Identifier& value() { return m_value; } + virtual bool isPure(BytecodeGenerator&) const JSC_FAST_CALL { return true; } + + private: + 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* emitThrowError(BytecodeGenerator&, ErrorType, const char* msg); + RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* msg, const Identifier&); + + private: + uint32_t m_divot; + uint16_t m_startOffset; + uint16_t m_endOffset; + }; + + class ThrowableSubExpressionData : public ThrowableExpressionData { + public: + ThrowableSubExpressionData() + : ThrowableExpressionData() + , 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() + : ThrowableExpressionData() + , m_subexpressionDivotOffset(0) + , m_subexpressionStartOffset(0) + { + } + + ThrowablePrefixedSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset) + : ThrowableExpressionData(divot, startOffset, endOffset) + , m_subexpressionDivotOffset(0) + , m_subexpressionStartOffset(0) + { + } + + void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset) + { + ASSERT(subexpressionDivot >= divot()); + if ((subexpressionDivot - divot()) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot + return; + m_subexpressionDivotOffset = subexpressionDivot - divot(); + m_subexpressionStartOffset = subexpressionOffset; + } + + protected: + uint16_t m_subexpressionDivotOffset; + uint16_t m_subexpressionStartOffset; + }; + + class RegExpNode : public ExpressionNode, public ThrowableExpressionData { + public: + RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_pattern(pattern) + , m_flags(flags) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + UString m_pattern; + UString m_flags; + }; + + class ThisNode : public ExpressionNode { + public: + ThisNode(JSGlobalData* globalData) JSC_FAST_CALL + : ExpressionNode(globalData) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + }; + + class ResolveNode : public ExpressionNode { + public: + ResolveNode(JSGlobalData* globalData, const Identifier& ident, int startOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_ident(ident) + , m_startOffset(startOffset) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isPure(BytecodeGenerator&) const JSC_FAST_CALL; + virtual bool isLocation() const JSC_FAST_CALL { return true; } + virtual bool isResolveNode() const JSC_FAST_CALL { return true; } + const Identifier& identifier() const JSC_FAST_CALL { return m_ident; } + + private: + Identifier m_ident; + int32_t m_startOffset; + }; + + class ElementNode : public ParserRefCounted { + public: + ElementNode(JSGlobalData* globalData, int elision, ExpressionNode* node) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_elision(elision) + , m_node(node) + { + } + + ElementNode(JSGlobalData* globalData, ElementNode* l, int elision, ExpressionNode* node) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_elision(elision) + , m_node(node) + { + l->m_next = this; + } + + virtual ~ElementNode(); + virtual void releaseNodes(NodeReleaser&); + + int elision() const { return m_elision; } + ExpressionNode* value() { return m_node.get(); } + + ElementNode* next() { return m_next.get(); } + + private: + RefPtr<ElementNode> m_next; + int m_elision; + RefPtr<ExpressionNode> m_node; + }; + + class ArrayNode : public ExpressionNode { + public: + ArrayNode(JSGlobalData* globalData, int elision) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_elision(elision) + , m_optional(true) + { + } + + ArrayNode(JSGlobalData* globalData, ElementNode* element) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_element(element) + , m_elision(0) + , m_optional(false) + { + } + + ArrayNode(JSGlobalData* globalData, int elision, ElementNode* element) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_element(element) + , m_elision(elision) + , m_optional(true) + { + } + + virtual ~ArrayNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ElementNode> m_element; + int m_elision; + bool m_optional; + }; + + class PropertyNode : public ParserRefCounted { + public: + enum Type { Constant, Getter, Setter }; + + PropertyNode(JSGlobalData* globalData, const Identifier& name, ExpressionNode* assign, Type type) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_name(name) + , m_assign(assign) + , m_type(type) + { + } + + virtual ~PropertyNode(); + virtual void releaseNodes(NodeReleaser&); + + const Identifier& name() const { return m_name; } + + private: + friend class PropertyListNode; + Identifier m_name; + RefPtr<ExpressionNode> m_assign; + Type m_type; + }; + + class PropertyListNode : public Node { + public: + PropertyListNode(JSGlobalData* globalData, PropertyNode* node) JSC_FAST_CALL + : Node(globalData) + , m_node(node) + { + } + + PropertyListNode(JSGlobalData* globalData, PropertyNode* node, PropertyListNode* list) JSC_FAST_CALL + : Node(globalData) + , m_node(node) + { + list->m_next = this; + } + + virtual ~PropertyListNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<PropertyNode> m_node; + RefPtr<PropertyListNode> m_next; + }; + + class ObjectLiteralNode : public ExpressionNode { + public: + ObjectLiteralNode(JSGlobalData* globalData) JSC_FAST_CALL + : ExpressionNode(globalData) + { + } + + ObjectLiteralNode(JSGlobalData* globalData, PropertyListNode* list) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_list(list) + { + } + + virtual ~ObjectLiteralNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<PropertyListNode> m_list; + }; + + class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData { + public: + BracketAccessorNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_base(base) + , m_subscript(subscript) + , m_subscriptHasAssignments(subscriptHasAssignments) + { + } + + virtual ~BracketAccessorNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isLocation() const JSC_FAST_CALL { return true; } + virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return true; } + ExpressionNode* base() JSC_FAST_CALL { return m_base.get(); } + ExpressionNode* subscript() JSC_FAST_CALL { return m_subscript.get(); } + + private: + RefPtr<ExpressionNode> m_base; + RefPtr<ExpressionNode> m_subscript; + bool m_subscriptHasAssignments; + }; + + class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData { + public: + DotAccessorNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_base(base) + , m_ident(ident) + { + } + + virtual ~DotAccessorNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isLocation() const JSC_FAST_CALL { return true; } + virtual bool isDotAccessorNode() const JSC_FAST_CALL { return true; } + ExpressionNode* base() const JSC_FAST_CALL { return m_base.get(); } + const Identifier& identifier() const JSC_FAST_CALL { return m_ident; } + + private: + RefPtr<ExpressionNode> m_base; + Identifier m_ident; + }; + + class ArgumentListNode : public Node { + public: + ArgumentListNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : Node(globalData) + , m_expr(expr) + { + } + + ArgumentListNode(JSGlobalData* globalData, ArgumentListNode* listNode, ExpressionNode* expr) JSC_FAST_CALL + : Node(globalData) + , m_expr(expr) + { + listNode->m_next = this; + } + + virtual ~ArgumentListNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + RefPtr<ArgumentListNode> m_next; + RefPtr<ExpressionNode> m_expr; + }; + + class ArgumentsNode : public ParserRefCounted { + public: + ArgumentsNode(JSGlobalData* globalData) JSC_FAST_CALL + : ParserRefCounted(globalData) + { + } + + ArgumentsNode(JSGlobalData* globalData, ArgumentListNode* listNode) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_listNode(listNode) + { + } + + virtual ~ArgumentsNode(); + virtual void releaseNodes(NodeReleaser&); + + RefPtr<ArgumentListNode> m_listNode; + }; + + class NewExprNode : public ExpressionNode, public ThrowableExpressionData { + public: + NewExprNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_expr(expr) + { + } + + NewExprNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_expr(expr) + , m_args(args) + { + } + + virtual ~NewExprNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + RefPtr<ArgumentsNode> m_args; + }; + + class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData { + public: + EvalFunctionCallNode(JSGlobalData* globalData, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_args(args) + { + } + + virtual ~EvalFunctionCallNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ArgumentsNode> m_args; + }; + + class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData { + public: + FunctionCallValueNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_expr(expr) + , m_args(args) + { + } + + virtual ~FunctionCallValueNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + RefPtr<ArgumentsNode> m_args; + }; + + class FunctionCallResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + FunctionCallResolveNode(JSGlobalData* globalData, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + , m_args(args) + { + } + + virtual ~FunctionCallResolveNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Identifier m_ident; + RefPtr<ArgumentsNode> m_args; + size_t m_index; // Used by LocalVarFunctionCallNode. + size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode + }; + + class FunctionCallBracketNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + FunctionCallBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_args(args) + { + } + + virtual ~FunctionCallBracketNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + RefPtr<ExpressionNode> m_subscript; + RefPtr<ArgumentsNode> m_args; + }; + + class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + FunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_args(args) + { + } + + virtual ~FunctionCallDotNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + Identifier m_ident; + RefPtr<ArgumentsNode> m_args; + }; + + class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::constNumber()) // could be reusable for pre? + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + { + } + + protected: + Identifier m_ident; + }; + + class PostfixResolveNode : public PrePostResolveNode { + public: + PostfixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset) + , m_operator(oper) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Operator m_operator; + }; + + class PostfixBracketNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + PostfixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_operator(oper) + { + } + + virtual ~PostfixBracketNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + RefPtr<ExpressionNode> m_subscript; + Operator m_operator; + }; + + class PostfixDotNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + PostfixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_operator(oper) + { + } + + virtual ~PostfixDotNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + Identifier m_ident; + Operator m_operator; + }; + + class PostfixErrorNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + PostfixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_expr(expr) + , m_operator(oper) + { + } + + virtual ~PostfixErrorNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + Operator m_operator; + }; + + class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + DeleteResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Identifier m_ident; + }; + + class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData { + public: + DeleteBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + { + } + + virtual ~DeleteBracketNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + RefPtr<ExpressionNode> m_subscript; + }; + + class DeleteDotNode : public ExpressionNode, public ThrowableExpressionData { + public: + DeleteDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + { + } + + virtual ~DeleteDotNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + Identifier m_ident; + }; + + class DeleteValueNode : public ExpressionNode { + public: + DeleteValueNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_expr(expr) + { + } + + virtual ~DeleteValueNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + }; + + class VoidNode : public ExpressionNode { + public: + VoidNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_expr(expr) + { + } + + virtual ~VoidNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + }; + + class TypeOfResolveNode : public ExpressionNode { + public: + TypeOfResolveNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::string()) + , m_ident(ident) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + const Identifier& identifier() const JSC_FAST_CALL { return m_ident; } + + private: + Identifier m_ident; + }; + + class TypeOfValueNode : public ExpressionNode { + public: + TypeOfValueNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::string()) + , m_expr(expr) + { + } + + virtual ~TypeOfValueNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + }; + + class PrefixResolveNode : public PrePostResolveNode { + public: + PrefixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset) + , m_operator(oper) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Operator m_operator; + }; + + class PrefixBracketNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData { + public: + PrefixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_operator(oper) + { + } + + virtual ~PrefixBracketNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + RefPtr<ExpressionNode> m_subscript; + Operator m_operator; + }; + + class PrefixDotNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData { + public: + PrefixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_operator(oper) + { + } + + virtual ~PrefixDotNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + Identifier m_ident; + Operator m_operator; + }; + + class PrefixErrorNode : public ExpressionNode, public ThrowableExpressionData { + public: + PrefixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_expr(expr) + , m_operator(oper) + { + } + + virtual ~PrefixErrorNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + Operator m_operator; + }; + + class UnaryOpNode : public ExpressionNode { + public: + UnaryOpNode(JSGlobalData* globalData, ExpressionNode* expr) + : ExpressionNode(globalData) + , m_expr(expr) + { + } + + UnaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr) + : ExpressionNode(globalData, type) + , m_expr(expr) + { + } + + virtual ~UnaryOpNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + virtual OpcodeID opcodeID() const JSC_FAST_CALL = 0; + + protected: + RefPtr<ExpressionNode> m_expr; + }; + + class UnaryPlusNode : public UnaryOpNode { + public: + UnaryPlusNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : UnaryOpNode(globalData, ResultType::constNumber(), expr) + { + } + + virtual ExpressionNode* stripUnaryPlus() { return m_expr.get(); } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_to_jsnumber; } + }; + + class NegateNode : public UnaryOpNode { + public: + NegateNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : UnaryOpNode(globalData, ResultType::reusableNumber(), expr) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_negate; } + }; + + class BitwiseNotNode : public UnaryOpNode { + public: + BitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : UnaryOpNode(globalData, ResultType::reusableNumber(), expr) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_bitnot; } + }; + + class LogicalNotNode : public UnaryOpNode { + public: + LogicalNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : UnaryOpNode(globalData, ResultType::boolean(), expr) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_not; } + }; + + class BinaryOpNode : public ExpressionNode { + public: + BinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : ExpressionNode(globalData) + , m_expr1(expr1) + , m_expr2(expr2) + , m_rightHasAssignments(rightHasAssignments) + { + } + + BinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : ExpressionNode(globalData, type) + , m_expr1(expr1) + , m_expr2(expr2) + , m_rightHasAssignments(rightHasAssignments) + { + } + + virtual ~BinaryOpNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + virtual OpcodeID opcodeID() const JSC_FAST_CALL = 0; + + protected: + RefPtr<ExpressionNode> m_expr1; + RefPtr<ExpressionNode> m_expr2; + bool m_rightHasAssignments; + }; + + class ReverseBinaryOpNode : public BinaryOpNode { + public: + ReverseBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, expr1, expr2, rightHasAssignments) + { + } + + ReverseBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, type, expr1, expr2, rightHasAssignments) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + }; + + class MultNode : public BinaryOpNode { + public: + MultNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_mul; } + }; + + class DivNode : public BinaryOpNode { + public: + DivNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_div; } + }; + + class ModNode : public BinaryOpNode { + public: + ModNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_mod; } + }; + + class AddNode : public BinaryOpNode { + public: + AddNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_add; } + }; + + class SubNode : public BinaryOpNode { + public: + SubNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_sub; } + }; + + class LeftShiftNode : public BinaryOpNode { + public: + LeftShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_lshift; } + }; + + class RightShiftNode : public BinaryOpNode { + public: + RightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_rshift; } + }; + + class UnsignedRightShiftNode : public BinaryOpNode { + public: + UnsignedRightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_urshift; } + }; + + class LessNode : public BinaryOpNode { + public: + LessNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_less; } + }; + + class GreaterNode : public ReverseBinaryOpNode { + public: + GreaterNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_less; } + }; + + class LessEqNode : public BinaryOpNode { + public: + LessEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_lesseq; } + }; + + class GreaterEqNode : public ReverseBinaryOpNode { + public: + GreaterEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_lesseq; } + }; + + class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData { + public: + ThrowableBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, type, expr1, expr2, rightHasAssignments) + { + } + ThrowableBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, expr1, expr2, rightHasAssignments) + { + } + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + }; + + class InstanceOfNode : public ThrowableBinaryOpNode { + public: + InstanceOfNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : ThrowableBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_instanceof; } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + }; + + class InNode : public ThrowableBinaryOpNode { + public: + InNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : ThrowableBinaryOpNode(globalData, expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_in; } + }; + + class EqualNode : public BinaryOpNode { + public: + EqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_eq; } + }; + + class NotEqualNode : public BinaryOpNode { + public: + NotEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_neq; } + }; + + class StrictEqualNode : public BinaryOpNode { + public: + StrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_stricteq; } + }; + + class NotStrictEqualNode : public BinaryOpNode { + public: + NotStrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_nstricteq; } + }; + + class BitAndNode : public BinaryOpNode { + public: + BitAndNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_bitand; } + }; + + class BitOrNode : public BinaryOpNode { + public: + BitOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_bitor; } + }; + + class BitXOrNode : public BinaryOpNode { + public: + BitXOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL + : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments) + { + } + + virtual OpcodeID opcodeID() const JSC_FAST_CALL { return op_bitxor; } + }; + + /** + * m_expr1 && m_expr2, m_expr1 || m_expr2 + */ + class LogicalOpNode : public ExpressionNode { + public: + LogicalOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper) JSC_FAST_CALL + : ExpressionNode(globalData, ResultType::boolean()) + , m_expr1(expr1) + , m_expr2(expr2) + , m_operator(oper) + { + } + + virtual ~LogicalOpNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr1; + RefPtr<ExpressionNode> m_expr2; + LogicalOperator m_operator; + }; + + /** + * The ternary operator, "m_logical ? m_expr1 : m_expr2" + */ + class ConditionalNode : public ExpressionNode { + public: + ConditionalNode(JSGlobalData* globalData, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_logical(logical) + , m_expr1(expr1) + , m_expr2(expr2) + { + } + + virtual ~ConditionalNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_logical; + RefPtr<ExpressionNode> m_expr1; + RefPtr<ExpressionNode> m_expr2; + }; + + class ReadModifyResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + ReadModifyResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + , m_right(right) + , m_operator(oper) + , m_rightHasAssignments(rightHasAssignments) + { + } + + virtual ~ReadModifyResolveNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Identifier m_ident; + RefPtr<ExpressionNode> m_right; + size_t m_index; // Used by ReadModifyLocalVarNode. + Operator m_operator : 31; + bool m_rightHasAssignments : 1; + }; + + class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignResolveNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_ident(ident) + , m_right(right) + , m_rightHasAssignments(rightHasAssignments) + { + } + + virtual ~AssignResolveNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Identifier m_ident; + RefPtr<ExpressionNode> m_right; + size_t m_index; // Used by ReadModifyLocalVarNode. + bool m_rightHasAssignments; + }; + + class ReadModifyBracketNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + ReadModifyBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_right(right) + , m_operator(oper) + , m_subscriptHasAssignments(subscriptHasAssignments) + , m_rightHasAssignments(rightHasAssignments) + { + } + + virtual ~ReadModifyBracketNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + RefPtr<ExpressionNode> m_subscript; + RefPtr<ExpressionNode> m_right; + Operator m_operator : 30; + bool m_subscriptHasAssignments : 1; + bool m_rightHasAssignments : 1; + }; + + class AssignBracketNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_right(right) + , m_subscriptHasAssignments(subscriptHasAssignments) + , m_rightHasAssignments(rightHasAssignments) + { + } + + virtual ~AssignBracketNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + RefPtr<ExpressionNode> m_subscript; + RefPtr<ExpressionNode> m_right; + bool m_subscriptHasAssignments : 1; + bool m_rightHasAssignments : 1; + }; + + class AssignDotNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_right(right) + , m_rightHasAssignments(rightHasAssignments) + { + } + + virtual ~AssignDotNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + Identifier m_ident; + RefPtr<ExpressionNode> m_right; + bool m_rightHasAssignments; + }; + + class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + ReadModifyDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_right(right) + , m_operator(oper) + , m_rightHasAssignments(rightHasAssignments) + { + } + + virtual ~ReadModifyDotNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_base; + Identifier m_ident; + RefPtr<ExpressionNode> m_right; + Operator m_operator : 31; + bool m_rightHasAssignments : 1; + }; + + class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignErrorNode(JSGlobalData* globalData, ExpressionNode* left, Operator oper, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_left(left) + , m_operator(oper) + , m_right(right) + { + } + + virtual ~AssignErrorNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_left; + Operator m_operator; + RefPtr<ExpressionNode> m_right; + }; + + class CommaNode : public ExpressionNode { + public: + CommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_expr1(expr1) + , m_expr2(expr2) + { + } + + virtual ~CommaNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr1; + RefPtr<ExpressionNode> m_expr2; + }; + + class VarDeclCommaNode : public CommaNode { + public: + VarDeclCommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL + : CommaNode(globalData, expr1, expr2) + { + } + }; + + class ConstDeclNode : public ExpressionNode { + public: + ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in) JSC_FAST_CALL; + + virtual ~ConstDeclNode(); + virtual void releaseNodes(NodeReleaser&); + + Identifier m_ident; + RefPtr<ConstDeclNode> m_next; + RefPtr<ExpressionNode> m_init; + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + virtual RegisterID* emitCodeSingle(BytecodeGenerator&) JSC_FAST_CALL; + }; + + class ConstStatementNode : public StatementNode { + public: + ConstStatementNode(JSGlobalData* globalData, ConstDeclNode* next) JSC_FAST_CALL + : StatementNode(globalData) + , m_next(next) + { + } + + virtual ~ConstStatementNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ConstDeclNode> m_next; + }; + + typedef Vector<RefPtr<StatementNode> > StatementVector; + + class SourceElements : public ParserRefCounted { + public: + SourceElements(JSGlobalData* globalData) : ParserRefCounted(globalData) {} + + void append(PassRefPtr<StatementNode>); + void releaseContentsIntoVector(StatementVector& destination) + { + ASSERT(destination.isEmpty()); + m_statements.swap(destination); + destination.shrinkToFit(); + } + + private: + StatementVector m_statements; + }; + + class BlockNode : public StatementNode { + public: + BlockNode(JSGlobalData*, SourceElements* children) JSC_FAST_CALL; + + virtual ~BlockNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + StatementVector& children() { return m_children; } + + virtual bool isBlock() const JSC_FAST_CALL { return true; } + + private: + StatementVector m_children; + }; + + class EmptyStatementNode : public StatementNode { + public: + EmptyStatementNode(JSGlobalData* globalData) JSC_FAST_CALL // debug + : StatementNode(globalData) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isEmptyStatement() const JSC_FAST_CALL { return true; } + }; + + class DebuggerStatementNode : public StatementNode { + public: + DebuggerStatementNode(JSGlobalData* globalData) JSC_FAST_CALL + : StatementNode(globalData) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + }; + + class ExprStatementNode : public StatementNode { + public: + ExprStatementNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : StatementNode(globalData) + , m_expr(expr) + { + } + + virtual bool isExprStatement() const JSC_FAST_CALL { return true; } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + ExpressionNode* expr() const { return m_expr.get(); } + + private: + RefPtr<ExpressionNode> m_expr; + }; + + class VarStatementNode : public StatementNode { + public: + VarStatementNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : StatementNode(globalData) + , m_expr(expr) + { + } + + virtual ~VarStatementNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + }; + + class IfNode : public StatementNode { + public: + IfNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock) JSC_FAST_CALL + : StatementNode(globalData) + , m_condition(condition) + , m_ifBlock(ifBlock) + { + } + + virtual ~IfNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + protected: + RefPtr<ExpressionNode> m_condition; + RefPtr<StatementNode> m_ifBlock; + }; + + class IfElseNode : public IfNode { + public: + IfElseNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock) JSC_FAST_CALL + : IfNode(globalData, condition, ifBlock) + , m_elseBlock(elseBlock) + { + } + + virtual ~IfElseNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<StatementNode> m_elseBlock; + }; + + class DoWhileNode : public StatementNode { + public: + DoWhileNode(JSGlobalData* globalData, StatementNode* statement, ExpressionNode* expr) JSC_FAST_CALL + : StatementNode(globalData) + , m_statement(statement) + , m_expr(expr) + { + } + + virtual ~DoWhileNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isLoop() const JSC_FAST_CALL { return true; } + + private: + RefPtr<StatementNode> m_statement; + RefPtr<ExpressionNode> m_expr; + }; + + class WhileNode : public StatementNode { + public: + WhileNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement) JSC_FAST_CALL + : StatementNode(globalData) + , m_expr(expr) + , m_statement(statement) + { + } + + virtual ~WhileNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isLoop() const JSC_FAST_CALL { return true; } + + private: + RefPtr<ExpressionNode> m_expr; + RefPtr<StatementNode> m_statement; + }; + + class ForNode : public StatementNode { + public: + ForNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl) JSC_FAST_CALL + : StatementNode(globalData) + , m_expr1(expr1) + , m_expr2(expr2) + , m_expr3(expr3) + , m_statement(statement) + , m_expr1WasVarDecl(expr1 && expr1WasVarDecl) + { + ASSERT(statement); + } + + virtual ~ForNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isLoop() const JSC_FAST_CALL { return true; } + + private: + RefPtr<ExpressionNode> m_expr1; + RefPtr<ExpressionNode> m_expr2; + RefPtr<ExpressionNode> m_expr3; + RefPtr<StatementNode> m_statement; + bool m_expr1WasVarDecl; + }; + + class ForInNode : public StatementNode, public ThrowableExpressionData { + public: + ForInNode(JSGlobalData*, ExpressionNode*, ExpressionNode*, StatementNode*) JSC_FAST_CALL; + ForInNode(JSGlobalData*, const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*, int divot, int startOffset, int endOffset) JSC_FAST_CALL; + + virtual ~ForInNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + virtual bool isLoop() const JSC_FAST_CALL { return true; } + + private: + Identifier m_ident; + RefPtr<ExpressionNode> m_init; + RefPtr<ExpressionNode> m_lexpr; + RefPtr<ExpressionNode> m_expr; + RefPtr<StatementNode> m_statement; + bool m_identIsVarDecl; + }; + + class ContinueNode : public StatementNode, public ThrowableExpressionData { + public: + ContinueNode(JSGlobalData* globalData) JSC_FAST_CALL + : StatementNode(globalData) + { + } + + ContinueNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL + : StatementNode(globalData) + , m_ident(ident) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Identifier m_ident; + }; + + class BreakNode : public StatementNode, public ThrowableExpressionData { + public: + BreakNode(JSGlobalData* globalData) JSC_FAST_CALL + : StatementNode(globalData) + { + } + + BreakNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL + : StatementNode(globalData) + , m_ident(ident) + { + } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Identifier m_ident; + }; + + class ReturnNode : public StatementNode, public ThrowableExpressionData { + public: + ReturnNode(JSGlobalData* globalData, ExpressionNode* value) JSC_FAST_CALL + : StatementNode(globalData) + , m_value(value) + { + } + + virtual ~ReturnNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + virtual bool isReturnNode() const JSC_FAST_CALL { return true; } + + private: + RefPtr<ExpressionNode> m_value; + }; + + class WithNode : public StatementNode { + public: + WithNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement, uint32_t divot, uint32_t expressionLength) JSC_FAST_CALL + : StatementNode(globalData) + , m_expr(expr) + , m_statement(statement) + , m_divot(divot) + , m_expressionLength(expressionLength) + { + } + + virtual ~WithNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + RefPtr<StatementNode> m_statement; + uint32_t m_divot; + uint32_t m_expressionLength; + }; + + class LabelNode : public StatementNode, public ThrowableExpressionData { + public: + LabelNode(JSGlobalData* globalData, const Identifier& name, StatementNode* statement) JSC_FAST_CALL + : StatementNode(globalData) + , m_name(name) + , m_statement(statement) + { + } + + virtual ~LabelNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + Identifier m_name; + RefPtr<StatementNode> m_statement; + }; + + class ThrowNode : public StatementNode, public ThrowableExpressionData { + public: + ThrowNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : StatementNode(globalData) + , m_expr(expr) + { + } + + virtual ~ThrowNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + }; + + class TryNode : public StatementNode { + public: + TryNode(JSGlobalData* globalData, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock) JSC_FAST_CALL + : StatementNode(globalData) + , m_tryBlock(tryBlock) + , m_exceptionIdent(exceptionIdent) + , m_catchBlock(catchBlock) + , m_finallyBlock(finallyBlock) + , m_catchHasEval(catchHasEval) + { + } + + virtual ~TryNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* dst = 0) JSC_FAST_CALL; + + private: + RefPtr<StatementNode> m_tryBlock; + Identifier m_exceptionIdent; + RefPtr<StatementNode> m_catchBlock; + RefPtr<StatementNode> m_finallyBlock; + bool m_catchHasEval; + }; + + class ParameterNode : public ParserRefCounted { + public: + ParameterNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_ident(ident) + { + } + + ParameterNode(JSGlobalData* globalData, ParameterNode* l, const Identifier& ident) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_ident(ident) + { + l->m_next = this; + } + + virtual ~ParameterNode(); + virtual void releaseNodes(NodeReleaser&); + + const Identifier& ident() const JSC_FAST_CALL { return m_ident; } + ParameterNode* nextParam() const JSC_FAST_CALL { return m_next.get(); } + + private: + Identifier m_ident; + RefPtr<ParameterNode> m_next; + }; + + struct ScopeNodeData { + typedef DeclarationStacks::VarStack VarStack; + typedef DeclarationStacks::FunctionStack FunctionStack; + + ScopeNodeData(SourceElements*, VarStack*, FunctionStack*, int numConstants); + + VarStack m_varStack; + FunctionStack m_functionStack; + int m_numConstants; + StatementVector m_children; + }; + + class ScopeNode : public StatementNode { + public: + typedef DeclarationStacks::VarStack VarStack; + typedef DeclarationStacks::FunctionStack FunctionStack; + + ScopeNode(JSGlobalData*) JSC_FAST_CALL; + ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants) JSC_FAST_CALL; + virtual ~ScopeNode(); + virtual void releaseNodes(NodeReleaser&); + + void adoptData(std::auto_ptr<ScopeNodeData> data) { m_data.adopt(data); } + ScopeNodeData* data() const { return m_data.get(); } + void destroyData() { m_data.clear(); } + + const SourceCode& source() const { return m_source; } + const UString& sourceURL() const JSC_FAST_CALL { 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; } + void setUsesArguments() { m_features |= ArgumentsFeature; } + bool usesThis() const { return m_features & ThisFeature; } + bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } + + VarStack& varStack() { ASSERT(m_data); return m_data->m_varStack; } + FunctionStack& functionStack() { ASSERT(m_data); return m_data->m_functionStack; } + + StatementVector& children() { ASSERT(m_data); return m_data->m_children; } + + 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; + } + + 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 ProgramNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; + + ProgramCodeBlock& bytecode(ScopeChainNode* scopeChain) JSC_FAST_CALL + { + if (!m_code) + generateBytecode(scopeChain); + return *m_code; + } + + private: + ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; + + void generateBytecode(ScopeChainNode*) JSC_FAST_CALL; + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + OwnPtr<ProgramCodeBlock> m_code; + }; + + class EvalNode : public ScopeNode { + public: + static EvalNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; + + EvalCodeBlock& bytecode(ScopeChainNode* scopeChain) JSC_FAST_CALL + { + if (!m_code) + generateBytecode(scopeChain); + return *m_code; + } + + EvalCodeBlock& bytecodeForExceptionInfoReparse(ScopeChainNode*) JSC_FAST_CALL; + + private: + EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; + + void generateBytecode(ScopeChainNode*) JSC_FAST_CALL; + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + OwnPtr<EvalCodeBlock> m_code; + }; + + class FunctionBodyNode : public ScopeNode { + friend class JIT; + public: + static FunctionBodyNode* create(JSGlobalData*) JSC_FAST_CALL; + static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; + virtual ~FunctionBodyNode(); + + const Identifier* parameters() const JSC_FAST_CALL { return m_parameters; } + size_t parameterCount() const { return m_parameterCount; } + UString paramString() const JSC_FAST_CALL; + Identifier* copyParameters(); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + CodeBlock& bytecode(ScopeChainNode* scopeChain) JSC_FAST_CALL + { + ASSERT(scopeChain); + if (!m_code) + generateBytecode(scopeChain); + return *m_code; + } + + CodeBlock& generatedBytecode() JSC_FAST_CALL + { + ASSERT(m_code); + return *m_code; + } + + bool isGenerated() JSC_FAST_CALL + { + return m_code; + } + + void mark(); + + void finishParsing(const SourceCode&, ParameterNode*); + void finishParsing(Identifier* parameters, size_t parameterCount); + + UString toSourceString() const JSC_FAST_CALL { return UString("{") + source().toString() + UString("}"); } + + // These objects are ref/deref'd a lot in the scope chain, so this is a faster ref/deref. + // If the virtual machine changes so this doesn't happen as much we can change back. + void ref() + { + if (++m_refCount == 1) + ScopeNode::ref(); + } + void deref() + { + ASSERT(m_refCount); + if (!--m_refCount) + ScopeNode::deref(); + } + + CodeBlock& bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChain) JSC_FAST_CALL; + + private: + FunctionBodyNode(JSGlobalData*) JSC_FAST_CALL; + FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL; + + void generateBytecode(ScopeChainNode*) JSC_FAST_CALL; + + Identifier* m_parameters; + size_t m_parameterCount; + OwnPtr<CodeBlock> m_code; + unsigned m_refCount; + }; + + class FuncExprNode : public ExpressionNode { + public: + FuncExprNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0) JSC_FAST_CALL + : ExpressionNode(globalData) + , m_ident(ident) + , m_parameter(parameter) + , m_body(body) + { + m_body->finishParsing(source, m_parameter.get()); + } + + virtual ~FuncExprNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual bool isFuncExprNode() const JSC_FAST_CALL { return true; } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + JSFunction* makeFunction(ExecState*, ScopeChainNode*) JSC_FAST_CALL; + + FunctionBodyNode* body() { return m_body.get(); } + + private: + Identifier m_ident; + RefPtr<ParameterNode> m_parameter; + RefPtr<FunctionBodyNode> m_body; + }; + + class FuncDeclNode : public StatementNode { + public: + FuncDeclNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0) JSC_FAST_CALL + : StatementNode(globalData) + , m_ident(ident) + , m_parameter(parameter) + , m_body(body) + { + m_body->finishParsing(source, m_parameter.get()); + } + + virtual ~FuncDeclNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + JSFunction* makeFunction(ExecState*, ScopeChainNode*) JSC_FAST_CALL; + + Identifier m_ident; + + FunctionBodyNode* body() { return m_body.get(); } + + private: + RefPtr<ParameterNode> m_parameter; + RefPtr<FunctionBodyNode> m_body; + }; + + class CaseClauseNode : public ParserRefCounted { + public: + CaseClauseNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_expr(expr) + { + } + + CaseClauseNode(JSGlobalData* globalData, ExpressionNode* expr, SourceElements* children) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_expr(expr) + { + if (children) + children->releaseContentsIntoVector(m_children); + } + + virtual ~CaseClauseNode(); + virtual void releaseNodes(NodeReleaser&); + + ExpressionNode* expr() const { return m_expr.get(); } + StatementVector& children() { return m_children; } + + private: + RefPtr<ExpressionNode> m_expr; + StatementVector m_children; + }; + + class ClauseListNode : public ParserRefCounted { + public: + ClauseListNode(JSGlobalData* globalData, CaseClauseNode* clause) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_clause(clause) + { + } + + ClauseListNode(JSGlobalData* globalData, ClauseListNode* clauseList, CaseClauseNode* clause) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_clause(clause) + { + clauseList->m_next = this; + } + + virtual ~ClauseListNode(); + virtual void releaseNodes(NodeReleaser&); + + CaseClauseNode* getClause() const JSC_FAST_CALL { return m_clause.get(); } + ClauseListNode* getNext() const JSC_FAST_CALL { return m_next.get(); } + + private: + RefPtr<CaseClauseNode> m_clause; + RefPtr<ClauseListNode> m_next; + }; + + class CaseBlockNode : public ParserRefCounted { + public: + CaseBlockNode(JSGlobalData* globalData, ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2) JSC_FAST_CALL + : ParserRefCounted(globalData) + , m_list1(list1) + , m_defaultClause(defaultClause) + , m_list2(list2) + { + } + + virtual ~CaseBlockNode(); + virtual void releaseNodes(NodeReleaser&); + + RegisterID* emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* dst = 0) JSC_FAST_CALL; + + private: + SwitchInfo::SwitchType tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num); + RefPtr<ClauseListNode> m_list1; + RefPtr<CaseClauseNode> m_defaultClause; + RefPtr<ClauseListNode> m_list2; + }; + + class SwitchNode : public StatementNode { + public: + SwitchNode(JSGlobalData* globalData, ExpressionNode* expr, CaseBlockNode* block) JSC_FAST_CALL + : StatementNode(globalData) + , m_expr(expr) + , m_block(block) + { + } + + virtual ~SwitchNode(); + virtual void releaseNodes(NodeReleaser&); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0) JSC_FAST_CALL; + + private: + RefPtr<ExpressionNode> m_expr; + RefPtr<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/src/3rdparty/webkit/JavaScriptCore/parser/Parser.cpp b/src/3rdparty/webkit/JavaScriptCore/parser/Parser.cpp new file mode 100644 index 0000000..1b1e4d7 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Parser.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "Parser.h" + +#include "Debugger.h" +#include "Lexer.h" +#include <wtf/HashSet.h> +#include <wtf/Vector.h> +#include <memory> + +using std::auto_ptr; + +extern int jscyyparse(void*); + +namespace JSC { + +void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg) +{ + ASSERT(!m_sourceElements); + + int defaultErrLine; + UString defaultErrMsg; + + if (!errLine) + errLine = &defaultErrLine; + if (!errMsg) + errMsg = &defaultErrMsg; + + *errLine = -1; + *errMsg = 0; + + Lexer& lexer = *globalData->lexer; + lexer.setCode(*m_source); + + int parseError = jscyyparse(globalData); + bool lexError = lexer.sawError(); + lexer.clear(); + + ParserRefCounted::deleteNewObjects(globalData); + + if (parseError || lexError) { + *errLine = lexer.lineNo(); + *errMsg = "Parse error"; + m_sourceElements.clear(); + } +} + +void Parser::reparseInPlace(JSGlobalData* globalData, FunctionBodyNode* functionBodyNode) +{ + ASSERT(!functionBodyNode->data()); + + m_source = &functionBodyNode->source(); + globalData->lexer->setIsReparsing(); + parse(globalData, 0, 0); + ASSERT(m_sourceElements); + + functionBodyNode->adoptData(std::auto_ptr<ScopeNodeData>(new ScopeNodeData(m_sourceElements.get(), + m_varDeclarations ? &m_varDeclarations->data : 0, + m_funcDeclarations ? &m_funcDeclarations->data : 0, + m_numConstants))); + bool usesArguments = functionBodyNode->usesArguments(); + functionBodyNode->setFeatures(m_features); + if (usesArguments && !functionBodyNode->usesArguments()) + functionBodyNode->setUsesArguments(); + + m_source = 0; + m_sourceElements = 0; + m_varDeclarations = 0; + m_funcDeclarations = 0; +} + +void Parser::didFinishParsing(SourceElements* sourceElements, ParserRefCountedData<DeclarationStacks::VarStack>* varStack, + ParserRefCountedData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants) +{ + m_sourceElements = sourceElements; + m_varDeclarations = varStack; + m_funcDeclarations = funcStack; + m_features = features; + m_lastLine = lastLine; + m_numConstants = numConstants; +} + +} // namespace JSC diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/Parser.h b/src/3rdparty/webkit/JavaScriptCore/parser/Parser.h new file mode 100644 index 0000000..6191ccb --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/Parser.h @@ -0,0 +1,123 @@ +/* + * 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 "SourceProvider.h" +#include "Debugger.h" +#include "Nodes.h" +#include <wtf/Forward.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class FunctionBodyNode; + class ProgramNode; + class UString; + + template <typename T> + struct ParserRefCountedData : ParserRefCounted { + ParserRefCountedData(JSGlobalData* globalData) + : ParserRefCounted(globalData) + { + } + + T data; + }; + + class Parser : Noncopyable { + public: + template <class ParsedNode> PassRefPtr<ParsedNode> parse(ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0); + template <class ParsedNode> PassRefPtr<ParsedNode> reparse(JSGlobalData*, ParsedNode*); + void reparseInPlace(JSGlobalData*, FunctionBodyNode*); + + void didFinishParsing(SourceElements*, ParserRefCountedData<DeclarationStacks::VarStack>*, + ParserRefCountedData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants); + + private: + void parse(JSGlobalData*, int* errLine, UString* errMsg); + + const SourceCode* m_source; + RefPtr<SourceElements> m_sourceElements; + RefPtr<ParserRefCountedData<DeclarationStacks::VarStack> > m_varDeclarations; + RefPtr<ParserRefCountedData<DeclarationStacks::FunctionStack> > m_funcDeclarations; + CodeFeatures m_features; + int m_lastLine; + int m_numConstants; + }; + + template <class ParsedNode> PassRefPtr<ParsedNode> Parser::parse(ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) + { + m_source = &source; + parse(&exec->globalData(), errLine, errMsg); + RefPtr<ParsedNode> result; + if (m_sourceElements) { + result = ParsedNode::create(&exec->globalData(), + m_sourceElements.get(), + m_varDeclarations ? &m_varDeclarations->data : 0, + m_funcDeclarations ? &m_funcDeclarations->data : 0, + *m_source, + m_features, + m_numConstants); + result->setLoc(m_source->firstLine(), m_lastLine); + } + + m_source = 0; + m_sourceElements = 0; + m_varDeclarations = 0; + m_funcDeclarations = 0; + + if (debugger) + debugger->sourceParsed(exec, source, *errLine, *errMsg); + return result.release(); + } + + template <class ParsedNode> PassRefPtr<ParsedNode> Parser::reparse(JSGlobalData* globalData, ParsedNode* oldParsedNode) + { + m_source = &oldParsedNode->source(); + parse(globalData, 0, 0); + RefPtr<ParsedNode> result; + if (m_sourceElements) { + result = ParsedNode::create(globalData, + m_sourceElements.get(), + m_varDeclarations ? &m_varDeclarations->data : 0, + m_funcDeclarations ? &m_funcDeclarations->data : 0, + *m_source, + oldParsedNode->features(), + m_numConstants); + result->setLoc(m_source->firstLine(), m_lastLine); + } + + m_source = 0; + m_sourceElements = 0; + m_varDeclarations = 0; + m_funcDeclarations = 0; + + return result.release(); + } + +} // namespace JSC + +#endif // Parser_h diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/ResultType.h b/src/3rdparty/webkit/JavaScriptCore/parser/ResultType.h new file mode 100644 index 0000000..4913887 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/ResultType.h @@ -0,0 +1,159 @@ +/* + * 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 TypeMaybeNumber = 2; + static const Type TypeMaybeString = 4; + static const Type TypeMaybeNull = 8; + static const Type TypeMaybeBool = 16; + static const Type TypeMaybeOther = 32; + + static const Type TypeReusableNumber = 3; + static const Type TypeStringOrReusableNumber = 4; + + explicit ResultType(Type type) + : m_type(type) + { + } + + bool isReusable() + { + return (m_type & TypeReusable); + } + + bool definitelyIsNumber() + { + return ((m_type & ~TypeReusable) == TypeMaybeNumber); + } + + bool isNotNumber() + { + return ((m_type & TypeMaybeNumber) == 0); + } + + bool mightBeNumber() + { + return !isNotNumber(); + } + + static ResultType nullType() + { + return ResultType(TypeMaybeNull); + } + + static ResultType boolean() + { + return ResultType(TypeMaybeBool); + } + + static ResultType constNumber() + { + return ResultType(TypeMaybeNumber); + } + + static ResultType reusableNumber() + { + return ResultType(TypeReusable | TypeMaybeNumber); + } + + static ResultType reusableNumberOrString() + { + return ResultType(TypeReusable | TypeMaybeNumber | TypeMaybeString); + } + + static ResultType string() + { + return ResultType(TypeMaybeString); + } + + static ResultType unknown() + { + return ResultType(TypeMaybeNumber | TypeMaybeString | TypeMaybeNull | TypeMaybeBool | TypeMaybeOther); + } + + static ResultType forAdd(ResultType op1, ResultType op2) + { + if (op1.definitelyIsNumber() && op2.definitelyIsNumber()) + return reusableNumber(); + if (op1.isNotNumber() || op2.isNotNumber()) + return string(); + return reusableNumberOrString(); + } + + private: + Type m_type; + }; + + struct OperandTypes + { + OperandTypes(ResultType first = ResultType::unknown(), ResultType second = ResultType::unknown()) + { + 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/src/3rdparty/webkit/JavaScriptCore/parser/SourceCode.h b/src/3rdparty/webkit/JavaScriptCore/parser/SourceCode.h new file mode 100644 index 0000000..84360b8 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/SourceCode.h @@ -0,0 +1,91 @@ +/* + * 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_startChar(0) + , m_endChar(0) + , m_firstLine(0) + { + } + + SourceCode(PassRefPtr<SourceProvider> provider, int firstLine = 1) + : m_provider(provider) + , m_startChar(0) + , m_endChar(m_provider->length()) + , m_firstLine(std::max(firstLine, 1)) + { + } + + SourceCode(PassRefPtr<SourceProvider> provider, int start, int end, int firstLine) + : m_provider(provider) + , m_startChar(start) + , m_endChar(end) + , m_firstLine(std::max(firstLine, 1)) + { + } + + UString toString() const + { + if (!m_provider) + return UString(); + return m_provider->getRange(m_startChar, m_endChar); + } + + bool isNull() const { return !m_provider; } + SourceProvider* provider() const { return m_provider.get(); } + int firstLine() const { return m_firstLine; } + int startOffset() const { return m_startChar; } + int endOffset() const { return m_endChar; } + const UChar* data() const { return m_provider->data() + m_startChar; } + int length() const { return m_endChar - m_startChar; } + + private: + RefPtr<SourceProvider> m_provider; + int m_startChar; + int m_endChar; + int m_firstLine; + }; + + inline SourceCode makeSource(const UString& source, const UString& url = UString(), int firstLine = 1) + { + return SourceCode(UStringSourceProvider::create(source, url), firstLine); + } + +} // namespace JSC + +#endif // SourceCode_h diff --git a/src/3rdparty/webkit/JavaScriptCore/parser/SourceProvider.h b/src/3rdparty/webkit/JavaScriptCore/parser/SourceProvider.h new file mode 100644 index 0000000..07da9e0 --- /dev/null +++ b/src/3rdparty/webkit/JavaScriptCore/parser/SourceProvider.h @@ -0,0 +1,79 @@ +/* + * 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 SourceProvider_h +#define SourceProvider_h + +#include "UString.h" +#include <wtf/RefCounted.h> + +namespace JSC { + + class SourceProvider : public RefCounted<SourceProvider> { + public: + SourceProvider(const UString& url) + : m_url(url) + { + } + virtual ~SourceProvider() { } + + virtual UString getRange(int start, int end) const = 0; + virtual const UChar* data() const = 0; + virtual int length() const = 0; + + const UString& url() { return m_url; } + intptr_t asID() { return reinterpret_cast<intptr_t>(this); } + + private: + UString m_url; + }; + + class UStringSourceProvider : public SourceProvider { + public: + static PassRefPtr<UStringSourceProvider> create(const UString& source, const UString& url) + { + return adoptRef(new UStringSourceProvider(source, url)); + } + + UString getRange(int start, int end) const { return m_source.substr(start, end - start); } + const UChar* data() const { return m_source.data(); } + int length() const { return m_source.size(); } + + private: + UStringSourceProvider(const UString& source, const UString& url) + : SourceProvider(url) + , m_source(source) + { + } + + UString m_source; + }; + +} // namespace JSC + +#endif // SourceProvider_h |