/* * 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 YYLTYPE 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.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); 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 = heap_alloc_zero(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; }