/* ** parse.y - mruby parser ** ** See Copyright Notice in mruby.h */ %{ // can first specify namespace // could specify using directives // [this has not been done here to stress-test the skeleton] using System; using Bridge; using Bridge.Html5; namespace WebMrbc { public enum MrbTokens { %} %token keyword_class keyword_module keyword_def keyword_begin keyword_if keyword_unless keyword_while keyword_until keyword_for %token keyword_undef keyword_rescue keyword_ensure keyword_end keyword_then keyword_elsif keyword_else keyword_case keyword_when keyword_break keyword_next keyword_redo keyword_retry keyword_in keyword_do keyword_do_cond keyword_do_block keyword_do_LAMBDA keyword_return keyword_yield keyword_super keyword_self keyword_nil keyword_true keyword_false keyword_and keyword_or keyword_not modifier_if modifier_unless modifier_while modifier_until modifier_rescue keyword_alias keyword_BEGIN keyword_END keyword__LINE__ keyword__FILE__ keyword__ENCODING__ %token tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL %token tINTEGER tFLOAT tCHAR tXSTRING tREGEXP %token tSTRING tSTRING_PART tSTRING_MID tLABEL_END %token tNTH_REF tBACK_REF %token tREGEXP_END %type singleton string string_rep string_interp xstring regexp %type literal numeric cpath symbol %type top_compstmt top_stmts top_stmt %type bodystmt compstmt stmts stmt expr arg primary command command_call method_call %type expr_value arg_rhs primary_value %type if_tail opt_else case_body cases opt_rescue exc_list exc_var opt_ensure %type args call_args opt_call_args %type paren_args opt_paren_args variable %type command_args aref_args opt_block_arg block_arg var_ref var_lhs %type command_asgn command_rhs mrhs superclass block_call block_command %type f_block_optarg f_block_opt %type f_arglist f_args f_arg f_arg_item f_optarg f_marg f_marg_list f_margs %type assoc_list assocs assoc undef_list backref for_var %type block_param opt_block_param block_param_def f_opt %type bv_decls opt_bv_decl bvar f_larglist lambda_body %type brace_block cmd_brace_block do_block lhs none f_bad_arg %type mlhs mlhs_list mlhs_post mlhs_basic mlhs_item mlhs_node mlhs_inner %type fsym sym basic_symbol operation operation2 operation3 %type cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_opt_asgn %type heredoc words symbols %type call_op call_op2 /* 0:'&.', 1:'.', 2:'::' */ %token tUPLUS /* unary+ */ %token tUMINUS /* unary- */ %token tPOW /* ** */ %token tCMP /* <=> */ %token tEQ /* == */ %token tEQQ /* === */ %token tNEQ /* != */ %token tGEQ /* >= */ %token tLEQ /* <= */ %token tANDOP tOROP /* && and || */ %token tMATCH tNMATCH /* =~ and !~ */ %token tDOT2 tDOT3 /* .. and ... */ %token tAREF tASET /* [] and []= */ %token tLSHFT tRSHFT /* << and >> */ %token tCOLON2 /* :: */ %token tCOLON3 /* :: at EXPR_BEG */ %token tOP_ASGN /* +=, -= etc. */ %token tASSOC /* => */ %token tLPAREN /* ( */ %token tLPAREN_ARG /* ( */ %token tRPAREN /* ) */ %token tLBRACK /* [ */ %token tLBRACE /* { */ %token tLBRACE_ARG /* { */ %token tSTAR /* * */ %token tAMPER /* & */ %token tLAMBDA /* -> */ %token tANDDOT /* &. */ %token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG %token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG %token tHEREDOC_BEG /* <<, <<- */ %token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM %token tHD_STRING_PART tHD_STRING_MID /* * precedence table */ %nonassoc tLOWEST %nonassoc tLBRACE_ARG %nonassoc modifier_if modifier_unless modifier_while modifier_until %left keyword_or keyword_and %right keyword_not %right '=' tOP_ASGN %left modifier_rescue %right '?' ':' %nonassoc tDOT2 tDOT3 %left tOROP %left tANDOP %nonassoc tCMP tEQ tEQQ tNEQ tMATCH tNMATCH %left '>' tGEQ '<' tLEQ %left '|' '^' %left '&' %left tLSHFT tRSHFT %left '+' '-' %left '*' '/' '%' %right tUMINUS_NUM tUMINUS %right tPOW %right '!' '~' tUPLUS %token tLAST_TOKEN %% %{ } /// /// start with an argument to trace /// public partial class MrbParser { // must specify class header // must not use yy[A-Z].* as identifiers // could overwrite some methods named yy[A-Z].* in subclass const int yyErrorCode = (int)MrbTokens.yyErrorCode; %} program : { this.lstate = mrb_lex_state_enum.EXPR_BEG; if (this.locals == null) this.locals = new locals_node(null); } top_compstmt { this.tree = new_scope($2); this.tree.NODE_LINENO($2); } ; top_compstmt : top_stmts opt_terms { $$ = $1; } ; top_stmts : none { $$ = new_begin(null); } | top_stmt { $$ = new_begin($1); $$.NODE_LINENO($1); } | top_stmts terms top_stmt { $$ = push($1, newline_node($3)); } | error top_stmt { $$ = new_begin(null); } ; top_stmt : stmt | keyword_BEGIN { $$ = local_switch(); } '{' top_compstmt '}' { yyError("BEGIN not supported"); local_resume($2); $$ = null; } ; bodystmt : compstmt opt_rescue opt_else opt_ensure { if ($2 != null) { $$ = new_rescue($1, $2, $3); $$.NODE_LINENO($1); } else if ($3 != null) { yyWarning("else without rescue is useless"); $$ = push($1, $3); } else { $$ = $1; } if ($4 != null) { if ($$ != null) { $$ = new_ensure($$, $4); } else { $$ = push($4, new_nil()); } } } ; compstmt : stmts opt_terms { $$ = $1; } ; stmts : none { $$ = new_begin(null); } | stmt { $$ = new_begin($1); $$.NODE_LINENO($1); } | stmts terms stmt { $$ = push($1, newline_node($3)); } | error stmt { $$ = new_begin($2); } ; stmt : keyword_alias fsym {this.lstate = mrb_lex_state_enum.EXPR_FNAME;} fsym { $$ = new_alias($2, $4); } | keyword_undef undef_list { $$ = $2; } | stmt modifier_if expr_value { $$ = new_if(cond($3), $1, null); } | stmt modifier_unless expr_value { $$ = new_unless(cond($3), $1, null); } | stmt modifier_while expr_value { $$ = new_while(cond($3), $1); } | stmt modifier_until expr_value { $$ = new_until(cond($3), $1); } | stmt modifier_rescue stmt { $$ = new_mod_rescue($1, $3); } | keyword_END '{' compstmt '}' { yyError("END not supported"); $$ = new_postexe($3); } | command_asgn | mlhs '=' command_call { $$ = new_masgn($1, $3); } | lhs '=' mrhs { $$ = new_asgn($1, new_array($3)); } | mlhs '=' arg { $$ = new_masgn($1, $3); } | mlhs '=' mrhs { $$ = new_masgn($1, new_array($3)); } | expr ; command_asgn : lhs '=' command_rhs { $$ = new_asgn($1, $3); } | var_lhs tOP_ASGN command_rhs { $$ = new_op_asgn($1, $2, $3); } | primary_value '[' opt_call_args rbracket tOP_ASGN command_rhs { $$ = new_op_asgn(new_call($1, intern("[]",2), $3, (MrbTokens)'.'), $5, $6); } | primary_value call_op tIDENTIFIER tOP_ASGN command_rhs { $$ = new_op_asgn(new_call($1, $3, null, $2), $4, $5); } | primary_value call_op tCONSTANT tOP_ASGN command_rhs { $$ = new_op_asgn(new_call($1, $3, null, $2), $4, $5); } | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call { yyError("constant re-assignment"); $$ = null; } | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_rhs { $$ = new_op_asgn(new_call($1, $3, null, MrbTokens.tCOLON2), $4, $5); } | backref tOP_ASGN command_rhs { backref_error($1); $$ = new_begin(null); } ; command_rhs : command_call %prec tOP_ASGN | command_call modifier_rescue stmt { $$ = new_mod_rescue($1, $3); } | command_asgn ; expr : command_call | expr keyword_and expr { $$ = new_and($1, $3); } | expr keyword_or expr { $$ = new_or($1, $3); } | keyword_not opt_nl expr { $$ = call_uni_op(cond($3), "!"); } | '!' command_call { $$ = call_uni_op(cond($2), "!"); } | arg ; expr_value : expr { if ($1 == null) $$ = new_nil(); else{ void_expr_error($1); $$ = $1; } } ; command_call : command | block_command ; block_command : block_call | block_call call_op2 operation2 command_args ; cmd_brace_block : tLBRACE_ARG { local_nest(); } opt_block_param compstmt '}' { $$ = new_block($3, $4, true); local_unnest(); } ; command : operation command_args %prec tLOWEST { $$ = new_fcall($1, $2); } | operation command_args cmd_brace_block { args_with_block($2, $3); $$ = new_fcall($1, $2); } | primary_value call_op operation2 command_args %prec tLOWEST { $$ = new_call($1, $3, $4, $2); } | primary_value call_op operation2 command_args cmd_brace_block { args_with_block($4, $5); $$ = new_call($1, $3, $4, $2); } | primary_value tCOLON2 operation2 command_args %prec tLOWEST { $$ = new_call($1, $3, $4, MrbTokens.tCOLON2); } | primary_value tCOLON2 operation2 command_args cmd_brace_block { args_with_block($4, $5); $$ = new_call($1, $3, $4, MrbTokens.tCOLON2); } | keyword_super command_args { $$ = new_super($2); } | keyword_yield command_args { $$ = new_yield($2); } | keyword_return call_args { $$ = new_return(ret_args($2)); } | keyword_break call_args { $$ = new_break(ret_args($2)); } | keyword_next call_args { $$ = new_next(ret_args($2)); } ; mlhs : mlhs_basic { $$ = $1; } | tLPAREN mlhs_inner rparen { $$ = $2; } ; mlhs_inner : mlhs_basic | tLPAREN mlhs_inner rparen { $$ = $2; } ; mlhs_basic : mlhs_list { $$ = list1($1); } | mlhs_list mlhs_item { $$ = list1(push($1, $2)); } | mlhs_list tSTAR mlhs_node { $$ = list2($1, $3); } | mlhs_list tSTAR mlhs_node ',' mlhs_post { $$ = list3($1, $3, $5); } | mlhs_list tSTAR { $$ = list2($1, new_nil()); } | mlhs_list tSTAR ',' mlhs_post { $$ = list3($1, new_nil(), $4); } | tSTAR mlhs_node { $$ = list2(null, $2); } | tSTAR mlhs_node ',' mlhs_post { $$ = list3(null, $2, $4); } | tSTAR { $$ = list2(null, new_nil()); } | tSTAR ',' mlhs_post { $$ = list3(null, new_nil(), $3); } ; mlhs_item : mlhs_node | tLPAREN mlhs_inner rparen { $$ = new_masgn($2, null); } ; mlhs_list : mlhs_item ',' { $$ = list1($1); } | mlhs_list mlhs_item ',' { $$ = push($1, $2); } ; mlhs_post : mlhs_item { $$ = list1($1); } | mlhs_list mlhs_item { $$ = push($1, $2); } ; mlhs_node : variable { assignable($1); } | primary_value '[' opt_call_args rbracket { $$ = new_call($1, intern("[]",2), $3, (MrbTokens)'.'); } | primary_value call_op tIDENTIFIER { $$ = new_call($1, $3, null, $2); } | primary_value tCOLON2 tIDENTIFIER { $$ = new_call($1, $3, null, MrbTokens.tCOLON2); } | primary_value call_op tCONSTANT { $$ = new_call($1, $3, null, $2); } | primary_value tCOLON2 tCONSTANT { if (this.in_def != 0 || this.in_single != 0) yyError("dynamic constant assignment"); $$ = new_colon2($1, $3); } | tCOLON3 tCONSTANT { if (this.in_def != 0 || this.in_single != 0) yyError("dynamic constant assignment"); $$ = new_colon3($2); } | backref { backref_error($1); $$ = null; } ; lhs : variable { assignable($1); } | primary_value '[' opt_call_args rbracket { $$ = new_call($1, intern("[]",2), $3, (MrbTokens)'.'); } | primary_value call_op tIDENTIFIER { $$ = new_call($1, $3, null, $2); } | primary_value tCOLON2 tIDENTIFIER { $$ = new_call($1, $3, null, MrbTokens.tCOLON2); } | primary_value call_op tCONSTANT { $$ = new_call($1, $3, null, $2); } | primary_value tCOLON2 tCONSTANT { if (this.in_def != 0 || this.in_single != 0) yyError("dynamic constant assignment"); $$ = new_colon2($1, $3); } | tCOLON3 tCONSTANT { if (this.in_def != 0 || this.in_single != 0) yyError("dynamic constant assignment"); $$ = new_colon3($2); } | backref { backref_error($1); $$ = null; } ; cname : tIDENTIFIER { yyError("class/module name must be CONSTANT"); } | tCONSTANT ; cpath : tCOLON3 cname { $$ = cons(1, $2); } | cname { $$ = cons(0, $1); } | primary_value tCOLON2 cname { $$ = cons($1, $3); } ; fname : tIDENTIFIER | tCONSTANT | tFID | op { this.lstate = mrb_lex_state_enum.EXPR_ENDFN; $$ = $1; } | reswords { this.lstate = mrb_lex_state_enum.EXPR_ENDFN; $$ = $1; } ; fsym : fname | basic_symbol ; undef_list : fsym { $$ = new_undef($1); } | undef_list ',' {this.lstate = mrb_lex_state_enum.EXPR_FNAME;} fsym { $$ = push($1, $4); } ; op : '|' { $$ = intern_c('|'); } | '^' { $$ = intern_c('^'); } | '&' { $$ = intern_c('&'); } | tCMP { $$ = intern("<=>",3); } | tEQ { $$ = intern("==",2); } | tEQQ { $$ = intern("===",3); } | tMATCH { $$ = intern("=~",2); } | tNMATCH { $$ = intern("!~",2); } | '>' { $$ = intern_c('>'); } | tGEQ { $$ = intern(">=",2); } | '<' { $$ = intern_c('<'); } | tLEQ { $$ = intern("<=",2); } | tNEQ { $$ = intern("!=",2); } | tLSHFT { $$ = intern("<<",2); } | tRSHFT { $$ = intern(">>",2); } | '+' { $$ = intern_c('+'); } | '-' { $$ = intern_c('-'); } | '*' { $$ = intern_c('*'); } | tSTAR { $$ = intern_c('*'); } | '/' { $$ = intern_c('/'); } | '%' { $$ = intern_c('%'); } | tPOW { $$ = intern("**",2); } | '!' { $$ = intern_c('!'); } | '~' { $$ = intern_c('~'); } | tUPLUS { $$ = intern("+@",2); } | tUMINUS { $$ = intern("-@",2); } | tAREF { $$ = intern("[]",2); } | tASET { $$ = intern("[]=",3); } | '`' { $$ = intern_c('`'); } ; reswords : keyword__LINE__ | keyword__FILE__ | keyword__ENCODING__ | keyword_BEGIN | keyword_END | keyword_alias | keyword_and | keyword_begin | keyword_break | keyword_case | keyword_class | keyword_def | keyword_do | keyword_else | keyword_elsif | keyword_end | keyword_ensure | keyword_false | keyword_for | keyword_in | keyword_module | keyword_next | keyword_nil | keyword_not | keyword_or | keyword_redo | keyword_rescue | keyword_retry | keyword_return | keyword_self | keyword_super | keyword_then | keyword_true | keyword_undef | keyword_when | keyword_yield | keyword_if | keyword_unless | keyword_while | keyword_until ; arg : lhs '=' arg_rhs { $$ = new_asgn($1, $3); } | var_lhs tOP_ASGN arg_rhs { $$ = new_op_asgn($1, $2, $3); } | primary_value '[' opt_call_args rbracket tOP_ASGN arg_rhs { $$ = new_op_asgn(new_call($1, intern("[]",2), $3, (MrbTokens)'.'), $5, $6); } | primary_value call_op tIDENTIFIER tOP_ASGN arg_rhs { $$ = new_op_asgn(new_call($1, $3, null, $2), $4, $5); } | primary_value call_op tCONSTANT tOP_ASGN arg_rhs { $$ = new_op_asgn(new_call($1, $3, null, $2), $4, $5); } | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg_rhs { $$ = new_op_asgn(new_call($1, $3, null, MrbTokens.tCOLON2), $4, $5); } | primary_value tCOLON2 tCONSTANT tOP_ASGN arg_rhs { yyError("constant re-assignment"); $$ = new_begin(null); } | tCOLON3 tCONSTANT tOP_ASGN arg_rhs { yyError("constant re-assignment"); $$ = new_begin(null); } | backref tOP_ASGN arg_rhs { backref_error($1); $$ = new_begin(null); } | arg tDOT2 arg { $$ = new_dot2($1, $3); } | arg tDOT3 arg { $$ = new_dot3($1, $3); } | arg '+' arg { $$ = call_bin_op($1, "+", $3); } | arg '-' arg { $$ = call_bin_op($1, "-", $3); } | arg '*' arg { $$ = call_bin_op($1, "*", $3); } | arg '/' arg { $$ = call_bin_op($1, "/", $3); } | arg '%' arg { $$ = call_bin_op($1, "%", $3); } | arg tPOW arg { $$ = call_bin_op($1, "**", $3); } | tUMINUS_NUM tINTEGER tPOW arg { $$ = call_uni_op(call_bin_op($2, "**", $4), "-@"); } | tUMINUS_NUM tFLOAT tPOW arg { $$ = call_uni_op(call_bin_op($2, "**", $4), "-@"); } | tUPLUS arg { $$ = call_uni_op($2, "+@"); } | tUMINUS arg { $$ = call_uni_op($2, "-@"); } | arg '|' arg { $$ = call_bin_op($1, "|", $3); } | arg '^' arg { $$ = call_bin_op($1, "^", $3); } | arg '&' arg { $$ = call_bin_op($1, "&", $3); } | arg tCMP arg { $$ = call_bin_op($1, "<=>", $3); } | arg '>' arg { $$ = call_bin_op($1, ">", $3); } | arg tGEQ arg { $$ = call_bin_op($1, ">=", $3); } | arg '<' arg { $$ = call_bin_op($1, "<", $3); } | arg tLEQ arg { $$ = call_bin_op($1, "<=", $3); } | arg tEQ arg { $$ = call_bin_op($1, "==", $3); } | arg tEQQ arg { $$ = call_bin_op($1, "===", $3); } | arg tNEQ arg { $$ = call_bin_op($1, "!=", $3); } | arg tMATCH arg { $$ = call_bin_op($1, "=~", $3); } | arg tNMATCH arg { $$ = call_bin_op($1, "!~", $3); } | '!' arg { $$ = call_uni_op(cond($2), "!"); } | '~' arg { $$ = call_uni_op(cond($2), "~"); } | arg tLSHFT arg { $$ = call_bin_op($1, "<<", $3); } | arg tRSHFT arg { $$ = call_bin_op($1, ">>", $3); } | arg tANDOP arg { $$ = new_and($1, $3); } | arg tOROP arg { $$ = new_or($1, $3); } | arg '?' arg opt_nl ':' arg { $$ = new_if(cond($1), $3, $6, true); } | primary { $$ = $1; } ; aref_args : none | args trailer { $$ = $1; $$.NODE_LINENO($1); } | args comma assocs trailer { $$ = push($1, new_hash($3)); } | assocs trailer { $$ = cons(new_hash($1), null); $$.NODE_LINENO($1); } ; arg_rhs : arg %prec tOP_ASGN { void_expr_error($1); $$ = $1; } | arg modifier_rescue arg { void_expr_error($1); $$ = new_mod_rescue($1, $3); } ; paren_args : '(' opt_call_args rparen { $$ = $2; } ; opt_paren_args : none | paren_args ; opt_call_args : none | call_args | args ',' { $$ = cons($1, null); $$.NODE_LINENO($1); } | args comma assocs ',' { $$ = cons(push($1, new_hash($3)), null); $$.NODE_LINENO($1); } | assocs ',' { $$ = cons(list1(new_hash($1)), null); $$.NODE_LINENO($1); } ; call_args : command { $$ = cons(list1($1), null); $$.NODE_LINENO($1); } | args opt_block_arg { $$ = cons($1, $2); $$.NODE_LINENO($1); } | assocs opt_block_arg { $$ = cons(list1(new_hash($1)), $2); $$.NODE_LINENO($1); } | args comma assocs opt_block_arg { $$ = cons(push($1, new_hash($3)), $4); $$.NODE_LINENO($1); } | block_arg { $$ = cons(null, $1); $$.NODE_LINENO($1); } ; command_args : { $$ = (stack_type)this.cmdarg_stack; CMDARG_PUSH(1); } call_args { this.cmdarg_stack = $1; $$ = $2; } ; block_arg : tAMPER arg { $$ = new_block_arg((node)$2); } ; opt_block_arg : comma block_arg { $$ = $2; } | none { $$ = null; } ; comma : ',' | ',' heredoc_bodies ; args : arg { void_expr_error($1); $$ = cons($1, null); $$.NODE_LINENO($1); } | tSTAR arg { void_expr_error($2); $$ = cons(new_splat($2), null); $$.NODE_LINENO($2); } | args comma arg { void_expr_error($3); $$ = push($1, $3); } | args comma tSTAR arg { void_expr_error($4); $$ = push($1, new_splat($4)); } ; mrhs : args comma arg { void_expr_error($3); $$ = push($1, $3); } | args comma tSTAR arg { void_expr_error($4); $$ = push($1, new_splat($4)); } | tSTAR arg { void_expr_error($2); $$ = list1(new_splat($2)); } ; primary : literal | string | xstring | regexp | heredoc | var_ref | backref | tFID { $$ = new_fcall($1, null); } | keyword_begin { $$ = (stack_type)this.cmdarg_stack; this.cmdarg_stack = 0; } bodystmt keyword_end { this.cmdarg_stack = $2; $$ = $3; } | tLPAREN_ARG { $$ = (stack_type)this.cmdarg_stack; this.cmdarg_stack = 0; } stmt {this.lstate = mrb_lex_state_enum.EXPR_ENDARG;} rparen { this.cmdarg_stack = $2; $$ = $3; } | tLPAREN_ARG {this.lstate = mrb_lex_state_enum.EXPR_ENDARG;} rparen { $$ = new_nil(); } | tLPAREN compstmt ')' { $$ = $2; } | primary_value tCOLON2 tCONSTANT { $$ = new_colon2($1, $3); } | tCOLON3 tCONSTANT { $$ = new_colon3($2); } | tLBRACK aref_args ']' { $$ = new_array($2); $$.NODE_LINENO($2); } | tLBRACE assoc_list '}' { $$ = new_hash($2); $$.NODE_LINENO($2); } | keyword_return { $$ = new_return(null); } | keyword_yield opt_paren_args { $$ = new_yield($2); } | keyword_not '(' expr rparen { $$ = call_uni_op(cond($3), "!"); } | keyword_not '(' rparen { $$ = call_uni_op(new_nil(), "!"); } | operation brace_block { $$ = new_fcall($1, cons(null, $2)); } | method_call | method_call brace_block { call_with_block($1, $2); $$ = $1; } | tLAMBDA { local_nest(); $$ = (int)this.lpar_beg; this.lpar_beg = ++this.paren_nest; } f_larglist { $$ = (stack_type)this.cmdarg_stack; this.cmdarg_stack = 0; } lambda_body { this.lpar_beg = $2; $$ = new_lambda($3, $5); local_unnest(); this.cmdarg_stack = $4; CMDARG_LEXPOP(); } | keyword_if expr_value then compstmt if_tail keyword_end { $$ = new_if(cond($2), $4, $5); $$.SET_LINENO($1); } | keyword_unless expr_value then compstmt opt_else keyword_end { $$ = new_unless(cond($2), $4, $5); $$.SET_LINENO($1); } | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} compstmt keyword_end { $$ = new_while(cond($3), $6); $$.SET_LINENO($1); } | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} compstmt keyword_end { $$ = new_until(cond($3), $6); $$.SET_LINENO($1); } | keyword_case expr_value opt_terms case_body keyword_end { $$ = new_case($2, $4); } | keyword_case opt_terms case_body keyword_end { $$ = new_case(null, $3); } | keyword_for for_var keyword_in {COND_PUSH(1);} expr_value do {COND_POP();} compstmt keyword_end { $$ = new_for($2, $5, $8); $$.SET_LINENO($1); } | keyword_class cpath superclass { if (this.in_def != 0 || this.in_single != 0) yyError("class definition in method body"); $$ = local_switch(); } bodystmt keyword_end { $$ = new_class($2, $3, $5); $$.SET_LINENO($1); local_resume($4); } | keyword_class tLSHFT expr { $$ = (int)this.in_def; this.in_def = 0; } term { $$ = cons(local_switch(), this.in_single); this.in_single = 0; } bodystmt keyword_end { $$ = new_sclass($3, $7); $$.SET_LINENO($1); local_resume((locals_node)$6.car); this.in_def = $4; this.in_single = (int)($6.cdr); } | keyword_module cpath { if (this.in_def != 0 || this.in_single != 0) yyError("module definition in method body"); $$ = local_switch(); } bodystmt keyword_end { $$ = new_module($2, $4); $$.SET_LINENO($1); local_resume($3); } | keyword_def fname { $$ = (stack_type)this.cmdarg_stack; this.cmdarg_stack = 0; } { this.in_def++; $$ = local_switch(); } f_arglist bodystmt keyword_end { $$ = new_def($2, $5, $6); $$.SET_LINENO($1); local_resume($4); this.in_def--; this.cmdarg_stack = $3; } | keyword_def singleton dot_or_colon { this.lstate = mrb_lex_state_enum.EXPR_FNAME; $$ = (stack_type)this.cmdarg_stack; this.cmdarg_stack = 0; } fname { this.in_single++; this.lstate = mrb_lex_state_enum.EXPR_ENDFN; /* force for args */ $$ = local_switch(); } f_arglist bodystmt keyword_end { $$ = new_sdef($2, $5, $7, $8); $$.SET_LINENO($1); local_resume($6); this.in_single--; this.cmdarg_stack = $4; } | keyword_break { $$ = new_break(null); } | keyword_next { $$ = new_next(null); } | keyword_redo { $$ = new_redo(); } | keyword_retry { $$ = new_retry(); } ; primary_value : primary { $$ = $1; if ($$ == null) $$ = new_nil(); } ; then : term | keyword_then | term keyword_then ; do : term | keyword_do_cond ; if_tail : opt_else | keyword_elsif expr_value then compstmt if_tail { $$ = new_if(cond($2), $4, $5); } ; opt_else : none | keyword_else compstmt { $$ = $2; } ; for_var : lhs { $$ = list1(list1($1)); } | mlhs ; f_marg : f_norm_arg { $$ = new_arg($1); } | tLPAREN f_margs rparen { $$ = new_masgn($2, null); } ; f_marg_list : f_marg { $$ = list1($1); } | f_marg_list ',' f_marg { $$ = push($1, $3); } ; f_margs : f_marg_list { $$ = list3($1, null, null); } | f_marg_list ',' tSTAR f_norm_arg { $$ = list3($1, new_arg($4), null); } | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list { $$ = list3($1, new_arg($4), $6); } | f_marg_list ',' tSTAR { $$ = list3($1, -1, null); } | f_marg_list ',' tSTAR ',' f_marg_list { $$ = list3($1, -1, $5); } | tSTAR f_norm_arg { $$ = list3(null, new_arg($2), null); } | tSTAR f_norm_arg ',' f_marg_list { $$ = list3(null, new_arg($2), $4); } | tSTAR { $$ = list3(null, -1, null); } | tSTAR ',' f_marg_list { $$ = list3(null, -1, $3); } ; block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg { $$ = new_args($1, $3, $5, null, $6); } | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args($1, $3, $5, $7, $8); } | f_arg ',' f_block_optarg opt_f_block_arg { $$ = new_args($1, $3, 0, null, $4); } | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg { $$ = new_args($1, $3, 0, $5, $6); } | f_arg ',' f_rest_arg opt_f_block_arg { $$ = new_args($1, null, $3, null, $4); } | f_arg ',' { $$ = new_args($1, null, (mrb_sym)0, null, 0); } | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args($1, null, $3, $5, $6); } | f_arg opt_f_block_arg { $$ = new_args($1, null, 0, null, $2); } | f_block_optarg ',' f_rest_arg opt_f_block_arg { $$ = new_args(null, $1, $3, null, $4); } | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args(null, $1, $3, $5, $6); } | f_block_optarg opt_f_block_arg { $$ = new_args(null, $1, 0, null, $2); } | f_block_optarg ',' f_arg opt_f_block_arg { $$ = new_args(null, $1, 0, $3, $4); } | f_rest_arg opt_f_block_arg { $$ = new_args(null, null, $1, null, $2); } | f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args(null, null, $1, $3, $4); } | f_block_arg { $$ = new_args(null, null, 0, null, $1); } ; opt_block_param : none | block_param_def { this.cmd_start = true; $$ = $1; } ; block_param_def : '|' opt_bv_decl '|' { $$ = null; } | tOROP { $$ = null; } | '|' block_param opt_bv_decl '|' { $$ = $2; } ; opt_bv_decl : opt_nl { $$ = null; } | opt_nl ';' bv_decls opt_nl { $$ = null; } ; bv_decls : bvar | bv_decls ',' bvar ; bvar : tIDENTIFIER { local_add_f($1); new_bv($1); } | f_bad_arg ; f_larglist : '(' f_args opt_bv_decl ')' { $$ = $2; } | f_args { $$ = $1; } ; lambda_body : tLAMBEG compstmt '}' { $$ = $2; } | keyword_do_LAMBDA compstmt keyword_end { $$ = $2; } ; do_block : keyword_do_block { local_nest(); } opt_block_param compstmt keyword_end { $$ = new_block($3, $4, false); local_unnest(); } ; block_call : command do_block { if ((node_type)$1.car == node_type.NODE_YIELD) { yyError("block given to yield"); } else { call_with_block($1, $2); } $$ = $1; } | block_call call_op2 operation2 opt_paren_args { $$ = new_call($1, $3, $4, $2); } | block_call call_op2 operation2 opt_paren_args brace_block { $$ = new_call($1, $3, $4, $2); call_with_block((node)$$, $5); } | block_call call_op2 operation2 command_args do_block { $$ = new_call($1, $3, $4, $2); call_with_block((node)$$, $5); } ; method_call : operation paren_args { $$ = new_fcall($1, $2); } | primary_value call_op operation2 opt_paren_args { $$ = new_call($1, $3, $4, $2); } | primary_value tCOLON2 operation2 paren_args { $$ = new_call($1, $3, $4, MrbTokens.tCOLON2); } | primary_value tCOLON2 operation3 { $$ = new_call($1, $3, null, MrbTokens.tCOLON2); } | primary_value call_op paren_args { $$ = new_call($1, intern("call",4), $3, $2); } | primary_value tCOLON2 paren_args { $$ = new_call($1, intern("call",4), $3, MrbTokens.tCOLON2); } | keyword_super paren_args { $$ = new_super($2); } | keyword_super { $$ = new_zsuper(); } | primary_value '[' opt_call_args rbracket { $$ = new_call($1, intern("[]",2), $3, (MrbTokens)'.'); } ; brace_block : '{' { local_nest(); $$ = (int)this.lineno; } opt_block_param compstmt '}' { $$ = new_block($3, $4, true); $$.SET_LINENO($2); local_unnest(); } | keyword_do { local_nest(); $$ = (int)this.lineno; } opt_block_param compstmt keyword_end { $$ = new_block($3, $4, false); $$.SET_LINENO($2); local_unnest(); } ; case_body : keyword_when args then compstmt cases { $$ = cons(cons($2, $4), $5); } ; cases : opt_else { if ($1 != null) { $$ = cons(cons(null, $1), null); } else { $$ = null; } } | case_body ; opt_rescue : keyword_rescue exc_list exc_var then compstmt opt_rescue { $$ = list1(list3($2, $3, $5)); if ($6 != null) $$ = append($$, $6); } | none ; exc_list : arg { $$ = list1($1); } | mrhs | none ; exc_var : tASSOC lhs { $$ = $2; } | none ; opt_ensure : keyword_ensure compstmt { $$ = $2; } | none ; literal : numeric | symbol | words | symbols ; string : tCHAR | tSTRING | tSTRING_BEG tSTRING { $$ = $2; } | tSTRING_BEG string_rep tSTRING { $$ = new_dstr(push($2, $3)); } ; string_rep : string_interp | string_rep string_interp { $$ = append($1, $2); } ; string_interp : tSTRING_MID { $$ = list1($1); } | tSTRING_PART { $$ = (node)this.lex_strterm; this.lex_strterm = null; } compstmt '}' { this.lex_strterm = $2; $$ = list2($1, $3); } | tLITERAL_DELIM { $$ = list1(new_literal_delim()); } | tHD_LITERAL_DELIM heredoc_bodies { $$ = list1(new_literal_delim()); } ; xstring : tXSTRING_BEG tXSTRING { $$ = $2; } | tXSTRING_BEG string_rep tXSTRING { $$ = new_dxstr(push($2, $3)); } ; regexp : tREGEXP_BEG tREGEXP { $$ = $2; } | tREGEXP_BEG string_rep tREGEXP { $$ = new_dregx($2, $3); } ; heredoc : tHEREDOC_BEG ; heredoc_bodies : heredoc_body | heredoc_bodies heredoc_body ; heredoc_body : tHEREDOC_END { parser_heredoc_info inf = parsing_heredoc_inf(); inf.push_doc(new_str(new Uint8Array(0), 0)); heredoc_end(); } | heredoc_string_rep tHEREDOC_END { heredoc_end(); } ; heredoc_string_rep : heredoc_string_interp | heredoc_string_rep heredoc_string_interp ; heredoc_string_interp : tHD_STRING_MID { parser_heredoc_info inf = parsing_heredoc_inf(); inf.push_doc($1); heredoc_treat_nextline(); } | tHD_STRING_PART { $$ = (node)this.lex_strterm; this.lex_strterm = null; } compstmt '}' { parser_heredoc_info inf = parsing_heredoc_inf(); this.lex_strterm = $2; inf.push_doc($1); inf.push_doc($3); } ; words : tWORDS_BEG tSTRING { $$ = new_words(list1($2)); } | tWORDS_BEG string_rep tSTRING { $$ = new_words(push($2, $3)); } ; symbol : basic_symbol { $$ = new_sym($1); } | tSYMBEG tSTRING_BEG string_rep tSTRING { this.lstate = mrb_lex_state_enum.EXPR_END; $$ = new_dsym(push($3, $4)); } ; basic_symbol : tSYMBEG sym { this.lstate = mrb_lex_state_enum.EXPR_END; $$ = $2; } ; sym : fname | tIVAR | tGVAR | tCVAR | tSTRING { $$ = new_strsym($1); } | tSTRING_BEG tSTRING { $$ = new_strsym($2); } ; symbols : tSYMBOLS_BEG tSTRING { $$ = new_symbols(list1($2)); } | tSYMBOLS_BEG string_rep tSTRING { $$ = new_symbols(push($2, $3)); } ; numeric : tINTEGER | tFLOAT | tUMINUS_NUM tINTEGER %prec tLOWEST { $$ = negate_lit($2); } | tUMINUS_NUM tFLOAT %prec tLOWEST { $$ = negate_lit($2); } ; variable : tIDENTIFIER { $$ = new_lvar($1); } | tIVAR { $$ = new_ivar($1); } | tGVAR { $$ = new_gvar($1); } | tCVAR { $$ = new_cvar($1); } | tCONSTANT { $$ = new_const($1); } ; var_lhs : variable { assignable($1); } ; var_ref : variable { $$ = var_reference($1); } | keyword_nil { $$ = new_nil(); } | keyword_self { $$ = new_self(); } | keyword_true { $$ = new_true(); } | keyword_false { $$ = new_false(); } | keyword__FILE__ { if (this.filename == null) { this.mrb_parser_set_filename("(null)"); } $$ = new_filename(this.filename); } | keyword__LINE__ { $$ = new_lineno(this.lineno); } ; backref : tNTH_REF | tBACK_REF ; superclass : /* term */ { $$ = null; } | '<' { this.lstate = mrb_lex_state_enum.EXPR_BEG; this.cmd_start = true; } expr_value term { $$ = $3; } /* | error term { yyErrorFlag = 0; $$ = null; } */ ; f_arglist : '(' f_args rparen { $$ = $2; this.lstate = mrb_lex_state_enum.EXPR_BEG; this.cmd_start = true; } | f_args term { $$ = $1; } ; f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg { $$ = new_args($1, $3, $5, null, $6); } | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args($1, $3, $5, $7, $8); } | f_arg ',' f_optarg opt_f_block_arg { $$ = new_args($1, $3, 0, null, $4); } | f_arg ',' f_optarg ',' f_arg opt_f_block_arg { $$ = new_args($1, $3, 0, $5, $6); } | f_arg ',' f_rest_arg opt_f_block_arg { $$ = new_args($1, null, $3, null, $4); } | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args($1, null, $3, $5, $6); } | f_arg opt_f_block_arg { $$ = new_args($1, null, 0, null, $2); } | f_optarg ',' f_rest_arg opt_f_block_arg { $$ = new_args(null, $1, $3, null, $4); } | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args(null, $1, $3, $5, $6); } | f_optarg opt_f_block_arg { $$ = new_args(null, $1, 0, null, $2); } | f_optarg ',' f_arg opt_f_block_arg { $$ = new_args(null, $1, 0, $3, $4); } | f_rest_arg opt_f_block_arg { $$ = new_args(null, null, $1, null, $2); } | f_rest_arg ',' f_arg opt_f_block_arg { $$ = new_args(null, null, $1, $3, $4); } | f_block_arg { $$ = new_args(null, null, 0, null, $1); } | /* none */ { local_add_f(0); $$ = new_args(null, null, 0, null, 0); } ; f_bad_arg : tCONSTANT { yyError("formal argument cannot be a constant"); $$ = null; } | tIVAR { yyError("formal argument cannot be an instance variable"); $$ = null; } | tGVAR { yyError("formal argument cannot be a global variable"); $$ = null; } | tCVAR { yyError("formal argument cannot be a class variable"); $$ = null; } ; f_norm_arg : f_bad_arg { $$ = null; } | tIDENTIFIER { local_add_f($1); $$ = $1; } ; f_arg_item : f_norm_arg { $$ = new_arg($1); } | tLPAREN f_margs rparen { $$ = new_masgn($2, null); } ; f_arg : f_arg_item { $$ = list1($1); } | f_arg ',' f_arg_item { $$ = push($1, $3); } ; f_opt_asgn : tIDENTIFIER '=' { local_add_f($1); $$ = $1; } ; f_opt : f_opt_asgn arg { $$ = cons($1, $2); } ; f_block_opt : f_opt_asgn primary_value { $$ = cons($1, $2); } ; f_block_optarg : f_block_opt { $$ = list1($1); } | f_block_optarg ',' f_block_opt { $$ = push($1, $3); } ; f_optarg : f_opt { $$ = list1($1); } | f_optarg ',' f_opt { $$ = push($1, $3); } ; restarg_mark : '*' | tSTAR ; f_rest_arg : restarg_mark tIDENTIFIER { local_add_f($2); $$ = $2; } | restarg_mark { local_add_f(0); $$ = -1; } ; blkarg_mark : '&' | tAMPER ; f_block_arg : blkarg_mark tIDENTIFIER { local_add_f($2); $$ = $2; } ; opt_f_block_arg : ',' f_block_arg { $$ = $2; } | none { local_add_f(0); $$ = 0; } ; singleton : var_ref { $$ = $1; if ($$ == null) $$ = new_nil(); } | '(' {this.lstate = mrb_lex_state_enum.EXPR_BEG;} expr rparen { if ($3 == 0) { yyError("can't define singleton method for ()."); } else { switch ((node_type)($3.car)) { case node_type.NODE_STR: case node_type.NODE_DSTR: case node_type.NODE_XSTR: case node_type.NODE_DXSTR: case node_type.NODE_DREGX: case node_type.NODE_MATCH: case node_type.NODE_FLOAT: case node_type.NODE_ARRAY: case node_type.NODE_HEREDOC: yyError("can't define singleton method for literals"); break; default: break; } } $$ = $3; } ; assoc_list : none | assocs trailer { $$ = $1; } ; assocs : assoc { $$ = list1($1); $$.NODE_LINENO($1); } | assocs ',' assoc { $$ = push($1, $3); } ; assoc : arg tASSOC arg { $$ = cons($1, $3); } | tLABEL arg { $$ = cons(new_sym($1), $2); } | tLABEL_END arg { $$ = cons(new_sym(new_strsym($1)), $2); } | tSTRING_BEG tLABEL_END arg { $$ = cons(new_sym(new_strsym($2)), $3); } | tSTRING_BEG string_rep tLABEL_END arg { $$ = cons(new_dsym(push($2, $3)), $4); } ; operation : tIDENTIFIER | tCONSTANT | tFID ; operation2 : tIDENTIFIER | tCONSTANT | tFID | op ; operation3 : tIDENTIFIER | tFID | op ; dot_or_colon : '.' | tCOLON2 ; call_op : '.' { $$ = (MrbTokens)'.'; } | tANDDOT { $$ = (MrbTokens)0; } ; call_op2 : call_op | tCOLON2 { $$ = MrbTokens.tCOLON2; } ; opt_terms : /* none */ | terms ; opt_nl : /* none */ | nl ; rparen : opt_nl ')' ; rbracket : opt_nl ']' ; trailer : /* none */ | nl | comma ; term : ';' {yyErrorFlag = 0;} | nl | heredoc_body ; nl : '\n' { this.lineno++; this.column = 0; } ; terms : term | terms term ; none : /* none */ { $$ = null; } ; %% } // must specify trailing } for parser class } // must specify trailing } for namespace, if any