blob: 3b1644bcb0568ab8e9ca6870584ac9262420f7fe [file] [log] [blame]
%{
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2006, 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
*
*/
#include "config.h"
#include <string.h>
#include <stdlib.h>
#include "value.h"
#include "object.h"
#include "types.h"
#include "interpreter.h"
#include "nodes.h"
#include "lexer.h"
#include "internal.h"
#include "CommonIdentifiers.h"
// Not sure why, but yacc doesn't add this define along with the others.
#define yylloc kjsyylloc
#define YYMAXDEPTH 10000
#define YYENABLE_NLS 0
/* default values for bison */
#define YYDEBUG 0
#if !PLATFORM(DARWIN)
// avoid triggering warnings in older bison
#define YYERROR_VERBOSE
#endif
extern int kjsyylex();
int kjsyyerror(const char *);
static bool allowAutomaticSemicolon();
#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon()) YYABORT; } while (0)
#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line)
using namespace KJS;
static Node* makeAssignNode(Node* loc, Operator, Node* expr);
static Node* makePrefixNode(Node* expr, Operator);
static Node* makePostfixNode(Node* expr, Operator);
static bool makeGetterOrSetterPropertyNode(PropertyNode*& result, Identifier &getOrSet, Identifier& name, ParameterNode *params, FunctionBodyNode *body);
static Node *makeFunctionCallNode(Node *func, ArgumentsNode *args);
static Node *makeTypeOfNode(Node *expr);
static Node *makeDeleteNode(Node *expr);
#if COMPILER(MSVC)
#pragma warning(disable: 4065)
#pragma warning(disable: 4244)
#pragma warning(disable: 4702)
// At least some of the time, the declarations of malloc and free that bison
// generates are causing warnings. A way to avoid this is to explicitly define
// the macros so that bison doesn't try to declare malloc and free.
#define YYMALLOC malloc
#define YYFREE free
#endif
%}
%union {
int ival;
double dval;
UString *ustr;
Identifier *ident;
Node *node;
StatementNode *stat;
ParameterNode *param;
FunctionBodyNode *body;
FuncDeclNode *func;
FuncExprNode *funcExpr;
ProgramNode *prog;
AssignExprNode *init;
SourceElementsNode *srcs;
ArgumentsNode *args;
ArgumentListNode *alist;
VarDeclNode *decl;
VarDeclListNode *vlist;
CaseBlockNode *cblk;
ClauseListNode *clist;
CaseClauseNode *ccl;
ElementNode *elm;
Operator op;
PropertyListNode *plist;
PropertyNode *pnode;
PropertyNameNode *pname;
}
%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 |= */
/* terminal types */
%token <dval> NUMBER
%token <ustr> STRING
%token <ident> IDENT
/* automatically inserted semicolon */
%token AUTOPLUSPLUS AUTOMINUSMINUS
/* non-terminal types */
%type <node> Literal ArrayLiteral
%type <node> PrimaryExpr PrimaryExprNoBrace
%type <node> MemberExpr MemberExprNoBF /* BF => brace or function */
%type <node> NewExpr NewExprNoBF
%type <node> CallExpr CallExprNoBF
%type <node> LeftHandSideExpr LeftHandSideExprNoBF
%type <node> PostfixExpr PostfixExprNoBF
%type <node> UnaryExpr UnaryExprNoBF UnaryExprCommon
%type <node> MultiplicativeExpr MultiplicativeExprNoBF
%type <node> AdditiveExpr AdditiveExprNoBF
%type <node> ShiftExpr ShiftExprNoBF
%type <node> RelationalExpr RelationalExprNoIn RelationalExprNoBF
%type <node> EqualityExpr EqualityExprNoIn EqualityExprNoBF
%type <node> BitwiseANDExpr BitwiseANDExprNoIn BitwiseANDExprNoBF
%type <node> BitwiseXORExpr BitwiseXORExprNoIn BitwiseXORExprNoBF
%type <node> BitwiseORExpr BitwiseORExprNoIn BitwiseORExprNoBF
%type <node> LogicalANDExpr LogicalANDExprNoIn LogicalANDExprNoBF
%type <node> LogicalORExpr LogicalORExprNoIn LogicalORExprNoBF
%type <node> ConditionalExpr ConditionalExprNoIn ConditionalExprNoBF
%type <node> AssignmentExpr AssignmentExprNoIn AssignmentExprNoBF
%type <node> Expr ExprNoIn ExprNoBF
%type <node> ExprOpt ExprNoInOpt
%type <stat> Statement Block
%type <stat> VariableStatement ConstStatement EmptyStatement ExprStatement
%type <stat> IfStatement IterationStatement ContinueStatement
%type <stat> BreakStatement ReturnStatement WithStatement
%type <stat> SwitchStatement LabelledStatement
%type <stat> ThrowStatement TryStatement
%type <stat> DebuggerStatement
%type <stat> SourceElement
%type <init> Initializer InitializerNoIn
%type <func> FunctionDeclaration
%type <funcExpr> FunctionExpr
%type <body> FunctionBody
%type <srcs> SourceElements
%type <param> FormalParameterList
%type <op> AssignmentOperator
%type <args> Arguments
%type <alist> ArgumentList
%type <vlist> VariableDeclarationList VariableDeclarationListNoIn ConstDeclarationList
%type <decl> VariableDeclaration VariableDeclarationNoIn ConstDeclaration
%type <cblk> CaseBlock
%type <ccl> CaseClause DefaultClause
%type <clist> CaseClauses CaseClausesOpt
%type <ival> Elision ElisionOpt
%type <elm> ElementList
%type <pname> PropertyName
%type <pnode> Property
%type <plist> PropertyList
%%
Literal:
NULLTOKEN { $$ = new NullNode(); }
| TRUETOKEN { $$ = new BooleanNode(true); }
| FALSETOKEN { $$ = new BooleanNode(false); }
| NUMBER { $$ = new NumberNode($1); }
| STRING { $$ = new StringNode($1); }
| '/' /* regexp */ {
Lexer *l = Lexer::curr();
if (!l->scanRegExp()) YYABORT;
$$ = new RegExpNode(l->pattern, l->flags);
}
| DIVEQUAL /* regexp with /= */ {
Lexer *l = Lexer::curr();
if (!l->scanRegExp()) YYABORT;
$$ = new RegExpNode("=" + l->pattern, l->flags);
}
;
PropertyName:
IDENT { $$ = new PropertyNameNode(*$1); }
| STRING { $$ = new PropertyNameNode(Identifier(*$1)); }
| NUMBER { $$ = new PropertyNameNode($1); }
;
Property:
PropertyName ':' AssignmentExpr { $$ = new PropertyNode($1, $3, PropertyNode::Constant); }
| IDENT IDENT '(' ')' FunctionBody { if (!makeGetterOrSetterPropertyNode($$, *$1, *$2, 0, $5)) YYABORT; }
| IDENT IDENT '(' FormalParameterList ')' FunctionBody
{ if (!makeGetterOrSetterPropertyNode($$, *$1, *$2, $4, $6)) YYABORT; }
;
PropertyList:
Property { $$ = new PropertyListNode($1); }
| PropertyList ',' Property { $$ = new PropertyListNode($3, $1); }
;
PrimaryExpr:
PrimaryExprNoBrace
| '{' '}' { $$ = new ObjectLiteralNode(); }
| '{' PropertyList '}' { $$ = new ObjectLiteralNode($2); }
/* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */
| '{' PropertyList ',' '}' { $$ = new ObjectLiteralNode($2); }
;
PrimaryExprNoBrace:
THISTOKEN { $$ = new ThisNode(); }
| Literal
| ArrayLiteral
| IDENT { $$ = new ResolveNode(*$1); }
| '(' Expr ')' { $$ = ($2->isResolveNode() || $2->isGroupNode()) ?
$2 : new GroupNode($2); }
;
ArrayLiteral:
'[' ElisionOpt ']' { $$ = new ArrayNode($2); }
| '[' ElementList ']' { $$ = new ArrayNode($2); }
| '[' ElementList ',' ElisionOpt ']' { $$ = new ArrayNode($4, $2); }
;
ElementList:
ElisionOpt AssignmentExpr { $$ = new ElementNode($1, $2); }
| ElementList ',' ElisionOpt AssignmentExpr
{ $$ = new ElementNode($1, $3, $4); }
;
ElisionOpt:
/* nothing */ { $$ = 0; }
| Elision
;
Elision:
',' { $$ = 1; }
| Elision ',' { $$ = $1 + 1; }
;
MemberExpr:
PrimaryExpr
| FunctionExpr { $$ = $1; }
| MemberExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| MemberExpr '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
| NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
;
MemberExprNoBF:
PrimaryExprNoBrace
| MemberExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| MemberExprNoBF '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
| NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
;
NewExpr:
MemberExpr
| NEW NewExpr { $$ = new NewExprNode($2); }
;
NewExprNoBF:
MemberExprNoBF
| NEW NewExpr { $$ = new NewExprNode($2); }
;
CallExpr:
MemberExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| CallExpr '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
;
CallExprNoBF:
MemberExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
| CallExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
| CallExprNoBF '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
;
Arguments:
'(' ')' { $$ = new ArgumentsNode(); }
| '(' ArgumentList ')' { $$ = new ArgumentsNode($2); }
;
ArgumentList:
AssignmentExpr { $$ = new ArgumentListNode($1); }
| ArgumentList ',' AssignmentExpr { $$ = new ArgumentListNode($1, $3); }
;
LeftHandSideExpr:
NewExpr
| CallExpr
;
LeftHandSideExprNoBF:
NewExprNoBF
| CallExprNoBF
;
PostfixExpr:
LeftHandSideExpr
| LeftHandSideExpr PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
| LeftHandSideExpr MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
;
PostfixExprNoBF:
LeftHandSideExprNoBF
| LeftHandSideExprNoBF PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
| LeftHandSideExprNoBF MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
;
UnaryExprCommon:
DELETETOKEN UnaryExpr { $$ = makeDeleteNode($2); }
| VOIDTOKEN UnaryExpr { $$ = new VoidNode($2); }
| TYPEOF UnaryExpr { $$ = makeTypeOfNode($2); }
| PLUSPLUS UnaryExpr { $$ = makePrefixNode($2, OpPlusPlus); }
| AUTOPLUSPLUS UnaryExpr { $$ = makePrefixNode($2, OpPlusPlus); }
| MINUSMINUS UnaryExpr { $$ = makePrefixNode($2, OpMinusMinus); }
| AUTOMINUSMINUS UnaryExpr { $$ = makePrefixNode($2, OpMinusMinus); }
| '+' UnaryExpr { $$ = new UnaryPlusNode($2); }
| '-' UnaryExpr { $$ = new NegateNode($2); }
| '~' UnaryExpr { $$ = new BitwiseNotNode($2); }
| '!' UnaryExpr { $$ = new LogicalNotNode($2); }
UnaryExpr:
PostfixExpr
| UnaryExprCommon
;
UnaryExprNoBF:
PostfixExprNoBF
| UnaryExprCommon
;
MultiplicativeExpr:
UnaryExpr
| MultiplicativeExpr '*' UnaryExpr { $$ = new MultNode($1, $3, '*'); }
| MultiplicativeExpr '/' UnaryExpr { $$ = new MultNode($1, $3, '/'); }
| MultiplicativeExpr '%' UnaryExpr { $$ = new MultNode($1, $3,'%'); }
;
MultiplicativeExprNoBF:
UnaryExprNoBF
| MultiplicativeExprNoBF '*' UnaryExpr
{ $$ = new MultNode($1, $3, '*'); }
| MultiplicativeExprNoBF '/' UnaryExpr
{ $$ = new MultNode($1, $3, '/'); }
| MultiplicativeExprNoBF '%' UnaryExpr
{ $$ = new MultNode($1, $3,'%'); }
;
AdditiveExpr:
MultiplicativeExpr
| AdditiveExpr '+' MultiplicativeExpr { $$ = new AddNode($1, $3, '+'); }
| AdditiveExpr '-' MultiplicativeExpr { $$ = new AddNode($1, $3, '-'); }
;
AdditiveExprNoBF:
MultiplicativeExprNoBF
| AdditiveExprNoBF '+' MultiplicativeExpr
{ $$ = new AddNode($1, $3, '+'); }
| AdditiveExprNoBF '-' MultiplicativeExpr
{ $$ = new AddNode($1, $3, '-'); }
;
ShiftExpr:
AdditiveExpr
| ShiftExpr LSHIFT AdditiveExpr { $$ = new ShiftNode($1, OpLShift, $3); }
| ShiftExpr RSHIFT AdditiveExpr { $$ = new ShiftNode($1, OpRShift, $3); }
| ShiftExpr URSHIFT AdditiveExpr { $$ = new ShiftNode($1, OpURShift, $3); }
;
ShiftExprNoBF:
AdditiveExprNoBF
| ShiftExprNoBF LSHIFT AdditiveExpr { $$ = new ShiftNode($1, OpLShift, $3); }
| ShiftExprNoBF RSHIFT AdditiveExpr { $$ = new ShiftNode($1, OpRShift, $3); }
| ShiftExprNoBF URSHIFT AdditiveExpr { $$ = new ShiftNode($1, OpURShift, $3); }
;
RelationalExpr:
ShiftExpr
| RelationalExpr '<' ShiftExpr { $$ = new RelationalNode($1, OpLess, $3); }
| RelationalExpr '>' ShiftExpr { $$ = new RelationalNode($1, OpGreater, $3); }
| RelationalExpr LE ShiftExpr { $$ = new RelationalNode($1, OpLessEq, $3); }
| RelationalExpr GE ShiftExpr { $$ = new RelationalNode($1, OpGreaterEq, $3); }
| RelationalExpr INSTANCEOF ShiftExpr { $$ = new RelationalNode($1, OpInstanceOf, $3); }
| RelationalExpr INTOKEN ShiftExpr { $$ = new RelationalNode($1, OpIn, $3); }
;
RelationalExprNoIn:
ShiftExpr
| RelationalExprNoIn '<' ShiftExpr { $$ = new RelationalNode($1, OpLess, $3); }
| RelationalExprNoIn '>' ShiftExpr { $$ = new RelationalNode($1, OpGreater, $3); }
| RelationalExprNoIn LE ShiftExpr { $$ = new RelationalNode($1, OpLessEq, $3); }
| RelationalExprNoIn GE ShiftExpr { $$ = new RelationalNode($1, OpGreaterEq, $3); }
| RelationalExprNoIn INSTANCEOF ShiftExpr
{ $$ = new RelationalNode($1, OpInstanceOf, $3); }
;
RelationalExprNoBF:
ShiftExprNoBF
| RelationalExprNoBF '<' ShiftExpr { $$ = new RelationalNode($1, OpLess, $3); }
| RelationalExprNoBF '>' ShiftExpr { $$ = new RelationalNode($1, OpGreater, $3); }
| RelationalExprNoBF LE ShiftExpr { $$ = new RelationalNode($1, OpLessEq, $3); }
| RelationalExprNoBF GE ShiftExpr { $$ = new RelationalNode($1, OpGreaterEq, $3); }
| RelationalExprNoBF INSTANCEOF ShiftExpr
{ $$ = new RelationalNode($1, OpInstanceOf, $3); }
| RelationalExprNoBF INTOKEN ShiftExpr { $$ = new RelationalNode($1, OpIn, $3); }
;
EqualityExpr:
RelationalExpr
| EqualityExpr EQEQ RelationalExpr { $$ = new EqualNode($1, OpEqEq, $3); }
| EqualityExpr NE RelationalExpr { $$ = new EqualNode($1, OpNotEq, $3); }
| EqualityExpr STREQ RelationalExpr { $$ = new EqualNode($1, OpStrEq, $3); }
| EqualityExpr STRNEQ RelationalExpr { $$ = new EqualNode($1, OpStrNEq, $3);}
;
EqualityExprNoIn:
RelationalExprNoIn
| EqualityExprNoIn EQEQ RelationalExprNoIn
{ $$ = new EqualNode($1, OpEqEq, $3); }
| EqualityExprNoIn NE RelationalExprNoIn
{ $$ = new EqualNode($1, OpNotEq, $3); }
| EqualityExprNoIn STREQ RelationalExprNoIn
{ $$ = new EqualNode($1, OpStrEq, $3); }
| EqualityExprNoIn STRNEQ RelationalExprNoIn
{ $$ = new EqualNode($1, OpStrNEq, $3);}
;
EqualityExprNoBF:
RelationalExprNoBF
| EqualityExprNoBF EQEQ RelationalExpr
{ $$ = new EqualNode($1, OpEqEq, $3); }
| EqualityExprNoBF NE RelationalExpr { $$ = new EqualNode($1, OpNotEq, $3); }
| EqualityExprNoBF STREQ RelationalExpr
{ $$ = new EqualNode($1, OpStrEq, $3); }
| EqualityExprNoBF STRNEQ RelationalExpr
{ $$ = new EqualNode($1, OpStrNEq, $3);}
;
BitwiseANDExpr:
EqualityExpr
| BitwiseANDExpr '&' EqualityExpr { $$ = new BitOperNode($1, OpBitAnd, $3); }
;
BitwiseANDExprNoIn:
EqualityExprNoIn
| BitwiseANDExprNoIn '&' EqualityExprNoIn
{ $$ = new BitOperNode($1, OpBitAnd, $3); }
;
BitwiseANDExprNoBF:
EqualityExprNoBF
| BitwiseANDExprNoBF '&' EqualityExpr { $$ = new BitOperNode($1, OpBitAnd, $3); }
;
BitwiseXORExpr:
BitwiseANDExpr
| BitwiseXORExpr '^' BitwiseANDExpr { $$ = new BitOperNode($1, OpBitXOr, $3); }
;
BitwiseXORExprNoIn:
BitwiseANDExprNoIn
| BitwiseXORExprNoIn '^' BitwiseANDExprNoIn
{ $$ = new BitOperNode($1, OpBitXOr, $3); }
;
BitwiseXORExprNoBF:
BitwiseANDExprNoBF
| BitwiseXORExprNoBF '^' BitwiseANDExpr
{ $$ = new BitOperNode($1, OpBitXOr, $3); }
;
BitwiseORExpr:
BitwiseXORExpr
| BitwiseORExpr '|' BitwiseXORExpr { $$ = new BitOperNode($1, OpBitOr, $3); }
;
BitwiseORExprNoIn:
BitwiseXORExprNoIn
| BitwiseORExprNoIn '|' BitwiseXORExprNoIn
{ $$ = new BitOperNode($1, OpBitOr, $3); }
;
BitwiseORExprNoBF:
BitwiseXORExprNoBF
| BitwiseORExprNoBF '|' BitwiseXORExpr
{ $$ = new BitOperNode($1, OpBitOr, $3); }
;
LogicalANDExpr:
BitwiseORExpr
| LogicalANDExpr AND BitwiseORExpr { $$ = new BinaryLogicalNode($1, OpAnd, $3); }
;
LogicalANDExprNoIn:
BitwiseORExprNoIn
| LogicalANDExprNoIn AND BitwiseORExprNoIn
{ $$ = new BinaryLogicalNode($1, OpAnd, $3); }
;
LogicalANDExprNoBF:
BitwiseORExprNoBF
| LogicalANDExprNoBF AND BitwiseORExpr
{ $$ = new BinaryLogicalNode($1, OpAnd, $3); }
;
LogicalORExpr:
LogicalANDExpr
| LogicalORExpr OR LogicalANDExpr { $$ = new BinaryLogicalNode($1, OpOr, $3); }
;
LogicalORExprNoIn:
LogicalANDExprNoIn
| LogicalORExprNoIn OR LogicalANDExprNoIn
{ $$ = new BinaryLogicalNode($1, OpOr, $3); }
;
LogicalORExprNoBF:
LogicalANDExprNoBF
| LogicalORExprNoBF OR LogicalANDExpr { $$ = new BinaryLogicalNode($1, OpOr, $3); }
;
ConditionalExpr:
LogicalORExpr
| LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr
{ $$ = new ConditionalNode($1, $3, $5); }
;
ConditionalExprNoIn:
LogicalORExprNoIn
| LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn
{ $$ = new ConditionalNode($1, $3, $5); }
;
ConditionalExprNoBF:
LogicalORExprNoBF
| LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr
{ $$ = new ConditionalNode($1, $3, $5); }
;
AssignmentExpr:
ConditionalExpr
| LeftHandSideExpr AssignmentOperator AssignmentExpr
{ $$ = makeAssignNode($1, $2, $3); }
;
AssignmentExprNoIn:
ConditionalExprNoIn
| LeftHandSideExpr AssignmentOperator AssignmentExprNoIn
{ $$ = makeAssignNode($1, $2, $3); }
;
AssignmentExprNoBF:
ConditionalExprNoBF
| LeftHandSideExprNoBF AssignmentOperator AssignmentExpr
{ $$ = makeAssignNode($1, $2, $3); }
;
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 { $$ = new CommaNode($1, $3); }
;
ExprNoIn:
AssignmentExprNoIn
| ExprNoIn ',' AssignmentExprNoIn { $$ = new CommaNode($1, $3); }
;
ExprNoBF:
AssignmentExprNoBF
| ExprNoBF ',' AssignmentExpr { $$ = new CommaNode($1, $3); }
;
Statement:
Block
| VariableStatement
| ConstStatement
| EmptyStatement
| ExprStatement
| IfStatement
| IterationStatement
| ContinueStatement
| BreakStatement
| ReturnStatement
| WithStatement
| SwitchStatement
| LabelledStatement
| ThrowStatement
| TryStatement
| DebuggerStatement
;
Block:
'{' '}' { $$ = new BlockNode(0); DBG($$, @2, @2); }
| '{' SourceElements '}' { $$ = new BlockNode($2); DBG($$, @3, @3); }
;
VariableStatement:
VAR VariableDeclarationList ';' { $$ = new VarStatementNode($2); DBG($$, @1, @3); }
| VAR VariableDeclarationList error { $$ = new VarStatementNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
VariableDeclarationList:
VariableDeclaration { $$ = new VarDeclListNode($1); }
| VariableDeclarationList ',' VariableDeclaration
{ $$ = new VarDeclListNode($1, $3); }
;
VariableDeclarationListNoIn:
VariableDeclarationNoIn { $$ = new VarDeclListNode($1); }
| VariableDeclarationListNoIn ',' VariableDeclarationNoIn
{ $$ = new VarDeclListNode($1, $3); }
;
VariableDeclaration:
IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
| IDENT Initializer { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
;
VariableDeclarationNoIn:
IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Variable); }
| IDENT InitializerNoIn { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Variable); }
;
ConstStatement:
CONSTTOKEN ConstDeclarationList ';' { $$ = new VarStatementNode($2); DBG($$, @1, @3); }
| CONSTTOKEN ConstDeclarationList error
{ $$ = new VarStatementNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
ConstDeclarationList:
ConstDeclaration { $$ = new VarDeclListNode($1); }
| ConstDeclarationList ',' ConstDeclaration
{ $$ = new VarDeclListNode($1, $3); }
;
ConstDeclaration:
IDENT { $$ = new VarDeclNode(*$1, 0, VarDeclNode::Constant); }
| IDENT Initializer { $$ = new VarDeclNode(*$1, $2, VarDeclNode::Constant); }
;
Initializer:
'=' AssignmentExpr { $$ = new AssignExprNode($2); }
;
InitializerNoIn:
'=' AssignmentExprNoIn { $$ = new AssignExprNode($2); }
;
EmptyStatement:
';' { $$ = new EmptyStatementNode(); }
;
ExprStatement:
ExprNoBF ';' { $$ = new ExprStatementNode($1); DBG($$, @1, @2); }
| ExprNoBF error { $$ = new ExprStatementNode($1); DBG($$, @1, @1); AUTO_SEMICOLON; }
;
IfStatement:
IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE
{ $$ = new IfNode($3, $5, 0); DBG($$, @1, @4); }
| IF '(' Expr ')' Statement ELSE Statement
{ $$ = new IfNode($3, $5, $7); DBG($$, @1, @4); }
;
IterationStatement:
DO Statement WHILE '(' Expr ')' ';' { $$ = new DoWhileNode($2, $5); DBG($$, @1, @3);}
| DO Statement WHILE '(' Expr ')' { $$ = new DoWhileNode($2, $5); DBG($$, @1, @3);}
| WHILE '(' Expr ')' Statement { $$ = new WhileNode($3, $5); DBG($$, @1, @4); }
| FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement
{ $$ = new ForNode($3, $5, $7, $9); DBG($$, @1, @8); }
| FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement
{ $$ = new ForNode($4, $6, $8, $10); DBG($$, @1, @9); }
| FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement
{
Node *n = $3->nodeInsideAllParens();
if (!n->isLocation())
YYABORT;
$$ = new ForInNode(n, $5, $7);
DBG($$, @1, @6);
}
| FOR '(' VAR IDENT INTOKEN Expr ')' Statement
{ $$ = new ForInNode(*$4, 0, $6, $8); DBG($$, @1, @7); }
| FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
{ $$ = new ForInNode(*$4, $5, $7, $9); DBG($$, @1, @8); }
;
ExprOpt:
/* nothing */ { $$ = 0; }
| Expr
;
ExprNoInOpt:
/* nothing */ { $$ = 0; }
| ExprNoIn
;
ContinueStatement:
CONTINUE ';' { $$ = new ContinueNode(); DBG($$, @1, @2); }
| CONTINUE error { $$ = new ContinueNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
| CONTINUE IDENT ';' { $$ = new ContinueNode(*$2); DBG($$, @1, @3); }
| CONTINUE IDENT error { $$ = new ContinueNode(*$2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
BreakStatement:
BREAK ';' { $$ = new BreakNode(); DBG($$, @1, @2); }
| BREAK error { $$ = new BreakNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
| BREAK IDENT ';' { $$ = new BreakNode(*$2); DBG($$, @1, @3); }
| BREAK IDENT error { $$ = new BreakNode(*$2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
ReturnStatement:
RETURN ';' { $$ = new ReturnNode(0); DBG($$, @1, @2); }
| RETURN error { $$ = new ReturnNode(0); DBG($$, @1, @1); AUTO_SEMICOLON; }
| RETURN Expr ';' { $$ = new ReturnNode($2); DBG($$, @1, @3); }
| RETURN Expr error { $$ = new ReturnNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
WithStatement:
WITH '(' Expr ')' Statement { $$ = new WithNode($3, $5); DBG($$, @1, @4); }
;
SwitchStatement:
SWITCH '(' Expr ')' CaseBlock { $$ = new SwitchNode($3, $5); DBG($$, @1, @4); }
;
CaseBlock:
'{' CaseClausesOpt '}' { $$ = new CaseBlockNode($2, 0, 0); }
| '{' CaseClausesOpt DefaultClause CaseClausesOpt '}'
{ $$ = new CaseBlockNode($2, $3, $4); }
;
CaseClausesOpt:
/* nothing */ { $$ = 0; }
| CaseClauses
;
CaseClauses:
CaseClause { $$ = new ClauseListNode($1); }
| CaseClauses CaseClause { $$ = new ClauseListNode($1, $2); }
;
CaseClause:
CASE Expr ':' { $$ = new CaseClauseNode($2); }
| CASE Expr ':' SourceElements { $$ = new CaseClauseNode($2, $4); }
;
DefaultClause:
DEFAULT ':' { $$ = new CaseClauseNode(0); }
| DEFAULT ':' SourceElements { $$ = new CaseClauseNode(0, $3); }
;
LabelledStatement:
IDENT ':' Statement { $3->pushLabel(*$1); $$ = new LabelNode(*$1, $3); }
;
ThrowStatement:
THROW Expr ';' { $$ = new ThrowNode($2); DBG($$, @1, @3); }
| THROW Expr error { $$ = new ThrowNode($2); DBG($$, @1, @2); AUTO_SEMICOLON; }
;
TryStatement:
TRY Block FINALLY Block { $$ = new TryNode($2, CommonIdentifiers::shared()->nullIdentifier, 0, $4); DBG($$, @1, @2); }
| TRY Block CATCH '(' IDENT ')' Block { $$ = new TryNode($2, *$5, $7, 0); DBG($$, @1, @2); }
| TRY Block CATCH '(' IDENT ')' Block FINALLY Block
{ $$ = new TryNode($2, *$5, $7, $9); DBG($$, @1, @2); }
;
DebuggerStatement:
DEBUGGER ';' { $$ = new EmptyStatementNode(); DBG($$, @1, @2); }
| DEBUGGER error { $$ = new EmptyStatementNode(); DBG($$, @1, @1); AUTO_SEMICOLON; }
;
FunctionDeclaration:
FUNCTION IDENT '(' ')' FunctionBody { $$ = new FuncDeclNode(*$2, $5); }
| FUNCTION IDENT '(' FormalParameterList ')' FunctionBody
{ $$ = new FuncDeclNode(*$2, $4, $6); }
;
FunctionExpr:
FUNCTION '(' ')' FunctionBody { $$ = new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, $4); }
| FUNCTION '(' FormalParameterList ')' FunctionBody
{ $$ = new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, $5, $3); }
| FUNCTION IDENT '(' ')' FunctionBody { $$ = new FuncExprNode(*$2, $5); }
| FUNCTION IDENT '(' FormalParameterList ')' FunctionBody
{ $$ = new FuncExprNode(*$2, $6, $4); }
;
FormalParameterList:
IDENT { $$ = new ParameterNode(*$1); }
| FormalParameterList ',' IDENT { $$ = new ParameterNode($1, *$3); }
;
FunctionBody:
'{' '}' /* not in spec */ { $$ = new FunctionBodyNode(0); DBG($$, @1, @2); }
| '{' SourceElements '}' { $$ = new FunctionBodyNode($2); DBG($$, @1, @3); }
;
Program:
/* not in spec */ { Parser::accept(new ProgramNode(0)); }
| SourceElements { Parser::accept(new ProgramNode($1)); }
;
SourceElements:
SourceElement { $$ = new SourceElementsNode($1); }
| SourceElements SourceElement { $$ = new SourceElementsNode($1, $2); }
;
SourceElement:
FunctionDeclaration { $$ = $1; }
| Statement { $$ = $1; }
;
%%
static Node* makeAssignNode(Node* loc, Operator op, Node* expr)
{
Node *n = loc->nodeInsideAllParens();
if (!n->isLocation())
return new AssignErrorNode(loc, op, expr);
if (n->isResolveNode()) {
ResolveNode *resolve = static_cast<ResolveNode *>(n);
return new AssignResolveNode(resolve->identifier(), op, expr);
}
if (n->isBracketAccessorNode()) {
BracketAccessorNode *bracket = static_cast<BracketAccessorNode *>(n);
return new AssignBracketNode(bracket->base(), bracket->subscript(), op, expr);
}
assert(n->isDotAccessorNode());
DotAccessorNode *dot = static_cast<DotAccessorNode *>(n);
return new AssignDotNode(dot->base(), dot->identifier(), op, expr);
}
static Node* makePrefixNode(Node *expr, Operator op)
{
Node *n = expr->nodeInsideAllParens();
if (!n->isLocation())
return new PrefixErrorNode(expr, op);
if (n->isResolveNode()) {
ResolveNode *resolve = static_cast<ResolveNode *>(n);
return new PrefixResolveNode(resolve->identifier(), op);
}
if (n->isBracketAccessorNode()) {
BracketAccessorNode *bracket = static_cast<BracketAccessorNode *>(n);
return new PrefixBracketNode(bracket->base(), bracket->subscript(), op);
}
assert(n->isDotAccessorNode());
DotAccessorNode *dot = static_cast<DotAccessorNode *>(n);
return new PrefixDotNode(dot->base(), dot->identifier(), op);
}
static Node* makePostfixNode(Node* expr, Operator op)
{
Node *n = expr->nodeInsideAllParens();
if (!n->isLocation())
return new PostfixErrorNode(expr, op);
if (n->isResolveNode()) {
ResolveNode *resolve = static_cast<ResolveNode *>(n);
return new PostfixResolveNode(resolve->identifier(), op);
}
if (n->isBracketAccessorNode()) {
BracketAccessorNode *bracket = static_cast<BracketAccessorNode *>(n);
return new PostfixBracketNode(bracket->base(), bracket->subscript(), op);
}
assert(n->isDotAccessorNode());
DotAccessorNode *dot = static_cast<DotAccessorNode *>(n);
return new PostfixDotNode(dot->base(), dot->identifier(), op);
}
static Node *makeFunctionCallNode(Node *func, ArgumentsNode *args)
{
Node *n = func->nodeInsideAllParens();
if (!n->isLocation())
return new FunctionCallValueNode(func, args);
else if (n->isResolveNode()) {
ResolveNode *resolve = static_cast<ResolveNode *>(n);
return new FunctionCallResolveNode(resolve->identifier(), args);
} else if (n->isBracketAccessorNode()) {
BracketAccessorNode *bracket = static_cast<BracketAccessorNode *>(n);
if (n != func)
return new FunctionCallParenBracketNode(bracket->base(), bracket->subscript(), args);
else
return new FunctionCallBracketNode(bracket->base(), bracket->subscript(), args);
} else {
assert(n->isDotAccessorNode());
DotAccessorNode *dot = static_cast<DotAccessorNode *>(n);
if (n != func)
return new FunctionCallParenDotNode(dot->base(), dot->identifier(), args);
else
return new FunctionCallDotNode(dot->base(), dot->identifier(), args);
}
}
static Node *makeTypeOfNode(Node *expr)
{
Node *n = expr->nodeInsideAllParens();
if (n->isResolveNode()) {
ResolveNode *resolve = static_cast<ResolveNode *>(n);
return new TypeOfResolveNode(resolve->identifier());
} else
return new TypeOfValueNode(expr);
}
static Node *makeDeleteNode(Node *expr)
{
Node *n = expr->nodeInsideAllParens();
if (!n->isLocation())
return new DeleteValueNode(expr);
else if (n->isResolveNode()) {
ResolveNode *resolve = static_cast<ResolveNode *>(n);
return new DeleteResolveNode(resolve->identifier());
} else if (n->isBracketAccessorNode()) {
BracketAccessorNode *bracket = static_cast<BracketAccessorNode *>(n);
return new DeleteBracketNode(bracket->base(), bracket->subscript());
} else {
assert(n->isDotAccessorNode());
DotAccessorNode *dot = static_cast<DotAccessorNode *>(n);
return new DeleteDotNode(dot->base(), dot->identifier());
}
}
static bool makeGetterOrSetterPropertyNode(PropertyNode*& result, Identifier& getOrSet, Identifier& name, ParameterNode *params, FunctionBodyNode *body)
{
PropertyNode::Type type;
if (getOrSet == "get")
type = PropertyNode::Getter;
else if (getOrSet == "set")
type = PropertyNode::Setter;
else
return false;
result = new PropertyNode(new PropertyNameNode(name),
new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, body, params), type);
return true;
}
/* called by yyparse on error */
int yyerror(const char *)
{
return 1;
}
/* may we automatically insert a semicolon ? */
static bool allowAutomaticSemicolon()
{
return yychar == '}' || yychar == 0 || Lexer::curr()->prevTerminator();
}