diff options
author | Simon Hausmann <simon.hausmann@nokia.com> | 2009-09-16 07:51:00 (GMT) |
---|---|---|
committer | Simon Hausmann <simon.hausmann@nokia.com> | 2009-09-16 07:58:16 (GMT) |
commit | 120329adb47dba60f532c1c2fd2ad0f37b812437 (patch) | |
tree | fc2311cef4b69fe7294e8f5aab27fe6af2546123 /src/3rdparty/javascriptcore/JavaScriptCore/parser | |
parent | ce17ae5a6159d8ce3a5d2cc98f804a2debb860e5 (diff) | |
download | Qt-120329adb47dba60f532c1c2fd2ad0f37b812437.zip Qt-120329adb47dba60f532c1c2fd2ad0f37b812437.tar.gz Qt-120329adb47dba60f532c1c2fd2ad0f37b812437.tar.bz2 |
Separate the copy of JavaScriptCore that QtScript uses from the copy that
QtWebKit uses.
This is needed to decouple QtScript from QtWebKit, as discussed in the
WebKit team.
Reviewed-by: Kent Hansen
Diffstat (limited to 'src/3rdparty/javascriptcore/JavaScriptCore/parser')
17 files changed, 9163 insertions, 0 deletions
diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/Grammar.y b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Grammar.y new file mode 100644 index 0000000..a3bf1fe --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Grammar.y @@ -0,0 +1,2093 @@ +%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 "NodeConstructors.h" +#include "Lexer.h" +#include "JSString.h" +#include "JSGlobalData.h" +#include "CommonIdentifiers.h" +#include "NodeInfo.h" +#include "Parser.h" +#include <wtf/FastMalloc.h> +#include <wtf/MathExtras.h> + +#define YYMALLOC fastMalloc +#define YYFREE fastFree + +#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, (s).first_column + 1) + +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* combineCommaNodes(void*, ExpressionNode* list, ExpressionNode* init); + +#if COMPILER(MSVC) + +#pragma warning(disable: 4065) +#pragma warning(disable: 4244) +#pragma warning(disable: 4702) + +#endif + +#define YYPARSE_PARAM globalPtr +#define YYLEX_PARAM globalPtr + +template <typename T> NodeDeclarationInfo<T> createNodeDeclarationInfo(T node, ParserArenaData<DeclarationStacks::VarStack>* varDecls, + ParserArenaData<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> inline 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); + + // Manually release as much as possible from the now-defunct declaration lists + // to avoid accumulating so many unused heap allocated vectors. + decls2->data.clear(); + + return decls1; +} + +static void appendToVarDeclarationList(void* globalPtr, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs) +{ + if (!varDecls) + varDecls = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; + + varDecls->data.append(make_pair(ident, attrs)); + +} + +static inline void appendToVarDeclarationList(void* globalPtr, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl) +{ + unsigned attrs = DeclarationStacks::IsConstant; + if (decl->hasInitializer()) + attrs |= DeclarationStacks::HasInitializer; + appendToVarDeclarationList(globalPtr, varDecls, decl->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 (GLOBAL_DATA) NullNode(GLOBAL_DATA), 0, 1); } + | TRUETOKEN { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BooleanNode(GLOBAL_DATA, true), 0, 1); } + | FALSETOKEN { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) BooleanNode(GLOBAL_DATA, false), 0, 1); } + | NUMBER { $$ = createNodeInfo<ExpressionNode*>(makeNumberNode(GLOBAL_DATA, $1), 0, 1); } + | STRING { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) StringNode(GLOBAL_DATA, *$1), 0, 1); } + | '/' /* regexp */ { + Lexer& l = *LEXER; + if (!l.scanRegExp()) + YYABORT; + RegExpNode* node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } + | STRING ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } + | NUMBER ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) ObjectLiteralNode(GLOBAL_DATA), 0, 0); } + | OPENBRACE PropertyList CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } +; + +PrimaryExprNoBrace: + THISTOKEN { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ThisNode(GLOBAL_DATA), ThisFeature, 0); } + | Literal + | ArrayLiteral + | IDENT { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ResolveNode(GLOBAL_DATA, *$1, @1.first_column), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); } + | '(' Expr ')' { $$ = $2; } +; + +ArrayLiteral: + '[' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ArrayNode(GLOBAL_DATA, $2), 0, $2 ? 1 : 0); } + | '[' ElementList ']' { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) ArrayNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } + | '[' ElementList ',' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) ArgumentsNode(GLOBAL_DATA), 0, 0); } + | '(' ArgumentList ')' { $$ = createNodeInfo<ArgumentsNode*>(new (GLOBAL_DATA) ArgumentsNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); } +; + +ArgumentList: + AssignmentExpr { $$.m_node.head = new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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*>(combineCommaNodes(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*>(combineCommaNodes(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*>(combineCommaNodes(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 (GLOBAL_DATA) BlockNode(GLOBAL_DATA, 0), 0, 0, 0, 0); + DBG($$.m_node, @1, @2); } + | OPENBRACE SourceElements CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; + 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; + 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 (GLOBAL_DATA) 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 = combineCommaNodes(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 (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; + 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; + 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 (GLOBAL_DATA) 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 = combineCommaNodes(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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; + 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 (GLOBAL_DATA) ConstDeclNode(GLOBAL_DATA, *$1, 0), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); } + | IDENT Initializer { $$ = createNodeInfo<ConstDeclNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) EmptyStatementNode(GLOBAL_DATA), 0, 0, 0, 0); } +; + +ExprStatement: + ExprNoBF ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants); + DBG($$.m_node, @1, @2); } + | ExprNoBF error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) BreakNode(GLOBAL_DATA); + SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA), 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + | BREAK IDENT ';' { BreakNode* node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2); + SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2), 0, 0, 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } +; + +ReturnStatement: + RETURN ';' { ReturnNode* node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) CaseClauseNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_features, $2.m_numConstants); } + | CASE Expr ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) CaseClauseNode(GLOBAL_DATA, 0), 0, 0, 0, 0); } + | DEFAULT ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0); + DBG($$.m_node, @1, @2); } + | DEBUGGER error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$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 (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) AssignResolveNode(GLOBAL_DATA, resolve->identifier(), expr, exprHasAssignments); + SET_EXCEPTION_LOCATION(node, start, divot, end); + return node; + } else + return new (GLOBAL_DATA) 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 (GLOBAL_DATA) AssignBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot()); + else { + ReadModifyBracketNode* node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) AssignDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot()); + + ReadModifyDotNode* node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) PrefixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); + + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new (GLOBAL_DATA) PrefixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + PrefixBracketNode* node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) PostfixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); + + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new (GLOBAL_DATA) PostfixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + PostfixBracketNode* node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) EvalFunctionCallNode(GLOBAL_DATA, args.m_node, divot, divot - start, end - divot), EvalFeature | features, numConstants); + return createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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; + if (dot->identifier() == GLOBAL_DATA->propertyNames->call) + node = new (GLOBAL_DATA) CallFunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); + else if (dot->identifier() == GLOBAL_DATA->propertyNames->apply) + node = new (GLOBAL_DATA) ApplyFunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); + else + node = new (GLOBAL_DATA) 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 (GLOBAL_DATA) TypeOfResolveNode(GLOBAL_DATA, resolve->identifier()); + } + return new (GLOBAL_DATA) TypeOfValueNode(GLOBAL_DATA, expr); +} + +static ExpressionNode* makeDeleteNode(void* globalPtr, ExpressionNode* expr, int start, int divot, int end) +{ + if (!expr->isLocation()) + return new (GLOBAL_DATA) DeleteValueNode(GLOBAL_DATA, expr); + if (expr->isResolveNode()) { + ResolveNode* resolve = static_cast<ResolveNode*>(expr); + return new (GLOBAL_DATA) DeleteResolveNode(GLOBAL_DATA, resolve->identifier(), divot, divot - start, end - divot); + } + if (expr->isBracketAccessorNode()) { + BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); + return new (GLOBAL_DATA) DeleteBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), divot, divot - start, end - divot); + } + ASSERT(expr->isDotAccessorNode()); + DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); + return new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) NegateNode(GLOBAL_DATA, n); +} + +static NumberNode* makeNumberNode(void* globalPtr, double d) +{ + return new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) UnaryPlusNode(GLOBAL_DATA, expr2); + + if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1) + return new (GLOBAL_DATA) UnaryPlusNode(GLOBAL_DATA, expr1); + + return new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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* combineCommaNodes(void* globalPtr, ExpressionNode* list, ExpressionNode* init) +{ + if (!list) + return init; + if (list->isCommaNode()) { + static_cast<CommaNode*>(list)->append(init); + return list; + } + return new (GLOBAL_DATA) CommaNode(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 (GLOBAL_DATA) EmptyStatementNode(GLOBAL_DATA); + return new (GLOBAL_DATA) VarStatementNode(GLOBAL_DATA, expr); +} + +#undef GLOBAL_DATA diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/Keywords.table b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Keywords.table new file mode 100644 index 0000000..490c1cc --- /dev/null +++ b/src/3rdparty/javascriptcore/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/javascriptcore/JavaScriptCore/parser/Lexer.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Lexer.cpp new file mode 100644 index 0000000..c36763c --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Lexer.cpp @@ -0,0 +1,997 @@ +/* + * 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/Assertions.h> + +using namespace WTF; +using namespace Unicode; + +// We can't specify the namespace in yacc's C output, so do it here instead. +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 the C++ world. +int jscyylex(void* lvalp, void* llocp, void* globalData) +{ + return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp); +} + +namespace JSC { + +static const UChar byteOrderMark = 0xFEFF; + +Lexer::Lexer(JSGlobalData* globalData) + : m_isReparsing(false) + , m_globalData(globalData) + , m_startColumnNumberCorrection(0) + , m_keywordTable(JSC::mainTable) +{ + m_buffer8.reserveInitialCapacity(initialReadBufferCapacity); + m_buffer16.reserveInitialCapacity(initialReadBufferCapacity); +} + +Lexer::~Lexer() +{ + m_keywordTable.deleteTable(); +} + +inline const UChar* Lexer::currentCharacter() const +{ + return m_code - 4; +} + +inline int Lexer::currentOffset() const +{ + return currentCharacter() - m_codeStart; +} + +ALWAYS_INLINE void Lexer::shift1() +{ + m_current = m_next1; + m_next1 = m_next2; + m_next2 = m_next3; + if (LIKELY(m_code < m_codeEnd)) + m_next3 = m_code[0]; + else + m_next3 = -1; + + ++m_code; +} + +ALWAYS_INLINE void Lexer::shift2() +{ + m_current = m_next2; + m_next1 = m_next3; + if (LIKELY(m_code + 1 < m_codeEnd)) { + m_next2 = m_code[0]; + m_next3 = m_code[1]; + } else { + m_next2 = m_code < m_codeEnd ? m_code[0] : -1; + m_next3 = -1; + } + + m_code += 2; +} + +ALWAYS_INLINE void Lexer::shift3() +{ + m_current = m_next3; + if (LIKELY(m_code + 2 < m_codeEnd)) { + m_next1 = m_code[0]; + m_next2 = m_code[1]; + m_next3 = m_code[2]; + } else { + m_next1 = m_code < m_codeEnd ? m_code[0] : -1; + m_next2 = m_code + 1 < m_codeEnd ? m_code[1] : -1; + m_next3 = -1; + } + + m_code += 3; +} + +ALWAYS_INLINE void Lexer::shift4() +{ + if (LIKELY(m_code + 3 < m_codeEnd)) { + m_current = m_code[0]; + m_next1 = m_code[1]; + m_next2 = m_code[2]; + m_next3 = m_code[3]; + } else { + m_current = m_code < m_codeEnd ? m_code[0] : -1; + m_next1 = m_code + 1 < m_codeEnd ? m_code[1] : -1; + m_next2 = m_code + 2 < m_codeEnd ? m_code[2] : -1; + m_next3 = -1; + } + + m_code += 4; +} + +void Lexer::setCode(const SourceCode& source) +{ + m_lineNumber = source.firstLine(); + m_delimited = false; + m_lastToken = -1; + + const UChar* data = source.provider()->data(); + + m_source = &source; + m_codeStart = data; + m_code = data + source.startOffset(); + m_codeEnd = data + source.endOffset(); + m_error = false; + m_atLineStart = true; + + // ECMA-262 calls for stripping all Cf characters, but we only strip BOM characters. + // See <https://bugs.webkit.org/show_bug.cgi?id=4931> for details. + if (source.provider()->hasBOMs()) { + for (const UChar* p = m_codeStart; p < m_codeEnd; ++p) { + if (UNLIKELY(*p == byteOrderMark)) { + copyCodeWithoutBOMs(); + break; + } + } + } + + // Read the first characters into the 4-character buffer. + shift4(); + ASSERT(currentOffset() == source.startOffset()); +} + +void Lexer::copyCodeWithoutBOMs() +{ + // Note: In this case, the character offset data for debugging will be incorrect. + // If it's important to correctly debug code with extraneous BOMs, then the caller + // should strip the BOMs when creating the SourceProvider object and do its own + // mapping of offsets within the stripped text to original text offset. + + m_codeWithoutBOMs.reserveCapacity(m_codeEnd - m_code); + for (const UChar* p = m_code; p < m_codeEnd; ++p) { + UChar c = *p; + if (c != byteOrderMark) + m_codeWithoutBOMs.append(c); + } + ptrdiff_t startDelta = m_codeStart - m_code; + m_code = m_codeWithoutBOMs.data(); + m_codeStart = m_code + startDelta; + m_codeEnd = m_codeWithoutBOMs.data() + m_codeWithoutBOMs.size(); +} + +void Lexer::shiftLineTerminator() +{ + ASSERT(isLineTerminator(m_current)); + + // Allow both CRLF and LFCR. + if (m_current + m_next1 == '\n' + '\r') + shift2(); + else + shift1(); + + m_startColumnNumberCorrection = currentOffset(); + ++m_lineNumber; +} + +ALWAYS_INLINE Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length) +{ + m_identifiers.append(Identifier(m_globalData, characters, length)); + return &m_identifiers.last(); +} + +inline bool Lexer::lastTokenWasRestrKeyword() const +{ + return m_lastToken == CONTINUE || m_lastToken == BREAK || m_lastToken == RETURN || m_lastToken == THROW; +} + +static NEVER_INLINE bool isNonASCIIIdentStart(int c) +{ + return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other); +} + +static inline bool isIdentStart(int c) +{ + return isASCII(c) ? isASCIIAlpha(c) || c == '$' || c == '_' : isNonASCIIIdentStart(c); +} + +static NEVER_INLINE bool isNonASCIIIdentPart(int c) +{ + return category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other + | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector); +} + +static inline bool isIdentPart(int c) +{ + return isASCII(c) ? isASCIIAlphanumeric(c) || c == '$' || c == '_' : isNonASCIIIdentPart(c); +} + +static inline int singleEscape(int c) +{ + switch (c) { + case 'b': + return 0x08; + case 't': + return 0x09; + case 'n': + return 0x0A; + case 'v': + return 0x0B; + case 'f': + return 0x0C; + case 'r': + return 0x0D; + default: + return c; + } +} + +inline void Lexer::record8(int c) +{ + ASSERT(c >= 0); + ASSERT(c <= 0xFF); + m_buffer8.append(static_cast<char>(c)); +} + +inline void Lexer::record16(UChar c) +{ + m_buffer16.append(c); +} + +inline void Lexer::record16(int c) +{ + ASSERT(c >= 0); + ASSERT(c <= USHRT_MAX); + record16(UChar(static_cast<unsigned short>(c))); +} + +int Lexer::lex(void* p1, void* p2) +{ + ASSERT(!m_error); + ASSERT(m_buffer8.isEmpty()); + ASSERT(m_buffer16.isEmpty()); + + YYSTYPE* lvalp = static_cast<YYSTYPE*>(p1); + YYLTYPE* llocp = static_cast<YYLTYPE*>(p2); + int token = 0; + m_terminator = false; + +start: + while (isWhiteSpace(m_current)) + shift1(); + + int startOffset = currentOffset(); + + if (m_current == -1) { +#ifndef QT_BUILD_SCRIPT_LIB /* the parser takes cate about automatic semicolon. + this might add incorrect semicolons */ + //m_delimited and m_isReparsing are now useless + if (!m_terminator && !m_delimited && !m_isReparsing) { + // automatic semicolon insertion if program incomplete + token = ';'; + goto doneSemicolon; + } +#endif + return 0; + } + + m_delimited = false; + switch (m_current) { + case '>': + if (m_next1 == '>' && m_next2 == '>') { + if (m_next3 == '=') { + shift4(); + token = URSHIFTEQUAL; + break; + } + shift3(); + token = URSHIFT; + break; + } + if (m_next1 == '>') { + if (m_next2 == '=') { + shift3(); + token = RSHIFTEQUAL; + break; + } + shift2(); + token = RSHIFT; + break; + } + if (m_next1 == '=') { + shift2(); + token = GE; + break; + } + shift1(); + token = '>'; + break; + case '=': + if (m_next1 == '=') { + if (m_next2 == '=') { + shift3(); + token = STREQ; + break; + } + shift2(); + token = EQEQ; + break; + } + shift1(); + token = '='; + break; + case '!': + if (m_next1 == '=') { + if (m_next2 == '=') { + shift3(); + token = STRNEQ; + break; + } + shift2(); + token = NE; + break; + } + shift1(); + token = '!'; + break; + case '<': + if (m_next1 == '!' && m_next2 == '-' && m_next3 == '-') { + // <!-- marks the beginning of a line comment (for www usage) + shift4(); + goto inSingleLineComment; + } + if (m_next1 == '<') { + if (m_next2 == '=') { + shift3(); + token = LSHIFTEQUAL; + break; + } + shift2(); + token = LSHIFT; + break; + } + if (m_next1 == '=') { + shift2(); + token = LE; + break; + } + shift1(); + token = '<'; + break; + case '+': + if (m_next1 == '+') { + shift2(); + if (m_terminator) { + token = AUTOPLUSPLUS; + break; + } + token = PLUSPLUS; + break; + } + if (m_next1 == '=') { + shift2(); + token = PLUSEQUAL; + break; + } + shift1(); + token = '+'; + break; + case '-': + if (m_next1 == '-') { + if (m_atLineStart && m_next2 == '>') { + shift3(); + goto inSingleLineComment; + } + shift2(); + if (m_terminator) { + token = AUTOMINUSMINUS; + break; + } + token = MINUSMINUS; + break; + } + if (m_next1 == '=') { + shift2(); + token = MINUSEQUAL; + break; + } + shift1(); + token = '-'; + break; + case '*': + if (m_next1 == '=') { + shift2(); + token = MULTEQUAL; + break; + } + shift1(); + token = '*'; + break; + case '/': + if (m_next1 == '/') { + shift2(); + goto inSingleLineComment; + } + if (m_next1 == '*') + goto inMultiLineComment; + if (m_next1 == '=') { + shift2(); + token = DIVEQUAL; + break; + } + shift1(); + token = '/'; + break; + case '&': + if (m_next1 == '&') { + shift2(); + token = AND; + break; + } + if (m_next1 == '=') { + shift2(); + token = ANDEQUAL; + break; + } + shift1(); + token = '&'; + break; + case '^': + if (m_next1 == '=') { + shift2(); + token = XOREQUAL; + break; + } + shift1(); + token = '^'; + break; + case '%': + if (m_next1 == '=') { + shift2(); + token = MODEQUAL; + break; + } + shift1(); + token = '%'; + break; + case '|': + if (m_next1 == '=') { + shift2(); + token = OREQUAL; + break; + } + if (m_next1 == '|') { + shift2(); + token = OR; + break; + } + shift1(); + token = '|'; + break; + case '.': + if (isASCIIDigit(m_next1)) { + record8('.'); + shift1(); + goto inNumberAfterDecimalPoint; + } + token = '.'; + shift1(); + break; + case ',': + case '~': + case '?': + case ':': + case '(': + case ')': + case '[': + case ']': + token = m_current; + shift1(); + break; + case ';': + shift1(); + m_delimited = true; + token = ';'; + break; + case '{': + lvalp->intValue = currentOffset(); + shift1(); + token = OPENBRACE; + break; + case '}': + lvalp->intValue = currentOffset(); + shift1(); + m_delimited = true; + token = CLOSEBRACE; + break; + case '\\': + goto startIdentifierWithBackslash; + case '0': + goto startNumberWithZeroDigit; + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + goto startNumber; + case '"': + case '\'': + goto startString; + default: + if (isIdentStart(m_current)) + goto startIdentifierOrKeyword; + if (isLineTerminator(m_current)) { + shiftLineTerminator(); + m_atLineStart = true; + m_terminator = true; + if (lastTokenWasRestrKeyword()) { + token = ';'; + goto doneSemicolon; + } + goto start; + } + goto returnError; + } + + m_atLineStart = false; + goto returnToken; + +startString: { + int stringQuoteCharacter = m_current; + shift1(); + + const UChar* stringStart = currentCharacter(); + while (m_current != stringQuoteCharacter) { + // Fast check for characters that require special handling. + // Catches -1, \n, \r, \, 0x2028, and 0x2029 as efficiently + // as possible, and lets through all common ASCII characters. + if (UNLIKELY(m_current == '\\') || UNLIKELY(((static_cast<unsigned>(m_current) - 0xE) & 0x2000))) { + m_buffer16.append(stringStart, currentCharacter() - stringStart); + goto inString; + } + shift1(); + } + lvalp->ident = makeIdentifier(stringStart, currentCharacter() - stringStart); + shift1(); + m_atLineStart = false; + m_delimited = false; + token = STRING; + goto returnToken; + +inString: + while (m_current != stringQuoteCharacter) { + if (m_current == '\\') + goto inStringEscapeSequence; + if (UNLIKELY(isLineTerminator(m_current))) + goto returnError; + if (UNLIKELY(m_current == -1)) + goto returnError; + record16(m_current); + shift1(); + } + goto doneString; + +inStringEscapeSequence: + shift1(); + if (m_current == 'x') { + shift1(); + if (isASCIIHexDigit(m_current) && isASCIIHexDigit(m_next1)) { + record16(convertHex(m_current, m_next1)); + shift2(); + goto inString; + } + record16('x'); + if (m_current == stringQuoteCharacter) + goto doneString; + goto inString; + } + if (m_current == 'u') { + shift1(); + if (isASCIIHexDigit(m_current) && isASCIIHexDigit(m_next1) && isASCIIHexDigit(m_next2) && isASCIIHexDigit(m_next3)) { + record16(convertUnicode(m_current, m_next1, m_next2, m_next3)); + shift4(); + goto inString; + } + if (m_current == stringQuoteCharacter) { + record16('u'); + goto doneString; + } + goto returnError; + } + if (isASCIIOctalDigit(m_current)) { + if (m_current >= '0' && m_current <= '3' && isASCIIOctalDigit(m_next1) && isASCIIOctalDigit(m_next2)) { + record16((m_current - '0') * 64 + (m_next1 - '0') * 8 + m_next2 - '0'); + shift3(); + goto inString; + } + if (isASCIIOctalDigit(m_next1)) { + record16((m_current - '0') * 8 + m_next1 - '0'); + shift2(); + goto inString; + } + record16(m_current - '0'); + shift1(); + goto inString; + } + if (isLineTerminator(m_current)) { + shiftLineTerminator(); + goto inString; + } + record16(singleEscape(m_current)); + shift1(); + goto inString; +} + +startIdentifierWithBackslash: + shift1(); + if (UNLIKELY(m_current != 'u')) + goto returnError; + shift1(); + if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(m_next1) || !isASCIIHexDigit(m_next2) || !isASCIIHexDigit(m_next3))) + goto returnError; + token = convertUnicode(m_current, m_next1, m_next2, m_next3); + if (UNLIKELY(!isIdentStart(token))) + goto returnError; + goto inIdentifierAfterCharacterCheck; + +startIdentifierOrKeyword: { + const UChar* identifierStart = currentCharacter(); + shift1(); + while (isIdentPart(m_current)) + shift1(); + if (LIKELY(m_current != '\\')) { + lvalp->ident = makeIdentifier(identifierStart, currentCharacter() - identifierStart); + goto doneIdentifierOrKeyword; + } + m_buffer16.append(identifierStart, currentCharacter() - identifierStart); +} + + do { + shift1(); + if (UNLIKELY(m_current != 'u')) + goto returnError; + shift1(); + if (UNLIKELY(!isASCIIHexDigit(m_current) || !isASCIIHexDigit(m_next1) || !isASCIIHexDigit(m_next2) || !isASCIIHexDigit(m_next3))) + goto returnError; + token = convertUnicode(m_current, m_next1, m_next2, m_next3); + if (UNLIKELY(!isIdentPart(token))) + goto returnError; +inIdentifierAfterCharacterCheck: + record16(token); + shift4(); + + while (isIdentPart(m_current)) { + record16(m_current); + shift1(); + } + } while (UNLIKELY(m_current == '\\')); + goto doneIdentifier; + +inSingleLineComment: + while (!isLineTerminator(m_current)) { + if (UNLIKELY(m_current == -1)) + return 0; + shift1(); + } + shiftLineTerminator(); + m_atLineStart = true; + m_terminator = true; + if (lastTokenWasRestrKeyword()) + goto doneSemicolon; + goto start; + +inMultiLineComment: + shift2(); + while (m_current != '*' || m_next1 != '/') { + if (isLineTerminator(m_current)) + shiftLineTerminator(); + else { + shift1(); + if (UNLIKELY(m_current == -1)) + goto returnError; + } + } + shift2(); + m_atLineStart = false; + goto start; + +startNumberWithZeroDigit: + shift1(); + if ((m_current | 0x20) == 'x' && isASCIIHexDigit(m_next1)) { + shift1(); + goto inHex; + } + if (m_current == '.') { + record8('0'); + record8('.'); + shift1(); + goto inNumberAfterDecimalPoint; + } + if ((m_current | 0x20) == 'e') { + record8('0'); + record8('e'); + shift1(); + goto inExponentIndicator; + } + if (isASCIIOctalDigit(m_current)) + goto inOctal; + if (isASCIIDigit(m_current)) + goto startNumber; + lvalp->doubleValue = 0; + goto doneNumeric; + +inNumberAfterDecimalPoint: + while (isASCIIDigit(m_current)) { + record8(m_current); + shift1(); + } + if ((m_current | 0x20) == 'e') { + record8('e'); + shift1(); + goto inExponentIndicator; + } + goto doneNumber; + +inExponentIndicator: + if (m_current == '+' || m_current == '-') { + record8(m_current); + shift1(); + } + if (!isASCIIDigit(m_current)) + goto returnError; + do { + record8(m_current); + shift1(); + } while (isASCIIDigit(m_current)); + goto doneNumber; + +inOctal: { + do { + record8(m_current); + shift1(); + } while (isASCIIOctalDigit(m_current)); + if (isASCIIDigit(m_current)) + goto startNumber; + + double dval = 0; + + const char* end = m_buffer8.end(); + for (const char* p = m_buffer8.data(); p < end; ++p) { + dval *= 8; + dval += *p - '0'; + } + if (dval >= mantissaOverflowLowerBound) + dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 8); + + m_buffer8.resize(0); + + lvalp->doubleValue = dval; + goto doneNumeric; +} + +inHex: { + do { + record8(m_current); + shift1(); + } while (isASCIIHexDigit(m_current)); + + double dval = 0; + + const char* end = m_buffer8.end(); + for (const char* p = m_buffer8.data(); p < end; ++p) { + dval *= 16; + dval += toASCIIHexValue(*p); + } + if (dval >= mantissaOverflowLowerBound) + dval = parseIntOverflow(m_buffer8.data(), end - m_buffer8.data(), 16); + + m_buffer8.resize(0); + + lvalp->doubleValue = dval; + goto doneNumeric; +} + +startNumber: + record8(m_current); + shift1(); + while (isASCIIDigit(m_current)) { + record8(m_current); + shift1(); + } + if (m_current == '.') { + record8('.'); + shift1(); + goto inNumberAfterDecimalPoint; + } + if ((m_current | 0x20) == 'e') { + record8('e'); + shift1(); + goto inExponentIndicator; + } + + // Fall through into doneNumber. + +doneNumber: + // Null-terminate string for strtod. + m_buffer8.append('\0'); + lvalp->doubleValue = WTF::strtod(m_buffer8.data(), 0); + m_buffer8.resize(0); + + // Fall through into doneNumeric. + +doneNumeric: + // No identifiers allowed directly after numeric literal, e.g. "3in" is bad. + if (UNLIKELY(isIdentStart(m_current))) + goto returnError; + + m_atLineStart = false; + m_delimited = false; + token = NUMBER; + goto returnToken; + +doneSemicolon: + token = ';'; + m_delimited = true; + goto returnToken; + +doneIdentifier: + m_atLineStart = false; + m_delimited = false; + lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size()); + m_buffer16.resize(0); + token = IDENT; + goto returnToken; + +doneIdentifierOrKeyword: { + m_atLineStart = false; + m_delimited = false; + m_buffer16.resize(0); + const HashEntry* entry = m_keywordTable.entry(m_globalData, *lvalp->ident); + token = entry ? entry->lexerValue() : IDENT; + goto returnToken; +} + +doneString: + // Atomize constant strings in case they're later used in property lookup. + shift1(); + m_atLineStart = false; + m_delimited = false; + lvalp->ident = makeIdentifier(m_buffer16.data(), m_buffer16.size()); + m_buffer16.resize(0); + token = STRING; + + // Fall through into returnToken. + +returnToken: { + llocp->first_line = m_lineNumber; + llocp->last_line = m_lineNumber; + + llocp->first_column = startOffset - m_startColumnNumberCorrection; + llocp->last_column = currentOffset() - m_startColumnNumberCorrection; + + m_lastToken = token; + return token; +} + +returnError: + m_error = true; + return -1; +} + +bool Lexer::scanRegExp() +{ + ASSERT(m_buffer16.isEmpty()); + + bool lastWasEscape = false; + bool inBrackets = false; + + while (true) { + if (isLineTerminator(m_current) || m_current == -1) + return false; + if (m_current != '/' || lastWasEscape || inBrackets) { + // 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.resize(0); + shift1(); + break; + } + shift1(); + } + + while (isIdentPart(m_current)) { + record16(m_current); + shift1(); + } + m_flags = UString(m_buffer16); + m_buffer16.resize(0); + + return true; +} + +void Lexer::clear() +{ + m_identifiers.clear(); + m_codeWithoutBOMs.clear(); + + Vector<char> newBuffer8; + newBuffer8.reserveInitialCapacity(initialReadBufferCapacity); + m_buffer8.swap(newBuffer8); + + Vector<UChar> newBuffer16; + newBuffer16.reserveInitialCapacity(initialReadBufferCapacity); + m_buffer16.swap(newBuffer16); + + m_isReparsing = false; + + m_pattern = UString(); + m_flags = UString(); +} + +SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine) +{ + if (m_codeWithoutBOMs.isEmpty()) + return SourceCode(m_source->provider(), openBrace, closeBrace + 1, firstLine); + + const UChar* data = m_source->provider()->data(); + + ASSERT(openBrace < closeBrace); + + int numBOMsBeforeOpenBrace = 0; + int numBOMsBetweenBraces = 0; + + int i; + for (i = m_source->startOffset(); i < openBrace; ++i) + numBOMsBeforeOpenBrace += data[i] == byteOrderMark; + for (; i < closeBrace; ++i) + numBOMsBetweenBraces += data[i] == byteOrderMark; + + return SourceCode(m_source->provider(), openBrace + numBOMsBeforeOpenBrace, + closeBrace + numBOMsBeforeOpenBrace + numBOMsBetweenBraces + 1, firstLine); +} + +} // namespace JSC diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/Lexer.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Lexer.h new file mode 100644 index 0000000..0ef6dd4 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Lexer.h @@ -0,0 +1,149 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2002, 2003, 2004, 2005, 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 Lexer_h +#define Lexer_h + +#include "Lookup.h" +#include "SourceCode.h" +#include <wtf/ASCIICType.h> +#include <wtf/SegmentedVector.h> +#include <wtf/Vector.h> +#include <wtf/unicode/Unicode.h> + +namespace JSC { + + class RegExp; + + class Lexer : public Noncopyable { + public: + // Character manipulation functions. + static bool isWhiteSpace(int character); + static bool isLineTerminator(int character); + static unsigned char convertHex(int c1, int c2); + static UChar convertUnicode(int c1, int c2, int c3, int c4); + + // Functions to set up parsing. + void setCode(const SourceCode&); + void setIsReparsing() { m_isReparsing = true; } + + // Functions for the parser itself. + int lex(void* lvalp, void* llocp); + int lineNumber() const { return m_lineNumber; } + bool prevTerminator() const { return m_terminator; } + SourceCode sourceCode(int openBrace, int closeBrace, int firstLine); + bool scanRegExp(); + const UString& pattern() const { return m_pattern; } + const UString& flags() const { return m_flags; } + + // Functions for use after parsing. + bool sawError() const { return m_error; } + void clear(); + + private: + friend class JSGlobalData; + + Lexer(JSGlobalData*); + ~Lexer(); + + void shift1(); + void shift2(); + void shift3(); + void shift4(); + void shiftLineTerminator(); + + void record8(int); + void record16(int); + void record16(UChar); + + void copyCodeWithoutBOMs(); + + int currentOffset() const; + const UChar* currentCharacter() const; + + JSC::Identifier* makeIdentifier(const UChar* buffer, size_t length); + + bool lastTokenWasRestrKeyword() const; + + static const size_t initialReadBufferCapacity = 32; + static const size_t initialIdentifierTableCapacity = 64; + + int m_lineNumber; + // this variable is supposed to keep index of last new line character ('\n' or '\r\n'or '\n\r'...) + // it is importent to calculate correct first_column in parser + int m_startColumnNumberCorrection; + + + Vector<char> m_buffer8; + Vector<UChar> m_buffer16; + bool m_terminator; + bool m_delimited; // encountered delimiter like "'" and "}" on last run + int m_lastToken; + + const SourceCode* m_source; + const UChar* m_code; + const UChar* m_codeStart; + const UChar* m_codeEnd; + bool m_isReparsing; + bool m_atLineStart; + bool m_error; + + // current and following unicode characters (int to allow for -1 for end-of-file marker) + int m_current; + int m_next1; + int m_next2; + int m_next3; + + WTF::SegmentedVector<JSC::Identifier, initialIdentifierTableCapacity> m_identifiers; + + JSGlobalData* m_globalData; + + UString m_pattern; + UString m_flags; + + const HashTable m_keywordTable; + + Vector<UChar> m_codeWithoutBOMs; + }; + + inline bool Lexer::isWhiteSpace(int ch) + { + return isASCII(ch) ? (ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC) : WTF::Unicode::isSeparatorSpace(ch); + } + + inline bool Lexer::isLineTerminator(int ch) + { + return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028; + } + + inline unsigned char Lexer::convertHex(int c1, int c2) + { + return (toASCIIHexValue(c1) << 4) | toASCIIHexValue(c2); + } + + inline UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4) + { + return (convertHex(c1, c2) << 8) | convertHex(c3, c4); + } + +} // namespace JSC + +#endif // Lexer_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/NodeConstructors.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/NodeConstructors.h new file mode 100644 index 0000000..a4374d3 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/NodeConstructors.h @@ -0,0 +1,900 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef NodeConstructors_h +#define NodeConstructors_h + +#include "Nodes.h" +#include "Lexer.h" +#include "Parser.h" + +namespace JSC { + + inline ParserArenaRefCounted::ParserArenaRefCounted(JSGlobalData* globalData) + { + globalData->parser->arena().derefWithArena(adoptRef(this)); + } + + inline Node::Node(JSGlobalData* globalData) + : m_line(globalData->lexer->lineNumber()) + { + } + + inline ExpressionNode::ExpressionNode(JSGlobalData* globalData, ResultType resultType) + : Node(globalData) + , m_resultType(resultType) + { + } + + inline StatementNode::StatementNode(JSGlobalData* globalData) + : Node(globalData) + , m_lastLine(-1) + , m_column(-1) + { + } + + inline NullNode::NullNode(JSGlobalData* globalData) + : ExpressionNode(globalData, ResultType::nullType()) + { + } + + inline BooleanNode::BooleanNode(JSGlobalData* globalData, bool value) + : ExpressionNode(globalData, ResultType::booleanType()) + , m_value(value) + { + } + + inline NumberNode::NumberNode(JSGlobalData* globalData, double v) + : ExpressionNode(globalData, ResultType::numberType()) + , m_double(v) + { + } + + inline StringNode::StringNode(JSGlobalData* globalData, const Identifier& v) + : ExpressionNode(globalData, ResultType::stringType()) + , m_value(v) + { + } + + inline RegExpNode::RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags) + : ExpressionNode(globalData) + , m_pattern(pattern) + , m_flags(flags) + { + } + + inline ThisNode::ThisNode(JSGlobalData* globalData) + : ExpressionNode(globalData) + { + } + + inline ResolveNode::ResolveNode(JSGlobalData* globalData, const Identifier& ident, int startOffset) + : ExpressionNode(globalData) + , m_ident(ident) + , m_startOffset(startOffset) + { + } + + inline ElementNode::ElementNode(JSGlobalData*, int elision, ExpressionNode* node) + : m_next(0) + , m_elision(elision) + , m_node(node) + { + } + + inline ElementNode::ElementNode(JSGlobalData*, ElementNode* l, int elision, ExpressionNode* node) + : m_next(0) + , m_elision(elision) + , m_node(node) + { + l->m_next = this; + } + + inline ArrayNode::ArrayNode(JSGlobalData* globalData, int elision) + : ExpressionNode(globalData) + , m_element(0) + , m_elision(elision) + , m_optional(true) + { + } + + inline ArrayNode::ArrayNode(JSGlobalData* globalData, ElementNode* element) + : ExpressionNode(globalData) + , m_element(element) + , m_elision(0) + , m_optional(false) + { + } + + inline ArrayNode::ArrayNode(JSGlobalData* globalData, int elision, ElementNode* element) + : ExpressionNode(globalData) + , m_element(element) + , m_elision(elision) + , m_optional(true) + { + } + + inline PropertyNode::PropertyNode(JSGlobalData*, const Identifier& name, ExpressionNode* assign, Type type) + : m_name(name) + , m_assign(assign) + , m_type(type) + { + } + + inline PropertyListNode::PropertyListNode(JSGlobalData* globalData, PropertyNode* node) + : Node(globalData) + , m_node(node) + , m_next(0) + { + } + + inline PropertyListNode::PropertyListNode(JSGlobalData* globalData, PropertyNode* node, PropertyListNode* list) + : Node(globalData) + , m_node(node) + , m_next(0) + { + list->m_next = this; + } + + inline ObjectLiteralNode::ObjectLiteralNode(JSGlobalData* globalData) + : ExpressionNode(globalData) + , m_list(0) + { + } + + inline ObjectLiteralNode::ObjectLiteralNode(JSGlobalData* globalData, PropertyListNode* list) + : ExpressionNode(globalData) + , m_list(list) + { + } + + inline BracketAccessorNode::BracketAccessorNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments) + : ExpressionNode(globalData) + , m_base(base) + , m_subscript(subscript) + , m_subscriptHasAssignments(subscriptHasAssignments) + { + } + + inline DotAccessorNode::DotAccessorNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident) + : ExpressionNode(globalData) + , m_base(base) + , m_ident(ident) + { + } + + inline ArgumentListNode::ArgumentListNode(JSGlobalData* globalData, ExpressionNode* expr) + : Node(globalData) + , m_next(0) + , m_expr(expr) + { + } + + inline ArgumentListNode::ArgumentListNode(JSGlobalData* globalData, ArgumentListNode* listNode, ExpressionNode* expr) + : Node(globalData) + , m_next(0) + , m_expr(expr) + { + listNode->m_next = this; + } + + inline ArgumentsNode::ArgumentsNode(JSGlobalData*) + : m_listNode(0) + { + } + + inline ArgumentsNode::ArgumentsNode(JSGlobalData*, ArgumentListNode* listNode) + : m_listNode(listNode) + { + } + + inline NewExprNode::NewExprNode(JSGlobalData* globalData, ExpressionNode* expr) + : ExpressionNode(globalData) + , m_expr(expr) + , m_args(0) + { + } + + inline NewExprNode::NewExprNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args) + : ExpressionNode(globalData) + , m_expr(expr) + , m_args(args) + { + } + + inline EvalFunctionCallNode::EvalFunctionCallNode(JSGlobalData* globalData, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_args(args) + { + } + + inline FunctionCallValueNode::FunctionCallValueNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_expr(expr) + , m_args(args) + { + } + + inline FunctionCallResolveNode::FunctionCallResolveNode(JSGlobalData* globalData, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + , m_args(args) + { + } + + inline FunctionCallBracketNode::FunctionCallBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_args(args) + { + } + + inline FunctionCallDotNode::FunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_args(args) + { + } + + inline CallFunctionCallDotNode::CallFunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) + : FunctionCallDotNode(globalData, base, ident, args, divot, startOffset, endOffset) + { + } + + inline ApplyFunctionCallDotNode::ApplyFunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) + : FunctionCallDotNode(globalData, base, ident, args, divot, startOffset, endOffset) + { + } + + inline PrePostResolveNode::PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData, ResultType::numberType()) // could be reusable for pre? + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + { + } + + inline PostfixResolveNode::PostfixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset) + , m_operator(oper) + { + } + + inline PostfixBracketNode::PostfixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_operator(oper) + { + } + + inline PostfixDotNode::PostfixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_operator(oper) + { + } + + inline PostfixErrorNode::PostfixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_expr(expr) + , m_operator(oper) + { + } + + inline DeleteResolveNode::DeleteResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + { + } + + inline DeleteBracketNode::DeleteBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + { + } + + inline DeleteDotNode::DeleteDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + { + } + + inline DeleteValueNode::DeleteValueNode(JSGlobalData* globalData, ExpressionNode* expr) + : ExpressionNode(globalData) + , m_expr(expr) + { + } + + inline VoidNode::VoidNode(JSGlobalData* globalData, ExpressionNode* expr) + : ExpressionNode(globalData) + , m_expr(expr) + { + } + + inline TypeOfResolveNode::TypeOfResolveNode(JSGlobalData* globalData, const Identifier& ident) + : ExpressionNode(globalData, ResultType::stringType()) + , m_ident(ident) + { + } + + inline TypeOfValueNode::TypeOfValueNode(JSGlobalData* globalData, ExpressionNode* expr) + : ExpressionNode(globalData, ResultType::stringType()) + , m_expr(expr) + { + } + + inline PrefixResolveNode::PrefixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset) + , m_operator(oper) + { + } + + inline PrefixBracketNode::PrefixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_operator(oper) + { + } + + inline PrefixDotNode::PrefixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_operator(oper) + { + } + + inline PrefixErrorNode::PrefixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_expr(expr) + , m_operator(oper) + { + } + + inline UnaryOpNode::UnaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr, OpcodeID opcodeID) + : ExpressionNode(globalData, type) + , m_expr(expr) + , m_opcodeID(opcodeID) + { + } + + inline UnaryPlusNode::UnaryPlusNode(JSGlobalData* globalData, ExpressionNode* expr) + : UnaryOpNode(globalData, ResultType::numberType(), expr, op_to_jsnumber) + { + } + + inline NegateNode::NegateNode(JSGlobalData* globalData, ExpressionNode* expr) + : UnaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr, op_negate) + { + } + + inline BitwiseNotNode::BitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr) + : UnaryOpNode(globalData, ResultType::forBitOp(), expr, op_bitnot) + { + } + + inline LogicalNotNode::LogicalNotNode(JSGlobalData* globalData, ExpressionNode* expr) + : UnaryOpNode(globalData, ResultType::booleanType(), expr, op_not) + { + } + + inline BinaryOpNode::BinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments) + : ExpressionNode(globalData) + , m_expr1(expr1) + , m_expr2(expr2) + , m_opcodeID(opcodeID) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline BinaryOpNode::BinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments) + : ExpressionNode(globalData, type) + , m_expr1(expr1) + , m_expr2(expr2) + , m_opcodeID(opcodeID) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline ReverseBinaryOpNode::ReverseBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments) + : BinaryOpNode(globalData, expr1, expr2, opcodeID, rightHasAssignments) + { + } + + inline ReverseBinaryOpNode::ReverseBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments) + : BinaryOpNode(globalData, type, expr1, expr2, opcodeID, rightHasAssignments) + { + } + + inline MultNode::MultNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_mul, rightHasAssignments) + { + } + + inline DivNode::DivNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_div, rightHasAssignments) + { + } + + + inline ModNode::ModNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_mod, rightHasAssignments) + { + } + + inline AddNode::AddNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, op_add, rightHasAssignments) + { + } + + inline SubNode::SubNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_sub, rightHasAssignments) + { + } + + inline LeftShiftNode::LeftShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_lshift, rightHasAssignments) + { + } + + inline RightShiftNode::RightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_rshift, rightHasAssignments) + { + } + + inline UnsignedRightShiftNode::UnsignedRightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::numberTypeCanReuse(), expr1, expr2, op_urshift, rightHasAssignments) + { + } + + inline LessNode::LessNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_less, rightHasAssignments) + { + } + + inline GreaterNode::GreaterNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : ReverseBinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_less, rightHasAssignments) + { + } + + inline LessEqNode::LessEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_lesseq, rightHasAssignments) + { + } + + inline GreaterEqNode::GreaterEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : ReverseBinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_lesseq, rightHasAssignments) + { + } + + inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments) + : BinaryOpNode(globalData, type, expr1, expr2, opcodeID, rightHasAssignments) + { + } + + inline ThrowableBinaryOpNode::ThrowableBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID opcodeID, bool rightHasAssignments) + : BinaryOpNode(globalData, expr1, expr2, opcodeID, rightHasAssignments) + { + } + + inline InstanceOfNode::InstanceOfNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : ThrowableBinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_instanceof, rightHasAssignments) + { + } + + inline InNode::InNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : ThrowableBinaryOpNode(globalData, expr1, expr2, op_in, rightHasAssignments) + { + } + + inline EqualNode::EqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_eq, rightHasAssignments) + { + } + + inline NotEqualNode::NotEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_neq, rightHasAssignments) + { + } + + inline StrictEqualNode::StrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_stricteq, rightHasAssignments) + { + } + + inline NotStrictEqualNode::NotStrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::booleanType(), expr1, expr2, op_nstricteq, rightHasAssignments) + { + } + + inline BitAndNode::BitAndNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_bitand, rightHasAssignments) + { + } + + inline BitOrNode::BitOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_bitor, rightHasAssignments) + { + } + + inline BitXOrNode::BitXOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) + : BinaryOpNode(globalData, ResultType::forBitOp(), expr1, expr2, op_bitxor, rightHasAssignments) + { + } + + inline LogicalOpNode::LogicalOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper) + : ExpressionNode(globalData, ResultType::booleanType()) + , m_expr1(expr1) + , m_expr2(expr2) + , m_operator(oper) + { + } + + inline ConditionalNode::ConditionalNode(JSGlobalData* globalData, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2) + : ExpressionNode(globalData) + , m_logical(logical) + , m_expr1(expr1) + , m_expr2(expr2) + { + } + + inline ReadModifyResolveNode::ReadModifyResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_ident(ident) + , m_right(right) + , m_operator(oper) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline AssignResolveNode::AssignResolveNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments) + : ExpressionNode(globalData) + , m_ident(ident) + , m_right(right) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline ReadModifyBracketNode::ReadModifyBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_right(right) + , m_operator(oper) + , m_subscriptHasAssignments(subscriptHasAssignments) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline AssignBracketNode::AssignBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_subscript(subscript) + , m_right(right) + , m_subscriptHasAssignments(subscriptHasAssignments) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline AssignDotNode::AssignDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_right(right) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline ReadModifyDotNode::ReadModifyDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableSubExpressionData(divot, startOffset, endOffset) + , m_base(base) + , m_ident(ident) + , m_right(right) + , m_operator(oper) + , m_rightHasAssignments(rightHasAssignments) + { + } + + inline AssignErrorNode::AssignErrorNode(JSGlobalData* globalData, ExpressionNode* left, Operator oper, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset) + : ExpressionNode(globalData) + , ThrowableExpressionData(divot, startOffset, endOffset) + , m_left(left) + , m_operator(oper) + , m_right(right) + { + } + + inline CommaNode::CommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2) + : ExpressionNode(globalData) + { + m_expressions.append(expr1); + m_expressions.append(expr2); + } + + inline ConstStatementNode::ConstStatementNode(JSGlobalData* globalData, ConstDeclNode* next) + : StatementNode(globalData) + , m_next(next) + { + } + + inline SourceElements::SourceElements(JSGlobalData*) + { + } + + inline EmptyStatementNode::EmptyStatementNode(JSGlobalData* globalData) + : StatementNode(globalData) + { + } + + inline DebuggerStatementNode::DebuggerStatementNode(JSGlobalData* globalData) + : StatementNode(globalData) + { + } + + inline ExprStatementNode::ExprStatementNode(JSGlobalData* globalData, ExpressionNode* expr) + : StatementNode(globalData) + , m_expr(expr) + { + } + + inline VarStatementNode::VarStatementNode(JSGlobalData* globalData, ExpressionNode* expr) + : StatementNode(globalData) + , m_expr(expr) + { + } + + inline IfNode::IfNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock) + : StatementNode(globalData) + , m_condition(condition) + , m_ifBlock(ifBlock) + { + } + + inline IfElseNode::IfElseNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock) + : IfNode(globalData, condition, ifBlock) + , m_elseBlock(elseBlock) + { + } + + inline DoWhileNode::DoWhileNode(JSGlobalData* globalData, StatementNode* statement, ExpressionNode* expr) + : StatementNode(globalData) + , m_statement(statement) + , m_expr(expr) + { + } + + inline WhileNode::WhileNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement) + : StatementNode(globalData) + , m_expr(expr) + , m_statement(statement) + { + } + + inline ForNode::ForNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl) + : StatementNode(globalData) + , m_expr1(expr1) + , m_expr2(expr2) + , m_expr3(expr3) + , m_statement(statement) + , m_expr1WasVarDecl(expr1 && expr1WasVarDecl) + { + ASSERT(statement); + } + + inline ContinueNode::ContinueNode(JSGlobalData* globalData) + : StatementNode(globalData) + { + } + + inline ContinueNode::ContinueNode(JSGlobalData* globalData, const Identifier& ident) + : StatementNode(globalData) + , m_ident(ident) + { + } + + inline BreakNode::BreakNode(JSGlobalData* globalData) + : StatementNode(globalData) + { + } + + inline BreakNode::BreakNode(JSGlobalData* globalData, const Identifier& ident) + : StatementNode(globalData) + , m_ident(ident) + { + } + + inline ReturnNode::ReturnNode(JSGlobalData* globalData, ExpressionNode* value) + : StatementNode(globalData) + , m_value(value) + { + } + + inline WithNode::WithNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement, uint32_t divot, uint32_t expressionLength) + : StatementNode(globalData) + , m_expr(expr) + , m_statement(statement) + , m_divot(divot) + , m_expressionLength(expressionLength) + { + } + + inline LabelNode::LabelNode(JSGlobalData* globalData, const Identifier& name, StatementNode* statement) + : StatementNode(globalData) + , m_name(name) + , m_statement(statement) + { + } + + inline ThrowNode::ThrowNode(JSGlobalData* globalData, ExpressionNode* expr) + : StatementNode(globalData) + , m_expr(expr) + { + } + + inline TryNode::TryNode(JSGlobalData* globalData, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock) + : StatementNode(globalData) + , m_tryBlock(tryBlock) + , m_exceptionIdent(exceptionIdent) + , m_catchBlock(catchBlock) + , m_finallyBlock(finallyBlock) + , m_catchHasEval(catchHasEval) + { + } + + inline ParameterNode::ParameterNode(JSGlobalData*, const Identifier& ident) + : m_ident(ident) + , m_next(0) + { + } + + inline ParameterNode::ParameterNode(JSGlobalData*, ParameterNode* l, const Identifier& ident) + : m_ident(ident) + , m_next(0) + { + l->m_next = this; + } + + inline FuncExprNode::FuncExprNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter) + : ExpressionNode(globalData) + , ParserArenaRefCounted(globalData) + , m_ident(ident) + , m_body(body) + { + m_body->finishParsing(source, parameter); + } + + inline FuncDeclNode::FuncDeclNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter) + : StatementNode(globalData) + , ParserArenaRefCounted(globalData) + , m_ident(ident) + , m_body(body) + { + m_body->finishParsing(source, parameter); + } + + inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr) + : m_expr(expr) + { + } + + inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr, SourceElements* children) + : m_expr(expr) + { + if (children) + children->releaseContentsIntoVector(m_children); + } + + inline ClauseListNode::ClauseListNode(JSGlobalData*, CaseClauseNode* clause) + : m_clause(clause) + , m_next(0) + { + } + + inline ClauseListNode::ClauseListNode(JSGlobalData*, ClauseListNode* clauseList, CaseClauseNode* clause) + : m_clause(clause) + , m_next(0) + { + clauseList->m_next = this; + } + + inline CaseBlockNode::CaseBlockNode(JSGlobalData*, ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2) + : m_list1(list1) + , m_defaultClause(defaultClause) + , m_list2(list2) + { + } + + inline SwitchNode::SwitchNode(JSGlobalData* globalData, ExpressionNode* expr, CaseBlockNode* block) + : StatementNode(globalData) + , m_expr(expr) + , m_block(block) + { + } + + inline ConstDeclNode::ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* init) + : ExpressionNode(globalData) + , m_ident(ident) + , m_next(0) + , m_init(init) + { + } + + inline BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* children) + : StatementNode(globalData) + { + if (children) + children->releaseContentsIntoVector(m_children); + } + + inline ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement) + : StatementNode(globalData) + , m_init(0) + , m_lexpr(l) + , m_expr(expr) + , m_statement(statement) + , m_identIsVarDecl(false) + { + } + + inline ForInNode::ForInNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement, int divot, int startOffset, int endOffset) + : StatementNode(globalData) + , m_ident(ident) + , m_init(0) + , m_lexpr(new (globalData) ResolveNode(globalData, ident, divot - startOffset)) + , m_expr(expr) + , m_statement(statement) + , m_identIsVarDecl(true) + { + if (in) { + AssignResolveNode* node = new (globalData) AssignResolveNode(globalData, ident, in, true); + node->setExceptionSourceCode(divot, divot - startOffset, endOffset - divot); + m_init = node; + } + // for( var foo = bar in baz ) + } + +} // namespace JSC + +#endif // NodeConstructors_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/NodeInfo.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/NodeInfo.h new file mode 100644 index 0000000..7f4deff --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/NodeInfo.h @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2007 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef NodeInfo_h +#define NodeInfo_h + +#include "Nodes.h" +#include "Parser.h" + +namespace JSC { + + template <typename T> struct NodeInfo { + T m_node; + CodeFeatures m_features; + int m_numConstants; + }; + + typedef NodeInfo<FuncDeclNode*> FuncDeclNodeInfo; + typedef NodeInfo<FuncExprNode*> FuncExprNodeInfo; + typedef NodeInfo<ExpressionNode*> ExpressionNodeInfo; + typedef NodeInfo<ArgumentsNode*> ArgumentsNodeInfo; + typedef NodeInfo<ConstDeclNode*> ConstDeclNodeInfo; + typedef NodeInfo<PropertyNode*> PropertyNodeInfo; + typedef NodeInfo<PropertyList> PropertyListInfo; + typedef NodeInfo<ElementList> ElementListInfo; + typedef NodeInfo<ArgumentList> ArgumentListInfo; + + template <typename T> struct NodeDeclarationInfo { + T m_node; + ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations; + ParserArenaData<DeclarationStacks::FunctionStack>* m_funcDeclarations; + CodeFeatures m_features; + int m_numConstants; + }; + + typedef NodeDeclarationInfo<StatementNode*> StatementNodeInfo; + typedef NodeDeclarationInfo<CaseBlockNode*> CaseBlockNodeInfo; + typedef NodeDeclarationInfo<CaseClauseNode*> CaseClauseNodeInfo; + typedef NodeDeclarationInfo<SourceElements*> SourceElementsInfo; + typedef NodeDeclarationInfo<ClauseList> ClauseListInfo; + typedef NodeDeclarationInfo<ExpressionNode*> VarDeclListInfo; + typedef NodeDeclarationInfo<ConstDeclList> ConstDeclListInfo; + typedef NodeDeclarationInfo<ParameterList> ParameterListInfo; + +} // namespace JSC + +#endif // NodeInfo_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/Nodes.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Nodes.cpp new file mode 100644 index 0000000..9d9fe72 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Nodes.cpp @@ -0,0 +1,2215 @@ +/* +* Copyright (C) 1999-2002 Harri Porten (porten@kde.org) +* Copyright (C) 2001 Peter Kelly (pmk@post.com) +* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. +* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) +* Copyright (C) 2007 Maks Orlovich +* Copyright (C) 2007 Eric Seidel <eric@webkit.org> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public License +* along with this library; see the file COPYING.LIB. If not, write to +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301, USA. +* +*/ + +#include "config.h" +#include "Nodes.h" +#include "NodeConstructors.h" + +#include "BytecodeGenerator.h" +#include "CallFrame.h" +#include "Debugger.h" +#include "JIT.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "JSStaticScopeObject.h" +#include "LabelScope.h" +#include "Lexer.h" +#include "Operations.h" +#include "Parser.h" +#include "PropertyNameArray.h" +#include "RegExpObject.h" +#include "SamplingTool.h" +#include <wtf/Assertions.h> +#include <wtf/RefCountedLeakCounter.h> +#include <wtf/Threading.h> + +using namespace WTF; + +namespace JSC { + +static void substitute(UString& string, const UString& substring); + +// ------------------------------ 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 -------------------------------- + +void StatementNode::setLoc(int firstLine, int lastLine, int column) +{ + m_line = firstLine; + m_lastLine = lastLine; + m_column = column; +} + +// ------------------------------ SourceElements -------------------------------- + +void SourceElements::append(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); +} + +// ------------------------------ ArrayNode ------------------------------------ + +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; firstPutElement; firstPutElement = firstPutElement->next()) { + if (firstPutElement->elision()) + break; + ++length; + } + + if (!firstPutElement && !m_elision) + return generator.emitNewArray(generator.finalDestination(dst), m_element); + + RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element); + + 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()); +} + +bool ArrayNode::isSimpleArray() const +{ + if (m_elision || m_optional) + return false; + for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { + if (ptr->elision()) + return false; + } + return true; +} + +ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const +{ + ASSERT(!m_elision && !m_optional); + ElementNode* ptr = m_element; + if (!ptr) + return 0; + ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); + ArgumentListNode* tail = head; + ptr = ptr->next(); + for (; ptr; ptr = ptr->next()) { + ASSERT(!ptr->elision()); + tail = new (globalData) ArgumentListNode(globalData, tail, ptr->value()); + } + return head; +} + +// ------------------------------ ObjectLiteralNode ---------------------------- + +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); +} + +// ------------------------------ PropertyListNode ----------------------------- + +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) { + RegisterID* value = generator.emitNode(p->m_node->m_assign); + + 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 -------------------------------- + +RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); + RegisterID* property = generator.emitNode(m_subscript); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); +} + +// ------------------------------ DotAccessorNode -------------------------------- + +RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* base = generator.emitNode(m_base); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetById(generator.finalDestination(dst), base, m_ident); +} + +// ------------------------------ ArgumentListNode ----------------------------- + +RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expr); + return generator.emitNode(dst, m_expr); +} + +// ------------------------------ NewExprNode ---------------------------------- + +RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.emitNode(m_expr); + return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args, divot(), startOffset(), endOffset()); +} + +// ------------------------------ EvalFunctionCallNode ---------------------------------- + +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, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallValueNode ---------------------------------- + +RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.emitNode(m_expr); + RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallResolveNode ---------------------------------- + +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, 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, divot(), startOffset(), endOffset()); + } + + RefPtr<RegisterID> func = generator.newTemporary(); + 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, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallBracketNode ---------------------------------- + +RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + RegisterID* property = generator.emitNode(m_subscript); + 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, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallDotNode ---------------------------------- + +RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitMethodCheck(); + 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, divot(), startOffset(), endOffset()); +} + +RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<Label> realCall = generator.newLabel(); + RefPtr<Label> end = generator.newLabel(); + RefPtr<RegisterID> base = generator.emitNode(m_base); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get()); + generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); + { + RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + ArgumentListNode* oldList = m_args->m_listNode; + if (m_args->m_listNode && m_args->m_listNode->m_expr) { + generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + m_args->m_listNode = m_args->m_listNode->m_next; + } else + generator.emitLoad(thisRegister.get(), jsNull()); + + generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + generator.emitJump(end.get()); + m_args->m_listNode = oldList; + } + generator.emitLabel(realCall.get()); + { + RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + } + generator.emitLabel(end.get()); + return finalDestination.get(); +} + +static bool areTrivialApplyArguments(ArgumentsNode* args) +{ + return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next + || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); +} + +RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + // A few simple cases can be trivially handled as ordinary function calls. + // function.apply(), function.apply(arg) -> identical to function.call + // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation + bool mayBeCall = areTrivialApplyArguments(m_args); + + RefPtr<Label> realCall = generator.newLabel(); + RefPtr<Label> end = generator.newLabel(); + RefPtr<RegisterID> base = generator.emitNode(m_base); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get()); + generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); + { + if (mayBeCall) { + RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + ArgumentListNode* oldList = m_args->m_listNode; + if (m_args->m_listNode && m_args->m_listNode->m_expr) { + generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + m_args->m_listNode = m_args->m_listNode->m_next; + if (m_args->m_listNode) { + ASSERT(m_args->m_listNode->m_expr->isSimpleArray()); + ASSERT(!m_args->m_listNode->m_next); + m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_expr)->toArgumentList(generator.globalData()); + } + } else + generator.emitLoad(thisRegister.get(), jsNull()); + generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + m_args->m_listNode = oldList; + } else { + ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); + RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get()); + RefPtr<RegisterID> argsCountRegister = generator.newTemporary(); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + RefPtr<RegisterID> argsRegister = generator.newTemporary(); + generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + ArgumentListNode* args = m_args->m_listNode->m_next; + bool isArgumentsApply = false; + if (args->m_expr->isResolveNode()) { + ResolveNode* resolveNode = static_cast<ResolveNode*>(args->m_expr); + isArgumentsApply = generator.willResolveToArguments(resolveNode->identifier()); + if (isArgumentsApply) + generator.emitMove(argsRegister.get(), generator.uncheckedRegisterForArguments()); + } + if (!isArgumentsApply) + generator.emitNode(argsRegister.get(), args->m_expr); + while ((args = args->m_next)) + generator.emitNode(args->m_expr); + + generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get()); + generator.emitCallVarargs(finalDestination.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset()); + } + generator.emitJump(end.get()); + } + generator.emitLabel(realCall.get()); + { + RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + } + generator.emitLabel(end.get()); + return finalDestination.get(); +} + +// ------------------------------ 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) +{ + if (srcDst == dst) + return generator.emitToJSNumber(dst, srcDst); + 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 ---------------------------------- + +RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + RefPtr<RegisterID> property = generator.emitNode(m_subscript); + + 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 ---------------------------------- + +RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + + 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 ----------------------------------- + +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.emitLoad(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 ----------------------------------- + +RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> r0 = generator.emitNode(m_base); + RegisterID* r1 = generator.emitNode(m_subscript); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); +} + +// ------------------------------ DeleteDotNode ----------------------------------- + +RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* r0 = generator.emitNode(m_base); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); +} + +// ------------------------------ DeleteValueNode ----------------------------------- + +RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitNode(generator.ignoredResult(), m_expr); + + // delete on a non-location expression ignores the value and returns true + return generator.emitLoad(generator.finalDestination(dst), true); +} + +// ------------------------------ VoidNode ------------------------------------- + +RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr); + return 0; + } + RefPtr<RegisterID> r0 = generator.emitNode(m_expr); + 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 ----------------------------------- + +RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr); + return 0; + } + RefPtr<RegisterID> src = generator.emitNode(m_expr); + 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.emitLoad(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 ---------------------------------- + +RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + RefPtr<RegisterID> property = generator.emitNode(m_subscript); + 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 ---------------------------------- + +RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + 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 ----------------------------------- + +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 ----------------------------------- + +RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* src = generator.emitNode(m_expr); + return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); +} + +// ------------------------------ Binary Operation Nodes ----------------------------------- + +// BinaryOpNode::emitStrcat: +// +// This node generates an op_strcat operation. This opcode can handle concatenation of three or +// more values, where we can determine a set of separate op_add operations would be operating on +// string values. +// +// This function expects to be operating on a graph of AST nodes looking something like this: +// +// (a)... (b) +// \ / +// (+) (c) +// \ / +// [d] ((+)) +// \ / +// [+=] +// +// The assignment operation is optional, if it exists the register holding the value on the +// lefthand side of the assignment should be passing as the optional 'lhs' argument. +// +// The method should be called on the node at the root of the tree of regular binary add +// operations (marked in the diagram with a double set of parentheses). This node must +// be performing a string concatenation (determined by statically detecting that at least +// one child must be a string). +// +// Since the minimum number of values being concatenated together is expected to be 3, if +// a lhs to a concatenating assignment is not provided then the root add should have at +// least one left child that is also an add that can be determined to be operating on strings. +// +RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) +{ + ASSERT(isAdd()); + ASSERT(resultDescriptor().definitelyIsString()); + + // Create a list of expressions for all the adds in the tree of nodes we can convert into + // a string concatenation. The rightmost node (c) is added first. The rightmost node is + // added first, and the leftmost child is never added, so the vector produced for the + // example above will be [ c, b ]. + Vector<ExpressionNode*, 16> reverseExpressionList; + reverseExpressionList.append(m_expr2); + + // Examine the left child of the add. So long as this is a string add, add its right-child + // to the list, and keep processing along the left fork. + ExpressionNode* leftMostAddChild = m_expr1; + while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { + reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); + leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; + } + + Vector<RefPtr<RegisterID>, 16> temporaryRegisters; + + // If there is an assignment, allocate a temporary to hold the lhs after conversion. + // We could possibly avoid this (the lhs is converted last anyway, we could let the + // op_strcat node handle its conversion if required). + if (lhs) + temporaryRegisters.append(generator.newTemporary()); + + // Emit code for the leftmost node ((a) in the example). + temporaryRegisters.append(generator.newTemporary()); + RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); + generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); + + // Note on ordering of conversions: + // + // We maintain the same ordering of conversions as we would see if the concatenations + // was performed as a sequence of adds (otherwise this optimization could change + // behaviour should an object have been provided a valueOf or toString method). + // + // Considering the above example, the sequnce of execution is: + // * evaluate operand (a) + // * evaluate operand (b) + // * convert (a) to primitive <- (this would be triggered by the first add) + // * convert (b) to primitive <- (ditto) + // * evaluate operand (c) + // * convert (c) to primitive <- (this would be triggered by the second add) + // And optionally, if there is an assignment: + // * convert (d) to primitive <- (this would be triggered by the assigning addition) + // + // As such we do not plant an op to convert the leftmost child now. Instead, use + // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion + // once the second node has been generated. However, if the leftmost child is an + // immediate we can trivially determine that no conversion will be required. + // If this is the case + if (leftMostAddChild->isString()) + leftMostAddChildTempRegister = 0; + + while (reverseExpressionList.size()) { + ExpressionNode* node = reverseExpressionList.last(); + reverseExpressionList.removeLast(); + + // Emit the code for the current node. + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), node); + + // On the first iteration of this loop, when we first reach this point we have just + // generated the second node, which means it is time to convert the leftmost operand. + if (leftMostAddChildTempRegister) { + generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); + leftMostAddChildTempRegister = 0; // Only do this once. + } + // Plant a conversion for this node, if necessary. + if (!node->isString()) + generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); + } + ASSERT(temporaryRegisters.size() >= 3); + + // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. + // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. + if (emitExpressionInfoForMe) + generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); + + // If there is an assignment convert the lhs now. This will also copy lhs to + // the temporary register we allocated for it. + if (lhs) + generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); + + return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); +} + +RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + OpcodeID opcodeID = this->opcodeID(); + + if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) + return emitStrcat(generator, dst); + + 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 : m_expr1); + return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); + } + } + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + 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 : m_expr1); + return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); + } + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + 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, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + 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, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + 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, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + 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, m_rightHasAssignments, m_expr2->isPure(generator)); + RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); + + 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 ---------------------------- + +RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> temp = generator.tempDestination(dst); + RefPtr<Label> target = generator.newLabel(); + + generator.emitNode(temp.get(), m_expr1); + if (m_operator == OpLogicalAnd) + generator.emitJumpIfFalse(temp.get(), target.get()); + else + generator.emitJumpIfTrue(temp.get(), target.get()); + generator.emitNode(temp.get(), m_expr2); + generator.emitLabel(target.get()); + + return generator.moveToDestinationIfNeeded(dst, temp.get()); +} + +// ------------------------------ ConditionalNode ------------------------------ + +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); + generator.emitJumpIfFalse(cond, beforeElse.get()); + + generator.emitNode(newDst.get(), m_expr1); + generator.emitJump(afterElse.get()); + + generator.emitLabel(beforeElse.get()); + generator.emitNode(newDst.get(), m_expr2); + + generator.emitLabel(afterElse.get()); + + return newDst.get(); +} + +// ------------------------------ ReadModifyResolveNode ----------------------------------- + +// FIXME: should this be moved to be a method on BytecodeGenerator? +static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) +{ + OpcodeID opcodeID; + switch (oper) { + case OpMultEq: + opcodeID = op_mul; + break; + case OpDivEq: + opcodeID = op_div; + break; + case OpPlusEq: + if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) + return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); + 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; + } + + RegisterID* src2 = generator.emitNode(m_right); + + // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. + // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. + if (emitExpressionInfoForMe) + generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); + + 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)) { + return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + } + + if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { + RefPtr<RegisterID> result = generator.newTemporary(); + generator.emitMove(result.get(), local); + emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + generator.emitMove(local, result.get()); + return generator.moveToDestinationIfNeeded(dst, result.get()); + } + + RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), 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* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), 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* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); + return generator.emitPutById(base.get(), m_ident, result); +} + +// ------------------------------ AssignResolveNode ----------------------------------- + +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); + + RegisterID* result = generator.emitNode(local, m_right); + 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); + 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); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitPutById(base.get(), m_ident, value); +} + +// ------------------------------ AssignDotNode ----------------------------------- + +RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); + RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); + RegisterID* result = generator.emitNode(value.get(), m_right); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, result); + return generator.moveToDestinationIfNeeded(dst, result); +} + +// ------------------------------ ReadModifyDotNode ----------------------------------- + +RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, 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* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitPutById(base.get(), m_ident, updatedValue); +} + +// ------------------------------ AssignErrorNode ----------------------------------- + +RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference."); +} + +// ------------------------------ AssignBracketNode ----------------------------------- + +RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); + RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); + RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); + RegisterID* result = generator.emitNode(value.get(), m_right); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), result); + return generator.moveToDestinationIfNeeded(dst, result); +} + +// ------------------------------ ReadModifyBracketNode ----------------------------------- + +RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); + RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, 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* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), updatedValue); + + return updatedValue; +} + +// ------------------------------ CommaNode ------------------------------------ + +RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expressions.size() > 1); + for (size_t i = 0; i < m_expressions.size() - 1; i++) + generator.emitNode(generator.ignoredResult(), m_expressions[i]); + return generator.emitNode(dst, m_expressions.last()); +} + +// ------------------------------ ConstDeclNode ------------------------------------ + +RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) +{ + if (RegisterID* local = generator.constRegisterFor(m_ident)) { + if (!m_init) + return local; + + return generator.emitNode(local, m_init); + } + + // 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) : 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) + result = n->emitCodeSingle(generator); + + return result; +} + +// ------------------------------ ConstStatementNode ----------------------------- + +RegisterID* ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + return generator.emitNode(m_next); +} + +// ------------------------------ Helper functions for handling Vectors of StatementNode ------------------------------- + +static inline void statementListEmitCode(const StatementVector& statements, BytecodeGenerator& generator, RegisterID* dst) +{ + size_t size = statements.size(); + for (size_t i = 0; i < size; ++i) + generator.emitNode(dst, statements[i]); +} + +// ------------------------------ BlockNode ------------------------------------ + +RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + statementListEmitCode(m_children, generator, dst); + return 0; +} + +// ------------------------------ EmptyStatementNode --------------------------- + +RegisterID* EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + return dst; +} + +// ------------------------------ DebuggerStatementNode --------------------------- + +RegisterID* DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine(), column()); + return dst; +} + +// ------------------------------ ExprStatementNode ---------------------------- + +RegisterID* ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expr); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + return generator.emitNode(dst, m_expr); +} + +// ------------------------------ VarStatementNode ---------------------------- + +RegisterID* VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + ASSERT(m_expr); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + return generator.emitNode(m_expr); +} + +// ------------------------------ IfNode --------------------------------------- + +RegisterID* IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + RefPtr<Label> afterThen = generator.newLabel(); + + RegisterID* cond = generator.emitNode(m_condition); + generator.emitJumpIfFalse(cond, afterThen.get()); + + generator.emitNode(dst, m_ifBlock); + generator.emitLabel(afterThen.get()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion. + return 0; +} + +// ------------------------------ IfElseNode --------------------------------------- + +RegisterID* IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + RefPtr<Label> beforeElse = generator.newLabel(); + RefPtr<Label> afterElse = generator.newLabel(); + + RegisterID* cond = generator.emitNode(m_condition); + generator.emitJumpIfFalse(cond, beforeElse.get()); + + generator.emitNode(dst, m_ifBlock); + generator.emitJump(afterElse.get()); + + generator.emitLabel(beforeElse.get()); + + generator.emitNode(dst, m_elseBlock); + + generator.emitLabel(afterElse.get()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion. + return 0; +} + +// ------------------------------ DoWhileNode ---------------------------------- + +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(), column()); + + RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); +#ifndef QT_BUILD_SCRIPT_LIB + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo(), column()); +#endif + RegisterID* cond = generator.emitNode(m_expr); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + + generator.emitLabel(scope->breakTarget()); + return result.get(); +} + +// ------------------------------ WhileNode ------------------------------------ + +RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); +#ifdef QT_BUILD_SCRIPT_LIB + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo(), column()); +#endif + generator.emitJump(scope->continueTarget()); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); +#ifndef QT_BUILD_SCRIPT_LIB + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo(), column()); +#endif + RegisterID* cond = generator.emitNode(m_expr); + 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 -------------------------------------- + +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(), column()); + + if (m_expr1) + generator.emitNode(generator.ignoredResult(), m_expr1); + + RefPtr<Label> condition = generator.newLabel(); + generator.emitJump(condition.get()); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); +#ifndef QT_BUILD_SCRIPT_LIB + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); +#endif + if (m_expr3) + generator.emitNode(generator.ignoredResult(), m_expr3); + + generator.emitLabel(condition.get()); + if (m_expr2) { + RegisterID* cond = generator.emitNode(m_expr2); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + } else + generator.emitJump(topOfLoop.get()); + + generator.emitLabel(scope->breakTarget()); + return result.get(); +} + +// ------------------------------ ForInNode ------------------------------------ + +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(), column()); + + if (m_init) + generator.emitNode(generator.ignoredResult(), m_init); + RegisterID* forInBase = generator.emitNode(m_expr); + 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)->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); + 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); + 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); + } + + generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); + generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get()); +#ifndef QT_BUILD_SCRIPT_LIB + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); +#endif + generator.emitLabel(scope->breakTarget()); + return dst; +} + +// ------------------------------ ContinueNode --------------------------------- + +// ECMA 12.7 +RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + 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) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + 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 ----------------------------------- + +RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + 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) : generator.emitLoad(dst, jsUndefined()); + RefPtr<RegisterID> returnRegister; + if (generator.scopeDepth()) { + RefPtr<Label> l0 = generator.newLabel(); + if (generator.hasFinaliser() && !r0->isTemporary()) { + returnRegister = generator.emitMove(generator.newTemporary(), r0); + r0 = returnRegister.get(); + } + generator.emitJumpScopes(l0.get(), 0); + generator.emitLabel(l0.get()); + } + generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine(), column()); + return generator.emitReturn(r0); +} + +// ------------------------------ WithNode ------------------------------------- + +RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + RefPtr<RegisterID> scope = generator.newTemporary(); + generator.emitNode(scope.get(), m_expr); // scope must be protected until popped + generator.emitExpressionInfo(m_divot, m_expressionLength, 0); + generator.emitPushScope(scope.get()); + RegisterID* result = generator.emitNode(dst, m_statement); + generator.emitPopScope(); + return result; +} + +// ------------------------------ CaseBlockNode -------------------------------- + +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(); + JSValue jsValue = JSValue::makeInt32Fast(static_cast<int32_t>(value)); + if ((typeForTable & ~SwitchNumber) || !jsValue || (jsValue.getInt32Fast() != 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, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); + processClauseList(m_list2, 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; 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; 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; list; list = list->getNext()) { + generator.emitLabel(labelVector[i++].get()); + statementListEmitCode(list->getClause()->children(), generator, dst); + } + + if (m_defaultClause) { + generator.emitLabel(defaultLabel.get()); + statementListEmitCode(m_defaultClause->children(), generator, dst); + } + + for (ClauseListNode* list = m_list2; list; list = list->getNext()) { + generator.emitLabel(labelVector[i++].get()); + 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 ----------------------------------- + +RegisterID* SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); + + RefPtr<RegisterID> r0 = generator.emitNode(m_expr); + RegisterID* r1 = m_block->emitBytecodeForBlock(generator, r0.get(), dst); + + generator.emitLabel(scope->breakTarget()); + return r1; +} + +// ------------------------------ LabelNode ------------------------------------ + +RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + 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); + + generator.emitLabel(scope->breakTarget()); + return r0; +} + +// ------------------------------ ThrowNode ------------------------------------ + +RegisterID* ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); + + if (dst == generator.ignoredResult()) + dst = 0; + RefPtr<RegisterID> expr = generator.emitNode(m_expr); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitThrow(expr.get()); + return 0; +} + +// ------------------------------ TryNode -------------------------------------- + +RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ +#ifndef QT_BUILD_SCRIPT_LIB + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine(), column()); +#endif + + 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); + 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); + 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); + generator.emitSubroutineReturn(finallyReturnAddr.get()); + + generator.emitLabel(finallyEndLabel.get()); + } + + return dst; +} + +// -----------------------------ScopeNodeData --------------------------- + +ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, int numConstants) + : m_numConstants(numConstants) +{ + m_arena.swap(arena); + if (varStack) + m_varStack.swap(*varStack); + if (funcStack) + m_functionStack.swap(*funcStack); + if (children) + children->releaseContentsIntoVector(m_children); +} + +void ScopeNodeData::mark() +{ + FunctionStack::iterator end = m_functionStack.end(); + for (FunctionStack::iterator ptr = m_functionStack.begin(); ptr != end; ++ptr) { + FunctionBodyNode* body = (*ptr)->body(); + if (!body->isGenerated()) + continue; + body->generatedBytecode().mark(); + } +} + +// ------------------------------ ScopeNode ----------------------------- + +ScopeNode::ScopeNode(JSGlobalData* globalData) + : StatementNode(globalData) + , ParserArenaRefCounted(globalData) + , m_features(NoFeatures) +{ +#if ENABLE(CODEBLOCK_SAMPLING) + if (SamplingTool* sampler = globalData->interpreter->sampler()) + sampler->notifyOfScope(this); +#endif +} + +ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants) + : StatementNode(globalData) + , ParserArenaRefCounted(globalData) + , m_data(new ScopeNodeData(globalData->parser->arena(), children, varStack, funcStack, numConstants)) + , m_features(features) + , m_source(source) +{ +#if ENABLE(CODEBLOCK_SAMPLING) + if (SamplingTool* sampler = globalData->interpreter->sampler()) + sampler->notifyOfScope(this); +#endif +} + +// ------------------------------ ProgramNode ----------------------------- + +inline 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) +{ +} + +PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) +{ + RefPtr<ProgramNode> node = new ProgramNode(globalData, children, varStack, funcStack, source, features, numConstants); + + ASSERT(node->data()->m_arena.last() == node); + node->data()->m_arena.removeLast(); + ASSERT(!node->data()->m_arena.contains(node.get())); + + return node.release(); +} + +RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine(), column()); + + RefPtr<RegisterID> dstRegister = generator.newTemporary(); + generator.emitLoad(dstRegister.get(), jsUndefined()); + statementListEmitCode(children(), generator, dstRegister.get()); + + generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine(), column()); + 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())); + + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get())); + generator->generate(); + + destroyData(); +} + +#if ENABLE(JIT) +void ProgramNode::generateJITCode(ScopeChainNode* scopeChainNode) +{ + bytecode(scopeChainNode); + ASSERT(m_code); + ASSERT(!m_jitCode); + JIT::compile(scopeChainNode->globalData, m_code.get()); + ASSERT(m_jitCode); +} +#endif + +// ------------------------------ EvalNode ----------------------------- + +inline 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) +{ +} + +PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) +{ + RefPtr<EvalNode> node = new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants); + + ASSERT(node->data()->m_arena.last() == node); + node->data()->m_arena.removeLast(); + ASSERT(!node->data()->m_arena.contains(node.get())); + + return node.release(); +} + +RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine(), column()); + + RefPtr<RegisterID> dstRegister = generator.newTemporary(); + generator.emitLoad(dstRegister.get(), jsUndefined()); + statementListEmitCode(children(), generator, dstRegister.get()); + + generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine(), column()); + 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(), scopeChain.localDepth())); + + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(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, CodeBlock* codeBlockBeingRegeneratedFrom) +{ + ASSERT(!m_code); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + m_code.set(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); + + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get())); + generator->setRegeneratingForExceptionInfo(codeBlockBeingRegeneratedFrom); + generator->generate(); + + return *m_code; +} + +void EvalNode::mark() +{ + // We don't need to mark our own CodeBlock as the JSGlobalObject takes care of that + data()->mark(); +} + +#if ENABLE(JIT) +void EvalNode::generateJITCode(ScopeChainNode* scopeChainNode) +{ + bytecode(scopeChainNode); + ASSERT(m_code); + ASSERT(!m_jitCode); + JIT::compile(scopeChainNode->globalData, m_code.get()); + ASSERT(m_jitCode); +} +#endif + +// ------------------------------ FunctionBodyNode ----------------------------- + +inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData) + : ScopeNode(globalData) + , m_parameters(0) + , m_parameterCount(0) +{ +#ifdef QT_BUILD_SCRIPT_LIB + sourceToken = globalData->scriptpool->objectRegister(); +#endif +} + +inline 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) +{ +#ifdef QT_BUILD_SCRIPT_LIB + sourceToken = globalData->scriptpool->objectRegister(); +#endif +} + +FunctionBodyNode::~FunctionBodyNode() +{ +#ifdef QT_BUILD_SCRIPT_LIB + if (sourceToken) delete sourceToken; +#endif + for (size_t i = 0; i < m_parameterCount; ++i) + m_parameters[i].~Identifier(); + 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(); +} + +#if ENABLE(JIT) +PassRefPtr<FunctionBodyNode> FunctionBodyNode::createNativeThunk(JSGlobalData* globalData) +{ + RefPtr<FunctionBodyNode> body = new FunctionBodyNode(globalData); + globalData->parser->arena().reset(); + body->m_code.set(new CodeBlock(body.get())); + body->m_jitCode = JITCode(JITCode::HostFunction(globalData->jitStubs.ctiNativeCallThunk())); + return body.release(); +} +#endif + +bool FunctionBodyNode::isHostFunction() const +{ + return m_code && m_code->codeType() == NativeCode; +} + +FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData) +{ + return new FunctionBodyNode(globalData); +} + +PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants) +{ + RefPtr<FunctionBodyNode> node = new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants); + + ASSERT(node->data()->m_arena.last() == node); + node->data()->m_arena.removeLast(); + ASSERT(!node->data()->m_arena.contains(node.get())); + + return node.release(); +} + +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())); + + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get())); + generator->generate(); + + destroyData(); +} + +#if ENABLE(JIT) +void FunctionBodyNode::generateJITCode(ScopeChainNode* scopeChainNode) +{ + bytecode(scopeChainNode); + ASSERT(m_code); + ASSERT(!m_jitCode); + JIT::compile(scopeChainNode->globalData, m_code.get()); + ASSERT(m_jitCode); +} +#endif + +CodeBlock& FunctionBodyNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode, CodeBlock* codeBlockBeingRegeneratedFrom) +{ + ASSERT(!m_code); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset())); + + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get())); + generator->setRegeneratingForExceptionInfo(codeBlockBeingRegeneratedFrom); + generator->generate(); + + return *m_code; +} + +RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine(), column()); + statementListEmitCode(children(), generator, generator.ignoredResult()); + if (children().size() && children().last()->isBlock()) { + BlockNode* blockNode = static_cast<BlockNode*>(children().last()); + if (blockNode->children().size() && blockNode->children().last()->isReturnNode()) + return 0; + } + + RegisterID* r0 = generator.emitLoad(0, jsUndefined()); + generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine(), column()); + 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 --------------------------------- + +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 --------------------------------- + +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/javascriptcore/JavaScriptCore/parser/Nodes.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Nodes.h new file mode 100644 index 0000000..185cede --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Nodes.h @@ -0,0 +1,1734 @@ +/* + * Copyright (C) 1999-2000 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) + * Copyright (C) 2007 Maks Orlovich + * Copyright (C) 2007 Eric Seidel <eric@webkit.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Nodes_h +#define Nodes_h + +#include "Error.h" +#include "JITCode.h" +#include "Opcode.h" +#include "ParserArena.h" +#include "ResultType.h" +#include "SourceCode.h" +#include "SymbolTable.h" +#include <wtf/MathExtras.h> +#include <wtf/OwnPtr.h> + +#ifdef QT_BUILD_SCRIPT_LIB +#include "SourcePoolQt.h" +#endif + +namespace JSC { + + class ArgumentListNode; + class CodeBlock; + class BytecodeGenerator; + class FuncDeclNode; + class EvalCodeBlock; + class JSFunction; + class ProgramCodeBlock; + class PropertyListNode; + class ReadModifyResolveNode; + 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<FuncDeclNode*> FunctionStack; + } + + struct SwitchInfo { + enum SwitchType { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString }; + uint32_t bytecodeOffset; + SwitchType switchType; + }; + + class ParserArenaDeletable { + protected: + ParserArenaDeletable() { } + + public: + virtual ~ParserArenaDeletable() { } + + // Objects created with this version of new are deleted when the arena is deleted. + void* operator new(size_t, JSGlobalData*); + + // Objects created with this version of new are not deleted when the arena is deleted. + // Other arrangements must be made. + void* operator new(size_t); + + void operator delete(void*); + }; + + class ParserArenaRefCounted : public RefCountedCustomAllocated<ParserArenaRefCounted> { + protected: + ParserArenaRefCounted(JSGlobalData*); + + public: + virtual ~ParserArenaRefCounted() + { + ASSERT(deletionHasBegun()); + } + }; + + class Node : public ParserArenaDeletable { + protected: + Node(JSGlobalData*); + + public: + /* + 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) = 0; + + int lineNo() const { return m_line; } + + protected: + int m_line; + }; + + class ExpressionNode : public Node { + public: + ExpressionNode(JSGlobalData*, ResultType = ResultType::unknownType()); + + virtual bool isNumber() const { return false; } + virtual bool isString() const { return false; } + virtual bool isNull() const { return false; } + virtual bool isPure(BytecodeGenerator&) const { return false; } + virtual bool isLocation() const { return false; } + virtual bool isResolveNode() const { return false; } + virtual bool isBracketAccessorNode() const { return false; } + virtual bool isDotAccessorNode() const { return false; } + virtual bool isFuncExprNode() const { return false; } + virtual bool isCommaNode() const { return false; } + virtual bool isSimpleArray() const { return false; } + virtual bool isAdd() const { return false; } + + virtual ExpressionNode* stripUnaryPlus() { return this; } + + ResultType resultDescriptor() const { return m_resultType; } + + // This needs to be in public in order to compile using GCC 3.x + typedef enum { EvalOperator, FunctionCall } CallerType; + + private: + ResultType m_resultType; + }; + + class StatementNode : public Node { + public: + StatementNode(JSGlobalData*); + + void setLoc(int line0, int line1, int column); + int firstLine() const { return lineNo(); } + int lastLine() const { return m_lastLine; } + int column() const { return m_column; } + + virtual bool isEmptyStatement() const { return false; } + virtual bool isReturnNode() const { return false; } + virtual bool isExprStatement() const { return false; } + + virtual bool isBlock() const { return false; } + + private: + int m_lastLine; + int m_column; + }; + + class NullNode : public ExpressionNode { + public: + NullNode(JSGlobalData*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isNull() const { return true; } + }; + + class BooleanNode : public ExpressionNode { + public: + BooleanNode(JSGlobalData*, bool value); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isPure(BytecodeGenerator&) const { return true; } + + bool m_value; + }; + + class NumberNode : public ExpressionNode { + public: + NumberNode(JSGlobalData*, double v); + + double value() const { return m_double; } + void setValue(double d) { m_double = d; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isNumber() const { return true; } + virtual bool isPure(BytecodeGenerator&) const { return true; } + + double m_double; + }; + + class StringNode : public ExpressionNode { + public: + StringNode(JSGlobalData*, const Identifier& v); + + const Identifier& value() { return m_value; } + virtual bool isPure(BytecodeGenerator&) const { return true; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isString() const { return true; } + + 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*, const UString& pattern, const UString& flags); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + UString m_pattern; + UString m_flags; + }; + + class ThisNode : public ExpressionNode { + public: + ThisNode(JSGlobalData*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class ResolveNode : public ExpressionNode { + public: + ResolveNode(JSGlobalData*, const Identifier&, int startOffset); + + const Identifier& identifier() const { return m_ident; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isPure(BytecodeGenerator&) const ; + virtual bool isLocation() const { return true; } + virtual bool isResolveNode() const { return true; } + + Identifier m_ident; + int32_t m_startOffset; + }; + + class ElementNode : public ParserArenaDeletable { + public: + ElementNode(JSGlobalData*, int elision, ExpressionNode*); + ElementNode(JSGlobalData*, ElementNode*, int elision, ExpressionNode*); + + int elision() const { return m_elision; } + ExpressionNode* value() { return m_node; } + ElementNode* next() { return m_next; } + + private: + ElementNode* m_next; + int m_elision; + ExpressionNode* m_node; + }; + + class ArrayNode : public ExpressionNode { + public: + ArrayNode(JSGlobalData*, int elision); + ArrayNode(JSGlobalData*, ElementNode*); + ArrayNode(JSGlobalData*, int elision, ElementNode*); + + ArgumentListNode* toArgumentList(JSGlobalData*) const; + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isSimpleArray() const ; + + ElementNode* m_element; + int m_elision; + bool m_optional; + }; + + class PropertyNode : public ParserArenaDeletable { + public: + enum Type { Constant, Getter, Setter }; + + PropertyNode(JSGlobalData*, const Identifier& name, ExpressionNode* value, Type); + + const Identifier& name() const { return m_name; } + + private: + friend class PropertyListNode; + Identifier m_name; + ExpressionNode* m_assign; + Type m_type; + }; + + class PropertyListNode : public Node { + public: + PropertyListNode(JSGlobalData*, PropertyNode*); + PropertyListNode(JSGlobalData*, PropertyNode*, PropertyListNode*); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + private: + PropertyNode* m_node; + PropertyListNode* m_next; + }; + + class ObjectLiteralNode : public ExpressionNode { + public: + ObjectLiteralNode(JSGlobalData*); + ObjectLiteralNode(JSGlobalData*, PropertyListNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + PropertyListNode* m_list; + }; + + class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData { + public: + BracketAccessorNode(JSGlobalData*, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments); + + ExpressionNode* base() const { return m_base; } + ExpressionNode* subscript() const { return m_subscript; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isLocation() const { return true; } + virtual bool isBracketAccessorNode() const { return true; } + + ExpressionNode* m_base; + ExpressionNode* m_subscript; + bool m_subscriptHasAssignments; + }; + + class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData { + public: + DotAccessorNode(JSGlobalData*, ExpressionNode* base, const Identifier&); + + ExpressionNode* base() const { return m_base; } + const Identifier& identifier() const { return m_ident; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isLocation() const { return true; } + virtual bool isDotAccessorNode() const { return true; } + + ExpressionNode* m_base; + Identifier m_ident; + }; + + class ArgumentListNode : public Node { + public: + ArgumentListNode(JSGlobalData*, ExpressionNode*); + ArgumentListNode(JSGlobalData*, ArgumentListNode*, ExpressionNode*); + + ArgumentListNode* m_next; + ExpressionNode* m_expr; + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class ArgumentsNode : public ParserArenaDeletable { + public: + ArgumentsNode(JSGlobalData*); + ArgumentsNode(JSGlobalData*, ArgumentListNode*); + + ArgumentListNode* m_listNode; + }; + + class NewExprNode : public ExpressionNode, public ThrowableExpressionData { + public: + NewExprNode(JSGlobalData*, ExpressionNode*); + NewExprNode(JSGlobalData*, ExpressionNode*, ArgumentsNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + ArgumentsNode* m_args; + }; + + class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData { + public: + EvalFunctionCallNode(JSGlobalData*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ArgumentsNode* m_args; + }; + + class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData { + public: + FunctionCallValueNode(JSGlobalData*, ExpressionNode*, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + ArgumentsNode* m_args; + }; + + class FunctionCallResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + FunctionCallResolveNode(JSGlobalData*, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + ArgumentsNode* m_args; + size_t m_index; // Used by LocalVarFunctionCallNode. + size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode + }; + + class FunctionCallBracketNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + FunctionCallBracketNode(JSGlobalData*, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + ExpressionNode* m_subscript; + ArgumentsNode* m_args; + }; + + class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + FunctionCallDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + protected: + ExpressionNode* m_base; + const Identifier m_ident; + ArgumentsNode* m_args; + }; + + class CallFunctionCallDotNode : public FunctionCallDotNode { + public: + CallFunctionCallDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class ApplyFunctionCallDotNode : public FunctionCallDotNode { + public: + ApplyFunctionCallDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, ArgumentsNode*, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + PrePostResolveNode(JSGlobalData*, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset); + + protected: + const Identifier m_ident; + }; + + class PostfixResolveNode : public PrePostResolveNode { + public: + PostfixResolveNode(JSGlobalData*, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Operator m_operator; + }; + + class PostfixBracketNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + PostfixBracketNode(JSGlobalData*, ExpressionNode* base, ExpressionNode* subscript, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + ExpressionNode* m_subscript; + Operator m_operator; + }; + + class PostfixDotNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + PostfixDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + Identifier m_ident; + Operator m_operator; + }; + + class PostfixErrorNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + PostfixErrorNode(JSGlobalData*, ExpressionNode*, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + Operator m_operator; + }; + + class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + DeleteResolveNode(JSGlobalData*, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + }; + + class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData { + public: + DeleteBracketNode(JSGlobalData*, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + ExpressionNode* m_subscript; + }; + + class DeleteDotNode : public ExpressionNode, public ThrowableExpressionData { + public: + DeleteDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + Identifier m_ident; + }; + + class DeleteValueNode : public ExpressionNode { + public: + DeleteValueNode(JSGlobalData*, ExpressionNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + }; + + class VoidNode : public ExpressionNode { + public: + VoidNode(JSGlobalData*, ExpressionNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + }; + + class TypeOfResolveNode : public ExpressionNode { + public: + TypeOfResolveNode(JSGlobalData*, const Identifier&); + + const Identifier& identifier() const { return m_ident; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + }; + + class TypeOfValueNode : public ExpressionNode { + public: + TypeOfValueNode(JSGlobalData*, ExpressionNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + }; + + class PrefixResolveNode : public PrePostResolveNode { + public: + PrefixResolveNode(JSGlobalData*, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Operator m_operator; + }; + + class PrefixBracketNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData { + public: + PrefixBracketNode(JSGlobalData*, ExpressionNode* base, ExpressionNode* subscript, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + ExpressionNode* m_subscript; + Operator m_operator; + }; + + class PrefixDotNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData { + public: + PrefixDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + Identifier m_ident; + Operator m_operator; + }; + + class PrefixErrorNode : public ExpressionNode, public ThrowableExpressionData { + public: + PrefixErrorNode(JSGlobalData*, ExpressionNode*, Operator, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + Operator m_operator; + }; + + class UnaryOpNode : public ExpressionNode { + public: + UnaryOpNode(JSGlobalData*, ResultType, ExpressionNode*, OpcodeID); + + protected: + ExpressionNode* expr() { return m_expr; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + OpcodeID opcodeID() const { return m_opcodeID; } + + ExpressionNode* m_expr; + OpcodeID m_opcodeID; + }; + + class UnaryPlusNode : public UnaryOpNode { + public: + UnaryPlusNode(JSGlobalData*, ExpressionNode*); + + private: + virtual ExpressionNode* stripUnaryPlus() { return expr(); } + }; + + class NegateNode : public UnaryOpNode { + public: + NegateNode(JSGlobalData*, ExpressionNode*); + }; + + class BitwiseNotNode : public UnaryOpNode { + public: + BitwiseNotNode(JSGlobalData*, ExpressionNode*); + }; + + class LogicalNotNode : public UnaryOpNode { + public: + LogicalNotNode(JSGlobalData*, ExpressionNode*); + }; + + class BinaryOpNode : public ExpressionNode { + public: + BinaryOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); + BinaryOpNode(JSGlobalData*, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); + + RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + protected: + OpcodeID opcodeID() const { return m_opcodeID; } + + protected: + ExpressionNode* m_expr1; + ExpressionNode* m_expr2; + private: + OpcodeID m_opcodeID; + protected: + bool m_rightHasAssignments; + }; + + class ReverseBinaryOpNode : public BinaryOpNode { + public: + ReverseBinaryOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); + ReverseBinaryOpNode(JSGlobalData*, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class MultNode : public BinaryOpNode { + public: + MultNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class DivNode : public BinaryOpNode { + public: + DivNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class ModNode : public BinaryOpNode { + public: + ModNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class AddNode : public BinaryOpNode { + public: + AddNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + + virtual bool isAdd() const { return true; } + }; + + class SubNode : public BinaryOpNode { + public: + SubNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class LeftShiftNode : public BinaryOpNode { + public: + LeftShiftNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class RightShiftNode : public BinaryOpNode { + public: + RightShiftNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class UnsignedRightShiftNode : public BinaryOpNode { + public: + UnsignedRightShiftNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class LessNode : public BinaryOpNode { + public: + LessNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class GreaterNode : public ReverseBinaryOpNode { + public: + GreaterNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class LessEqNode : public BinaryOpNode { + public: + LessEqNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class GreaterEqNode : public ReverseBinaryOpNode { + public: + GreaterEqNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData { + public: + ThrowableBinaryOpNode(JSGlobalData*, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); + ThrowableBinaryOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class InstanceOfNode : public ThrowableBinaryOpNode { + public: + InstanceOfNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class InNode : public ThrowableBinaryOpNode { + public: + InNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class EqualNode : public BinaryOpNode { + public: + EqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class NotEqualNode : public BinaryOpNode { + public: + NotEqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class StrictEqualNode : public BinaryOpNode { + public: + StrictEqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class NotStrictEqualNode : public BinaryOpNode { + public: + NotStrictEqualNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class BitAndNode : public BinaryOpNode { + public: + BitAndNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class BitOrNode : public BinaryOpNode { + public: + BitOrNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + class BitXOrNode : public BinaryOpNode { + public: + BitXOrNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments); + }; + + // m_expr1 && m_expr2, m_expr1 || m_expr2 + class LogicalOpNode : public ExpressionNode { + public: + LogicalOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr1; + ExpressionNode* m_expr2; + LogicalOperator m_operator; + }; + + // The ternary operator, "m_logical ? m_expr1 : m_expr2" + class ConditionalNode : public ExpressionNode { + public: + ConditionalNode(JSGlobalData*, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_logical; + ExpressionNode* m_expr1; + ExpressionNode* m_expr2; + }; + + class ReadModifyResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + ReadModifyResolveNode(JSGlobalData*, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + ExpressionNode* m_right; + size_t m_index; // Used by ReadModifyLocalVarNode. + Operator m_operator; + bool m_rightHasAssignments; + }; + + class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignResolveNode(JSGlobalData*, const Identifier&, ExpressionNode* right, bool rightHasAssignments); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + ExpressionNode* m_right; + size_t m_index; // Used by ReadModifyLocalVarNode. + bool m_rightHasAssignments; + }; + + class ReadModifyBracketNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + ReadModifyBracketNode(JSGlobalData*, ExpressionNode* base, ExpressionNode* subscript, Operator, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + ExpressionNode* m_subscript; + ExpressionNode* m_right; + Operator m_operator : 30; + bool m_subscriptHasAssignments : 1; + bool m_rightHasAssignments : 1; + }; + + class AssignBracketNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignBracketNode(JSGlobalData*, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + ExpressionNode* m_subscript; + ExpressionNode* m_right; + bool m_subscriptHasAssignments : 1; + bool m_rightHasAssignments : 1; + }; + + class AssignDotNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + Identifier m_ident; + ExpressionNode* m_right; + bool m_rightHasAssignments; + }; + + class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData { + public: + ReadModifyDotNode(JSGlobalData*, ExpressionNode* base, const Identifier&, Operator, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_base; + Identifier m_ident; + ExpressionNode* m_right; + Operator m_operator : 31; + bool m_rightHasAssignments : 1; + }; + + class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData { + public: + AssignErrorNode(JSGlobalData*, ExpressionNode* left, Operator, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_left; + Operator m_operator; + ExpressionNode* m_right; + }; + + typedef Vector<ExpressionNode*, 8> ExpressionVector; + + class CommaNode : public ExpressionNode { + public: + CommaNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2); + + void append(ExpressionNode* expr) { m_expressions.append(expr); } + + private: + virtual bool isCommaNode() const { return true; } + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionVector m_expressions; + }; + + class ConstDeclNode : public ExpressionNode { + public: + ConstDeclNode(JSGlobalData*, const Identifier&, ExpressionNode*); + + bool hasInitializer() const { return m_init; } + const Identifier& ident() { return m_ident; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + virtual RegisterID* emitCodeSingle(BytecodeGenerator&); + + Identifier m_ident; + + public: + ConstDeclNode* m_next; + + private: + ExpressionNode* m_init; + }; + + class ConstStatementNode : public StatementNode { + public: + ConstStatementNode(JSGlobalData*, ConstDeclNode* next); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ConstDeclNode* m_next; + }; + + typedef Vector<StatementNode*> StatementVector; + + class SourceElements : public ParserArenaDeletable { + public: + SourceElements(JSGlobalData*); + + void append(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); + + StatementVector& children() { return m_children; } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isBlock() const { return true; } + + StatementVector m_children; + }; + + class EmptyStatementNode : public StatementNode { + public: + EmptyStatementNode(JSGlobalData*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isEmptyStatement() const { return true; } + }; + + class DebuggerStatementNode : public StatementNode { + public: + DebuggerStatementNode(JSGlobalData*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; + + class ExprStatementNode : public StatementNode { + public: + ExprStatementNode(JSGlobalData*, ExpressionNode*); + + ExpressionNode* expr() const { return m_expr; } + + private: + virtual bool isExprStatement() const { return true; } + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + }; + + class VarStatementNode : public StatementNode { + public: + VarStatementNode(JSGlobalData*, ExpressionNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + }; + + class IfNode : public StatementNode { + public: + IfNode(JSGlobalData*, ExpressionNode* condition, StatementNode* ifBlock); + + protected: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_condition; + StatementNode* m_ifBlock; + }; + + class IfElseNode : public IfNode { + public: + IfElseNode(JSGlobalData*, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + StatementNode* m_elseBlock; + }; + + class DoWhileNode : public StatementNode { + public: + DoWhileNode(JSGlobalData*, StatementNode* statement, ExpressionNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + StatementNode* m_statement; + ExpressionNode* m_expr; + }; + + class WhileNode : public StatementNode { + public: + WhileNode(JSGlobalData*, ExpressionNode*, StatementNode* statement); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + StatementNode* m_statement; + }; + + class ForNode : public StatementNode { + public: + ForNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr1; + ExpressionNode* m_expr2; + ExpressionNode* m_expr3; + StatementNode* m_statement; + bool m_expr1WasVarDecl; + }; + + class ForInNode : public StatementNode, public ThrowableExpressionData { + public: + ForInNode(JSGlobalData*, ExpressionNode*, ExpressionNode*, StatementNode*); + ForInNode(JSGlobalData*, const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*, int divot, int startOffset, int endOffset); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + ExpressionNode* m_init; + ExpressionNode* m_lexpr; + ExpressionNode* m_expr; + StatementNode* m_statement; + bool m_identIsVarDecl; + }; + + class ContinueNode : public StatementNode, public ThrowableExpressionData { + public: + ContinueNode(JSGlobalData*); + ContinueNode(JSGlobalData*, const Identifier&); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + }; + + class BreakNode : public StatementNode, public ThrowableExpressionData { + public: + BreakNode(JSGlobalData*); + BreakNode(JSGlobalData*, const Identifier&); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_ident; + }; + + class ReturnNode : public StatementNode, public ThrowableExpressionData { + public: + ReturnNode(JSGlobalData*, ExpressionNode* value); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isReturnNode() const { return true; } + + ExpressionNode* m_value; + }; + + class WithNode : public StatementNode { + public: + WithNode(JSGlobalData*, ExpressionNode*, StatementNode*, uint32_t divot, uint32_t expressionLength); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + StatementNode* m_statement; + uint32_t m_divot; + uint32_t m_expressionLength; + }; + + class LabelNode : public StatementNode, public ThrowableExpressionData { + public: + LabelNode(JSGlobalData*, const Identifier& name, StatementNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + Identifier m_name; + StatementNode* m_statement; + }; + + class ThrowNode : public StatementNode, public ThrowableExpressionData { + public: + ThrowNode(JSGlobalData*, ExpressionNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + }; + + class TryNode : public StatementNode { + public: + TryNode(JSGlobalData*, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* dst = 0); + + StatementNode* m_tryBlock; + Identifier m_exceptionIdent; + StatementNode* m_catchBlock; + StatementNode* m_finallyBlock; + bool m_catchHasEval; + }; + + class ParameterNode : public ParserArenaDeletable { + public: + ParameterNode(JSGlobalData*, const Identifier&); + ParameterNode(JSGlobalData*, ParameterNode*, const Identifier&); + + const Identifier& ident() const { return m_ident; } + ParameterNode* nextParam() const { return m_next; } + + private: + Identifier m_ident; + ParameterNode* m_next; + }; + + struct ScopeNodeData { + typedef DeclarationStacks::VarStack VarStack; + typedef DeclarationStacks::FunctionStack FunctionStack; + + ScopeNodeData(ParserArena&, SourceElements*, VarStack*, FunctionStack*, int numConstants); + + ParserArena m_arena; + VarStack m_varStack; + FunctionStack m_functionStack; + int m_numConstants; + StatementVector m_children; + + void mark(); + }; + + class ScopeNode : public StatementNode, public ParserArenaRefCounted { + public: + typedef DeclarationStacks::VarStack VarStack; + typedef DeclarationStacks::FunctionStack FunctionStack; + + ScopeNode(JSGlobalData*); + ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants); + + void adoptData(std::auto_ptr<ScopeNodeData> data) + { + ASSERT(!data->m_arena.contains(this)); + ASSERT(!m_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 { 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; + } + + virtual void mark() { } + +#if ENABLE(JIT) + JITCode& generatedJITCode() + { + ASSERT(m_jitCode); + return m_jitCode; + } + + ExecutablePool* getExecutablePool() + { + return m_jitCode.getExecutablePool(); + } + + void setJITCode(const JITCode jitCode) + { + m_jitCode = jitCode; + } +#endif + + protected: + void setSource(const SourceCode& source) { m_source = source; } + +#if ENABLE(JIT) + JITCode m_jitCode; +#endif + + private: + OwnPtr<ScopeNodeData> m_data; + CodeFeatures m_features; + SourceCode m_source; + }; + + class ProgramNode : public ScopeNode { + public: + static PassRefPtr<ProgramNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); + + ProgramCodeBlock& bytecode(ScopeChainNode* scopeChain) + { + if (!m_code) + generateBytecode(scopeChain); + return *m_code; + } + +#if ENABLE(JIT) + JITCode& jitCode(ScopeChainNode* scopeChain) + { + if (!m_jitCode) + generateJITCode(scopeChain); + return m_jitCode; + } +#endif + + private: + ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); + + void generateBytecode(ScopeChainNode*); + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + +#if ENABLE(JIT) + void generateJITCode(ScopeChainNode*); +#endif + + OwnPtr<ProgramCodeBlock> m_code; + }; + + class EvalNode : public ScopeNode { + public: + static PassRefPtr<EvalNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); + + EvalCodeBlock& bytecode(ScopeChainNode* scopeChain) + { + if (!m_code) + generateBytecode(scopeChain); + return *m_code; + } + + EvalCodeBlock& bytecodeForExceptionInfoReparse(ScopeChainNode*, CodeBlock*); + + virtual void mark(); + +#if ENABLE(JIT) + JITCode& jitCode(ScopeChainNode* scopeChain) + { + if (!m_jitCode) + generateJITCode(scopeChain); + return m_jitCode; + } +#endif + + private: + EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); + + void generateBytecode(ScopeChainNode*); + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + +#if ENABLE(JIT) + void generateJITCode(ScopeChainNode*); +#endif + + OwnPtr<EvalCodeBlock> m_code; + }; + + class FunctionBodyNode : public ScopeNode { + friend class JIT; + public: +#if ENABLE(JIT) + static PassRefPtr<FunctionBodyNode> createNativeThunk(JSGlobalData*); +#endif + static FunctionBodyNode* create(JSGlobalData*); + static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); + virtual ~FunctionBodyNode(); + + const Identifier* parameters() const { return m_parameters; } + size_t parameterCount() const { return m_parameterCount; } + UString paramString() const ; + Identifier* copyParameters(); + + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + bool isGenerated() const + { + return m_code; + } + + bool isHostFunction() const; + + virtual void mark(); + + void finishParsing(const SourceCode&, ParameterNode*); + void finishParsing(Identifier* parameters, size_t parameterCount); + + UString toSourceString() const { return source().toString(); } + + CodeBlock& bytecodeForExceptionInfoReparse(ScopeChainNode*, CodeBlock*); +#if ENABLE(JIT) + JITCode& jitCode(ScopeChainNode* scopeChain) + { + if (!m_jitCode) + generateJITCode(scopeChain); + return m_jitCode; + } +#endif + + CodeBlock& bytecode(ScopeChainNode* scopeChain) + { + ASSERT(scopeChain); + if (!m_code) + generateBytecode(scopeChain); + return *m_code; + } + + CodeBlock& generatedBytecode() + { + ASSERT(m_code); + return *m_code; + } + + private: + FunctionBodyNode(JSGlobalData*); + FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); + + void generateBytecode(ScopeChainNode*); +#if ENABLE(JIT) + void generateJITCode(ScopeChainNode*); +#endif + Identifier* m_parameters; + size_t m_parameterCount; + OwnPtr<CodeBlock> m_code; +#ifdef QT_BUILD_SCRIPT_LIB + SourcePool::SourcePoolToken* sourceToken; +#endif + }; + + class FuncExprNode : public ExpressionNode, public ParserArenaRefCounted { + public: + FuncExprNode(JSGlobalData*, const Identifier&, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0); + + JSFunction* makeFunction(ExecState*, ScopeChainNode*); + + FunctionBodyNode* body() { return m_body.get(); } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + virtual bool isFuncExprNode() const { return true; } + + Identifier m_ident; + RefPtr<FunctionBodyNode> m_body; + }; + + class FuncDeclNode : public StatementNode, public ParserArenaRefCounted { + public: + FuncDeclNode(JSGlobalData*, const Identifier&, FunctionBodyNode*, const SourceCode&, ParameterNode* = 0); + + JSFunction* makeFunction(ExecState*, ScopeChainNode*); + + Identifier m_ident; + + FunctionBodyNode* body() { return m_body.get(); } + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + RefPtr<FunctionBodyNode> m_body; + }; + + class CaseClauseNode : public ParserArenaDeletable { + public: + CaseClauseNode(JSGlobalData*, ExpressionNode*); + CaseClauseNode(JSGlobalData*, ExpressionNode*, SourceElements*); + + ExpressionNode* expr() const { return m_expr; } + StatementVector& children() { return m_children; } + + private: + ExpressionNode* m_expr; + StatementVector m_children; + }; + + class ClauseListNode : public ParserArenaDeletable { + public: + ClauseListNode(JSGlobalData*, CaseClauseNode*); + ClauseListNode(JSGlobalData*, ClauseListNode*, CaseClauseNode*); + + CaseClauseNode* getClause() const { return m_clause; } + ClauseListNode* getNext() const { return m_next; } + + private: + CaseClauseNode* m_clause; + ClauseListNode* m_next; + }; + + class CaseBlockNode : public ParserArenaDeletable { + public: + CaseBlockNode(JSGlobalData*, ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2); + + RegisterID* emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* dst = 0); + + private: + SwitchInfo::SwitchType tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num); + ClauseListNode* m_list1; + CaseClauseNode* m_defaultClause; + ClauseListNode* m_list2; + }; + + class SwitchNode : public StatementNode { + public: + SwitchNode(JSGlobalData*, ExpressionNode*, CaseBlockNode*); + + private: + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + + ExpressionNode* m_expr; + CaseBlockNode* m_block; + }; + + struct ElementList { + ElementNode* head; + ElementNode* tail; + }; + + struct PropertyList { + PropertyListNode* head; + PropertyListNode* tail; + }; + + struct ArgumentList { + ArgumentListNode* head; + ArgumentListNode* tail; + }; + + struct ConstDeclList { + ConstDeclNode* head; + ConstDeclNode* tail; + }; + + struct ParameterList { + ParameterNode* head; + ParameterNode* tail; + }; + + struct ClauseList { + ClauseListNode* head; + ClauseListNode* tail; + }; + +} // namespace JSC + +#endif // Nodes_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/Parser.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Parser.cpp new file mode 100644 index 0000000..96f4ae6 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Parser.cpp @@ -0,0 +1,108 @@ +/* + * 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; + +#ifndef yyparse +extern int jscyyparse(void*); +#endif + +namespace JSC { + +void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg) +{ + m_sourceElements = 0; + + 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(); + int lineNumber = lexer.lineNumber(); + lexer.clear(); + + if (parseError || lexError) { + *errLine = lineNumber; + *errMsg = "Parse error"; + m_sourceElements = 0; + } +} + +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(globalData->parser->arena(), + m_sourceElements, + 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(); + + ASSERT(globalData->parser->arena().isEmpty()); + + m_source = 0; + m_sourceElements = 0; + m_varDeclarations = 0; + m_funcDeclarations = 0; +} + +void Parser::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack, + ParserArenaData<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/javascriptcore/JavaScriptCore/parser/Parser.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Parser.h new file mode 100644 index 0000000..5a182a6 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/Parser.h @@ -0,0 +1,122 @@ +/* + * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) + * Copyright (C) 2001 Peter Kelly (pmk@post.com) + * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public License + * along with this library; see the file COPYING.LIB. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#ifndef Parser_h +#define Parser_h + +#include "Debugger.h" +#include "Nodes.h" +#include "SourceProvider.h" +#include <wtf/Forward.h> +#include <wtf/Noncopyable.h> +#include <wtf/OwnPtr.h> +#include <wtf/RefPtr.h> + +namespace JSC { + + class FunctionBodyNode; + class ProgramNode; + class UString; + + template <typename T> struct ParserArenaData : ParserArenaDeletable { T data; }; + + class Parser : public Noncopyable { + public: + template <class ParsedNode> PassRefPtr<ParsedNode> parse(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*, ParserArenaData<DeclarationStacks::VarStack>*, + ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants); + + ParserArena& arena() { return m_arena; } + + private: + void parse(JSGlobalData*, int* errLine, UString* errMsg); + + ParserArena m_arena; + const SourceCode* m_source; + SourceElements* m_sourceElements; + ParserArenaData<DeclarationStacks::VarStack>* m_varDeclarations; + ParserArenaData<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, + m_varDeclarations ? &m_varDeclarations->data : 0, + m_funcDeclarations ? &m_funcDeclarations->data : 0, + *m_source, + m_features, + m_numConstants); + int column = m_source->startOffset(); //is it good way to find column number? + result->setLoc(m_source->firstLine(), m_lastLine, column); + } + + m_arena.reset(); + + m_source = 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, + m_varDeclarations ? &m_varDeclarations->data : 0, + m_funcDeclarations ? &m_funcDeclarations->data : 0, + *m_source, + oldParsedNode->features(), + m_numConstants); + int column = m_source->startOffset(); //is it good way to find column number? + result->setLoc(m_source->firstLine(), m_lastLine, column); + } + + m_arena.reset(); + + m_source = 0; + m_varDeclarations = 0; + m_funcDeclarations = 0; + + return result.release(); + } + +} // namespace JSC + +#endif // Parser_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/ParserArena.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/parser/ParserArena.cpp new file mode 100644 index 0000000..78c5196 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/ParserArena.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Parser.h" +#include "ParserArena.h" + +#include "Nodes.h" + +namespace JSC { + +ParserArena::~ParserArena() +{ + deleteAllValues(m_deletableObjects); +} + +bool ParserArena::contains(ParserArenaRefCounted* object) const +{ + return m_refCountedObjects.find(object) != notFound; +} + +ParserArenaRefCounted* ParserArena::last() const +{ + return m_refCountedObjects.last().get(); +} + +void ParserArena::removeLast() +{ + m_refCountedObjects.removeLast(); +} + +void ParserArena::reset() +{ + deleteAllValues(m_deletableObjects); + m_deletableObjects.shrink(0); + m_refCountedObjects.shrink(0); +} + +void* ParserArenaDeletable::operator new(size_t size, JSGlobalData* globalData) +{ + ParserArenaDeletable* deletable = static_cast<ParserArenaDeletable*>(fastMalloc(size)); + globalData->parser->arena().deleteWithArena(deletable); + return deletable; +} + +void* ParserArenaDeletable::operator new(size_t size) +{ + return fastMalloc(size); +} + +void ParserArenaDeletable::operator delete(void* p) +{ + fastFree(p); +} + +} diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/ParserArena.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/ParserArena.h new file mode 100644 index 0000000..66c8529 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/ParserArena.h @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ParserArena_h +#define ParserArena_h + +#include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> +#include <wtf/Vector.h> + +namespace JSC { + + class ParserArenaDeletable; + class ParserArenaRefCounted; + + class ParserArena { + public: + void swap(ParserArena& otherArena) + { + m_deletableObjects.swap(otherArena.m_deletableObjects); + m_refCountedObjects.swap(otherArena.m_refCountedObjects); + } + ~ParserArena(); + + void deleteWithArena(ParserArenaDeletable* object) { m_deletableObjects.append(object); } + void derefWithArena(PassRefPtr<ParserArenaRefCounted> object) { m_refCountedObjects.append(object); } + + bool contains(ParserArenaRefCounted*) const; + ParserArenaRefCounted* last() const; + void removeLast(); + + bool isEmpty() const { return m_deletableObjects.isEmpty() && m_refCountedObjects.isEmpty(); } + void reset(); + + private: + Vector<ParserArenaDeletable*> m_deletableObjects; + Vector<RefPtr<ParserArenaRefCounted> > m_refCountedObjects; + }; + +} + +#endif diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/ResultType.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/ResultType.h new file mode 100644 index 0000000..27b8112 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/ResultType.h @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2008 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ResultType_h +#define ResultType_h + +namespace JSC { + + struct ResultType { + friend struct OperandTypes; + + typedef char Type; + static const Type TypeReusable = 1; + static const Type TypeInt32 = 2; + + static const Type TypeMaybeNumber = 0x04; + static const Type TypeMaybeString = 0x08; + static const Type TypeMaybeNull = 0x10; + static const Type TypeMaybeBool = 0x20; + static const Type TypeMaybeOther = 0x40; + + static const Type TypeBits = TypeMaybeNumber | TypeMaybeString | TypeMaybeNull | TypeMaybeBool | TypeMaybeOther; + + explicit ResultType(Type type) + : m_type(type) + { + } + + bool isReusable() + { + return m_type & TypeReusable; + } + + bool isInt32() + { + return m_type & TypeInt32; + } + + bool definitelyIsNumber() + { + return (m_type & TypeBits) == TypeMaybeNumber; + } + + bool definitelyIsString() + { + return (m_type & TypeBits) == TypeMaybeString; + } + + bool mightBeNumber() + { + return m_type & TypeMaybeNumber; + } + + bool isNotNumber() + { + return !mightBeNumber(); + } + + static ResultType nullType() + { + return ResultType(TypeMaybeNull); + } + + static ResultType booleanType() + { + return ResultType(TypeMaybeBool); + } + + static ResultType numberType() + { + return ResultType(TypeMaybeNumber); + } + + static ResultType numberTypeCanReuse() + { + return ResultType(TypeReusable | TypeMaybeNumber); + } + + static ResultType numberTypeCanReuseIsInt32() + { + return ResultType(TypeReusable | TypeInt32 | TypeMaybeNumber); + } + + static ResultType stringOrNumberTypeCanReuse() + { + return ResultType(TypeReusable | TypeMaybeNumber | TypeMaybeString); + } + + static ResultType stringType() + { + return ResultType(TypeMaybeString); + } + + static ResultType unknownType() + { + return ResultType(TypeBits); + } + + static ResultType forAdd(ResultType op1, ResultType op2) + { + if (op1.definitelyIsNumber() && op2.definitelyIsNumber()) + return numberTypeCanReuse(); + if (op1.definitelyIsString() || op2.definitelyIsString()) + return stringType(); + return stringOrNumberTypeCanReuse(); + } + + static ResultType forBitOp() + { + return numberTypeCanReuseIsInt32(); + } + + private: + Type m_type; + }; + + struct OperandTypes + { + OperandTypes(ResultType first = ResultType::unknownType(), ResultType second = ResultType::unknownType()) + { + // We have to initialize one of the int to ensure that + // the entire struct is initialized. + m_u.i = 0; + m_u.rds.first = first.m_type; + m_u.rds.second = second.m_type; + } + + union { + struct { + ResultType::Type first; + ResultType::Type second; + } rds; + int i; + } m_u; + + ResultType first() + { + return ResultType(m_u.rds.first); + } + + ResultType second() + { + return ResultType(m_u.rds.second); + } + + int toInt() + { + return m_u.i; + } + static OperandTypes fromInt(int value) + { + OperandTypes types; + types.m_u.i = value; + return types; + } + }; + +} // namespace JSC + +#endif // ResultType_h diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourceCode.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourceCode.h new file mode 100644 index 0000000..305b804 --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourceCode.h @@ -0,0 +1,99 @@ +/* + * 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()) +#ifdef QT_BUILD_SCRIPT_LIB + , m_firstLine(firstLine) +#else + , m_firstLine(std::max(firstLine, 1)) +#endif + { + } + + SourceCode(PassRefPtr<SourceProvider> provider, int start, int end, int firstLine) + : m_provider(provider) + , m_startChar(start) + , m_endChar(end) +#ifdef QT_BUILD_SCRIPT_LIB + , m_firstLine(firstLine) +#else + , m_firstLine(std::max(firstLine, 1)) +#endif + { + } + + 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/javascriptcore/JavaScriptCore/parser/SourcePoolQt.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourcePoolQt.cpp new file mode 100644 index 0000000..4fc859f --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourcePoolQt.cpp @@ -0,0 +1,109 @@ +/* + Copyright (C) 2008, 2009 Nokia Corporation and/or its subsidiary(-ies) + + 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 "SourcePoolQt.h" + + +#ifdef QT_BUILD_SCRIPT_LIB + +#include "SourceCode.h" +#include "Debugger.h" + + +namespace JSC { + + void SourcePool::startEvaluating(const SourceCode& source) + { + int id = source.provider()->asID(); + + codes.insert(id,source.toString()); + + currentScript.push(id); + scriptRef.insert(id,ScriptActivCount()); + + if (debug) + debug->scriptLoad(id,source.toString(),source.provider()->url(),source.firstLine()); + } + + + void SourcePool::stopEvaluating(const SourceCode& source) + { + int id = source.provider()->asID(); + currentScript.pop(); + + if (scriptRef.contains(id)) { + ScriptActivCount info = scriptRef.take(id); + if (info.getCount()) { + //we can't remove info from scriptRef + info.isActive = false; + scriptRef.insert(id,info); + } else { + //we are unloading source code + if (debug) + debug->scriptUnload(id); + } + } + } + + SourcePool::SourcePoolToken* SourcePool::objectRegister() + { + if (currentScript.isEmpty()) { + return 0; + } + + int id = currentScript.top(); + + SourcePoolToken* token = new SourcePoolToken(id,this); + + ScriptActivCount info = scriptRef.take(id); + + info.incCount(); + scriptRef.insert(id,info); + return token; + } + + void SourcePool::objectUnregister(const SourcePool::SourcePoolToken *token) + { + int id = token->id; + + ScriptActivCount info = scriptRef.take(id); + info.decCount(); + if (info.isActive) { + scriptRef.insert(id,info); + } else { + if (info.getCount() == 0) { + //remove from scriptRef (script is not active and there is no objects connected) + if(debug) + debug->scriptUnload(id); + } else { + scriptRef.insert(id,info); + } + } + + } + + + void SourcePool::setDebugger(JSC::Debugger *debugger) { this->debug = debugger; } + Debugger* SourcePool::debugger() { return debug; } + +} //namespace JSC + + +#endif //QT_BUILD_SCRIPT_LIB diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourcePoolQt.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourcePoolQt.h new file mode 100644 index 0000000..da58edb --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourcePoolQt.h @@ -0,0 +1,93 @@ +/* + Copyright (C) 2008, 2009 Nokia Corporation and/or its subsidiary(-ies) + + 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 SOURCEPOOL_H +#define SOURCEPOOL_H + +#ifdef QT_BUILD_SCRIPT_LIB + +#include "qhash.h" +#include "qstack.h" +#include "qdebug.h" +#include <stdint.h> + +namespace JSC { + + QT_USE_NAMESPACE + + class SourceCode; + class Debugger; + + class SourcePool + { + class ScriptActivCount + { + int count; + public: + void incCount() + { + count++; + }; + void decCount() + { + count--; + }; + int getCount() const + { + return count; + }; + bool isActive; + ScriptActivCount() : count(0), isActive(true) {} + }; + QStack<intptr_t> currentScript; + QHash<unsigned, ScriptActivCount> scriptRef; + QHash<int, QString> codes; //debug + Debugger *debug; + + friend class SourcePoolToken; + public: + class SourcePoolToken + { + unsigned id; + SourcePool *ptr; + SourcePoolToken(unsigned scriptId, SourcePool *scriptPool) : id(scriptId),ptr(scriptPool) {} + SourcePoolToken(const SourcePoolToken&) : id(0), ptr(0) {} //private - do not use - will crash + public: + ~SourcePoolToken() { ptr->objectUnregister(this); } + friend class SourcePool; + }; + + SourcePool() : debug(0) {} + + void startEvaluating(const SourceCode& source); + void stopEvaluating(const SourceCode& source); + SourcePoolToken* objectRegister(); + + void setDebugger(Debugger *debugger); + Debugger* debugger(); + + private: + void objectUnregister(const SourcePoolToken *token); + }; + +} //namespace JSC + + +#endif //QT_BUILD_SCRIPT_LIB + +#endif // SOURCEPOOL_H diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourceProvider.h b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourceProvider.h new file mode 100644 index 0000000..1c59eed --- /dev/null +++ b/src/3rdparty/javascriptcore/JavaScriptCore/parser/SourceProvider.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SourceProvider_h +#define SourceProvider_h + +#include "UString.h" +#include <wtf/RefCounted.h> + +namespace JSC { + + enum SourceBOMPresence { SourceHasNoBOMs, SourceCouldHaveBOMs }; + + class SourceProvider : public RefCounted<SourceProvider> { + public: + SourceProvider(const UString& url, SourceBOMPresence hasBOMs = SourceCouldHaveBOMs) + : m_url(url) + , m_hasBOMs(hasBOMs) + { + } + 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); } + + SourceBOMPresence hasBOMs() const { return m_hasBOMs; } + + private: + UString m_url; + SourceBOMPresence m_hasBOMs; + }; + + 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 |