wine/dlls/jscript/parser.y
Gabriel Ivăncescu ae73e09a8d jscript: Use CRT allocation functions.
Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com>
2022-11-21 22:10:43 +01:00

1664 lines
58 KiB
Text

/*
* Copyright 2008 Jacek Caban for CodeWeavers
*
* 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.1 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 St, Fifth Floor, Boston, MA 02110-1301, USA
*/
%{
#include "jscript.h"
#include "engine.h"
#include "parser.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(jscript);
static int parser_error(unsigned*,parser_ctx_t*,const char*);
static void set_error(parser_ctx_t*,unsigned,HRESULT);
static BOOL explicit_error(parser_ctx_t*,void*,WCHAR);
static BOOL allow_auto_semicolon(parser_ctx_t*);
static literal_t *new_string_literal(parser_ctx_t*,jsstr_t*);
static literal_t *new_null_literal(parser_ctx_t*);
typedef struct _property_list_t {
property_definition_t *head;
property_definition_t *tail;
} property_list_t;
static property_definition_t *new_property_definition(parser_ctx_t *ctx, property_definition_type_t,
literal_t *name, expression_t *value);
static property_list_t *new_property_list(parser_ctx_t*,property_definition_t*);
static property_list_t *property_list_add(parser_ctx_t*,property_list_t*,property_definition_t*);
typedef struct _element_list_t {
array_element_t *head;
array_element_t *tail;
} element_list_t;
static element_list_t *new_element_list(parser_ctx_t*,int,expression_t*);
static element_list_t *element_list_add(parser_ctx_t*,element_list_t*,int,expression_t*);
typedef struct _argument_list_t {
argument_t *head;
argument_t *tail;
} argument_list_t;
static argument_list_t *new_argument_list(parser_ctx_t*,expression_t*);
static argument_list_t *argument_list_add(parser_ctx_t*,argument_list_t*,expression_t*);
typedef struct _case_list_t {
case_clausule_t *head;
case_clausule_t *tail;
} case_list_t;
typedef struct _statement_list_t {
statement_t *head;
statement_t *tail;
} statement_list_t;
static catch_block_t *new_catch_block(parser_ctx_t*,const WCHAR*,statement_t*);
static case_clausule_t *new_case_clausule(parser_ctx_t*,unsigned,expression_t*,statement_list_t*);
static case_list_t *new_case_list(parser_ctx_t*,case_clausule_t*);
static case_list_t *case_list_add(parser_ctx_t*,case_list_t*,case_clausule_t*);
static case_clausule_t *new_case_block(parser_ctx_t*,case_list_t*,case_clausule_t*,case_list_t*);
typedef struct _variable_list_t {
variable_declaration_t *head;
variable_declaration_t *tail;
} variable_list_t;
static variable_declaration_t *new_variable_declaration(parser_ctx_t*,const WCHAR*,expression_t*);
static variable_list_t *new_variable_list(parser_ctx_t*,variable_declaration_t*);
static variable_list_t *variable_list_add(parser_ctx_t*,variable_list_t*,variable_declaration_t*);
static void *new_statement(parser_ctx_t*,statement_type_t,size_t,unsigned);
static statement_t *new_block_statement(parser_ctx_t*,unsigned,statement_list_t*);
static statement_t *new_var_statement(parser_ctx_t*,BOOL,BOOL,unsigned,variable_list_t*);
static statement_t *new_expression_statement(parser_ctx_t*,unsigned,expression_t*);
static statement_t *new_if_statement(parser_ctx_t*,unsigned,expression_t*,statement_t*,statement_t*);
static statement_t *new_while_statement(parser_ctx_t*,unsigned,BOOL,expression_t*,statement_t*);
static statement_t *new_for_statement(parser_ctx_t*,unsigned,variable_declaration_t*,expression_t*,expression_t*,unsigned,
expression_t*,unsigned,statement_t*);
static statement_t *new_forin_statement(parser_ctx_t*,unsigned,variable_declaration_t*,expression_t*,expression_t*,statement_t*);
static statement_t *new_continue_statement(parser_ctx_t*,unsigned,const WCHAR*);
static statement_t *new_break_statement(parser_ctx_t*,unsigned,const WCHAR*);
static statement_t *new_return_statement(parser_ctx_t*,unsigned,expression_t*);
static statement_t *new_with_statement(parser_ctx_t*,unsigned,expression_t*,statement_t*);
static statement_t *new_labelled_statement(parser_ctx_t*,unsigned,const WCHAR*,statement_t*);
static statement_t *new_switch_statement(parser_ctx_t*,unsigned,expression_t*,case_clausule_t*);
static statement_t *new_throw_statement(parser_ctx_t*,unsigned,expression_t*);
static statement_t *new_try_statement(parser_ctx_t*,statement_t*,catch_block_t*,statement_t*,unsigned);
static statement_list_t *new_statement_list(parser_ctx_t*,statement_t*);
static statement_list_t *statement_list_add(statement_list_t*,statement_t*);
typedef struct _parameter_list_t {
parameter_t *head;
parameter_t *tail;
} parameter_list_t;
static parameter_list_t *new_parameter_list(parser_ctx_t*,const WCHAR*);
static parameter_list_t *parameter_list_add(parser_ctx_t*,parameter_list_t*,const WCHAR*);
static void *new_expression(parser_ctx_t *ctx,expression_type_t,size_t);
static expression_t *new_function_expression(parser_ctx_t*,const WCHAR*,parameter_list_t*,
statement_list_t*,const WCHAR*,const WCHAR*,DWORD);
static expression_t *new_binary_expression(parser_ctx_t*,expression_type_t,expression_t*,expression_t*);
static expression_t *new_unary_expression(parser_ctx_t*,expression_type_t,expression_t*);
static expression_t *new_conditional_expression(parser_ctx_t*,expression_t*,expression_t*,expression_t*);
static expression_t *new_member_expression(parser_ctx_t*,expression_t*,const WCHAR*);
static expression_t *new_new_expression(parser_ctx_t*,expression_t*,argument_list_t*);
static expression_t *new_call_expression(parser_ctx_t*,expression_t*,argument_list_t*);
static expression_t *new_identifier_expression(parser_ctx_t*,const WCHAR*);
static expression_t *new_literal_expression(parser_ctx_t*,literal_t*);
static expression_t *new_array_literal_expression(parser_ctx_t*,element_list_t*,int);
static expression_t *new_prop_and_value_expression(parser_ctx_t*,property_list_t*);
#define PARSER_LTYPE unsigned
#define YYLLOC_DEFAULT(Cur, Rhs, N) Cur = YYRHSLOC((Rhs), (N) ? 1 : 0)
%}
%lex-param { parser_ctx_t *ctx }
%parse-param { parser_ctx_t *ctx }
%define api.prefix {parser_}
%define api.pure
%start Script
%union {
int ival;
jsstr_t *str;
literal_t *literal;
struct _argument_list_t *argument_list;
case_clausule_t *case_clausule;
struct _case_list_t *case_list;
catch_block_t *catch_block;
struct _element_list_t *element_list;
expression_t *expr;
const WCHAR *identifier;
struct _parameter_list_t *parameter_list;
struct _property_list_t *property_list;
property_definition_t *property_definition;
statement_t *statement;
struct _statement_list_t *statement_list;
struct _variable_list_t *variable_list;
variable_declaration_t *variable_declaration;
}
/* keywords */
%token <identifier> kBREAK kCASE kCATCH kCONST kCONTINUE kDEFAULT kDELETE kDO kELSE kFUNCTION kIF kFINALLY kFOR
%token <identifier> kGET kIN kLET kSET kINSTANCEOF kNEW kNULL kRETURN kSWITCH kTHIS kTHROW kTRUE kFALSE
%token <identifier> kTRY kTYPEOF kVAR kVOID kWHILE kWITH
%token tANDAND tOROR tINC tDEC tHTMLCOMMENT kDIVEQ kDCOL
/* tokens */
%token <identifier> tIdentifier
%token <ival> tAssignOper tEqOper tShiftOper tRelOper
%token <literal> tNumericLiteral tBooleanLiteral
%token <str> tStringLiteral
%type <statement_list> FunctionBody
%type <statement_list> ScriptBody
%type <statement_list> FunctionStatementList
%type <statement> Statement
%type <statement> Declaration
%type <statement> Block
%type <statement> LexicalDeclaration
%type <statement> LexicalDeclarationNoIn
%type <statement> VariableStatement
%type <statement> EmptyStatement
%type <statement> ExpressionStatement
%type <statement> IfStatement
%type <statement> IterationStatement
%type <statement> ContinueStatement
%type <statement> BreakStatement
%type <statement> ReturnStatement
%type <statement> WithStatement
%type <statement> LabelledStatement
%type <statement> SwitchStatement
%type <statement> ThrowStatement
%type <statement> TryStatement
%type <statement> Finally
%type <statement> StatementListItem
%type <statement_list> StatementList StatementList_opt
%type <parameter_list> FormalParameterList FormalParameterList_opt
%type <expr> Expression Expression_opt Expression_err
%type <expr> ExpressionNoIn ExpressionNoIn_opt
%type <expr> FunctionExpression
%type <expr> AssignmentExpression AssignmentExpressionNoIn
%type <expr> ConditionalExpression ConditionalExpressionNoIn
%type <expr> LeftHandSideExpression
%type <expr> LogicalORExpression LogicalORExpressionNoIn
%type <expr> LogicalANDExpression LogicalANDExpressionNoIn
%type <expr> BitwiseORExpression BitwiseORExpressionNoIn
%type <expr> BitwiseXORExpression BitwiseXORExpressionNoIn
%type <expr> BitwiseANDExpression BitwiseANDExpressionNoIn
%type <expr> EqualityExpression EqualityExpressionNoIn
%type <expr> RelationalExpression RelationalExpressionNoIn
%type <expr> ShiftExpression
%type <expr> AdditiveExpression
%type <expr> MultiplicativeExpression
%type <expr> Initialiser_opt Initialiser
%type <expr> InitialiserNoIn_opt InitialiserNoIn
%type <expr> UnaryExpression
%type <expr> PostfixExpression
%type <expr> NewExpression
%type <expr> CallExpression
%type <expr> MemberExpression
%type <expr> PrimaryExpression
%type <expr> GetterSetterMethod
%type <identifier> Identifier_opt
%type <variable_list> VariableDeclarationList
%type <variable_list> VariableDeclarationListNoIn
%type <variable_declaration> VariableDeclaration
%type <variable_declaration> VariableDeclarationNoIn
%type <case_list> CaseClausules CaseClausules_opt
%type <case_clausule> CaseClausule DefaultClausule CaseBlock
%type <catch_block> Catch
%type <argument_list> Arguments
%type <argument_list> ArgumentList
%type <literal> Literal
%type <expr> ArrayLiteral
%type <expr> ObjectLiteral
%type <ival> Elision Elision_opt
%type <element_list> ElementList
%type <property_list> PropertyNameAndValueList
%type <property_definition> PropertyDefinition
%type <literal> PropertyName
%type <literal> BooleanLiteral
%type <ival> AssignOper
%type <identifier> IdentifierName ReservedAsIdentifier
%nonassoc LOWER_THAN_ELSE
%nonassoc kELSE
%%
/* ECMA-262 10th Edition 15.1 */
Script
: ScriptBody HtmlComment { ctx->source = $1 ? $1->head : NULL; }
/* ECMA-262 10th Edition 15.1 */
ScriptBody
: StatementList_opt { $$ = $1; }
HtmlComment
: tHTMLCOMMENT
| /* empty */
/* ECMA-262 10th Edition 14.1 */
FunctionStatementList
: StatementList_opt { $$ = $1; }
/* ECMA-262 3rd Edition 13 */
FunctionExpression
: kFUNCTION left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}'
{ $$ = new_function_expression(ctx, NULL, $3, $6, NULL, ctx->begin + @1, @7 - @1 + 1); }
| kFUNCTION tIdentifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}'
{ $$ = new_function_expression(ctx, $2, $4, $7, NULL, ctx->begin + @1, @8 - @1 + 1); }
| kFUNCTION tIdentifier kDCOL tIdentifier left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}'
{ $$ = new_function_expression(ctx, $4, $6, $9, $2, ctx->begin + @1, @10 - @1 + 1); }
/* ECMA-262 10th Edition 14.1 */
FunctionBody
: FunctionStatementList { $$ = $1; }
/* ECMA-262 3rd Edition 13 */
FormalParameterList
: tIdentifier { $$ = new_parameter_list(ctx, $1); }
| FormalParameterList ',' tIdentifier
{ $$ = parameter_list_add(ctx, $1, $3); }
/* ECMA-262 3rd Edition 13 */
FormalParameterList_opt
: /* empty */ { $$ = NULL; }
| FormalParameterList { $$ = $1; }
/* ECMA-262 3rd Edition 12 */
Statement
: Block { $$ = $1; }
| VariableStatement { $$ = $1; }
| EmptyStatement { $$ = $1; }
| FunctionExpression { $$ = new_expression_statement(ctx, @$, $1); }
| ExpressionStatement { $$ = $1; }
| IfStatement { $$ = $1; }
| IterationStatement { $$ = $1; }
| ContinueStatement { $$ = $1; }
| BreakStatement { $$ = $1; }
| ReturnStatement { $$ = $1; }
| WithStatement { $$ = $1; }
| LabelledStatement { $$ = $1; }
| SwitchStatement { $$ = $1; }
| ThrowStatement { $$ = $1; }
| TryStatement { $$ = $1; }
/* ECMA-262 10th Edition 13. TODO: HoistableDeclaration */
Declaration
: LexicalDeclaration { $$ = $1; }
/* ECMA-262 10th Edition 13.2 */
StatementListItem
: Statement { $$ = $1; }
| Declaration { $$ = $1; }
/* ECMA-262 10th Edition 13.2 */
StatementList
: StatementListItem { $$ = new_statement_list(ctx, $1); }
| StatementList StatementListItem
{ $$ = statement_list_add($1, $2); }
/* ECMA-262 3rd Edition 12.2 */
StatementList_opt
: /* empty */ { $$ = NULL; }
| StatementList { $$ = $1; }
/* ECMA-262 3rd Edition 12.1 */
Block
: '{' StatementList '}' { $$ = new_block_statement(ctx, @2, $2); }
| '{' '}' { $$ = new_block_statement(ctx, @$, NULL); }
/* ECMA-262 10th Edition 13.3.1, TODO: BindingList*/
LexicalDeclaration
: kLET VariableDeclarationList semicolon_opt
{ $$ = new_var_statement(ctx, TRUE, FALSE, @$, $2); }
| kCONST VariableDeclarationList semicolon_opt
{
if(ctx->script->version < SCRIPTLANGUAGEVERSION_ES5) {
WARN("const var declaration %s in legacy mode.\n",
debugstr_w($1));
set_error(ctx, @$, JS_E_SYNTAX);
YYABORT;
}
$$ = new_var_statement(ctx, TRUE, TRUE, @$, $2);
}
/* ECMA-262 10th Edition 13.3.1, TODO: BindingList*/
LexicalDeclarationNoIn
: kLET VariableDeclarationListNoIn semicolon_opt
{ $$ = new_var_statement(ctx, TRUE, FALSE, @$, $2); }
| kCONST VariableDeclarationListNoIn semicolon_opt
{
if(ctx->script->version < SCRIPTLANGUAGEVERSION_ES5) {
WARN("const var declaration %s in legacy mode.\n",
debugstr_w($1));
set_error(ctx, @$, JS_E_SYNTAX);
YYABORT;
}
$$ = new_var_statement(ctx, TRUE, TRUE, @$, $2);
}
/* ECMA-262 3rd Edition 12.2 */
VariableStatement
: kVAR VariableDeclarationList semicolon_opt
{ $$ = new_var_statement(ctx, FALSE, FALSE, @$, $2); }
/* ECMA-262 3rd Edition 12.2 */
VariableDeclarationList
: VariableDeclaration { $$ = new_variable_list(ctx, $1); }
| VariableDeclarationList ',' VariableDeclaration
{ $$ = variable_list_add(ctx, $1, $3); }
/* ECMA-262 3rd Edition 12.2 */
VariableDeclarationListNoIn
: VariableDeclarationNoIn
{ $$ = new_variable_list(ctx, $1); }
| VariableDeclarationListNoIn ',' VariableDeclarationNoIn
{ $$ = variable_list_add(ctx, $1, $3); }
/* ECMA-262 3rd Edition 12.2 */
VariableDeclaration
: tIdentifier Initialiser_opt
{ $$ = new_variable_declaration(ctx, $1, $2); }
/* ECMA-262 3rd Edition 12.2 */
VariableDeclarationNoIn
: tIdentifier InitialiserNoIn_opt
{ $$ = new_variable_declaration(ctx, $1, $2); }
/* ECMA-262 3rd Edition 12.2 */
Initialiser_opt
: /* empty */ { $$ = NULL; }
| Initialiser { $$ = $1; }
/* ECMA-262 3rd Edition 12.2 */
Initialiser
: '=' AssignmentExpression
{ $$ = $2; }
/* ECMA-262 3rd Edition 12.2 */
InitialiserNoIn_opt
: /* empty */ { $$ = NULL; }
| InitialiserNoIn { $$ = $1; }
/* ECMA-262 3rd Edition 12.2 */
InitialiserNoIn
: '=' AssignmentExpressionNoIn
{ $$ = $2; }
/* ECMA-262 3rd Edition 12.3 */
EmptyStatement
: ';' { $$ = new_statement(ctx, STAT_EMPTY, 0, @$); }
/* ECMA-262 3rd Edition 12.4 */
ExpressionStatement
: Expression semicolon_opt
{ $$ = new_expression_statement(ctx, @$, $1); }
/* ECMA-262 3rd Edition 12.5 */
IfStatement
: kIF left_bracket Expression_err right_bracket Statement kELSE Statement
{ $$ = new_if_statement(ctx, @$, $3, $5, $7); }
| kIF left_bracket Expression_err right_bracket Statement %prec LOWER_THAN_ELSE
{ $$ = new_if_statement(ctx, @$, $3, $5, NULL); }
/* ECMA-262 10th Edition 13.7 */
IterationStatement
: kDO Statement kWHILE left_bracket Expression_err right_bracket semicolon_opt
{ $$ = new_while_statement(ctx, @3, TRUE, $5, $2); }
| kWHILE left_bracket Expression_err right_bracket Statement
{ $$ = new_while_statement(ctx, @$, FALSE, $3, $5); }
| kFOR left_bracket ExpressionNoIn_opt
{ if(!explicit_error(ctx, $3, ';')) YYABORT; }
semicolon Expression_opt
{ if(!explicit_error(ctx, $6, ';')) YYABORT; }
semicolon Expression_opt right_bracket Statement
{ $$ = new_for_statement(ctx, @3, NULL, $3, $6, @6, $9, @9, $11); }
| kFOR left_bracket kVAR VariableDeclarationListNoIn
{ if(!explicit_error(ctx, $4, ';')) YYABORT; }
semicolon Expression_opt
{ if(!explicit_error(ctx, $7, ';')) YYABORT; }
semicolon Expression_opt right_bracket Statement
{ $$ = new_for_statement(ctx, @3, $4 ? $4->head : NULL, NULL, $7, @7, $10, @10, $12); }
| kFOR left_bracket LeftHandSideExpression kIN Expression_err right_bracket Statement
{ $$ = new_forin_statement(ctx, @$, NULL, $3, $5, $7); }
| kFOR left_bracket kVAR VariableDeclarationNoIn kIN Expression_err right_bracket Statement
{ $$ = new_forin_statement(ctx, @$, $4, NULL, $6, $8); }
| kFOR left_bracket LexicalDeclarationNoIn
{ if(!explicit_error(ctx, $3, ';')) YYABORT; }
Expression_opt
{ if(!explicit_error(ctx, $5, ';')) YYABORT; }
semicolon Expression_opt right_bracket Statement
{ $$ = new_for_statement(ctx, @3, ((var_statement_t *)$3)->variable_list,
NULL, $5, @5, $8, @8, $10); }
/* ECMA-262 3rd Edition 12.7 */
ContinueStatement
: kCONTINUE /* NONL */ Identifier_opt semicolon_opt
{ $$ = new_continue_statement(ctx, @$, $2); }
/* ECMA-262 3rd Edition 12.8 */
BreakStatement
: kBREAK /* NONL */ Identifier_opt semicolon_opt
{ $$ = new_break_statement(ctx, @$, $2); }
/* ECMA-262 3rd Edition 12.9 */
ReturnStatement
: kRETURN /* NONL */ Expression_opt semicolon_opt
{ $$ = new_return_statement(ctx, @$, $2); }
/* ECMA-262 3rd Edition 12.10 */
WithStatement
: kWITH left_bracket Expression right_bracket Statement
{ $$ = new_with_statement(ctx, @$, $3, $5); }
/* ECMA-262 3rd Edition 12.12 */
LabelledStatement
: tIdentifier ':' Statement
{ $$ = new_labelled_statement(ctx, @$, $1, $3); }
/* ECMA-262 3rd Edition 12.11 */
SwitchStatement
: kSWITCH left_bracket Expression right_bracket CaseBlock
{ $$ = new_switch_statement(ctx, @$, $3, $5); }
/* ECMA-262 3rd Edition 12.11 */
CaseBlock
: '{' CaseClausules_opt '}'
{ $$ = new_case_block(ctx, $2, NULL, NULL); }
| '{' CaseClausules_opt DefaultClausule CaseClausules_opt '}'
{ $$ = new_case_block(ctx, $2, $3, $4); }
/* ECMA-262 3rd Edition 12.11 */
CaseClausules_opt
: /* empty */ { $$ = NULL; }
| CaseClausules { $$ = $1; }
/* ECMA-262 3rd Edition 12.11 */
CaseClausules
: CaseClausule { $$ = new_case_list(ctx, $1); }
| CaseClausules CaseClausule
{ $$ = case_list_add(ctx, $1, $2); }
/* ECMA-262 3rd Edition 12.11 */
CaseClausule
: kCASE Expression ':' StatementList_opt
{ $$ = new_case_clausule(ctx, @$, $2, $4); }
/* ECMA-262 3rd Edition 12.11 */
DefaultClausule
: kDEFAULT ':' StatementList_opt
{ $$ = new_case_clausule(ctx, @$, NULL, $3); }
/* ECMA-262 3rd Edition 12.13 */
ThrowStatement
: kTHROW /* NONL */ Expression semicolon_opt
{ $$ = new_throw_statement(ctx, @$, $2); }
/* ECMA-262 3rd Edition 12.14 */
TryStatement
: kTRY Block Catch { $$ = new_try_statement(ctx, $2, $3, NULL, 0); }
| kTRY Block Finally { $$ = new_try_statement(ctx, $2, NULL, $3, @3); }
| kTRY Block Catch Finally
{ $$ = new_try_statement(ctx, $2, $3, $4, @4); }
/* ECMA-262 3rd Edition 12.14 */
Catch
: kCATCH left_bracket tIdentifier right_bracket Block
{ $$ = new_catch_block(ctx, $3, $5); }
/* ECMA-262 3rd Edition 12.14 */
Finally
: kFINALLY Block { @$ = @2; $$ = $2; }
/* ECMA-262 3rd Edition 11.14 */
Expression_opt
: /* empty */ { $$ = NULL; }
| Expression { $$ = $1; }
Expression_err
: Expression { $$ = $1; }
| error { set_error(ctx, @$, JS_E_SYNTAX); YYABORT; }
/* ECMA-262 3rd Edition 11.14 */
Expression
: AssignmentExpression { $$ = $1; }
| Expression ',' AssignmentExpression
{ $$ = new_binary_expression(ctx, EXPR_COMMA, $1, $3); }
/* ECMA-262 3rd Edition 11.14 */
ExpressionNoIn_opt
: /* empty */ { $$ = NULL; }
| ExpressionNoIn { $$ = $1; }
/* ECMA-262 3rd Edition 11.14 */
ExpressionNoIn
: AssignmentExpressionNoIn
{ $$ = $1; }
| ExpressionNoIn ',' AssignmentExpressionNoIn
{ $$ = new_binary_expression(ctx, EXPR_COMMA, $1, $3); }
AssignOper
: tAssignOper { $$ = $1; }
| kDIVEQ { $$ = EXPR_ASSIGNDIV; }
/* ECMA-262 3rd Edition 11.13 */
AssignmentExpression
: ConditionalExpression { $$ = $1; }
| LeftHandSideExpression '=' AssignmentExpression
{ $$ = new_binary_expression(ctx, EXPR_ASSIGN, $1, $3); }
| LeftHandSideExpression AssignOper AssignmentExpression
{ $$ = new_binary_expression(ctx, $2, $1, $3); }
/* ECMA-262 3rd Edition 11.13 */
AssignmentExpressionNoIn
: ConditionalExpressionNoIn
{ $$ = $1; }
| LeftHandSideExpression '=' AssignmentExpressionNoIn
{ $$ = new_binary_expression(ctx, EXPR_ASSIGN, $1, $3); }
| LeftHandSideExpression AssignOper AssignmentExpressionNoIn
{ $$ = new_binary_expression(ctx, $2, $1, $3); }
/* ECMA-262 3rd Edition 11.12 */
ConditionalExpression
: LogicalORExpression { $$ = $1; }
| LogicalORExpression '?' AssignmentExpression ':' AssignmentExpression
{ $$ = new_conditional_expression(ctx, $1, $3, $5); }
/* ECMA-262 3rd Edition 11.12 */
ConditionalExpressionNoIn
: LogicalORExpressionNoIn
{ $$ = $1; }
| LogicalORExpressionNoIn '?' AssignmentExpressionNoIn ':' AssignmentExpressionNoIn
{ $$ = new_conditional_expression(ctx, $1, $3, $5); }
/* ECMA-262 3rd Edition 11.11 */
LogicalORExpression
: LogicalANDExpression { $$ = $1; }
| LogicalORExpression tOROR LogicalANDExpression
{ $$ = new_binary_expression(ctx, EXPR_OR, $1, $3); }
/* ECMA-262 3rd Edition 11.11 */
LogicalORExpressionNoIn
: LogicalANDExpressionNoIn
{ $$ = $1; }
| LogicalORExpressionNoIn tOROR LogicalANDExpressionNoIn
{ $$ = new_binary_expression(ctx, EXPR_OR, $1, $3); }
/* ECMA-262 3rd Edition 11.11 */
LogicalANDExpression
: BitwiseORExpression { $$ = $1; }
| LogicalANDExpression tANDAND BitwiseORExpression
{ $$ = new_binary_expression(ctx, EXPR_AND, $1, $3); }
/* ECMA-262 3rd Edition 11.11 */
LogicalANDExpressionNoIn
: BitwiseORExpressionNoIn
{ $$ = $1; }
| LogicalANDExpressionNoIn tANDAND BitwiseORExpressionNoIn
{ $$ = new_binary_expression(ctx, EXPR_AND, $1, $3); }
/* ECMA-262 3rd Edition 11.10 */
BitwiseORExpression
: BitwiseXORExpression { $$ = $1; }
| BitwiseORExpression '|' BitwiseXORExpression
{ $$ = new_binary_expression(ctx, EXPR_BOR, $1, $3); }
/* ECMA-262 3rd Edition 11.10 */
BitwiseORExpressionNoIn
: BitwiseXORExpressionNoIn
{ $$ = $1; }
| BitwiseORExpressionNoIn '|' BitwiseXORExpressionNoIn
{ $$ = new_binary_expression(ctx, EXPR_BOR, $1, $3); }
/* ECMA-262 3rd Edition 11.10 */
BitwiseXORExpression
: BitwiseANDExpression { $$ = $1; }
| BitwiseXORExpression '^' BitwiseANDExpression
{ $$ = new_binary_expression(ctx, EXPR_BXOR, $1, $3); }
/* ECMA-262 3rd Edition 11.10 */
BitwiseXORExpressionNoIn
: BitwiseANDExpressionNoIn
{ $$ = $1; }
| BitwiseXORExpressionNoIn '^' BitwiseANDExpressionNoIn
{ $$ = new_binary_expression(ctx, EXPR_BXOR, $1, $3); }
/* ECMA-262 3rd Edition 11.10 */
BitwiseANDExpression
: EqualityExpression { $$ = $1; }
| BitwiseANDExpression '&' EqualityExpression
{ $$ = new_binary_expression(ctx, EXPR_BAND, $1, $3); }
/* ECMA-262 3rd Edition 11.10 */
BitwiseANDExpressionNoIn
: EqualityExpressionNoIn
{ $$ = $1; }
| BitwiseANDExpressionNoIn '&' EqualityExpressionNoIn
{ $$ = new_binary_expression(ctx, EXPR_BAND, $1, $3); }
/* ECMA-262 3rd Edition 11.9 */
EqualityExpression
: RelationalExpression { $$ = $1; }
| EqualityExpression tEqOper RelationalExpression
{ $$ = new_binary_expression(ctx, $2, $1, $3); }
/* ECMA-262 3rd Edition 11.9 */
EqualityExpressionNoIn
: RelationalExpressionNoIn { $$ = $1; }
| EqualityExpressionNoIn tEqOper RelationalExpressionNoIn
{ $$ = new_binary_expression(ctx, $2, $1, $3); }
/* ECMA-262 3rd Edition 11.8 */
RelationalExpression
: ShiftExpression { $$ = $1; }
| RelationalExpression tRelOper ShiftExpression
{ $$ = new_binary_expression(ctx, $2, $1, $3); }
| RelationalExpression kINSTANCEOF ShiftExpression
{ $$ = new_binary_expression(ctx, EXPR_INSTANCEOF, $1, $3); }
| RelationalExpression kIN ShiftExpression
{ $$ = new_binary_expression(ctx, EXPR_IN, $1, $3); }
/* ECMA-262 3rd Edition 11.8 */
RelationalExpressionNoIn
: ShiftExpression { $$ = $1; }
| RelationalExpressionNoIn tRelOper ShiftExpression
{ $$ = new_binary_expression(ctx, $2, $1, $3); }
| RelationalExpressionNoIn kINSTANCEOF ShiftExpression
{ $$ = new_binary_expression(ctx, EXPR_INSTANCEOF, $1, $3); }
/* ECMA-262 3rd Edition 11.7 */
ShiftExpression
: AdditiveExpression { $$ = $1; }
| ShiftExpression tShiftOper AdditiveExpression
{ $$ = new_binary_expression(ctx, $2, $1, $3); }
/* ECMA-262 3rd Edition 11.6 */
AdditiveExpression
: MultiplicativeExpression
{ $$ = $1; }
| AdditiveExpression '+' MultiplicativeExpression
{ $$ = new_binary_expression(ctx, EXPR_ADD, $1, $3); }
| AdditiveExpression '-' MultiplicativeExpression
{ $$ = new_binary_expression(ctx, EXPR_SUB, $1, $3); }
/* ECMA-262 3rd Edition 11.5 */
MultiplicativeExpression
: UnaryExpression { $$ = $1; }
| MultiplicativeExpression '*' UnaryExpression
{ $$ = new_binary_expression(ctx, EXPR_MUL, $1, $3); }
| MultiplicativeExpression '/' UnaryExpression
{ $$ = new_binary_expression(ctx, EXPR_DIV, $1, $3); }
| MultiplicativeExpression '%' UnaryExpression
{ $$ = new_binary_expression(ctx, EXPR_MOD, $1, $3); }
/* ECMA-262 3rd Edition 11.4 */
UnaryExpression
: PostfixExpression { $$ = $1; }
| kDELETE UnaryExpression
{ $$ = new_unary_expression(ctx, EXPR_DELETE, $2); }
| kVOID UnaryExpression { $$ = new_unary_expression(ctx, EXPR_VOID, $2); }
| kTYPEOF UnaryExpression
{ $$ = new_unary_expression(ctx, EXPR_TYPEOF, $2); }
| tINC UnaryExpression { $$ = new_unary_expression(ctx, EXPR_PREINC, $2); }
| tDEC UnaryExpression { $$ = new_unary_expression(ctx, EXPR_PREDEC, $2); }
| '+' UnaryExpression { $$ = new_unary_expression(ctx, EXPR_PLUS, $2); }
| '-' UnaryExpression { $$ = new_unary_expression(ctx, EXPR_MINUS, $2); }
| '~' UnaryExpression { $$ = new_unary_expression(ctx, EXPR_BITNEG, $2); }
| '!' UnaryExpression { $$ = new_unary_expression(ctx, EXPR_LOGNEG, $2); }
/* ECMA-262 3rd Edition 11.2 */
PostfixExpression
: LeftHandSideExpression
{ $$ = $1; }
| LeftHandSideExpression /* NONL */ tINC
{ $$ = new_unary_expression(ctx, EXPR_POSTINC, $1); }
| LeftHandSideExpression /* NONL */ tDEC
{ $$ = new_unary_expression(ctx, EXPR_POSTDEC, $1); }
/* ECMA-262 3rd Edition 11.2 */
LeftHandSideExpression
: NewExpression { $$ = $1; }
| CallExpression { $$ = $1; }
/* ECMA-262 3rd Edition 11.2 */
NewExpression
: MemberExpression { $$ = $1; }
| kNEW NewExpression { $$ = new_new_expression(ctx, $2, NULL); }
/* ECMA-262 3rd Edition 11.2 */
MemberExpression
: PrimaryExpression { $$ = $1; }
| FunctionExpression { $$ = $1; }
| MemberExpression '[' Expression ']'
{ $$ = new_binary_expression(ctx, EXPR_ARRAY, $1, $3); }
| MemberExpression '.' IdentifierName
{ $$ = new_member_expression(ctx, $1, $3); }
| kNEW MemberExpression Arguments
{ $$ = new_new_expression(ctx, $2, $3); }
/* ECMA-262 3rd Edition 11.2 */
CallExpression
: MemberExpression Arguments
{ $$ = new_call_expression(ctx, $1, $2); }
| CallExpression Arguments
{ $$ = new_call_expression(ctx, $1, $2); }
| CallExpression '[' Expression ']'
{ $$ = new_binary_expression(ctx, EXPR_ARRAY, $1, $3); }
| CallExpression '.' IdentifierName
{ $$ = new_member_expression(ctx, $1, $3); }
/* ECMA-262 3rd Edition 11.2 */
Arguments
: '(' ')' { $$ = NULL; }
| '(' ArgumentList ')' { $$ = $2; }
/* ECMA-262 3rd Edition 11.2 */
ArgumentList
: AssignmentExpression { $$ = new_argument_list(ctx, $1); }
| ArgumentList ',' AssignmentExpression
{ $$ = argument_list_add(ctx, $1, $3); }
/* ECMA-262 3rd Edition 11.1 */
PrimaryExpression
: kTHIS { $$ = new_expression(ctx, EXPR_THIS, 0); }
| tIdentifier { $$ = new_identifier_expression(ctx, $1); }
| Literal { $$ = new_literal_expression(ctx, $1); }
| ArrayLiteral { $$ = $1; }
| ObjectLiteral { $$ = $1; }
| '(' Expression ')' { $$ = $2; }
/* ECMA-262 3rd Edition 11.1.4 */
ArrayLiteral
: '[' ']' { $$ = new_array_literal_expression(ctx, NULL, 0); }
| '[' Elision ']' { $$ = new_array_literal_expression(ctx, NULL, $2+1); }
| '[' ElementList ']' { $$ = new_array_literal_expression(ctx, $2, 0); }
| '[' ElementList ',' Elision_opt ']'
{ $$ = new_array_literal_expression(ctx, $2, $4+1); }
/* ECMA-262 3rd Edition 11.1.4 */
ElementList
: Elision_opt AssignmentExpression
{ $$ = new_element_list(ctx, $1, $2); }
| ElementList ',' Elision_opt AssignmentExpression
{ $$ = element_list_add(ctx, $1, $3, $4); }
/* ECMA-262 3rd Edition 11.1.4 */
Elision
: ',' { $$ = 1; }
| Elision ',' { $$ = $1 + 1; }
/* ECMA-262 3rd Edition 11.1.4 */
Elision_opt
: /* empty */ { $$ = 0; }
| Elision { $$ = $1; }
/* ECMA-262 3rd Edition 11.1.5 */
ObjectLiteral
: '{' '}' { $$ = new_prop_and_value_expression(ctx, NULL); }
| '{' PropertyNameAndValueList '}'
{ $$ = new_prop_and_value_expression(ctx, $2); }
| '{' PropertyNameAndValueList ',' '}'
{
if(ctx->script->version < 2) {
WARN("Trailing comma in object literal is illegal in legacy mode.\n");
set_error(ctx, @3, JS_E_SYNTAX);
YYABORT;
}
$$ = new_prop_and_value_expression(ctx, $2);
}
/* ECMA-262 3rd Edition 11.1.5 */
PropertyNameAndValueList
: PropertyDefinition { $$ = new_property_list(ctx, $1); }
| PropertyNameAndValueList ',' PropertyDefinition
{ $$ = property_list_add(ctx, $1, $3); }
/* ECMA-262 5.1 Edition 12.2.6 */
PropertyDefinition
: PropertyName ':' AssignmentExpression
{ $$ = new_property_definition(ctx, PROPERTY_DEFINITION_VALUE, $1, $3); }
| kGET PropertyName GetterSetterMethod
{ $$ = new_property_definition(ctx, PROPERTY_DEFINITION_GETTER, $2, $3); }
| kSET PropertyName GetterSetterMethod
{ $$ = new_property_definition(ctx, PROPERTY_DEFINITION_SETTER, $2, $3); }
GetterSetterMethod
: left_bracket FormalParameterList_opt right_bracket '{' FunctionBody '}'
{ $$ = new_function_expression(ctx, NULL, $2, $5, NULL, ctx->begin + @1, @6 - @1 + 1); }
/* Ecma-262 3rd Edition 11.1.5 */
PropertyName
: IdentifierName { $$ = new_string_literal(ctx, compiler_alloc_string_len(ctx->compiler, $1, lstrlenW($1))); }
| tStringLiteral { $$ = new_string_literal(ctx, $1); }
| tNumericLiteral { $$ = $1; }
/* ECMA-262 3rd Edition 7.6 */
Identifier_opt
: /* empty*/ { $$ = NULL; }
| tIdentifier { $$ = $1; }
/* ECMA-262 5.1 Edition 7.6 */
IdentifierName
: tIdentifier { $$ = $1; }
| ReservedAsIdentifier
{
if(ctx->script->version < SCRIPTLANGUAGEVERSION_ES5) {
WARN("%s keyword used as an identifier in legacy mode.\n",
debugstr_w($1));
set_error(ctx, @$, JS_E_SYNTAX);
YYABORT;
}
$$ = $1;
}
ReservedAsIdentifier
: kBREAK { $$ = $1; }
| kCASE { $$ = $1; }
| kCATCH { $$ = $1; }
| kCONST { $$ = $1; }
| kCONTINUE { $$ = $1; }
| kDEFAULT { $$ = $1; }
| kDELETE { $$ = $1; }
| kDO { $$ = $1; }
| kELSE { $$ = $1; }
| kFALSE { $$ = $1; }
| kFINALLY { $$ = $1; }
| kFOR { $$ = $1; }
| kFUNCTION { $$ = $1; }
| kGET { $$ = $1; }
| kIF { $$ = $1; }
| kIN { $$ = $1; }
| kINSTANCEOF { $$ = $1; }
| kLET { $$ = $1; }
| kNEW { $$ = $1; }
| kNULL { $$ = $1; }
| kRETURN { $$ = $1; }
| kSET { $$ = $1; }
| kSWITCH { $$ = $1; }
| kTHIS { $$ = $1; }
| kTHROW { $$ = $1; }
| kTRUE { $$ = $1; }
| kTRY { $$ = $1; }
| kTYPEOF { $$ = $1; }
| kVAR { $$ = $1; }
| kVOID { $$ = $1; }
| kWHILE { $$ = $1; }
| kWITH { $$ = $1; }
/* ECMA-262 3rd Edition 7.8 */
Literal
: kNULL { $$ = new_null_literal(ctx); }
| BooleanLiteral { $$ = $1; }
| tNumericLiteral { $$ = $1; }
| tStringLiteral { $$ = new_string_literal(ctx, $1); }
| '/' { $$ = parse_regexp(ctx);
if(!$$) YYABORT; }
| kDIVEQ { $$ = parse_regexp(ctx);
if(!$$) YYABORT; }
/* ECMA-262 3rd Edition 7.8.2 */
BooleanLiteral
: kTRUE { $$ = new_boolean_literal(ctx, VARIANT_TRUE); }
| kFALSE { $$ = new_boolean_literal(ctx, VARIANT_FALSE); }
| tBooleanLiteral { $$ = $1; }
semicolon_opt
: ';'
| error { if(!allow_auto_semicolon(ctx)) {YYABORT;} else { ctx->hres = S_OK; ctx->error_loc = -1; } }
left_bracket
: '('
| error { set_error(ctx, @$, JS_E_MISSING_LBRACKET); YYABORT; }
right_bracket
: ')'
| error { set_error(ctx, @$, JS_E_MISSING_RBRACKET); YYABORT; }
semicolon
: ';'
| error { set_error(ctx, @$, JS_E_MISSING_SEMICOLON); YYABORT; }
%%
static BOOL allow_auto_semicolon(parser_ctx_t *ctx)
{
return ctx->nl || ctx->ptr == ctx->end || *(ctx->ptr-1) == '}';
}
static void *new_statement(parser_ctx_t *ctx, statement_type_t type, size_t size, unsigned loc)
{
statement_t *stat;
stat = parser_alloc(ctx, size ? size : sizeof(*stat));
if(!stat)
return NULL;
stat->type = type;
stat->loc = loc;
stat->next = NULL;
return stat;
}
static literal_t *new_string_literal(parser_ctx_t *ctx, jsstr_t *str)
{
literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
ret->type = LT_STRING;
ret->u.str = str;
return ret;
}
static literal_t *new_null_literal(parser_ctx_t *ctx)
{
literal_t *ret = parser_alloc(ctx, sizeof(literal_t));
ret->type = LT_NULL;
return ret;
}
static property_definition_t *new_property_definition(parser_ctx_t *ctx, property_definition_type_t type,
literal_t *name, expression_t *value)
{
property_definition_t *ret = parser_alloc(ctx, sizeof(property_definition_t));
ret->type = type;
ret->name = name;
ret->value = value;
ret->next = NULL;
return ret;
}
static property_list_t *new_property_list(parser_ctx_t *ctx, property_definition_t *prop)
{
property_list_t *ret = parser_alloc_tmp(ctx, sizeof(property_list_t));
ret->head = ret->tail = prop;
return ret;
}
static property_list_t *property_list_add(parser_ctx_t *ctx, property_list_t *list, property_definition_t *prop)
{
list->tail = list->tail->next = prop;
return list;
}
static array_element_t *new_array_element(parser_ctx_t *ctx, int elision, expression_t *expr)
{
array_element_t *ret = parser_alloc(ctx, sizeof(array_element_t));
ret->elision = elision;
ret->expr = expr;
ret->next = NULL;
return ret;
}
static element_list_t *new_element_list(parser_ctx_t *ctx, int elision, expression_t *expr)
{
element_list_t *ret = parser_alloc_tmp(ctx, sizeof(element_list_t));
ret->head = ret->tail = new_array_element(ctx, elision, expr);
return ret;
}
static element_list_t *element_list_add(parser_ctx_t *ctx, element_list_t *list, int elision, expression_t *expr)
{
list->tail = list->tail->next = new_array_element(ctx, elision, expr);
return list;
}
static argument_t *new_argument(parser_ctx_t *ctx, expression_t *expr)
{
argument_t *ret = parser_alloc(ctx, sizeof(argument_t));
ret->expr = expr;
ret->next = NULL;
return ret;
}
static argument_list_t *new_argument_list(parser_ctx_t *ctx, expression_t *expr)
{
argument_list_t *ret = parser_alloc_tmp(ctx, sizeof(argument_list_t));
ret->head = ret->tail = new_argument(ctx, expr);
return ret;
}
static argument_list_t *argument_list_add(parser_ctx_t *ctx, argument_list_t *list, expression_t *expr)
{
list->tail = list->tail->next = new_argument(ctx, expr);
return list;
}
static catch_block_t *new_catch_block(parser_ctx_t *ctx, const WCHAR *identifier, statement_t *statement)
{
catch_block_t *ret = parser_alloc(ctx, sizeof(catch_block_t));
ret->identifier = identifier;
ret->statement = statement;
return ret;
}
static case_clausule_t *new_case_clausule(parser_ctx_t *ctx, unsigned loc, expression_t *expr, statement_list_t *stat_list)
{
case_clausule_t *ret = parser_alloc(ctx, sizeof(case_clausule_t));
ret->expr = expr;
ret->stat = stat_list ? stat_list->head : NULL;
ret->loc = loc;
ret->next = NULL;
return ret;
}
static case_list_t *new_case_list(parser_ctx_t *ctx, case_clausule_t *case_clausule)
{
case_list_t *ret = parser_alloc_tmp(ctx, sizeof(case_list_t));
ret->head = ret->tail = case_clausule;
return ret;
}
static case_list_t *case_list_add(parser_ctx_t *ctx, case_list_t *list, case_clausule_t *case_clausule)
{
list->tail = list->tail->next = case_clausule;
return list;
}
static case_clausule_t *new_case_block(parser_ctx_t *ctx, case_list_t *case_list1,
case_clausule_t *default_clausule, case_list_t *case_list2)
{
case_clausule_t *ret = NULL, *iter = NULL, *iter2;
statement_t *stat = NULL;
if(case_list1) {
ret = case_list1->head;
iter = case_list1->tail;
}
if(default_clausule) {
if(ret)
iter = iter->next = default_clausule;
else
ret = iter = default_clausule;
}
if(case_list2) {
if(ret)
iter->next = case_list2->head;
else
ret = case_list2->head;
}
if(!ret)
return NULL;
for(iter = ret; iter; iter = iter->next) {
for(iter2 = iter; iter2 && !iter2->stat; iter2 = iter2->next);
if(!iter2)
break;
while(iter != iter2) {
iter->stat = iter2->stat;
iter = iter->next;
}
if(stat) {
while(stat->next)
stat = stat->next;
stat->next = iter->stat;
}else {
stat = iter->stat;
}
}
return ret;
}
static statement_t *new_block_statement(parser_ctx_t *ctx, unsigned loc, statement_list_t *list)
{
block_statement_t *ret;
ret = new_statement(ctx, STAT_BLOCK, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->scope_index = 0;
ret->stat_list = list ? list->head : NULL;
return &ret->stat;
}
static variable_declaration_t *new_variable_declaration(parser_ctx_t *ctx, const WCHAR *identifier, expression_t *expr)
{
variable_declaration_t *ret = parser_alloc(ctx, sizeof(variable_declaration_t));
ret->identifier = identifier;
ret->expr = expr;
ret->next = NULL;
ret->global_next = NULL;
ret->block_scope = FALSE;
ret->constant = FALSE;
return ret;
}
static variable_list_t *new_variable_list(parser_ctx_t *ctx, variable_declaration_t *decl)
{
variable_list_t *ret = parser_alloc_tmp(ctx, sizeof(variable_list_t));
ret->head = ret->tail = decl;
return ret;
}
static variable_list_t *variable_list_add(parser_ctx_t *ctx, variable_list_t *list, variable_declaration_t *decl)
{
list->tail = list->tail->next = decl;
return list;
}
static statement_t *new_var_statement(parser_ctx_t *ctx, BOOL block_scope, BOOL constant, unsigned loc,
variable_list_t *variable_list)
{
variable_declaration_t *var;
var_statement_t *ret;
ret = new_statement(ctx, STAT_VAR, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->variable_list = variable_list->head;
for (var = ret->variable_list; var; var = var->next)
{
var->block_scope = block_scope;
var->constant = constant;
}
return &ret->stat;
}
static statement_t *new_expression_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr)
{
expression_statement_t *ret;
ret = new_statement(ctx, STAT_EXPR, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->expr = expr;
return &ret->stat;
}
static statement_t *new_if_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr,
statement_t *if_stat, statement_t *else_stat)
{
if_statement_t *ret;
ret = new_statement(ctx, STAT_IF, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->expr = expr;
ret->if_stat = if_stat;
ret->else_stat = else_stat;
return &ret->stat;
}
static statement_t *new_while_statement(parser_ctx_t *ctx, unsigned loc, BOOL dowhile, expression_t *expr, statement_t *stat)
{
while_statement_t *ret;
ret = new_statement(ctx, STAT_WHILE, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->do_while = dowhile;
ret->expr = expr;
ret->statement = stat;
return &ret->stat;
}
static statement_t *new_for_statement(parser_ctx_t *ctx, unsigned loc, variable_declaration_t *variable_list, expression_t *begin_expr,
expression_t *expr, unsigned expr_loc, expression_t *end_expr, unsigned end_loc, statement_t *statement)
{
for_statement_t *ret;
ret = new_statement(ctx, STAT_FOR, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->variable_list = variable_list;
ret->begin_expr = begin_expr;
ret->expr = expr;
ret->expr_loc = expr_loc;
ret->end_expr = end_expr;
ret->end_loc = end_loc;
ret->statement = statement;
ret->scope_index = 0;
return &ret->stat;
}
static statement_t *new_forin_statement(parser_ctx_t *ctx, unsigned loc, variable_declaration_t *variable, expression_t *expr,
expression_t *in_expr, statement_t *statement)
{
forin_statement_t *ret;
ret = new_statement(ctx, STAT_FORIN, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->variable = variable;
ret->expr = expr;
ret->in_expr = in_expr;
ret->statement = statement;
return &ret->stat;
}
static statement_t *new_continue_statement(parser_ctx_t *ctx, unsigned loc, const WCHAR *identifier)
{
branch_statement_t *ret;
ret = new_statement(ctx, STAT_CONTINUE, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->identifier = identifier;
return &ret->stat;
}
static statement_t *new_break_statement(parser_ctx_t *ctx, unsigned loc, const WCHAR *identifier)
{
branch_statement_t *ret;
ret = new_statement(ctx, STAT_BREAK, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->identifier = identifier;
return &ret->stat;
}
static statement_t *new_return_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr)
{
expression_statement_t *ret;
ret = new_statement(ctx, STAT_RETURN, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->expr = expr;
return &ret->stat;
}
static statement_t *new_with_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr, statement_t *statement)
{
with_statement_t *ret;
ret = new_statement(ctx, STAT_WITH, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->expr = expr;
ret->statement = statement;
return &ret->stat;
}
static statement_t *new_labelled_statement(parser_ctx_t *ctx, unsigned loc, const WCHAR *identifier, statement_t *statement)
{
labelled_statement_t *ret;
ret = new_statement(ctx, STAT_LABEL, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->identifier = identifier;
ret->statement = statement;
return &ret->stat;
}
static statement_t *new_switch_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr, case_clausule_t *case_list)
{
switch_statement_t *ret;
ret = new_statement(ctx, STAT_SWITCH, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->expr = expr;
ret->case_list = case_list;
return &ret->stat;
}
static statement_t *new_throw_statement(parser_ctx_t *ctx, unsigned loc, expression_t *expr)
{
expression_statement_t *ret;
ret = new_statement(ctx, STAT_THROW, sizeof(*ret), loc);
if(!ret)
return NULL;
ret->expr = expr;
return &ret->stat;
}
static statement_t *new_try_statement(parser_ctx_t *ctx, statement_t *try_statement,
catch_block_t *catch_block, statement_t *finally_statement, unsigned finally_loc)
{
try_statement_t *ret;
ret = new_statement(ctx, STAT_TRY, sizeof(*ret), try_statement->loc);
if(!ret)
return NULL;
ret->try_statement = try_statement;
ret->catch_block = catch_block;
ret->finally_statement = finally_statement;
ret->finally_loc = finally_loc;
return &ret->stat;
}
static parameter_t *new_parameter(parser_ctx_t *ctx, const WCHAR *identifier)
{
parameter_t *ret = parser_alloc(ctx, sizeof(parameter_t));
ret->identifier = identifier;
ret->next = NULL;
return ret;
}
static parameter_list_t *new_parameter_list(parser_ctx_t *ctx, const WCHAR *identifier)
{
parameter_list_t *ret = parser_alloc_tmp(ctx, sizeof(parameter_list_t));
ret->head = ret->tail = new_parameter(ctx, identifier);
return ret;
}
static parameter_list_t *parameter_list_add(parser_ctx_t *ctx, parameter_list_t *list, const WCHAR *identifier)
{
list->tail = list->tail->next = new_parameter(ctx, identifier);
return list;
}
static expression_t *new_function_expression(parser_ctx_t *ctx, const WCHAR *identifier, parameter_list_t *parameter_list,
statement_list_t *statement_list, const WCHAR *event_target, const WCHAR *src_str, DWORD src_len)
{
function_expression_t *ret = new_expression(ctx, EXPR_FUNC, sizeof(*ret));
ret->identifier = identifier;
ret->parameter_list = parameter_list ? parameter_list->head : NULL;
ret->statement_list = statement_list ? statement_list->head : NULL;
ret->event_target = event_target;
ret->src_str = src_str;
ret->src_len = src_len;
ret->is_statement = FALSE;
ret->scope_index = 0;
ret->next = NULL;
return &ret->expr;
}
static void *new_expression(parser_ctx_t *ctx, expression_type_t type, size_t size)
{
expression_t *ret = parser_alloc(ctx, size ? size : sizeof(*ret));
ret->type = type;
return ret;
}
static expression_t *new_binary_expression(parser_ctx_t *ctx, expression_type_t type,
expression_t *expression1, expression_t *expression2)
{
binary_expression_t *ret = new_expression(ctx, type, sizeof(*ret));
ret->expression1 = expression1;
ret->expression2 = expression2;
return &ret->expr;
}
static expression_t *new_unary_expression(parser_ctx_t *ctx, expression_type_t type, expression_t *expression)
{
unary_expression_t *ret = new_expression(ctx, type, sizeof(*ret));
ret->expression = expression;
return &ret->expr;
}
static expression_t *new_conditional_expression(parser_ctx_t *ctx, expression_t *expression,
expression_t *true_expression, expression_t *false_expression)
{
conditional_expression_t *ret = new_expression(ctx, EXPR_COND, sizeof(*ret));
ret->expression = expression;
ret->true_expression = true_expression;
ret->false_expression = false_expression;
return &ret->expr;
}
static expression_t *new_member_expression(parser_ctx_t *ctx, expression_t *expression, const WCHAR *identifier)
{
member_expression_t *ret = new_expression(ctx, EXPR_MEMBER, sizeof(*ret));
ret->expression = expression;
ret->identifier = identifier;
return &ret->expr;
}
static expression_t *new_new_expression(parser_ctx_t *ctx, expression_t *expression, argument_list_t *argument_list)
{
call_expression_t *ret = new_expression(ctx, EXPR_NEW, sizeof(*ret));
ret->expression = expression;
ret->argument_list = argument_list ? argument_list->head : NULL;
return &ret->expr;
}
static expression_t *new_call_expression(parser_ctx_t *ctx, expression_t *expression, argument_list_t *argument_list)
{
call_expression_t *ret = new_expression(ctx, EXPR_CALL, sizeof(*ret));
ret->expression = expression;
ret->argument_list = argument_list ? argument_list->head : NULL;
return &ret->expr;
}
static int parser_error(unsigned *loc, parser_ctx_t *ctx, const char *str)
{
if(ctx->error_loc == -1)
ctx->error_loc = *loc;
if(ctx->hres == S_OK)
ctx->hres = JS_E_SYNTAX;
return 0;
}
static void set_error(parser_ctx_t *ctx, unsigned loc, HRESULT error)
{
ctx->hres = error;
ctx->error_loc = loc;
}
static BOOL explicit_error(parser_ctx_t *ctx, void *obj, WCHAR next)
{
if(obj || *(ctx->ptr-1)==next) return TRUE;
set_error(ctx, ctx->ptr - ctx->begin /* FIXME */, JS_E_SYNTAX);
return FALSE;
}
static expression_t *new_identifier_expression(parser_ctx_t *ctx, const WCHAR *identifier)
{
identifier_expression_t *ret = new_expression(ctx, EXPR_IDENT, sizeof(*ret));
ret->identifier = identifier;
return &ret->expr;
}
static expression_t *new_array_literal_expression(parser_ctx_t *ctx, element_list_t *element_list, int length)
{
array_literal_expression_t *ret = new_expression(ctx, EXPR_ARRAYLIT, sizeof(*ret));
ret->element_list = element_list ? element_list->head : NULL;
ret->length = length;
return &ret->expr;
}
static expression_t *new_prop_and_value_expression(parser_ctx_t *ctx, property_list_t *property_list)
{
property_value_expression_t *ret = new_expression(ctx, EXPR_PROPVAL, sizeof(*ret));
ret->property_list = property_list ? property_list->head : NULL;
return &ret->expr;
}
static expression_t *new_literal_expression(parser_ctx_t *ctx, literal_t *literal)
{
literal_expression_t *ret = new_expression(ctx, EXPR_LITERAL, sizeof(*ret));
ret->literal = literal;
return &ret->expr;
}
static statement_list_t *new_statement_list(parser_ctx_t *ctx, statement_t *statement)
{
statement_list_t *ret = parser_alloc_tmp(ctx, sizeof(statement_list_t));
ret->head = ret->tail = statement;
return ret;
}
static statement_list_t *statement_list_add(statement_list_t *list, statement_t *statement)
{
list->tail = list->tail->next = statement;
return list;
}
void parser_release(parser_ctx_t *ctx)
{
script_release(ctx->script);
heap_pool_free(&ctx->heap);
free(ctx);
}
HRESULT script_parse(script_ctx_t *ctx, struct _compiler_ctx_t *compiler, bytecode_t *code, const WCHAR *delimiter, BOOL from_eval,
parser_ctx_t **ret)
{
parser_ctx_t *parser_ctx;
heap_pool_t *mark;
HRESULT hres;
parser_ctx = calloc(1, sizeof(parser_ctx_t));
if(!parser_ctx)
return E_OUTOFMEMORY;
parser_ctx->error_loc = -1;
parser_ctx->is_html = delimiter && !wcsicmp(delimiter, L"</script>");
parser_ctx->begin = parser_ctx->ptr = code->source;
parser_ctx->end = parser_ctx->begin + lstrlenW(parser_ctx->begin);
script_addref(ctx);
parser_ctx->script = ctx;
mark = heap_pool_mark(&ctx->tmp_heap);
heap_pool_init(&parser_ctx->heap);
parser_ctx->compiler = compiler;
parser_parse(parser_ctx);
parser_ctx->compiler = NULL;
heap_pool_clear(mark);
hres = parser_ctx->hres;
if(FAILED(hres)) {
unsigned int error_loc = parser_ctx->error_loc == -1 ? 0 : parser_ctx->error_loc;
const WCHAR *line_start = code->source + error_loc, *line_end = line_start;
jsstr_t *line_str;
while(line_start > code->source && line_start[-1] != '\n')
line_start--;
while(*line_end && *line_end != '\n')
line_end++;
line_str = jsstr_alloc_len(line_start, line_end - line_start);
WARN("parser failed around %s in line %s\n",
debugstr_w(parser_ctx->begin+20 > parser_ctx->ptr ? parser_ctx->begin : parser_ctx->ptr-20),
debugstr_jsstr(line_str));
throw_error(ctx, hres, NULL);
set_error_location(ctx->ei, code, error_loc, IDS_COMPILATION_ERROR, line_str);
parser_release(parser_ctx);
if(line_str)
jsstr_release(line_str);
return DISP_E_EXCEPTION;
}
*ret = parser_ctx;
return S_OK;
}