diff options
Diffstat (limited to 'src/parse.y')
| -rw-r--r-- | src/parse.y | 6492 |
1 files changed, 3377 insertions, 3115 deletions
diff --git a/src/parse.y b/src/parse.y index 4fa9e70de..345ac5756 100644 --- a/src/parse.y +++ b/src/parse.y @@ -24,7 +24,9 @@ #include "mruby.h" #include "mruby/compile.h" #include "mruby/proc.h" +#include "mruby/error.h" #include "node.h" +#include "mrb_throw.h" #define YYLEX_PARAM p @@ -32,11 +34,13 @@ typedef mrb_ast_node node; typedef struct mrb_parser_state parser_state; typedef struct mrb_parser_heredoc_info parser_heredoc_info; +static int yyparse(parser_state *p); static int yylex(void *lval, parser_state *p); static void yyerror(parser_state *p, const char *s); static void yywarn(parser_state *p, const char *s); static void yywarning(parser_state *p, const char *s); static void backref_error(parser_state *p, node *n); +static void tokadd(parser_state *p, int32_t c); #ifndef isascii #define isascii(c) (((c) & ~0x7f) == 0) @@ -61,27 +65,29 @@ typedef unsigned int stack_type; #define CMDARG_LEXPOP() BITSTACK_LEXPOP(p->cmdarg_stack) #define CMDARG_P() BITSTACK_SET_P(p->cmdarg_stack) +#define SET_LINENO(c,n) ((c)->lineno = (n)) + #define sym(x) ((mrb_sym)(intptr_t)(x)) #define nsym(x) ((node*)(intptr_t)(x)) static inline mrb_sym -intern_gen(parser_state *p, const char *s) +intern_cstr_gen(parser_state *p, const char *s) { - return mrb_intern(p->mrb, s); + return mrb_intern_cstr(p->mrb, s); } -#define intern(s) intern_gen(p,(s)) +#define intern_cstr(s) intern_cstr_gen(p,(s)) static inline mrb_sym -intern_gen2(parser_state *p, const char *s, size_t len) +intern_gen(parser_state *p, const char *s, size_t len) { - return mrb_intern2(p->mrb, s, len); + return mrb_intern(p->mrb, s, len); } -#define intern2(s,len) intern_gen2(p,(s),(len)) +#define intern(s,len) intern_gen(p,(s),(len)) static inline mrb_sym intern_gen_c(parser_state *p, const char c) { - return mrb_intern2(p->mrb, &c, 1); + return mrb_intern(p->mrb, &c, 1); } #define intern_c(c) intern_gen_c(p,(c)) @@ -99,7 +105,7 @@ parser_palloc(parser_state *p, size_t size) void *m = mrb_pool_alloc(p->pool, size); if (!m) { - longjmp(p->jmp, 1); + MRB_THROW(p->jmp); } return m; } @@ -120,6 +126,7 @@ cons_gen(parser_state *p, node *car, node *cdr) c->car = car; c->cdr = cdr; c->lineno = p->lineno; + c->filename_index = p->current_filename_index; return c; } #define cons(a,b) cons_gen(p,(a),(b)) @@ -202,7 +209,7 @@ parser_strdup(parser_state *p, const char *s) #undef strdup #define strdup(s) parser_strdup(p, s) -// xxx ----------------------------- +/* xxx ----------------------------- */ static node* local_switch(parser_state *p) @@ -261,14 +268,14 @@ local_add(parser_state *p, mrb_sym sym) } } -// (:scope (vars..) (prog...)) +/* (:scope (vars..) (prog...)) */ static node* new_scope(parser_state *p, node *body) { return cons((node*)NODE_SCOPE, cons(p->locals->car, body)); } -// (:begin prog...) +/* (:begin prog...) */ static node* new_begin(parser_state *p, node *body) { @@ -279,84 +286,84 @@ new_begin(parser_state *p, node *body) #define newline_node(n) (n) -// (:rescue body rescue else) +/* (:rescue body rescue else) */ static node* new_rescue(parser_state *p, node *body, node *resq, node *els) { return list4((node*)NODE_RESCUE, body, resq, els); } -// (:ensure body ensure) +/* (:ensure body ensure) */ static node* new_ensure(parser_state *p, node *a, node *b) { return cons((node*)NODE_ENSURE, cons(a, cons(0, b))); } -// (:nil) +/* (:nil) */ static node* new_nil(parser_state *p) { return list1((node*)NODE_NIL); } -// (:true) +/* (:true) */ static node* new_true(parser_state *p) { return list1((node*)NODE_TRUE); } -// (:false) +/* (:false) */ static node* new_false(parser_state *p) { return list1((node*)NODE_FALSE); } -// (:alias new old) +/* (:alias new old) */ static node* new_alias(parser_state *p, mrb_sym a, mrb_sym b) { return cons((node*)NODE_ALIAS, cons(nsym(a), nsym(b))); } -// (:if cond then else) +/* (:if cond then else) */ static node* new_if(parser_state *p, node *a, node *b, node *c) { return list4((node*)NODE_IF, a, b, c); } -// (:unless cond then else) +/* (:unless cond then else) */ static node* new_unless(parser_state *p, node *a, node *b, node *c) { return list4((node*)NODE_IF, a, c, b); } -// (:while cond body) +/* (:while cond body) */ static node* new_while(parser_state *p, node *a, node *b) { return cons((node*)NODE_WHILE, cons(a, b)); } -// (:until cond body) +/* (:until cond body) */ static node* new_until(parser_state *p, node *a, node *b) { return cons((node*)NODE_UNTIL, cons(a, b)); } -// (:for var obj body) +/* (:for var obj body) */ static node* new_for(parser_state *p, node *v, node *o, node *b) { return list4((node*)NODE_FOR, v, o, b); } -// (:case a ((when ...) body) ((when...) body)) +/* (:case a ((when ...) body) ((when...) body)) */ static node* new_case(parser_state *p, node *a, node *b) { @@ -370,49 +377,49 @@ new_case(parser_state *p, node *a, node *b) return n; } -// (:postexe a) +/* (:postexe a) */ static node* new_postexe(parser_state *p, node *a) { return cons((node*)NODE_POSTEXE, a); } -// (:self) +/* (:self) */ static node* new_self(parser_state *p) { return list1((node*)NODE_SELF); } -// (:call a b c) +/* (:call a b c) */ static node* new_call(parser_state *p, node *a, mrb_sym b, node *c) { return list4((node*)NODE_CALL, a, nsym(b), c); } -// (:fcall self mid args) +/* (:fcall self mid args) */ static node* new_fcall(parser_state *p, mrb_sym b, node *c) { return list4((node*)NODE_FCALL, new_self(p), nsym(b), c); } -// (:super . c) +/* (:super . c) */ static node* new_super(parser_state *p, node *c) { return cons((node*)NODE_SUPER, c); } -// (:zsuper) +/* (:zsuper) */ static node* new_zsuper(parser_state *p) { return list1((node*)NODE_ZSUPER); } -// (:yield . c) +/* (:yield . c) */ static node* new_yield(parser_state *p, node *c) { @@ -425,105 +432,105 @@ new_yield(parser_state *p, node *c) return cons((node*)NODE_YIELD, 0); } -// (:return . c) +/* (:return . c) */ static node* new_return(parser_state *p, node *c) { return cons((node*)NODE_RETURN, c); } -// (:break . c) +/* (:break . c) */ static node* new_break(parser_state *p, node *c) { return cons((node*)NODE_BREAK, c); } -// (:next . c) +/* (:next . c) */ static node* new_next(parser_state *p, node *c) { return cons((node*)NODE_NEXT, c); } -// (:redo) +/* (:redo) */ static node* new_redo(parser_state *p) { return list1((node*)NODE_REDO); } -// (:retry) +/* (:retry) */ static node* new_retry(parser_state *p) { return list1((node*)NODE_RETRY); } -// (:dot2 a b) +/* (:dot2 a b) */ static node* new_dot2(parser_state *p, node *a, node *b) { return cons((node*)NODE_DOT2, cons(a, b)); } -// (:dot3 a b) +/* (:dot3 a b) */ static node* new_dot3(parser_state *p, node *a, node *b) { return cons((node*)NODE_DOT3, cons(a, b)); } -// (:colon2 b c) +/* (:colon2 b c) */ static node* new_colon2(parser_state *p, node *b, mrb_sym c) { return cons((node*)NODE_COLON2, cons(b, nsym(c))); } -// (:colon3 . c) +/* (:colon3 . c) */ static node* new_colon3(parser_state *p, mrb_sym c) { return cons((node*)NODE_COLON3, nsym(c)); } -// (:and a b) +/* (:and a b) */ static node* new_and(parser_state *p, node *a, node *b) { return cons((node*)NODE_AND, cons(a, b)); } -// (:or a b) +/* (:or a b) */ static node* new_or(parser_state *p, node *a, node *b) { return cons((node*)NODE_OR, cons(a, b)); } -// (:array a...) +/* (:array a...) */ static node* new_array(parser_state *p, node *a) { return cons((node*)NODE_ARRAY, a); } -// (:splat . a) +/* (:splat . a) */ static node* new_splat(parser_state *p, node *a) { return cons((node*)NODE_SPLAT, a); } -// (:hash (k . v) (k . v)...) +/* (:hash (k . v) (k . v)...) */ static node* new_hash(parser_state *p, node *a) { return cons((node*)NODE_HASH, a); } -// (:sym . a) +/* (:sym . a) */ static node* new_sym(parser_state *p, mrb_sym sym) { @@ -536,99 +543,99 @@ new_strsym(parser_state *p, node* str) const char *s = (const char*)str->cdr->car; size_t len = (size_t)str->cdr->cdr; - return mrb_intern2(p->mrb, s, len); + return mrb_intern(p->mrb, s, len); } -// (:lvar . a) +/* (:lvar . a) */ static node* new_lvar(parser_state *p, mrb_sym sym) { return cons((node*)NODE_LVAR, nsym(sym)); } -// (:gvar . a) +/* (:gvar . a) */ static node* new_gvar(parser_state *p, mrb_sym sym) { return cons((node*)NODE_GVAR, nsym(sym)); } -// (:ivar . a) +/* (:ivar . a) */ static node* new_ivar(parser_state *p, mrb_sym sym) { return cons((node*)NODE_IVAR, nsym(sym)); } -// (:cvar . a) +/* (:cvar . a) */ static node* new_cvar(parser_state *p, mrb_sym sym) { return cons((node*)NODE_CVAR, nsym(sym)); } -// (:const . a) +/* (:const . a) */ static node* new_const(parser_state *p, mrb_sym sym) { return cons((node*)NODE_CONST, nsym(sym)); } -// (:undef a...) +/* (:undef a...) */ static node* new_undef(parser_state *p, mrb_sym sym) { return list2((node*)NODE_UNDEF, nsym(sym)); } -// (:class class super body) +/* (:class class super body) */ static node* new_class(parser_state *p, node *c, node *s, node *b) { return list4((node*)NODE_CLASS, c, s, cons(p->locals->car, b)); } -// (:sclass obj body) +/* (:sclass obj body) */ static node* new_sclass(parser_state *p, node *o, node *b) { return list3((node*)NODE_SCLASS, o, cons(p->locals->car, b)); } -// (:module module body) +/* (:module module body) */ static node* new_module(parser_state *p, node *m, node *b) { return list3((node*)NODE_MODULE, m, cons(p->locals->car, b)); } -// (:def m lv (arg . body)) +/* (:def m lv (arg . body)) */ static node* new_def(parser_state *p, mrb_sym m, node *a, node *b) { return list5((node*)NODE_DEF, nsym(m), p->locals->car, a, b); } -// (:sdef obj m lv (arg . body)) +/* (:sdef obj m lv (arg . body)) */ static node* new_sdef(parser_state *p, node *o, mrb_sym m, node *a, node *b) { return list6((node*)NODE_SDEF, o, nsym(m), p->locals->car, a, b); } -// (:arg . sym) +/* (:arg . sym) */ static node* new_arg(parser_state *p, mrb_sym sym) { return cons((node*)NODE_ARG, nsym(sym)); } -// (m o r m2 b) -// m: (a b c) -// o: ((a . e1) (b . e2)) -// r: a -// m2: (a b c) -// b: a +/* (m o r m2 b) */ +/* m: (a b c) */ +/* o: ((a . e1) (b . e2)) */ +/* r: a */ +/* m2: (a b c) */ +/* b: a */ static node* new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym blk) { @@ -640,126 +647,126 @@ new_args(parser_state *p, node *m, node *opt, mrb_sym rest, node *m2, mrb_sym bl return cons(m, n); } -// (:block_arg . a) +/* (:block_arg . a) */ static node* new_block_arg(parser_state *p, node *a) { return cons((node*)NODE_BLOCK_ARG, a); } -// (:block arg body) +/* (:block arg body) */ static node* new_block(parser_state *p, node *a, node *b) { return list4((node*)NODE_BLOCK, p->locals->car, a, b); } -// (:lambda arg body) +/* (:lambda arg body) */ static node* new_lambda(parser_state *p, node *a, node *b) { return list4((node*)NODE_LAMBDA, p->locals->car, a, b); } -// (:asgn lhs rhs) +/* (:asgn lhs rhs) */ static node* new_asgn(parser_state *p, node *a, node *b) { return cons((node*)NODE_ASGN, cons(a, b)); } -// (:masgn mlhs=(pre rest post) mrhs) +/* (:masgn mlhs=(pre rest post) mrhs) */ static node* new_masgn(parser_state *p, node *a, node *b) { return cons((node*)NODE_MASGN, cons(a, b)); } -// (:asgn lhs rhs) +/* (:asgn lhs rhs) */ static node* new_op_asgn(parser_state *p, node *a, mrb_sym op, node *b) { return list4((node*)NODE_OP_ASGN, a, nsym(op), b); } -// (:int . i) +/* (:int . i) */ static node* new_int(parser_state *p, const char *s, int base) { return list3((node*)NODE_INT, (node*)strdup(s), (node*)(intptr_t)base); } -// (:float . i) +/* (:float . i) */ static node* new_float(parser_state *p, const char *s) { return cons((node*)NODE_FLOAT, (node*)strdup(s)); } -// (:str . (s . len)) +/* (:str . (s . len)) */ static node* new_str(parser_state *p, const char *s, int len) { return cons((node*)NODE_STR, cons((node*)strndup(s, len), (node*)(intptr_t)len)); } -// (:dstr . a) +/* (:dstr . a) */ static node* new_dstr(parser_state *p, node *a) { return cons((node*)NODE_DSTR, a); } -// (:str . (s . len)) +/* (:str . (s . len)) */ static node* new_xstr(parser_state *p, const char *s, int len) { return cons((node*)NODE_XSTR, cons((node*)strndup(s, len), (node*)(intptr_t)len)); } -// (:xstr . a) +/* (:xstr . a) */ static node* new_dxstr(parser_state *p, node *a) { return cons((node*)NODE_DXSTR, a); } -// (:dsym . a) +/* (:dsym . a) */ static node* new_dsym(parser_state *p, node *a) { return cons((node*)NODE_DSYM, new_dstr(p, a)); } -// (:str . (a . a)) +/* (:str . (a . a)) */ static node* new_regx(parser_state *p, const char *p1, const char* p2) { return cons((node*)NODE_REGX, cons((node*)p1, (node*)p2)); } -// (:dregx . a) +/* (:dregx . a) */ static node* new_dregx(parser_state *p, node *a, node *b) { return cons((node*)NODE_DREGX, cons(a, b)); } -// (:backref . n) +/* (:backref . n) */ static node* new_back_ref(parser_state *p, int n) { return cons((node*)NODE_BACK_REF, (node*)(intptr_t)n); } -// (:nthref . n) +/* (:nthref . n) */ static node* new_nth_ref(parser_state *p, int n) { return cons((node*)NODE_NTH_REF, (node*)(intptr_t)n); } -// (:heredoc . a) +/* (:heredoc . a) */ static node* new_heredoc(parser_state *p) { @@ -778,34 +785,34 @@ new_literal_delim(parser_state *p) return cons((node*)NODE_LITERAL_DELIM, 0); } -// (:words . a) +/* (:words . a) */ static node* new_words(parser_state *p, node *a) { return cons((node*)NODE_WORDS, a); } -// (:symbols . a) +/* (:symbols . a) */ static node* new_symbols(parser_state *p, node *a) { return cons((node*)NODE_SYMBOLS, a); } -// xxx ----------------------------- +/* xxx ----------------------------- */ -// (:call a op) +/* (:call a op) */ static node* -call_uni_op(parser_state *p, node *recv, char *m) +call_uni_op(parser_state *p, node *recv, const char *m) { - return new_call(p, recv, intern(m), 0); + return new_call(p, recv, intern_cstr(m), 0); } -// (:call a op b) +/* (:call a op b) */ static node* -call_bin_op(parser_state *p, node *recv, char *m, node *arg1) +call_bin_op(parser_state *p, node *recv, const char *m, node *arg1) { - return new_call(p, recv, intern(m), list1(list1(arg1))); + return new_call(p, recv, intern_cstr(m), list1(list1(arg1))); } static void @@ -857,6 +864,7 @@ ret_args(parser_state *p, node *n) { if (n->cdr) { yyerror(p, "block argument should not be given"); + return NULL; } if (!n->car->cdr) return n->car->car; return new_array(p, n->car); @@ -903,7 +911,7 @@ end_strterm(parser_state *p) p->lex_strterm = NULL; } -parser_heredoc_info * +static parser_heredoc_info * parsing_heredoc_inf(parser_state *p) { node *nd = p->parsing_heredoc; @@ -914,6 +922,51 @@ parsing_heredoc_inf(parser_state *p) } static void +heredoc_treat_nextline(parser_state *p) +{ + if (p->heredocs_from_nextline == NULL) + return; + if (p->parsing_heredoc == NULL) { + node *n; + p->parsing_heredoc = p->heredocs_from_nextline; + p->lex_strterm_before_heredoc = p->lex_strterm; + p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0); + n = p->all_heredocs; + if (n) { + while (n->cdr) + n = n->cdr; + n->cdr = p->parsing_heredoc; + } + else { + p->all_heredocs = p->parsing_heredoc; + } + } + else { + node *n, *m; + m = p->heredocs_from_nextline; + while (m->cdr) + m = m->cdr; + n = p->all_heredocs; + mrb_assert(n != NULL); + if (n == p->parsing_heredoc) { + m->cdr = n; + p->all_heredocs = p->heredocs_from_nextline; + p->parsing_heredoc = p->heredocs_from_nextline; + } + else { + while (n->cdr != p->parsing_heredoc) { + n = n->cdr; + mrb_assert(n != NULL); + } + m->cdr = n->cdr; + n->cdr = p->heredocs_from_nextline; + p->parsing_heredoc = p->heredocs_from_nextline; + } + } + p->heredocs_from_nextline = NULL; +} + +static void heredoc_end(parser_state *p) { p->parsing_heredoc = p->parsing_heredoc->cdr; @@ -921,19 +974,22 @@ heredoc_end(parser_state *p) p->lstate = EXPR_BEG; p->cmd_start = TRUE; end_strterm(p); + p->lex_strterm = p->lex_strterm_before_heredoc; + p->lex_strterm_before_heredoc = NULL; p->heredoc_end_now = TRUE; - } else { + } + else { /* next heredoc */ p->lex_strterm->car = (node*)(intptr_t)parsing_heredoc_inf(p)->type; } } #define is_strterm_type(p,str_func) ((int)(intptr_t)((p)->lex_strterm->car) & (str_func)) -// xxx ----------------------------- +/* xxx ----------------------------- */ %} -%pure_parser +%pure-parser %parse-param {parser_state *p} %lex-param {parser_state *p} @@ -946,54 +1002,54 @@ heredoc_end(parser_state *p) } %token - keyword_class - keyword_module - keyword_def - keyword_undef - keyword_begin - keyword_rescue - keyword_ensure - keyword_end - keyword_if - keyword_unless - keyword_then - keyword_elsif - keyword_else - keyword_case - keyword_when - keyword_while - keyword_until - keyword_for - 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__ + keyword_class + keyword_module + keyword_def + keyword_undef + keyword_begin + keyword_rescue + keyword_ensure + keyword_end + keyword_if + keyword_unless + keyword_then + keyword_elsif + keyword_else + keyword_case + keyword_when + keyword_while + keyword_until + keyword_for + 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 <id> tIDENTIFIER tFID tGVAR tIVAR tCONSTANT tCVAR tLABEL %token <nd> tINTEGER tFLOAT tCHAR tXSTRING tREGEXP @@ -1052,10 +1108,11 @@ heredoc_end(parser_state *p) %token tSYMBEG tREGEXP_BEG tWORDS_BEG tSYMBOLS_BEG %token tSTRING_BEG tXSTRING_BEG tSTRING_DVAR tLAMBEG %token <nd> tHEREDOC_BEG /* <<, <<- */ -%token tHEREDOC_END tLITERAL_DELIM +%token tHEREDOC_END tLITERAL_DELIM tHD_LITERAL_DELIM +%token <nd> tHD_STRING_PART tHD_STRING_MID /* - * precedence table + * precedence table */ %nonassoc tLOWEST @@ -1095,2027 +1152,2082 @@ heredoc_end(parser_state *p) %token tLAST_TOKEN %% -program : { - p->lstate = EXPR_BEG; - if (!p->locals) p->locals = cons(0,0); - } - top_compstmt - { - p->tree = new_scope(p, $2); - } - ; - -top_compstmt : top_stmts opt_terms - { - $$ = $1; - } - ; - -top_stmts : none - { - $$ = new_begin(p, 0); - } - | top_stmt - { - $$ = new_begin(p, $1); - } - | top_stmts terms top_stmt - { - $$ = push($1, newline_node($3)); - } - | error top_stmt - { - $$ = new_begin(p, 0); - } - ; - -top_stmt : stmt - | keyword_BEGIN - { - $<nd>$ = local_switch(p); - } - '{' top_compstmt '}' - { - yyerror(p, "BEGIN not supported"); - local_resume(p, $<nd>2); - $$ = 0; - } - ; - -bodystmt : compstmt - opt_rescue - opt_else - opt_ensure - { - if ($2) { - $$ = new_rescue(p, $1, $2, $3); - } - else if ($3) { - yywarn(p, "else without rescue is useless"); - $$ = push($1, $3); - } - else { - $$ = $1; - } - if ($4) { - if ($$) { - $$ = new_ensure(p, $$, $4); - } - else { - $$ = push($4, new_nil(p)); - } - } - } - ; - -compstmt : stmts opt_terms - { - $$ = $1; - } - ; - -stmts : none - { - $$ = new_begin(p, 0); - } - | stmt - { - $$ = new_begin(p, $1); - } - | stmts terms stmt - { - $$ = push($1, newline_node($3)); - } - | error stmt - { - $$ = new_begin(p, $2); - } - ; - -stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym - { - $$ = new_alias(p, $2, $4); - } - | keyword_undef undef_list - { - $$ = $2; - } - | stmt modifier_if expr_value - { - $$ = new_if(p, cond($3), $1, 0); - } - | stmt modifier_unless expr_value - { - $$ = new_unless(p, cond($3), $1, 0); - } - | stmt modifier_while expr_value - { - $$ = new_while(p, cond($3), $1); - } - | stmt modifier_until expr_value - { - $$ = new_until(p, cond($3), $1); - } - | stmt modifier_rescue stmt - { - $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0); - } - | keyword_END '{' compstmt '}' - { - yyerror(p, "END not suported"); - $$ = new_postexe(p, $3); - } - | command_asgn - | mlhs '=' command_call - { - $$ = new_masgn(p, $1, $3); - } - | var_lhs tOP_ASGN command_call - { - $$ = new_op_asgn(p, $1, $2, $3); - } - | primary_value '[' opt_call_args rbracket tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, intern2("[]",2), $3), $5, $6); - } - | primary_value '.' tIDENTIFIER tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value '.' tCONSTANT tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call - { - yyerror(p, "constant re-assignment"); - $$ = 0; - } - | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | backref tOP_ASGN command_call - { - backref_error(p, $1); - $$ = new_begin(p, 0); - } - | lhs '=' mrhs - { - $$ = new_asgn(p, $1, new_array(p, $3)); - } - | mlhs '=' arg_value - { - $$ = new_masgn(p, $1, $3); - } - | mlhs '=' mrhs - { - $$ = new_masgn(p, $1, new_array(p, $3)); - } - | expr - ; - -command_asgn : lhs '=' command_call - { - $$ = new_asgn(p, $1, $3); - } - | lhs '=' command_asgn - { - $$ = new_asgn(p, $1, $3); - } - ; - - -expr : command_call - | expr keyword_and expr - { - $$ = new_and(p, $1, $3); - } - | expr keyword_or expr - { - $$ = new_or(p, $1, $3); - } - | keyword_not opt_nl expr - { - $$ = call_uni_op(p, cond($3), "!"); - } - | '!' command_call - { - $$ = call_uni_op(p, cond($2), "!"); - } - | arg - ; - -expr_value : expr - { - if (!$1) $$ = new_nil(p); - else $$ = $1; - } - ; - -command_call : command - | block_command - ; - -block_command : block_call - | block_call dot_or_colon operation2 command_args - ; - -cmd_brace_block : tLBRACE_ARG - { - local_nest(p); - } - opt_block_param - compstmt - '}' - { - $$ = new_block(p, $3, $4); - local_unnest(p); - } - ; - -command : operation command_args %prec tLOWEST - { - $$ = new_fcall(p, $1, $2); - } - | operation command_args cmd_brace_block - { - args_with_block(p, $2, $3); - $$ = new_fcall(p, $1, $2); - } - | primary_value '.' operation2 command_args %prec tLOWEST - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value '.' operation2 command_args cmd_brace_block - { - args_with_block(p, $4, $5); - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 command_args %prec tLOWEST - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 command_args cmd_brace_block - { - args_with_block(p, $4, $5); - $$ = new_call(p, $1, $3, $4); - } - | keyword_super command_args - { - $$ = new_super(p, $2); - } - | keyword_yield command_args - { - $$ = new_yield(p, $2); - } - | keyword_return call_args - { - $$ = new_return(p, ret_args(p, $2)); - } - | keyword_break call_args - { - $$ = new_break(p, ret_args(p, $2)); - } - | keyword_next call_args - { - $$ = new_next(p, ret_args(p, $2)); - } - ; - -mlhs : mlhs_basic - { - $$ = $1; - } - | tLPAREN mlhs_inner rparen - { - $$ = $2; - } - ; - -mlhs_inner : mlhs_basic - | tLPAREN mlhs_inner rparen - { - $$ = list1($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(p)); - } - | mlhs_list tSTAR ',' mlhs_post - { - $$ = list3($1, new_nil(p), $4); - } - | tSTAR mlhs_node - { - $$ = list2(0, $2); - } - | tSTAR mlhs_node ',' mlhs_post - { - $$ = list3(0, $2, $4); - } - | tSTAR - { - $$ = list2(0, new_nil(p)); - } - | tSTAR ',' mlhs_post - { - $$ = list3(0, new_nil(p), $3); - } - ; - -mlhs_item : mlhs_node - | tLPAREN mlhs_inner rparen - { - $$ = $2; - } - ; - -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(p, $1); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern2("[]",2), $3); - } - | primary_value '.' tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' tCONSTANT - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon3(p, $2); - } - | backref - { - backref_error(p, $1); - $$ = 0; - } - ; - -lhs : variable - { - assignable(p, $1); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern2("[]",2), $3); - } - | primary_value '.' tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tIDENTIFIER - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' tCONSTANT - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value tCOLON2 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - if (p->in_def || p->in_single) - yyerror(p, "dynamic constant assignment"); - $$ = new_colon3(p, $2); - } - | backref - { - backref_error(p, $1); - $$ = 0; - } - ; - -cname : tIDENTIFIER - { - yyerror(p, "class/module name must be CONSTANT"); - } - | tCONSTANT - ; - -cpath : tCOLON3 cname - { - $$ = cons((node*)1, nsym($2)); - } - | cname - { - $$ = cons((node*)0, nsym($1)); - } - | primary_value tCOLON2 cname - { - $$ = cons($1, nsym($3)); - } - ; - -fname : tIDENTIFIER - | tCONSTANT - | tFID - | op - { - p->lstate = EXPR_ENDFN; - $$ = $1; - } - | reswords - { - p->lstate = EXPR_ENDFN; - $$ = $<id>1; - } - ; - -fsym : fname - | basic_symbol - ; - -undef_list : fsym - { - $$ = new_undef(p, $1); - } - | undef_list ',' {p->lstate = EXPR_FNAME;} fsym - { - $$ = push($1, nsym($4)); - } - ; - -op : '|' { $$ = intern_c('|'); } - | '^' { $$ = intern_c('^'); } - | '&' { $$ = intern_c('&'); } - | tCMP { $$ = intern2("<=>",3); } - | tEQ { $$ = intern2("==",2); } - | tEQQ { $$ = intern2("===",3); } - | tMATCH { $$ = intern2("=~",2); } - | tNMATCH { $$ = intern2("!~",2); } - | '>' { $$ = intern_c('>'); } - | tGEQ { $$ = intern2(">=",2); } - | '<' { $$ = intern_c('<'); } - | tLEQ { $$ = intern2("<=",2); } - | tNEQ { $$ = intern2("!=",2); } - | tLSHFT { $$ = intern2("<<",2); } - | tRSHFT { $$ = intern2(">>",2); } - | '+' { $$ = intern_c('+'); } - | '-' { $$ = intern_c('-'); } - | '*' { $$ = intern_c('*'); } - | tSTAR { $$ = intern_c('*'); } - | '/' { $$ = intern_c('/'); } - | '%' { $$ = intern_c('%'); } - | tPOW { $$ = intern2("**",2); } - | '!' { $$ = intern_c('!'); } - | '~' { $$ = intern_c('~'); } - | tUPLUS { $$ = intern2("+@",2); } - | tUMINUS { $$ = intern2("-@",2); } - | tAREF { $$ = intern2("[]",2); } - | tASET { $$ = intern2("[]=",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 - { - $$ = new_asgn(p, $1, $3); - } - | lhs '=' arg modifier_rescue arg - { - $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); - } - | var_lhs tOP_ASGN arg - { - $$ = new_op_asgn(p, $1, $2, $3); - } - | var_lhs tOP_ASGN arg modifier_rescue arg - { - $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); - } - | primary_value '[' opt_call_args rbracket tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, intern2("[]",2), $3), $5, $6); - } - | primary_value '.' tIDENTIFIER tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value '.' tCONSTANT tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg - { - $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); - } - | primary_value tCOLON2 tCONSTANT tOP_ASGN arg - { - yyerror(p, "constant re-assignment"); - $$ = new_begin(p, 0); - } - | tCOLON3 tCONSTANT tOP_ASGN arg - { - yyerror(p, "constant re-assignment"); - $$ = new_begin(p, 0); - } - | backref tOP_ASGN arg - { - backref_error(p, $1); - $$ = new_begin(p, 0); - } - | arg tDOT2 arg - { - $$ = new_dot2(p, $1, $3); - } - | arg tDOT3 arg - { - $$ = new_dot3(p, $1, $3); - } - | arg '+' arg - { - $$ = call_bin_op(p, $1, "+", $3); - } - | arg '-' arg - { - $$ = call_bin_op(p, $1, "-", $3); - } - | arg '*' arg - { - $$ = call_bin_op(p, $1, "*", $3); - } - | arg '/' arg - { - $$ = call_bin_op(p, $1, "/", $3); - } - | arg '%' arg - { - $$ = call_bin_op(p, $1, "%", $3); - } - | arg tPOW arg - { - $$ = call_bin_op(p, $1, "**", $3); - } - | tUMINUS_NUM tINTEGER tPOW arg - { - $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); - } - | tUMINUS_NUM tFLOAT tPOW arg - { - $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); - } - | tUPLUS arg - { - $$ = call_uni_op(p, $2, "+@"); - } - | tUMINUS arg - { - $$ = call_uni_op(p, $2, "-@"); - } - | arg '|' arg - { - $$ = call_bin_op(p, $1, "|", $3); - } - | arg '^' arg - { - $$ = call_bin_op(p, $1, "^", $3); - } - | arg '&' arg - { - $$ = call_bin_op(p, $1, "&", $3); - } - | arg tCMP arg - { - $$ = call_bin_op(p, $1, "<=>", $3); - } - | arg '>' arg - { - $$ = call_bin_op(p, $1, ">", $3); - } - | arg tGEQ arg - { - $$ = call_bin_op(p, $1, ">=", $3); - } - | arg '<' arg - { - $$ = call_bin_op(p, $1, "<", $3); - } - | arg tLEQ arg - { - $$ = call_bin_op(p, $1, "<=", $3); - } - | arg tEQ arg - { - $$ = call_bin_op(p, $1, "==", $3); - } - | arg tEQQ arg - { - $$ = call_bin_op(p, $1, "===", $3); - } - | arg tNEQ arg - { - $$ = call_bin_op(p, $1, "!=", $3); - } - | arg tMATCH arg - { - $$ = call_bin_op(p, $1, "=~", $3); - } - | arg tNMATCH arg - { - $$ = call_bin_op(p, $1, "!~", $3); - } - | '!' arg - { - $$ = call_uni_op(p, cond($2), "!"); - } - | '~' arg - { - $$ = call_uni_op(p, cond($2), "~"); - } - | arg tLSHFT arg - { - $$ = call_bin_op(p, $1, "<<", $3); - } - | arg tRSHFT arg - { - $$ = call_bin_op(p, $1, ">>", $3); - } - | arg tANDOP arg - { - $$ = new_and(p, $1, $3); - } - | arg tOROP arg - { - $$ = new_or(p, $1, $3); - } - | arg '?' arg opt_nl ':' arg - { - $$ = new_if(p, cond($1), $3, $6); - } - | primary - { - $$ = $1; - } - ; - -arg_value : arg - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - ; - -aref_args : none - | args trailer - { - $$ = $1; - } - | args ',' assocs trailer - { - $$ = push($1, new_hash(p, $3)); - } - | assocs trailer - { - $$ = cons(new_hash(p, $1), 0); - } - ; - -paren_args : '(' opt_call_args rparen - { - $$ = $2; - } - ; - -opt_paren_args : none - | paren_args - ; - -opt_call_args : none - | call_args - | args ',' - { - $$ = cons($1,0); - } - | args ',' assocs ',' - { - $$ = cons(push($1, new_hash(p, $3)), 0); - } - | assocs ',' - { - $$ = cons(list1(new_hash(p, $1)), 0); - } - ; - -call_args : command - { - $$ = cons(list1($1), 0); - } - | args opt_block_arg - { - $$ = cons($1, $2); - } - | assocs opt_block_arg - { - $$ = cons(list1(new_hash(p, $1)), $2); - } - | args ',' assocs opt_block_arg - { - $$ = cons(push($1, new_hash(p, $3)), $4); - } - | block_arg - { - $$ = cons(0, $1); - } - ; - -command_args : { - $<stack>$ = p->cmdarg_stack; - CMDARG_PUSH(1); - } - call_args - { - p->cmdarg_stack = $<stack>1; - $$ = $2; - } - ; - -block_arg : tAMPER arg_value - { - $$ = new_block_arg(p, $2); - } - ; - -opt_block_arg : ',' block_arg - { - $$ = $2; - } - | none - { - $$ = 0; - } - ; - -args : arg_value - { - $$ = cons($1, 0); - } - | tSTAR arg_value - { - $$ = cons(new_splat(p, $2), 0); - } - | args ',' arg_value - { - $$ = push($1, $3); - } - | args ',' tSTAR arg_value - { - $$ = push($1, new_splat(p, $4)); - } - ; - -mrhs : args ',' arg_value - { - $$ = push($1, $3); - } - | args ',' tSTAR arg_value - { - $$ = push($1, new_splat(p, $4)); - } - | tSTAR arg_value - { - $$ = list1(new_splat(p, $2)); - } - ; - -primary : literal - | string - | xstring - | regexp - | heredoc - | var_ref - | backref - | tFID - { - $$ = new_fcall(p, $1, 0); - } - | keyword_begin - { - $<stack>1 = p->cmdarg_stack; - p->cmdarg_stack = 0; - } - bodystmt - keyword_end - { - p->cmdarg_stack = $<stack>1; - $$ = $3; - } - | tLPAREN_ARG expr {p->lstate = EXPR_ENDARG;} rparen - { - $$ = $2; - } - | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen - { - $$ = 0; - } - | tLPAREN compstmt ')' - { - $$ = $2; - } - | primary_value tCOLON2 tCONSTANT - { - $$ = new_colon2(p, $1, $3); - } - | tCOLON3 tCONSTANT - { - $$ = new_colon3(p, $2); - } - | tLBRACK aref_args ']' - { - $$ = new_array(p, $2); - } - | tLBRACE assoc_list '}' - { - $$ = new_hash(p, $2); - } - | keyword_return - { - $$ = new_return(p, 0); - } - | keyword_yield '(' call_args rparen - { - $$ = new_yield(p, $3); - } - | keyword_yield '(' rparen - { - $$ = new_yield(p, 0); - } - | keyword_yield - { - $$ = new_yield(p, 0); - } - | keyword_not '(' expr rparen - { - $$ = call_uni_op(p, cond($3), "!"); - } - | keyword_not '(' rparen - { - $$ = call_uni_op(p, new_nil(p), "!"); - } - | operation brace_block - { - $$ = new_fcall(p, $1, cons(0, $2)); - } - | method_call - | method_call brace_block - { - call_with_block(p, $1, $2); - $$ = $1; - } - | tLAMBDA - { - local_nest(p); - $<num>$ = p->lpar_beg; - p->lpar_beg = ++p->paren_nest; - } - f_larglist - lambda_body - { - p->lpar_beg = $<num>2; - $$ = new_lambda(p, $3, $4); - local_unnest(p); - } - | keyword_if expr_value then - compstmt - if_tail - keyword_end - { - $$ = new_if(p, cond($2), $4, $5); - } - | keyword_unless expr_value then - compstmt - opt_else - keyword_end - { - $$ = new_unless(p, cond($2), $4, $5); - } - | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_while(p, cond($3), $6); - } - | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} - compstmt - keyword_end - { - $$ = new_until(p, cond($3), $6); - } - | keyword_case expr_value opt_terms - case_body - keyword_end - { - $$ = new_case(p, $2, $4); - } - | keyword_case opt_terms case_body keyword_end - { - $$ = new_case(p, 0, $3); - } - | keyword_for for_var keyword_in - {COND_PUSH(1);} - expr_value do - {COND_POP();} - compstmt - keyword_end - { - $$ = new_for(p, $2, $5, $8); - } - | keyword_class cpath superclass - { - if (p->in_def || p->in_single) - yyerror(p, "class definition in method body"); - $<nd>$ = local_switch(p); - } - bodystmt - keyword_end - { - $$ = new_class(p, $2, $3, $5); - local_resume(p, $<nd>4); - } - | keyword_class tLSHFT expr - { - $<num>$ = p->in_def; - p->in_def = 0; - } - term - { - $<nd>$ = cons(local_switch(p), (node*)(intptr_t)p->in_single); - p->in_single = 0; - } - bodystmt - keyword_end - { - $$ = new_sclass(p, $3, $7); - local_resume(p, $<nd>6->car); - p->in_def = $<num>4; - p->in_single = (int)(intptr_t)$<nd>6->cdr; - } - | keyword_module cpath - { - if (p->in_def || p->in_single) - yyerror(p, "module definition in method body"); - $<nd>$ = local_switch(p); - } - bodystmt - keyword_end - { - $$ = new_module(p, $2, $4); - local_resume(p, $<nd>3); - } - | keyword_def fname - { - p->in_def++; - $<nd>$ = local_switch(p); - } - f_arglist - bodystmt - keyword_end - { - $$ = new_def(p, $2, $4, $5); - local_resume(p, $<nd>3); - p->in_def--; - } - | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname - { - p->in_single++; - p->lstate = EXPR_ENDFN; /* force for args */ - $<nd>$ = local_switch(p); - } - f_arglist - bodystmt - keyword_end - { - $$ = new_sdef(p, $2, $5, $7, $8); - local_resume(p, $<nd>6); - p->in_single--; - } - | keyword_break - { - $$ = new_break(p, 0); - } - | keyword_next - { - $$ = new_next(p, 0); - } - | keyword_redo - { - $$ = new_redo(p); - } - | keyword_retry - { - $$ = new_retry(p); - } - ; - -primary_value : primary - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - ; - -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(p, 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(p, $1); - } - | tLPAREN f_margs rparen - { - $$ = new_masgn(p, $2, 0); - } - ; - -f_marg_list : f_marg - { - $$ = list1($1); - } - | f_marg_list ',' f_marg - { - $$ = push($1, $3); - } - ; - -f_margs : f_marg_list - { - $$ = list3($1,0,0); - } - | f_marg_list ',' tSTAR f_norm_arg - { - $$ = list3($1, new_arg(p, $4), 0); - } - | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list - { - $$ = list3($1, new_arg(p, $4), $6); - } - | f_marg_list ',' tSTAR - { - $$ = list3($1, (node*)-1, 0); - } - | f_marg_list ',' tSTAR ',' f_marg_list - { - $$ = list3($1, (node*)-1, $5); - } - | tSTAR f_norm_arg - { - $$ = list3(0, new_arg(p, $2), 0); - } - | tSTAR f_norm_arg ',' f_marg_list - { - $$ = list3(0, new_arg(p, $2), $4); - } - | tSTAR - { - $$ = list3(0, (node*)-1, 0); - } - | tSTAR ',' f_marg_list - { - $$ = list3(0, (node*)-1, $3); - } - ; - -block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, 0, $6); - } - | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, $7, $8); - } - | f_arg ',' f_block_optarg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, 0, $4); - } - | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, $5, $6); - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, 0, $4); - } - | f_arg ',' - { - $$ = new_args(p, $1, 0, 1, 0, 0); - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, $5, $6); - } - | f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, 0, 0, $2); - } - | f_block_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, 0, $4); - } - | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, $5, $6); - } - | f_block_optarg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, 0, $2); - } - | f_block_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, $3, $4); - } - | f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, 0, $2); - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, $3, $4); - } - | f_block_arg - { - $$ = new_args(p, 0, 0, 0, 0, $1); - } - ; - -opt_block_param : none - | block_param_def - { - p->cmd_start = TRUE; - $$ = $1; - } - ; - -block_param_def : '|' opt_bv_decl '|' - { - local_add_f(p, 0); - $$ = 0; - } - | tOROP - { - local_add_f(p, 0); - $$ = 0; - } - | '|' block_param opt_bv_decl '|' - { - $$ = $2; - } - ; - - -opt_bv_decl : opt_nl - { - $$ = 0; - } - | opt_nl ';' bv_decls opt_nl - { - $$ = 0; - } - ; - -bv_decls : bvar - | bv_decls ',' bvar - ; - -bvar : tIDENTIFIER - { - local_add_f(p, $1); - new_bv(p, $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(p); - } - opt_block_param - compstmt - keyword_end - { - $$ = new_block(p,$3,$4); - local_unnest(p); - } - ; - -block_call : command do_block - { - if ($1->car == (node*)NODE_YIELD) { - yyerror(p, "block given to yield"); - } - else { - call_with_block(p, $1, $2); - } - $$ = $1; - } - | block_call dot_or_colon operation2 opt_paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | block_call dot_or_colon operation2 opt_paren_args brace_block - { - $$ = new_call(p, $1, $3, $4); - call_with_block(p, $$, $5); - } - | block_call dot_or_colon operation2 command_args do_block - { - $$ = new_call(p, $1, $3, $4); - call_with_block(p, $$, $5); - } - ; - -method_call : operation paren_args - { - $$ = new_fcall(p, $1, $2); - } - | primary_value '.' operation2 opt_paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation2 paren_args - { - $$ = new_call(p, $1, $3, $4); - } - | primary_value tCOLON2 operation3 - { - $$ = new_call(p, $1, $3, 0); - } - | primary_value '.' paren_args - { - $$ = new_call(p, $1, intern2("call",4), $3); - } - | primary_value tCOLON2 paren_args - { - $$ = new_call(p, $1, intern2("call",4), $3); - } - | keyword_super paren_args - { - $$ = new_super(p, $2); - } - | keyword_super - { - $$ = new_zsuper(p); - } - | primary_value '[' opt_call_args rbracket - { - $$ = new_call(p, $1, intern2("[]",2), $3); - } - ; - -brace_block : '{' - { - local_nest(p); - } - opt_block_param - compstmt '}' - { - $$ = new_block(p,$3,$4); - local_unnest(p); - } - | keyword_do - { - local_nest(p); - } - opt_block_param - compstmt keyword_end - { - $$ = new_block(p,$3,$4); - local_unnest(p); - } - ; - -case_body : keyword_when args then - compstmt - cases - { - $$ = cons(cons($2, $4), $5); - } - ; - -cases : opt_else - { - if ($1) { - $$ = cons(cons(0, $1), 0); - } - else { - $$ = 0; - } - } - | case_body - ; - -opt_rescue : keyword_rescue exc_list exc_var then - compstmt - opt_rescue - { - $$ = list1(list3($2, $3, $5)); - if ($6) $$ = append($$, $6); - } - | none - ; - -exc_list : arg_value - { - $$ = 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(p, push($2, $3)); - } - ; +program : { + p->lstate = EXPR_BEG; + if (!p->locals) p->locals = cons(0,0); + } + top_compstmt + { + p->tree = new_scope(p, $2); + } + ; + +top_compstmt : top_stmts opt_terms + { + $$ = $1; + } + ; + +top_stmts : none + { + $$ = new_begin(p, 0); + } + | top_stmt + { + $$ = new_begin(p, $1); + } + | top_stmts terms top_stmt + { + $$ = push($1, newline_node($3)); + } + | error top_stmt + { + $$ = new_begin(p, 0); + } + ; + +top_stmt : stmt + | keyword_BEGIN + { + $<nd>$ = local_switch(p); + } + '{' top_compstmt '}' + { + yyerror(p, "BEGIN not supported"); + local_resume(p, $<nd>2); + $$ = 0; + } + ; + +bodystmt : compstmt + opt_rescue + opt_else + opt_ensure + { + if ($2) { + $$ = new_rescue(p, $1, $2, $3); + } + else if ($3) { + yywarn(p, "else without rescue is useless"); + $$ = push($1, $3); + } + else { + $$ = $1; + } + if ($4) { + if ($$) { + $$ = new_ensure(p, $$, $4); + } + else { + $$ = push($4, new_nil(p)); + } + } + } + ; + +compstmt : stmts opt_terms + { + $$ = $1; + } + ; + +stmts : none + { + $$ = new_begin(p, 0); + } + | stmt + { + $$ = new_begin(p, $1); + } + | stmts terms stmt + { + $$ = push($1, newline_node($3)); + } + | error stmt + { + $$ = new_begin(p, $2); + } + ; + +stmt : keyword_alias fsym {p->lstate = EXPR_FNAME;} fsym + { + $$ = new_alias(p, $2, $4); + } + | keyword_undef undef_list + { + $$ = $2; + } + | stmt modifier_if expr_value + { + $$ = new_if(p, cond($3), $1, 0); + } + | stmt modifier_unless expr_value + { + $$ = new_unless(p, cond($3), $1, 0); + } + | stmt modifier_while expr_value + { + $$ = new_while(p, cond($3), $1); + } + | stmt modifier_until expr_value + { + $$ = new_until(p, cond($3), $1); + } + | stmt modifier_rescue stmt + { + $$ = new_rescue(p, $1, list1(list3(0, 0, $3)), 0); + } + | keyword_END '{' compstmt '}' + { + yyerror(p, "END not suported"); + $$ = new_postexe(p, $3); + } + | command_asgn + | mlhs '=' command_call + { + $$ = new_masgn(p, $1, $3); + } + | var_lhs tOP_ASGN command_call + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); + } + | primary_value '.' tIDENTIFIER tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value '.' tCONSTANT tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN command_call + { + yyerror(p, "constant re-assignment"); + $$ = 0; + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN command_call + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | backref tOP_ASGN command_call + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + | lhs '=' mrhs + { + $$ = new_asgn(p, $1, new_array(p, $3)); + } + | mlhs '=' arg_value + { + $$ = new_masgn(p, $1, $3); + } + | mlhs '=' mrhs + { + $$ = new_masgn(p, $1, new_array(p, $3)); + } + | expr + ; + +command_asgn : lhs '=' command_call + { + $$ = new_asgn(p, $1, $3); + } + | lhs '=' command_asgn + { + $$ = new_asgn(p, $1, $3); + } + ; + + +expr : command_call + | expr keyword_and expr + { + $$ = new_and(p, $1, $3); + } + | expr keyword_or expr + { + $$ = new_or(p, $1, $3); + } + | keyword_not opt_nl expr + { + $$ = call_uni_op(p, cond($3), "!"); + } + | '!' command_call + { + $$ = call_uni_op(p, cond($2), "!"); + } + | arg + ; + +expr_value : expr + { + if (!$1) $$ = new_nil(p); + else $$ = $1; + } + ; + +command_call : command + | block_command + ; + +block_command : block_call + | block_call dot_or_colon operation2 command_args + ; + +cmd_brace_block : tLBRACE_ARG + { + local_nest(p); + } + opt_block_param + compstmt + '}' + { + $$ = new_block(p, $3, $4); + local_unnest(p); + } + ; + +command : operation command_args %prec tLOWEST + { + $$ = new_fcall(p, $1, $2); + } + | operation command_args cmd_brace_block + { + args_with_block(p, $2, $3); + $$ = new_fcall(p, $1, $2); + } + | primary_value '.' operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value '.' operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 command_args %prec tLOWEST + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 command_args cmd_brace_block + { + args_with_block(p, $4, $5); + $$ = new_call(p, $1, $3, $4); + } + | keyword_super command_args + { + $$ = new_super(p, $2); + } + | keyword_yield command_args + { + $$ = new_yield(p, $2); + } + | keyword_return call_args + { + $$ = new_return(p, ret_args(p, $2)); + } + | keyword_break call_args + { + $$ = new_break(p, ret_args(p, $2)); + } + | keyword_next call_args + { + $$ = new_next(p, ret_args(p, $2)); + } + ; + +mlhs : mlhs_basic + { + $$ = $1; + } + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +mlhs_inner : mlhs_basic + | tLPAREN mlhs_inner rparen + { + $$ = list1($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(p)); + } + | mlhs_list tSTAR ',' mlhs_post + { + $$ = list3($1, new_nil(p), $4); + } + | tSTAR mlhs_node + { + $$ = list2(0, $2); + } + | tSTAR mlhs_node ',' mlhs_post + { + $$ = list3(0, $2, $4); + } + | tSTAR + { + $$ = list2(0, new_nil(p)); + } + | tSTAR ',' mlhs_post + { + $$ = list3(0, new_nil(p), $3); + } + ; + +mlhs_item : mlhs_node + | tLPAREN mlhs_inner rparen + { + $$ = $2; + } + ; + +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(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + | primary_value '.' tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' tCONSTANT + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +lhs : variable + { + assignable(p, $1); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + | primary_value '.' tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tIDENTIFIER + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' tCONSTANT + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value tCOLON2 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + if (p->in_def || p->in_single) + yyerror(p, "dynamic constant assignment"); + $$ = new_colon3(p, $2); + } + | backref + { + backref_error(p, $1); + $$ = 0; + } + ; + +cname : tIDENTIFIER + { + yyerror(p, "class/module name must be CONSTANT"); + } + | tCONSTANT + ; + +cpath : tCOLON3 cname + { + $$ = cons((node*)1, nsym($2)); + } + | cname + { + $$ = cons((node*)0, nsym($1)); + } + | primary_value tCOLON2 cname + { + $$ = cons($1, nsym($3)); + } + ; + +fname : tIDENTIFIER + | tCONSTANT + | tFID + | op + { + p->lstate = EXPR_ENDFN; + $$ = $1; + } + | reswords + { + p->lstate = EXPR_ENDFN; + $$ = $<id>1; + } + ; + +fsym : fname + | basic_symbol + ; + +undef_list : fsym + { + $$ = new_undef(p, $1); + } + | undef_list ',' {p->lstate = EXPR_FNAME;} fsym + { + $$ = push($1, nsym($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 + { + $$ = new_asgn(p, $1, $3); + } + | lhs '=' arg modifier_rescue arg + { + $$ = new_asgn(p, $1, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); + } + | var_lhs tOP_ASGN arg + { + $$ = new_op_asgn(p, $1, $2, $3); + } + | var_lhs tOP_ASGN arg modifier_rescue arg + { + $$ = new_op_asgn(p, $1, $2, new_rescue(p, $3, list1(list3(0, 0, $5)), 0)); + } + | primary_value '[' opt_call_args rbracket tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, intern("[]",2), $3), $5, $6); + } + | primary_value '.' tIDENTIFIER tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value '.' tCONSTANT tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tIDENTIFIER tOP_ASGN arg + { + $$ = new_op_asgn(p, new_call(p, $1, $3, 0), $4, $5); + } + | primary_value tCOLON2 tCONSTANT tOP_ASGN arg + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | tCOLON3 tCONSTANT tOP_ASGN arg + { + yyerror(p, "constant re-assignment"); + $$ = new_begin(p, 0); + } + | backref tOP_ASGN arg + { + backref_error(p, $1); + $$ = new_begin(p, 0); + } + | arg tDOT2 arg + { + $$ = new_dot2(p, $1, $3); + } + | arg tDOT3 arg + { + $$ = new_dot3(p, $1, $3); + } + | arg '+' arg + { + $$ = call_bin_op(p, $1, "+", $3); + } + | arg '-' arg + { + $$ = call_bin_op(p, $1, "-", $3); + } + | arg '*' arg + { + $$ = call_bin_op(p, $1, "*", $3); + } + | arg '/' arg + { + $$ = call_bin_op(p, $1, "/", $3); + } + | arg '%' arg + { + $$ = call_bin_op(p, $1, "%", $3); + } + | arg tPOW arg + { + $$ = call_bin_op(p, $1, "**", $3); + } + | tUMINUS_NUM tINTEGER tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUMINUS_NUM tFLOAT tPOW arg + { + $$ = call_uni_op(p, call_bin_op(p, $2, "**", $4), "-@"); + } + | tUPLUS arg + { + $$ = call_uni_op(p, $2, "+@"); + } + | tUMINUS arg + { + $$ = call_uni_op(p, $2, "-@"); + } + | arg '|' arg + { + $$ = call_bin_op(p, $1, "|", $3); + } + | arg '^' arg + { + $$ = call_bin_op(p, $1, "^", $3); + } + | arg '&' arg + { + $$ = call_bin_op(p, $1, "&", $3); + } + | arg tCMP arg + { + $$ = call_bin_op(p, $1, "<=>", $3); + } + | arg '>' arg + { + $$ = call_bin_op(p, $1, ">", $3); + } + | arg tGEQ arg + { + $$ = call_bin_op(p, $1, ">=", $3); + } + | arg '<' arg + { + $$ = call_bin_op(p, $1, "<", $3); + } + | arg tLEQ arg + { + $$ = call_bin_op(p, $1, "<=", $3); + } + | arg tEQ arg + { + $$ = call_bin_op(p, $1, "==", $3); + } + | arg tEQQ arg + { + $$ = call_bin_op(p, $1, "===", $3); + } + | arg tNEQ arg + { + $$ = call_bin_op(p, $1, "!=", $3); + } + | arg tMATCH arg + { + $$ = call_bin_op(p, $1, "=~", $3); + } + | arg tNMATCH arg + { + $$ = call_bin_op(p, $1, "!~", $3); + } + | '!' arg + { + $$ = call_uni_op(p, cond($2), "!"); + } + | '~' arg + { + $$ = call_uni_op(p, cond($2), "~"); + } + | arg tLSHFT arg + { + $$ = call_bin_op(p, $1, "<<", $3); + } + | arg tRSHFT arg + { + $$ = call_bin_op(p, $1, ">>", $3); + } + | arg tANDOP arg + { + $$ = new_and(p, $1, $3); + } + | arg tOROP arg + { + $$ = new_or(p, $1, $3); + } + | arg '?' arg opt_nl ':' arg + { + $$ = new_if(p, cond($1), $3, $6); + } + | primary + { + $$ = $1; + } + ; + +arg_value : arg + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + ; + +aref_args : none + | args trailer + { + $$ = $1; + } + | args ',' assocs trailer + { + $$ = push($1, new_hash(p, $3)); + } + | assocs trailer + { + $$ = cons(new_hash(p, $1), 0); + } + ; + +paren_args : '(' opt_call_args rparen + { + $$ = $2; + } + ; + +opt_paren_args : none + | paren_args + ; + +opt_call_args : none + | call_args + | args ',' + { + $$ = cons($1,0); + } + | args ',' assocs ',' + { + $$ = cons(push($1, new_hash(p, $3)), 0); + } + | assocs ',' + { + $$ = cons(list1(new_hash(p, $1)), 0); + } + ; + +call_args : command + { + $$ = cons(list1($1), 0); + } + | args opt_block_arg + { + $$ = cons($1, $2); + } + | assocs opt_block_arg + { + $$ = cons(list1(new_hash(p, $1)), $2); + } + | args ',' assocs opt_block_arg + { + $$ = cons(push($1, new_hash(p, $3)), $4); + } + | block_arg + { + $$ = cons(0, $1); + } + ; + +command_args : { + $<stack>$ = p->cmdarg_stack; + CMDARG_PUSH(1); + } + call_args + { + p->cmdarg_stack = $<stack>1; + $$ = $2; + } + ; + +block_arg : tAMPER arg_value + { + $$ = new_block_arg(p, $2); + } + ; + +opt_block_arg : ',' block_arg + { + $$ = $2; + } + | none + { + $$ = 0; + } + ; + +args : arg_value + { + $$ = cons($1, 0); + } + | tSTAR arg_value + { + $$ = cons(new_splat(p, $2), 0); + } + | args ',' arg_value + { + $$ = push($1, $3); + } + | args ',' tSTAR arg_value + { + $$ = push($1, new_splat(p, $4)); + } + | args ',' heredoc_bodies arg_value + { + $$ = push($1, $4); + } + | args ',' heredoc_bodies tSTAR arg_value + { + $$ = push($1, new_splat(p, $5)); + } + ; + +mrhs : args ',' arg_value + { + $$ = push($1, $3); + } + | args ',' tSTAR arg_value + { + $$ = push($1, new_splat(p, $4)); + } + | tSTAR arg_value + { + $$ = list1(new_splat(p, $2)); + } + ; + +primary : literal + | string + | xstring + | regexp + | heredoc + | var_ref + | backref + | tFID + { + $$ = new_fcall(p, $1, 0); + } + | keyword_begin + { + $<stack>1 = p->cmdarg_stack; + p->cmdarg_stack = 0; + } + bodystmt + keyword_end + { + p->cmdarg_stack = $<stack>1; + $$ = $3; + } + | tLPAREN_ARG expr {p->lstate = EXPR_ENDARG;} rparen + { + $$ = $2; + } + | tLPAREN_ARG {p->lstate = EXPR_ENDARG;} rparen + { + $$ = 0; + } + | tLPAREN compstmt ')' + { + $$ = $2; + } + | primary_value tCOLON2 tCONSTANT + { + $$ = new_colon2(p, $1, $3); + } + | tCOLON3 tCONSTANT + { + $$ = new_colon3(p, $2); + } + | tLBRACK aref_args ']' + { + $$ = new_array(p, $2); + } + | tLBRACE assoc_list '}' + { + $$ = new_hash(p, $2); + } + | keyword_return + { + $$ = new_return(p, 0); + } + | keyword_yield '(' call_args rparen + { + $$ = new_yield(p, $3); + } + | keyword_yield '(' rparen + { + $$ = new_yield(p, 0); + } + | keyword_yield + { + $$ = new_yield(p, 0); + } + | keyword_not '(' expr rparen + { + $$ = call_uni_op(p, cond($3), "!"); + } + | keyword_not '(' rparen + { + $$ = call_uni_op(p, new_nil(p), "!"); + } + | operation brace_block + { + $$ = new_fcall(p, $1, cons(0, $2)); + } + | method_call + | method_call brace_block + { + call_with_block(p, $1, $2); + $$ = $1; + } + | tLAMBDA + { + local_nest(p); + $<num>$ = p->lpar_beg; + p->lpar_beg = ++p->paren_nest; + } + f_larglist + lambda_body + { + p->lpar_beg = $<num>2; + $$ = new_lambda(p, $3, $4); + local_unnest(p); + } + | keyword_if expr_value then + compstmt + if_tail + keyword_end + { + $$ = new_if(p, cond($2), $4, $5); + } + | keyword_unless expr_value then + compstmt + opt_else + keyword_end + { + $$ = new_unless(p, cond($2), $4, $5); + } + | keyword_while {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_while(p, cond($3), $6); + } + | keyword_until {COND_PUSH(1);} expr_value do {COND_POP();} + compstmt + keyword_end + { + $$ = new_until(p, cond($3), $6); + } + | keyword_case expr_value opt_terms + case_body + keyword_end + { + $$ = new_case(p, $2, $4); + } + | keyword_case opt_terms case_body keyword_end + { + $$ = new_case(p, 0, $3); + } + | keyword_for for_var keyword_in + {COND_PUSH(1);} + expr_value do + {COND_POP();} + compstmt + keyword_end + { + $$ = new_for(p, $2, $5, $8); + } + | keyword_class + { + $<num>$ = p->lineno; + } + cpath superclass + { + if (p->in_def || p->in_single) + yyerror(p, "class definition in method body"); + $<nd>$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_class(p, $3, $4, $6); + SET_LINENO($$, $<num>2); + local_resume(p, $<nd>5); + } + | keyword_class + { + $<num>$ = p->lineno; + } + tLSHFT expr + { + $<num>$ = p->in_def; + p->in_def = 0; + } + term + { + $<nd>$ = cons(local_switch(p), (node*)(intptr_t)p->in_single); + p->in_single = 0; + } + bodystmt + keyword_end + { + $$ = new_sclass(p, $4, $8); + SET_LINENO($$, $<num>2); + local_resume(p, $<nd>7->car); + p->in_def = $<num>5; + p->in_single = (int)(intptr_t)$<nd>7->cdr; + } + | keyword_module + { + $<num>$ = p->lineno; + } + cpath + { + if (p->in_def || p->in_single) + yyerror(p, "module definition in method body"); + $<nd>$ = local_switch(p); + } + bodystmt + keyword_end + { + $$ = new_module(p, $3, $5); + SET_LINENO($$, $<num>2); + local_resume(p, $<nd>4); + } + | keyword_def fname + { + p->in_def++; + $<nd>$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_def(p, $2, $4, $5); + local_resume(p, $<nd>3); + p->in_def--; + } + | keyword_def singleton dot_or_colon {p->lstate = EXPR_FNAME;} fname + { + p->in_single++; + p->lstate = EXPR_ENDFN; /* force for args */ + $<nd>$ = local_switch(p); + } + f_arglist + bodystmt + keyword_end + { + $$ = new_sdef(p, $2, $5, $7, $8); + local_resume(p, $<nd>6); + p->in_single--; + } + | keyword_break + { + $$ = new_break(p, 0); + } + | keyword_next + { + $$ = new_next(p, 0); + } + | keyword_redo + { + $$ = new_redo(p); + } + | keyword_retry + { + $$ = new_retry(p); + } + ; + +primary_value : primary + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + ; + +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(p, 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(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_marg_list : f_marg + { + $$ = list1($1); + } + | f_marg_list ',' f_marg + { + $$ = push($1, $3); + } + ; + +f_margs : f_marg_list + { + $$ = list3($1,0,0); + } + | f_marg_list ',' tSTAR f_norm_arg + { + $$ = list3($1, new_arg(p, $4), 0); + } + | f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3($1, new_arg(p, $4), $6); + } + | f_marg_list ',' tSTAR + { + $$ = list3($1, (node*)-1, 0); + } + | f_marg_list ',' tSTAR ',' f_marg_list + { + $$ = list3($1, (node*)-1, $5); + } + | tSTAR f_norm_arg + { + $$ = list3(0, new_arg(p, $2), 0); + } + | tSTAR f_norm_arg ',' f_marg_list + { + $$ = list3(0, new_arg(p, $2), $4); + } + | tSTAR + { + $$ = list3(0, (node*)-1, 0); + } + | tSTAR ',' f_marg_list + { + $$ = list3(0, (node*)-1, $3); + } + ; + +block_param : f_arg ',' f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_block_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' + { + $$ = new_args(p, $1, 0, 1, 0, 0); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_block_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_block_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_block_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_block_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + ; + +opt_block_param : none + | block_param_def + { + p->cmd_start = TRUE; + $$ = $1; + } + ; + +block_param_def : '|' opt_bv_decl '|' + { + local_add_f(p, 0); + $$ = 0; + } + | tOROP + { + local_add_f(p, 0); + $$ = 0; + } + | '|' block_param opt_bv_decl '|' + { + $$ = $2; + } + ; + + +opt_bv_decl : opt_nl + { + $$ = 0; + } + | opt_nl ';' bv_decls opt_nl + { + $$ = 0; + } + ; + +bv_decls : bvar + | bv_decls ',' bvar + ; + +bvar : tIDENTIFIER + { + local_add_f(p, $1); + new_bv(p, $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(p); + } + opt_block_param + compstmt + keyword_end + { + $$ = new_block(p,$3,$4); + local_unnest(p); + } + ; + +block_call : command do_block + { + if ($1->car == (node*)NODE_YIELD) { + yyerror(p, "block given to yield"); + } + else { + call_with_block(p, $1, $2); + } + $$ = $1; + } + | block_call dot_or_colon operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | block_call dot_or_colon operation2 opt_paren_args brace_block + { + $$ = new_call(p, $1, $3, $4); + call_with_block(p, $$, $5); + } + | block_call dot_or_colon operation2 command_args do_block + { + $$ = new_call(p, $1, $3, $4); + call_with_block(p, $$, $5); + } + ; + +method_call : operation paren_args + { + $$ = new_fcall(p, $1, $2); + } + | primary_value '.' operation2 opt_paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation2 paren_args + { + $$ = new_call(p, $1, $3, $4); + } + | primary_value tCOLON2 operation3 + { + $$ = new_call(p, $1, $3, 0); + } + | primary_value '.' paren_args + { + $$ = new_call(p, $1, intern("call",4), $3); + } + | primary_value tCOLON2 paren_args + { + $$ = new_call(p, $1, intern("call",4), $3); + } + | keyword_super paren_args + { + $$ = new_super(p, $2); + } + | keyword_super + { + $$ = new_zsuper(p); + } + | primary_value '[' opt_call_args rbracket + { + $$ = new_call(p, $1, intern("[]",2), $3); + } + ; + +brace_block : '{' + { + local_nest(p); + $<num>$ = p->lineno; + } + opt_block_param + compstmt '}' + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $<num>2); + local_unnest(p); + } + | keyword_do + { + local_nest(p); + $<num>$ = p->lineno; + } + opt_block_param + compstmt keyword_end + { + $$ = new_block(p,$3,$4); + SET_LINENO($$, $<num>2); + local_unnest(p); + } + ; + +case_body : keyword_when args then + compstmt + cases + { + $$ = cons(cons($2, $4), $5); + } + ; + +cases : opt_else + { + if ($1) { + $$ = cons(cons(0, $1), 0); + } + else { + $$ = 0; + } + } + | case_body + ; + +opt_rescue : keyword_rescue exc_list exc_var then + compstmt + opt_rescue + { + $$ = list1(list3($2, $3, $5)); + if ($6) $$ = append($$, $6); + } + | none + ; + +exc_list : arg_value + { + $$ = 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(p, push($2, $3)); + } + ; string_rep : string_interp - | string_rep string_interp - { - $$ = append($1, $2); - } - ; - -string_interp : tSTRING_MID - { - $$ = list1($1); - } - | tSTRING_PART - { - $<nd>$ = p->lex_strterm; - p->lex_strterm = NULL; - } - compstmt - '}' - { - p->lex_strterm = $<nd>2; - $$ = list2($1, $3); - } - | tLITERAL_DELIM - { - $$ = list1(new_literal_delim(p)); - } - ; - -xstring : tXSTRING_BEG tXSTRING - { - $$ = $2; - } - | tXSTRING_BEG string_rep tXSTRING - { - $$ = new_dxstr(p, push($2, $3)); - } - ; - -regexp : tREGEXP_BEG tREGEXP - { - $$ = $2; - } - | tREGEXP_BEG string_rep tREGEXP - { - $$ = new_dregx(p, $2, $3); - } - ; - -heredoc : tHEREDOC_BEG - ; - -opt_heredoc_bodies : none - | heredoc_bodies - ; - -heredoc_bodies : heredoc_body - | heredoc_bodies heredoc_body - ; - -heredoc_body : tHEREDOC_END - { - parsing_heredoc_inf(p)->doc = list1(new_str(p, "", 0)); - heredoc_end(p); - } - | string_rep tHEREDOC_END - { - parsing_heredoc_inf(p)->doc = $1; - heredoc_end(p); - } - ; - -words : tWORDS_BEG tSTRING - { - $$ = new_words(p, list1($2)); - } - | tWORDS_BEG string_rep tSTRING - { - $$ = new_words(p, push($2, $3)); - } - ; - - -symbol : basic_symbol - { - $$ = new_sym(p, $1); - } - | tSYMBEG tSTRING_BEG string_interp tSTRING - { - p->lstate = EXPR_END; - $$ = new_dsym(p, push($3, $4)); - } - ; - -basic_symbol : tSYMBEG sym - { - p->lstate = EXPR_END; - $$ = $2; - } - ; - -sym : fname - | tIVAR - | tGVAR - | tCVAR - | tSTRING - { - $$ = new_strsym(p, $1); - } - | tSTRING_BEG tSTRING - { - $$ = new_strsym(p, $2); - } - ; - -symbols : tSYMBOLS_BEG tSTRING - { - $$ = new_symbols(p, list1($2)); - } - | tSYMBOLS_BEG string_rep tSTRING - { - $$ = new_symbols(p, push($2, $3)); - } - ; - -numeric : tINTEGER - | tFLOAT - | tUMINUS_NUM tINTEGER %prec tLOWEST - { - $$ = negate_lit(p, $2); - } - | tUMINUS_NUM tFLOAT %prec tLOWEST - { - $$ = negate_lit(p, $2); - } - ; - -variable : tIDENTIFIER - { - $$ = new_lvar(p, $1); - } - | tIVAR - { - $$ = new_ivar(p, $1); - } - | tGVAR - { - $$ = new_gvar(p, $1); - } - | tCVAR - { - $$ = new_cvar(p, $1); - } - | tCONSTANT - { - $$ = new_const(p, $1); - } - ; - -var_lhs : variable - { - assignable(p, $1); - } - ; - -var_ref : variable - { - $$ = var_reference(p, $1); - } - | keyword_nil - { - $$ = new_nil(p); - } - | keyword_self - { - $$ = new_self(p); - } - | keyword_true - { - $$ = new_true(p); - } - | keyword_false - { - $$ = new_false(p); - } - | keyword__FILE__ - { - if (!p->filename) { - p->filename = "(null)"; - } - $$ = new_str(p, p->filename, strlen(p->filename)); - } - | keyword__LINE__ - { - char buf[16]; - - snprintf(buf, sizeof(buf), "%d", p->lineno); - $$ = new_int(p, buf, 10); - } - ; - -backref : tNTH_REF - | tBACK_REF - ; - -superclass : term - { - $$ = 0; - } - | '<' - { - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - } - expr_value term - { - $$ = $3; - } - | error term - { - yyerrok; - $$ = 0; - } - ; - -f_arglist : '(' f_args rparen - { - $$ = $2; - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - } - | f_args term - { - $$ = $1; - } - ; - -f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, 0, $6); - } - | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, $5, $7, $8); - } - | f_arg ',' f_optarg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, 0, $4); - } - | f_arg ',' f_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, $3, 0, $5, $6); - } - | f_arg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, 0, $4); - } - | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, $3, $5, $6); - } - | f_arg opt_f_block_arg - { - $$ = new_args(p, $1, 0, 0, 0, $2); - } - | f_optarg ',' f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, 0, $4); - } - | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, $3, $5, $6); - } - | f_optarg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, 0, $2); - } - | f_optarg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, $1, 0, $3, $4); - } - | f_rest_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, 0, $2); - } - | f_rest_arg ',' f_arg opt_f_block_arg - { - $$ = new_args(p, 0, 0, $1, $3, $4); - } - | f_block_arg - { - $$ = new_args(p, 0, 0, 0, 0, $1); - } - | /* none */ - { - local_add_f(p, 0); - $$ = new_args(p, 0, 0, 0, 0, 0); - } - ; - -f_bad_arg : tCONSTANT - { - yyerror(p, "formal argument cannot be a constant"); - $$ = 0; - } - | tIVAR - { - yyerror(p, "formal argument cannot be an instance variable"); - $$ = 0; - } - | tGVAR - { - yyerror(p, "formal argument cannot be a global variable"); - $$ = 0; - } - | tCVAR - { - yyerror(p, "formal argument cannot be a class variable"); - $$ = 0; - } - ; - -f_norm_arg : f_bad_arg - { - $$ = 0; - } - | tIDENTIFIER - { - local_add_f(p, $1); - $$ = $1; - } - ; - -f_arg_item : f_norm_arg - { - $$ = new_arg(p, $1); - } - | tLPAREN f_margs rparen - { - $$ = new_masgn(p, $2, 0); - } - ; - -f_arg : f_arg_item - { - $$ = list1($1); - } - | f_arg ',' f_arg_item - { - $$ = push($1, $3); - } - ; - -f_opt : tIDENTIFIER '=' arg_value - { - local_add_f(p, $1); - $$ = cons(nsym($1), $3); - } - ; - -f_block_opt : tIDENTIFIER '=' primary_value - { - local_add_f(p, $1); - $$ = cons(nsym($1), $3); - } - ; - -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(p, $2); - $$ = $2; - } - | restarg_mark - { - local_add_f(p, 0); - $$ = -1; - } - ; - -blkarg_mark : '&' - | tAMPER - ; - -f_block_arg : blkarg_mark tIDENTIFIER - { - local_add_f(p, $2); - $$ = $2; - } - ; - -opt_f_block_arg : ',' f_block_arg - { - $$ = $2; - } - | none - { - local_add_f(p, 0); - $$ = 0; - } - ; - -singleton : var_ref - { - $$ = $1; - if (!$$) $$ = new_nil(p); - } - | '(' {p->lstate = EXPR_BEG;} expr rparen - { - if ($3 == 0) { - yyerror(p, "can't define singleton method for ()."); - } - else { - switch ((enum node_type)(int)(intptr_t)$3->car) { - case NODE_STR: - case NODE_DSTR: - case NODE_XSTR: - case NODE_DXSTR: - case NODE_DREGX: - case NODE_MATCH: - case NODE_FLOAT: - case NODE_ARRAY: - case NODE_HEREDOC: - yyerror(p, "can't define singleton method for literals"); - default: - break; - } - } - $$ = $3; - } - ; - -assoc_list : none - | assocs trailer - { - $$ = $1; - } - ; - -assocs : assoc - { - $$ = list1($1); - } - | assocs ',' assoc - { - $$ = push($1, $3); - } - ; - -assoc : arg_value tASSOC arg_value - { - $$ = cons($1, $3); - } - | tLABEL arg_value - { - $$ = cons(new_sym(p, $1), $2); - } - ; - -operation : tIDENTIFIER - | tCONSTANT - | tFID - ; - -operation2 : tIDENTIFIER - | tCONSTANT - | tFID - | op - ; - -operation3 : tIDENTIFIER - | tFID - | op - ; - -dot_or_colon : '.' - | tCOLON2 - ; - -opt_terms : /* none */ - | terms - ; - -opt_nl : /* none */ - | nl - ; - -rparen : opt_nl ')' - ; - -rbracket : opt_nl ']' - ; - -trailer : /* none */ - | nl - | ',' - ; - -term : ';' {yyerrok;} - | nl - ; - -nl : '\n' - { - p->lineno++; - p->column = 0; - } - opt_heredoc_bodies - -terms : term - | terms ';' {yyerrok;} - ; - -none : /* none */ - { - $$ = 0; - } - ; + | string_rep string_interp + { + $$ = append($1, $2); + } + ; + +string_interp : tSTRING_MID + { + $$ = list1($1); + } + | tSTRING_PART + { + $<nd>$ = p->lex_strterm; + p->lex_strterm = NULL; + } + compstmt + '}' + { + p->lex_strterm = $<nd>2; + $$ = list2($1, $3); + } + | tLITERAL_DELIM + { + $$ = list1(new_literal_delim(p)); + } + | tHD_LITERAL_DELIM heredoc_bodies + { + $$ = list1(new_literal_delim(p)); + } + ; + +xstring : tXSTRING_BEG tXSTRING + { + $$ = $2; + } + | tXSTRING_BEG string_rep tXSTRING + { + $$ = new_dxstr(p, push($2, $3)); + } + ; + +regexp : tREGEXP_BEG tREGEXP + { + $$ = $2; + } + | tREGEXP_BEG string_rep tREGEXP + { + $$ = new_dregx(p, $2, $3); + } + ; + +heredoc : tHEREDOC_BEG + ; + +opt_heredoc_bodies : /* none */ + | heredoc_bodies + ; + +heredoc_bodies : heredoc_body + | heredoc_bodies heredoc_body + ; + +heredoc_body : tHEREDOC_END + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + inf->doc = push(inf->doc, new_str(p, "", 0)); + heredoc_end(p); + } + | heredoc_string_rep tHEREDOC_END + { + heredoc_end(p); + } + ; + +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(p); + inf->doc = push(inf->doc, $1); + heredoc_treat_nextline(p); + } + | tHD_STRING_PART + { + $<nd>$ = p->lex_strterm; + p->lex_strterm = NULL; + } + compstmt + '}' + { + parser_heredoc_info * inf = parsing_heredoc_inf(p); + p->lex_strterm = $<nd>2; + inf->doc = push(push(inf->doc, $1), $3); + } + ; + +words : tWORDS_BEG tSTRING + { + $$ = new_words(p, list1($2)); + } + | tWORDS_BEG string_rep tSTRING + { + $$ = new_words(p, push($2, $3)); + } + ; + + +symbol : basic_symbol + { + $$ = new_sym(p, $1); + } + | tSYMBEG tSTRING_BEG string_interp tSTRING + { + p->lstate = EXPR_END; + $$ = new_dsym(p, push($3, $4)); + } + ; + +basic_symbol : tSYMBEG sym + { + p->lstate = EXPR_END; + $$ = $2; + } + ; + +sym : fname + | tIVAR + | tGVAR + | tCVAR + | tSTRING + { + $$ = new_strsym(p, $1); + } + | tSTRING_BEG tSTRING + { + $$ = new_strsym(p, $2); + } + ; + +symbols : tSYMBOLS_BEG tSTRING + { + $$ = new_symbols(p, list1($2)); + } + | tSYMBOLS_BEG string_rep tSTRING + { + $$ = new_symbols(p, push($2, $3)); + } + ; + +numeric : tINTEGER + | tFLOAT + | tUMINUS_NUM tINTEGER %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + | tUMINUS_NUM tFLOAT %prec tLOWEST + { + $$ = negate_lit(p, $2); + } + ; + +variable : tIDENTIFIER + { + $$ = new_lvar(p, $1); + } + | tIVAR + { + $$ = new_ivar(p, $1); + } + | tGVAR + { + $$ = new_gvar(p, $1); + } + | tCVAR + { + $$ = new_cvar(p, $1); + } + | tCONSTANT + { + $$ = new_const(p, $1); + } + ; + +var_lhs : variable + { + assignable(p, $1); + } + ; + +var_ref : variable + { + $$ = var_reference(p, $1); + } + | keyword_nil + { + $$ = new_nil(p); + } + | keyword_self + { + $$ = new_self(p); + } + | keyword_true + { + $$ = new_true(p); + } + | keyword_false + { + $$ = new_false(p); + } + | keyword__FILE__ + { + if (!p->filename) { + p->filename = "(null)"; + } + $$ = new_str(p, p->filename, strlen(p->filename)); + } + | keyword__LINE__ + { + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", p->lineno); + $$ = new_int(p, buf, 10); + } + ; + +backref : tNTH_REF + | tBACK_REF + ; + +superclass : term + { + $$ = 0; + } + | '<' + { + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + expr_value term + { + $$ = $3; + } + | error term + { + yyerrok; + $$ = 0; + } + ; + +f_arglist : '(' f_args rparen + { + $$ = $2; + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + } + | f_args term + { + $$ = $1; + } + ; + +f_args : f_arg ',' f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, 0, $6); + } + | f_arg ',' f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, $5, $7, $8); + } + | f_arg ',' f_optarg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, 0, $4); + } + | f_arg ',' f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, $3, 0, $5, $6); + } + | f_arg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, 0, $4); + } + | f_arg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, $3, $5, $6); + } + | f_arg opt_f_block_arg + { + $$ = new_args(p, $1, 0, 0, 0, $2); + } + | f_optarg ',' f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, 0, $4); + } + | f_optarg ',' f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, $3, $5, $6); + } + | f_optarg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, 0, $2); + } + | f_optarg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, $1, 0, $3, $4); + } + | f_rest_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, 0, $2); + } + | f_rest_arg ',' f_arg opt_f_block_arg + { + $$ = new_args(p, 0, 0, $1, $3, $4); + } + | f_block_arg + { + $$ = new_args(p, 0, 0, 0, 0, $1); + } + | /* none */ + { + local_add_f(p, 0); + $$ = new_args(p, 0, 0, 0, 0, 0); + } + ; + +f_bad_arg : tCONSTANT + { + yyerror(p, "formal argument cannot be a constant"); + $$ = 0; + } + | tIVAR + { + yyerror(p, "formal argument cannot be an instance variable"); + $$ = 0; + } + | tGVAR + { + yyerror(p, "formal argument cannot be a global variable"); + $$ = 0; + } + | tCVAR + { + yyerror(p, "formal argument cannot be a class variable"); + $$ = 0; + } + ; + +f_norm_arg : f_bad_arg + { + $$ = 0; + } + | tIDENTIFIER + { + local_add_f(p, $1); + $$ = $1; + } + ; + +f_arg_item : f_norm_arg + { + $$ = new_arg(p, $1); + } + | tLPAREN f_margs rparen + { + $$ = new_masgn(p, $2, 0); + } + ; + +f_arg : f_arg_item + { + $$ = list1($1); + } + | f_arg ',' f_arg_item + { + $$ = push($1, $3); + } + ; + +f_opt : tIDENTIFIER '=' arg_value + { + local_add_f(p, $1); + $$ = cons(nsym($1), $3); + } + ; + +f_block_opt : tIDENTIFIER '=' primary_value + { + local_add_f(p, $1); + $$ = cons(nsym($1), $3); + } + ; + +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(p, $2); + $$ = $2; + } + | restarg_mark + { + local_add_f(p, 0); + $$ = -1; + } + ; + +blkarg_mark : '&' + | tAMPER + ; + +f_block_arg : blkarg_mark tIDENTIFIER + { + local_add_f(p, $2); + $$ = $2; + } + ; + +opt_f_block_arg : ',' f_block_arg + { + $$ = $2; + } + | none + { + local_add_f(p, 0); + $$ = 0; + } + ; + +singleton : var_ref + { + $$ = $1; + if (!$$) $$ = new_nil(p); + } + | '(' {p->lstate = EXPR_BEG;} expr rparen + { + if ($3 == 0) { + yyerror(p, "can't define singleton method for ()."); + } + else { + switch ((enum node_type)(int)(intptr_t)$3->car) { + case NODE_STR: + case NODE_DSTR: + case NODE_XSTR: + case NODE_DXSTR: + case NODE_DREGX: + case NODE_MATCH: + case NODE_FLOAT: + case NODE_ARRAY: + case NODE_HEREDOC: + yyerror(p, "can't define singleton method for literals"); + default: + break; + } + } + $$ = $3; + } + ; + +assoc_list : none + | assocs trailer + { + $$ = $1; + } + ; + +assocs : assoc + { + $$ = list1($1); + } + | assocs ',' assoc + { + $$ = push($1, $3); + } + ; + +assoc : arg_value tASSOC arg_value + { + $$ = cons($1, $3); + } + | tLABEL arg_value + { + $$ = cons(new_sym(p, $1), $2); + } + ; + +operation : tIDENTIFIER + | tCONSTANT + | tFID + ; + +operation2 : tIDENTIFIER + | tCONSTANT + | tFID + | op + ; + +operation3 : tIDENTIFIER + | tFID + | op + ; + +dot_or_colon : '.' + | tCOLON2 + ; + +opt_terms : /* none */ + | terms + ; + +opt_nl : /* none */ + | nl + ; + +rparen : opt_nl ')' + ; + +rbracket : opt_nl ']' + ; + +trailer : /* none */ + | nl + | ',' + ; + +term : ';' {yyerrok;} + | nl + ; + +nl : '\n' + { + p->lineno++; + p->column = 0; + } + opt_heredoc_bodies + +terms : term + | terms ';' {yyerrok;} + ; + +none : /* none */ + { + $$ = 0; + } + ; %% #define yylval (*((YYSTYPE*)(p->ylval))) @@ -3206,15 +3318,18 @@ backref_error(parser_state *p, node *n) if (c == NODE_NTH_REF) { yyerror_i(p, "can't set variable $%d", (int)(intptr_t)n->cdr); - } else if (c == NODE_BACK_REF) { + } + else if (c == NODE_BACK_REF) { yyerror_i(p, "can't set variable $%c", (int)(intptr_t)n->cdr); - } else { - mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %d", c); + } + else { + mrb_bug(p->mrb, "Internal error in backref_error() : n=>car == %S", mrb_fixnum_value(c)); } } -static int peeks(parser_state *p, const char *s); -static int skips(parser_state *p, const char *s); +static void pushback(parser_state *p, int c); +static mrb_bool peeks(parser_state *p, const char *s); +static mrb_bool skips(parser_state *p, const char *s); static inline int nextc(parser_state *p) @@ -3232,32 +3347,36 @@ nextc(parser_state *p) else { #ifdef ENABLE_STDIO if (p->f) { - if (feof(p->f)) goto end_retry; + if (feof(p->f)) goto eof; c = fgetc(p->f); - if (c == EOF) goto end_retry; + if (c == EOF) goto eof; } else #endif - if (!p->s || p->s >= p->send) { - goto end_retry; - } - else { - c = (unsigned char)*p->s++; - } + if (!p->s || p->s >= p->send) { + goto eof; + } + else { + c = (unsigned char)*p->s++; + } } p->column++; + if (c == '\r') { + c = nextc(p); + if (c != '\n') { + pushback(p, c); + return '\r'; + } + return c; + } return c; - end_retry: + eof: if (!p->cxt) return -1; else { - mrbc_context *cxt = p->cxt; - - if (cxt->partial_hook(p) < 0) return -1; - p->cxt = NULL; - c = nextc(p); - p->cxt = cxt; - return c; + if (p->cxt->partial_hook(p) < 0) + return -1; + return -2; } } @@ -3281,7 +3400,7 @@ skip(parser_state *p, char term) } } -static int +static mrb_bool peek_n(parser_state *p, int c, int n) { node *list = 0; @@ -3303,7 +3422,7 @@ peek_n(parser_state *p, int c, int n) } #define peek(p,c) peek_n((p), (c), 0) -static int +static mrb_bool peeks(parser_state *p, const char *s) { int len = strlen(s); @@ -3318,19 +3437,19 @@ peeks(parser_state *p, const char *s) } else #endif - if (p->s && p->s + len >= p->send) { - if (memcmp(p->s, s, len) == 0) return TRUE; - } + if (p->s && p->s + len >= p->send) { + if (memcmp(p->s, s, len) == 0) return TRUE; + } return FALSE; } -static int +static mrb_bool skips(parser_state *p, const char *s) { int c; for (;;) { - // skip until first char + /* skip until first char */ for (;;) { c = nextc(p); if (c < 0) return c; @@ -3341,11 +3460,11 @@ skips(parser_state *p, const char *s) int len = strlen(s); while (len--) { - nextc(p); + nextc(p); } return TRUE; } - else{ + else{ s--; } } @@ -3361,10 +3480,48 @@ newtok(parser_state *p) } static void -tokadd(parser_state *p, int c) +tokadd(parser_state *p, int32_t c) { - if (p->bidx < MRB_PARSER_BUF_SIZE) { - p->buf[p->bidx++] = c; + char utf8[4]; + unsigned len; + + /* mrb_assert(-0x10FFFF <= c && c <= 0xFF); */ + if (c >= 0) { + /* Single byte from source or non-Unicode escape */ + utf8[0] = (char)c; + len = 1; + } + else { + /* Unicode character */ + c = -c; + if (c < 0x80) { + utf8[0] = (char)c; + len = 1; + } + else if (c < 0x800) { + utf8[0] = (char)(0xC0 | (c >> 6)); + utf8[1] = (char)(0x80 | (c & 0x3F)); + len = 2; + } + else if (c < 0x10000) { + utf8[0] = (char)(0xE0 | (c >> 12) ); + utf8[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[2] = (char)(0x80 | ( c & 0x3F)); + len = 3; + } + else { + utf8[0] = (char)(0xF0 | (c >> 18) ); + utf8[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + utf8[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + utf8[3] = (char)(0x80 | ( c & 0x3F)); + len = 4; + } + } + if (p->bidx+len <= MRB_PARSER_BUF_SIZE) { + unsigned i; + for (i = 0; i < len; i++) { + p->buf[p->bidx++] = utf8[i]; + } } } @@ -3418,15 +3575,15 @@ scan_oct(const int *start, int len, int *retlen) return retval; } -static int +static int32_t scan_hex(const int *start, int len, int *retlen) { static const char hexdigit[] = "0123456789abcdef0123456789ABCDEF"; - register const int *s = start; - register int retval = 0; + const int *s = start; + int32_t retval = 0; char *tmp; - /* mrb_assert(len <= 2) */ + /* mrb_assert(len <= 8) */ while (len-- && *s && (tmp = (char*)strchr(hexdigit, *s))) { retval <<= 4; retval |= (tmp - hexdigit) & 15; @@ -3437,80 +3594,131 @@ scan_hex(const int *start, int len, int *retlen) return retval; } -static int +/* Return negative to indicate Unicode code point */ +static int32_t read_escape(parser_state *p) { - int c; + int32_t c; switch (c = nextc(p)) { - case '\\': /* Backslash */ + case '\\':/* Backslash */ return c; - case 'n': /* newline */ + case 'n':/* newline */ return '\n'; - case 't': /* horizontal tab */ + case 't':/* horizontal tab */ return '\t'; - case 'r': /* carriage-return */ + case 'r':/* carriage-return */ return '\r'; - case 'f': /* form-feed */ + case 'f':/* form-feed */ return '\f'; - case 'v': /* vertical tab */ + case 'v':/* vertical tab */ return '\13'; - case 'a': /* alarm(bell) */ + case 'a':/* alarm(bell) */ return '\007'; - case 'e': /* escape */ + case 'e':/* escape */ return 033; case '0': case '1': case '2': case '3': /* octal constant */ case '4': case '5': case '6': case '7': - { - int buf[3]; - int i; + { + int buf[3]; + int i; - buf[0] = c; - for (i=1; i<3; i++) { + buf[0] = c; + for (i=1; i<3; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (buf[i] < '0' || '7' < buf[i]) { + pushback(p, buf[i]); + break; + } + } + c = scan_oct(buf, i, &i); + } + return c; + + case 'x': /* hex constant */ + { + int buf[2]; + int i; + + for (i=0; i<2; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } + } + c = scan_hex(buf, i, &i); + if (i == 0) { + yyerror(p, "Invalid escape character syntax"); + return 0; + } + } + return c; + + case 'u': /* Unicode */ + { + int buf[9]; + int i; + + /* Look for opening brace */ + i = 0; + buf[0] = nextc(p); + if (buf[0] < 0) goto eof; + if (buf[0] == '{') { + /* \u{xxxxxxxx} form */ + for (i=0; i<9; i++) { buf[i] = nextc(p); - if (buf[i] == -1) goto eof; - if (buf[i] < '0' || '7' < buf[i]) { - pushback(p, buf[i]); + if (buf[i] < 0) goto eof; + if (buf[i] == '}') { break; } + else if (!ISXDIGIT(buf[i])) { + yyerror(p, "Invalid escape character syntax"); + pushback(p, buf[i]); + return 0; + } } - c = scan_oct(buf, i, &i); } - return c; - - case 'x': /* hex constant */ - { - int buf[2]; - int i; - - for (i=0; i<2; i++) { - buf[i] = nextc(p); - if (buf[i] == -1) goto eof; - if (!ISXDIGIT(buf[i])) { - pushback(p, buf[i]); - break; - } - } - c = scan_hex(buf, i, &i); - if (i == 0) { - yyerror(p, "Invalid escape character syntax"); - return 0; + else if (ISXDIGIT(buf[0])) { + /* \uxxxx form */ + for (i=1; i<4; i++) { + buf[i] = nextc(p); + if (buf[i] < 0) goto eof; + if (!ISXDIGIT(buf[i])) { + pushback(p, buf[i]); + break; + } } } - return c; + else { + pushback(p, buf[0]); + } + c = scan_hex(buf, i, &i); + if (i == 0) { + yyerror(p, "Invalid escape character syntax"); + return 0; + } + if (c < 0 || c > 0x10FFFF || (c & 0xFFFFF800) == 0xD800) { + yyerror(p, "Invalid Unicode code point"); + return 0; + } + } + return -c; - case 'b': /* backspace */ + case 'b':/* backspace */ return '\010'; - case 's': /* space */ + case 's':/* space */ return ' '; case 'M': @@ -3522,7 +3730,7 @@ read_escape(parser_state *p) if ((c = nextc(p)) == '\\') { return read_escape(p) | 0x80; } - else if (c == -1) goto eof; + else if (c < 0) goto eof; else { return ((c & 0xff) | 0x80); } @@ -3539,11 +3747,12 @@ read_escape(parser_state *p) } else if (c == '?') return 0177; - else if (c == -1) goto eof; + else if (c < 0) goto eof; return c & 0x9f; - eof: + eof: case -1: + case -2: yyerror(p, "Invalid escape character syntax"); return '\0'; @@ -3552,7 +3761,6 @@ read_escape(parser_state *p) } } - static int parse_string(parser_state *p) { @@ -3565,7 +3773,7 @@ parse_string(parser_state *p) newtok(p); while ((c = nextc(p)) != end || nest_level != 0) { - if (hinf && (c == '\n' || c == -1)) { + if (hinf && (c == '\n' || c < 0)) { int line_head; tokadd(p, '\n'); tokfix(p); @@ -3574,29 +3782,29 @@ parse_string(parser_state *p) line_head = hinf->line_head; hinf->line_head = TRUE; if (line_head) { - /* check whether end of heredoc */ - const char *s = tok(p); - int len = toklen(p); - if (hinf->allow_indent) { - while (ISSPACE(*s) && len > 0) { - ++s; - --len; - } - } - if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) { - return tHEREDOC_END; - } + /* check whether end of heredoc */ + const char *s = tok(p); + int len = toklen(p); + if (hinf->allow_indent) { + while (ISSPACE(*s) && len > 0) { + ++s; + --len; + } + } + if ((len-1 == hinf->term_len) && (strncmp(s, hinf->term, len-1) == 0)) { + return tHEREDOC_END; + } } - if (c == -1) { - char buf[256]; - snprintf(buf, sizeof(buf), "can't find string \"%s\" anywhere before EOF", hinf->term); - yyerror(p, buf); - return 0; + if (c < 0) { + char buf[256]; + snprintf(buf, sizeof(buf), "can't find heredoc delimiter \"%s\" anywhere before EOF", hinf->term); + yyerror(p, buf); + return 0; } yylval.nd = new_str(p, tok(p), toklen(p)); - return tSTRING_MID; + return tHD_STRING_MID; } - if (c == -1) { + if (c < 0) { yyerror(p, "unterminated string meets end of file"); return 0; } @@ -3611,56 +3819,53 @@ parse_string(parser_state *p) else if (c == '\\') { c = nextc(p); if (type & STR_FUNC_EXPAND) { - if (c == end || c == beg) { - tokadd(p, c); - } - else if ((c == '\n') && (type & STR_FUNC_ARRAY)) { - p->lineno++; - p->column = 0; - tokadd(p, '\n'); - } - else { - if (type & STR_FUNC_REGEXP) { - tokadd(p, '\\'); - if (c != -1) - tokadd(p, c); - } else { - pushback(p, c); - tokadd(p, read_escape(p)); - } - if (hinf) - hinf->line_head = FALSE; - } - } else { - if (c != beg && c != end) { - switch (c) { - case '\n': - p->lineno++; - p->column = 0; - break; - - case '\\': - break; - - default: - if (! ISSPACE(c)) - tokadd(p, '\\'); - } - } - tokadd(p, c); + if (c == end || c == beg) { + tokadd(p, c); + } + else if (c == '\n') { + p->lineno++; + p->column = 0; + if (type & STR_FUNC_ARRAY) { + tokadd(p, '\n'); + } + } + else if (type & STR_FUNC_REGEXP) { + tokadd(p, '\\'); + tokadd(p, c); + } + else { + pushback(p, c); + tokadd(p, read_escape(p)); + if (hinf) + hinf->line_head = FALSE; + } + } + else { + if (c != beg && c != end) { + if (c == '\n') { + p->lineno++; + p->column = 0; + } + if (!(c == '\\' || ((type & STR_FUNC_ARRAY) && ISSPACE(c)))) { + tokadd(p, '\\'); + } + } + tokadd(p, c); } continue; } else if ((c == '#') && (type & STR_FUNC_EXPAND)) { c = nextc(p); if (c == '{') { - tokfix(p); - p->lstate = EXPR_BEG; - p->cmd_start = TRUE; - yylval.nd = new_str(p, tok(p), toklen(p)); - if (hinf) - hinf->line_head = FALSE; - return tSTRING_PART; + tokfix(p); + p->lstate = EXPR_BEG; + p->cmd_start = TRUE; + yylval.nd = new_str(p, tok(p), toklen(p)); + if (hinf) { + hinf->line_head = FALSE; + return tHD_STRING_PART; + } + return tSTRING_PART; } tokadd(p, '#'); pushback(p, c); @@ -3668,24 +3873,27 @@ parse_string(parser_state *p) } if ((type & STR_FUNC_ARRAY) && ISSPACE(c)) { if (toklen(p) == 0) { - do { - if (c == '\n') { - p->lineno++; - p->column = 0; - } - } while (ISSPACE(c = nextc(p))); - pushback(p, c); - return tLITERAL_DELIM; - } else { - pushback(p, c); - tokfix(p); - yylval.nd = new_str(p, tok(p), toklen(p)); - return tSTRING_MID; + do { + if (c == '\n') { + p->lineno++; + p->column = 0; + heredoc_treat_nextline(p); + if (p->parsing_heredoc != NULL) { + return tHD_LITERAL_DELIM; + } + } + } while (ISSPACE(c = nextc(p))); + pushback(p, c); + return tLITERAL_DELIM; + } + else { + pushback(p, c); + tokfix(p); + yylval.nd = new_str(p, tok(p), toklen(p)); + return tSTRING_MID; } } - tokadd(p, c); - } tokfix(p); @@ -3701,10 +3909,12 @@ parse_string(parser_state *p) int f = 0; int c; char *s = strndup(tok(p), toklen(p)); - char flag[4] = { '\0' }; + char flags[3]; + char *flag = flags; + char *dup; newtok(p); - while (c = nextc(p), ISALPHA(c)) { + while (c = nextc(p), c >= 0 && ISALPHA(c)) { switch (c) { case 'i': f |= 1; break; case 'x': f |= 2; break; @@ -3717,13 +3927,19 @@ parse_string(parser_state *p) char msg[128]; tokfix(p); snprintf(msg, sizeof(msg), "unknown regexp option%s - %s", - toklen(p) > 1 ? "s" : "", tok(p)); + toklen(p) > 1 ? "s" : "", tok(p)); yyerror(p, msg); } - if (f & 1) strcat(flag, "i"); - if (f & 2) strcat(flag, "x"); - if (f & 4) strcat(flag, "m"); - yylval.nd = new_regx(p, s, strdup(flag)); + if (f != 0) { + if (f & 1) *flag++ = 'i'; + if (f & 2) *flag++ = 'x'; + if (f & 4) *flag++ = 'm'; + dup = strndup(flags, (size_t)(flag - flags)); + } + else { + dup = NULL; + } + yylval.nd = new_regx(p, s, dup); return tREGEXP; } @@ -3738,8 +3954,8 @@ heredoc_identifier(parser_state *p) { int c; int type = str_heredoc; - int indent = FALSE; - int quote = FALSE; + mrb_bool indent = FALSE; + mrb_bool quote = FALSE; node *newnode; parser_heredoc_info *info; @@ -3757,18 +3973,22 @@ heredoc_identifier(parser_state *p) if (c == '\'') quote = TRUE; newtok(p); - while ((c = nextc(p)) != -1 && c != term) { + while ((c = nextc(p)) >= 0 && c != term) { if (c == '\n') { - c = -1; - break; + c = -1; + break; } tokadd(p, c); } - if (c == -1) { + if (c < 0) { yyerror(p, "unterminated here document identifier"); return 0; } - } else { + } + else { + if (c < 0) { + return 0; /* missing here document identifier */ + } if (! identchar(c)) { pushback(p, c); if (indent) pushback(p, '-'); @@ -3777,7 +3997,7 @@ heredoc_identifier(parser_state *p) newtok(p); do { tokadd(p, c); - } while ((c = nextc(p)) != -1 && identchar(c)); + } while ((c = nextc(p)) >= 0 && identchar(c)); pushback(p, c); } tokfix(p); @@ -3791,14 +4011,7 @@ heredoc_identifier(parser_state *p) info->allow_indent = indent; info->line_head = TRUE; info->doc = NULL; - p->heredocs = push(p->heredocs, newnode); - if (p->parsing_heredoc == NULL) { - node *n = p->heredocs; - while (n->cdr) - n = n->cdr; - p->parsing_heredoc = n; - } - p->heredoc_starts_nextline = TRUE; + p->heredocs_from_nextline = push(p->heredocs_from_nextline, newnode); p->lstate = EXPR_END; yylval.nd = newnode; @@ -3817,7 +4030,7 @@ arg_ambiguous(parser_state *p) static int parser_yylex(parser_state *p) { - register int c; + int32_t c; int space_seen = 0; int cmd_state; enum mrb_lex_state_enum last_state; @@ -3825,21 +4038,24 @@ parser_yylex(parser_state *p) if (p->lex_strterm) { if (is_strterm_type(p, STR_FUNC_HEREDOC)) { - if ((p->parsing_heredoc != NULL) && (! p->heredoc_starts_nextline)) - return parse_string(p); + if (p->parsing_heredoc != NULL) + return parse_string(p); } else return parse_string(p); } cmd_state = p->cmd_start; p->cmd_start = FALSE; - retry: + retry: last_state = p->lstate; switch (c = nextc(p)) { case '\0': /* NUL */ case '\004': /* ^D */ case '\032': /* ^Z */ + return 0; case -1: /* end of script. */ + if (p->heredocs_from_nextline) + goto maybe_heredoc; return 0; /* white spaces */ @@ -3850,80 +4066,86 @@ parser_yylex(parser_state *p) case '#': /* it's a comment */ skip(p, '\n'); - /* fall through */ + /* fall through */ + case -2: /* end of partial script. */ case '\n': - p->heredoc_starts_nextline = FALSE; + maybe_heredoc: + heredoc_treat_nextline(p); + switch (p->lstate) { + case EXPR_BEG: + case EXPR_FNAME: + case EXPR_DOT: + case EXPR_CLASS: + case EXPR_VALUE: + p->lineno++; + p->column = 0; if (p->parsing_heredoc != NULL) { - p->lex_strterm = new_strterm(p, parsing_heredoc_inf(p)->type, 0, 0); - goto normal_newline; + return parse_string(p); } - switch (p->lstate) { - case EXPR_BEG: - case EXPR_FNAME: - case EXPR_DOT: - case EXPR_CLASS: - case EXPR_VALUE: - p->lineno++; - p->column = 0; - goto retry; - default: + goto retry; + default: + break; + } + if (p->parsing_heredoc != NULL) { + return '\n'; + } + while ((c = nextc(p))) { + switch (c) { + case ' ': case '\t': case '\f': case '\r': + case '\13': /* '\v' */ + space_seen = 1; break; - } - while ((c = nextc(p))) { - switch (c) { - case ' ': case '\t': case '\f': case '\r': - case '\13': /* '\v' */ - space_seen = 1; - break; - case '.': - if ((c = nextc(p)) != '.') { - pushback(p, c); - pushback(p, '.'); - goto retry; - } - case -1: /* EOF */ - goto normal_newline; - default: - pushback(p, c); - goto normal_newline; + case '.': + if ((c = nextc(p)) != '.') { + pushback(p, c); + pushback(p, '.'); + goto retry; } + case -1: /* EOF */ + case -2: /* end of partial script */ + goto normal_newline; + default: + pushback(p, c); + goto normal_newline; } + } normal_newline: - p->cmd_start = TRUE; - p->lstate = EXPR_BEG; - return '\n'; + p->cmd_start = TRUE; + p->lstate = EXPR_BEG; + return '\n'; case '*': if ((c = nextc(p)) == '*') { if ((c = nextc(p)) == '=') { - yylval.id = intern2("**",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("**",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); c = tPOW; } else { if (c == '=') { - yylval.id = intern_c('*'); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern_c('*'); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); if (IS_SPCARG(c)) { - yywarning(p, "`*' interpreted as argument prefix"); - c = tSTAR; + yywarning(p, "`*' interpreted as argument prefix"); + c = tSTAR; } else if (IS_BEG()) { - c = tSTAR; + c = tSTAR; } else { - c = '*'; + c = '*'; } } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; } return c; @@ -3933,7 +4155,7 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if (c == '@') { - return '!'; + return '!'; } } else { @@ -3951,18 +4173,19 @@ parser_yylex(parser_state *p) case '=': if (p->column == 1) { if (peeks(p, "begin\n")) { - skips(p, "\n=end\n"); - goto retry; + skips(p, "\n=end\n"); + goto retry; } } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; } if ((c = nextc(p)) == '=') { if ((c = nextc(p)) == '=') { - return tEQQ; + return tEQQ; } pushback(p, c); return tEQ; @@ -3980,34 +4203,35 @@ parser_yylex(parser_state *p) last_state = p->lstate; c = nextc(p); if (c == '<' && - p->lstate != EXPR_DOT && - p->lstate != EXPR_CLASS && - !IS_END() && - (!IS_ARG() || space_seen)) { + p->lstate != EXPR_DOT && + p->lstate != EXPR_CLASS && + !IS_END() && + (!IS_ARG() || space_seen)) { int token = heredoc_identifier(p); if (token) - return token; + return token; } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; if (p->lstate == EXPR_CLASS) { - p->cmd_start = TRUE; + p->cmd_start = TRUE; } } if (c == '=') { if ((c = nextc(p)) == '>') { - return tCMP; + return tCMP; } pushback(p, c); return tLEQ; } if (c == '<') { if ((c = nextc(p)) == '=') { - yylval.id = intern2("<<",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("<<",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tLSHFT; @@ -4018,7 +4242,8 @@ parser_yylex(parser_state *p) case '>': if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; } if ((c = nextc(p)) == '=') { @@ -4026,9 +4251,9 @@ parser_yylex(parser_state *p) } if (c == '>') { if ((c = nextc(p)) == '=') { - yylval.id = intern2(">>",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern(">>",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tRSHFT; @@ -4065,68 +4290,59 @@ parser_yylex(parser_state *p) return '?'; } c = nextc(p); - if (c == -1) { + if (c < 0) { yyerror(p, "incomplete character syntax"); return 0; } if (isspace(c)) { if (!IS_ARG()) { - int c2; - switch (c) { - case ' ': - c2 = 's'; - break; - case '\n': - c2 = 'n'; - break; - case '\t': - c2 = 't'; - break; - case '\v': - c2 = 'v'; - break; - case '\r': - c2 = 'r'; - break; - case '\f': - c2 = 'f'; - break; - default: - c2 = 0; - break; - } - if (c2) { - char buf[256]; - snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); - yyerror(p, buf); - } + int c2; + switch (c) { + case ' ': + c2 = 's'; + break; + case '\n': + c2 = 'n'; + break; + case '\t': + c2 = 't'; + break; + case '\v': + c2 = 'v'; + break; + case '\r': + c2 = 'r'; + break; + case '\f': + c2 = 'f'; + break; + default: + c2 = 0; + break; + } + if (c2) { + char buf[256]; + snprintf(buf, sizeof(buf), "invalid character syntax; use ?\\%c", c2); + yyerror(p, buf); + } } - ternary: + ternary: pushback(p, c); p->lstate = EXPR_VALUE; return '?'; } token_column = newtok(p); - // need support UTF-8 if configured + /* need support UTF-8 if configured */ if ((isalnum(c) || c == '_')) { int c2 = nextc(p); pushback(p, c2); if ((isalnum(c2) || c2 == '_')) { - goto ternary; + goto ternary; } } if (c == '\\') { - c = nextc(p); - if (c == 'u') { -#if 0 - tokadd_utf8(p); -#endif - } - else { - pushback(p, c); - c = read_escape(p); - tokadd(p, c); - } + c = read_escape(p); + tokadd(p, c); } else { tokadd(p, c); @@ -4140,9 +4356,9 @@ parser_yylex(parser_state *p) if ((c = nextc(p)) == '&') { p->lstate = EXPR_BEG; if ((c = nextc(p)) == '=') { - yylval.id = intern2("&&",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("&&",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tANDOP; @@ -4165,7 +4381,8 @@ parser_yylex(parser_state *p) } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; } return c; @@ -4174,9 +4391,9 @@ parser_yylex(parser_state *p) if ((c = nextc(p)) == '|') { p->lstate = EXPR_BEG; if ((c = nextc(p)) == '=') { - yylval.id = intern2("||",2); - p->lstate = EXPR_BEG; - return tOP_ASGN; + yylval.id = intern("||",2); + p->lstate = EXPR_BEG; + return tOP_ASGN; } pushback(p, c); return tOROP; @@ -4200,7 +4417,7 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if (c == '@') { - return tUPLUS; + return tUPLUS; } pushback(p, c); return '+'; @@ -4213,9 +4430,9 @@ parser_yylex(parser_state *p) if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { p->lstate = EXPR_BEG; pushback(p, c); - if (c != -1 && ISDIGIT(c)) { - c = '+'; - goto start_num; + if (c >= 0 && ISDIGIT(c)) { + c = '+'; + goto start_num; } return tUPLUS; } @@ -4228,7 +4445,7 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if (c == '@') { - return tUMINUS; + return tUMINUS; } pushback(p, c); return '-'; @@ -4245,8 +4462,8 @@ parser_yylex(parser_state *p) if (IS_BEG() || (IS_SPCARG(c) && arg_ambiguous(p))) { p->lstate = EXPR_BEG; pushback(p, c); - if (c != -1 && ISDIGIT(c)) { - return tUMINUS_NUM; + if (c >= 0 && ISDIGIT(c)) { + return tUMINUS_NUM; } return tUMINUS; } @@ -4258,244 +4475,244 @@ parser_yylex(parser_state *p) p->lstate = EXPR_BEG; if ((c = nextc(p)) == '.') { if ((c = nextc(p)) == '.') { - return tDOT3; + return tDOT3; } pushback(p, c); return tDOT2; } pushback(p, c); - if (c != -1 && ISDIGIT(c)) { + if (c >= 0 && ISDIGIT(c)) { yyerror(p, "no .<digit> floating literal anymore; put 0 before dot"); } p->lstate = EXPR_DOT; return '.'; - start_num: + start_num: case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - { - int is_float, seen_point, seen_e, nondigit; + { + int is_float, seen_point, seen_e, nondigit; - is_float = seen_point = seen_e = nondigit = 0; - p->lstate = EXPR_END; - token_column = newtok(p); - if (c == '-' || c == '+') { - tokadd(p, c); - c = nextc(p); - } - if (c == '0') { + is_float = seen_point = seen_e = nondigit = 0; + p->lstate = EXPR_END; + token_column = newtok(p); + if (c == '-' || c == '+') { + tokadd(p, c); + c = nextc(p); + } + if (c == '0') { #define no_digits() do {yyerror(p,"numeric literal without digits"); return 0;} while (0) - int start = toklen(p); - c = nextc(p); - if (c == 'x' || c == 'X') { - /* hexadecimal */ - c = nextc(p); - if (c != -1 && ISXDIGIT(c)) { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (!ISXDIGIT(c)) break; - nondigit = 0; - tokadd(p, tolower(c)); - } while ((c = nextc(p)) != -1); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 16); - return tINTEGER; - } - if (c == 'b' || c == 'B') { - /* binary */ - c = nextc(p); - if (c == '0' || c == '1') { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (c != '0' && c != '1') break; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) != -1); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 2); - return tINTEGER; - } - if (c == 'd' || c == 'D') { - /* decimal */ - c = nextc(p); - if (c != -1 && ISDIGIT(c)) { - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (!ISDIGIT(c)) break; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) != -1); - } - pushback(p, c); - tokfix(p); - if (toklen(p) == start) { - no_digits(); - } - else if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 10); - return tINTEGER; - } - if (c == '_') { - /* 0_0 */ - goto octal_number; - } - if (c == 'o' || c == 'O') { - /* prefixed octal */ - c = nextc(p); - if (c == -1 || c == '_' || !ISDIGIT(c)) { - no_digits(); - } - } - if (c >= '0' && c <= '7') { - /* octal */ - octal_number: - do { - if (c == '_') { - if (nondigit) break; - nondigit = c; - continue; - } - if (c < '0' || c > '9') break; - if (c > '7') goto invalid_octal; - nondigit = 0; - tokadd(p, c); - } while ((c = nextc(p)) != -1); - - if (toklen(p) > start) { - pushback(p, c); - tokfix(p); - if (nondigit) goto trailing_uc; - yylval.nd = new_int(p, tok(p), 8); - return tINTEGER; - } - if (nondigit) { - pushback(p, c); - goto trailing_uc; - } - } - if (c > '7' && c <= '9') { - invalid_octal: - yyerror(p, "Invalid octal digit"); - } - else if (c == '.' || c == 'e' || c == 'E') { - tokadd(p, '0'); - } - else { - pushback(p, c); - yylval.nd = new_int(p, "0", 10); - return tINTEGER; - } + int start = toklen(p); + c = nextc(p); + if (c == 'x' || c == 'X') { + /* hexadecimal */ + c = nextc(p); + if (c >= 0 && ISXDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISXDIGIT(c)) break; + nondigit = 0; + tokadd(p, tolower(c)); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 16); + return tINTEGER; + } + if (c == 'b' || c == 'B') { + /* binary */ + c = nextc(p); + if (c == '0' || c == '1') { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c != '0' && c != '1') break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 2); + return tINTEGER; + } + if (c == 'd' || c == 'D') { + /* decimal */ + c = nextc(p); + if (c >= 0 && ISDIGIT(c)) { + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (!ISDIGIT(c)) break; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + } + pushback(p, c); + tokfix(p); + if (toklen(p) == start) { + no_digits(); + } + else if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 10); + return tINTEGER; + } + if (c == '_') { + /* 0_0 */ + goto octal_number; + } + if (c == 'o' || c == 'O') { + /* prefixed octal */ + c = nextc(p); + if (c < 0 || c == '_' || !ISDIGIT(c)) { + no_digits(); + } + } + if (c >= '0' && c <= '7') { + /* octal */ + octal_number: + do { + if (c == '_') { + if (nondigit) break; + nondigit = c; + continue; + } + if (c < '0' || c > '9') break; + if (c > '7') goto invalid_octal; + nondigit = 0; + tokadd(p, c); + } while ((c = nextc(p)) >= 0); + + if (toklen(p) > start) { + pushback(p, c); + tokfix(p); + if (nondigit) goto trailing_uc; + yylval.nd = new_int(p, tok(p), 8); + return tINTEGER; + } + if (nondigit) { + pushback(p, c); + goto trailing_uc; + } + } + if (c > '7' && c <= '9') { + invalid_octal: + yyerror(p, "Invalid octal digit"); + } + else if (c == '.' || c == 'e' || c == 'E') { + tokadd(p, '0'); } + else { + pushback(p, c); + yylval.nd = new_int(p, "0", 10); + return tINTEGER; + } + } - for (;;) { - switch (c) { - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - nondigit = 0; - tokadd(p, c); - break; - - case '.': - if (nondigit) goto trailing_uc; - if (seen_point || seen_e) { - goto decode_num; - } - else { - int c0 = nextc(p); - if (c0 == -1 || !ISDIGIT(c0)) { - pushback(p, c0); - goto decode_num; - } - c = c0; - } - tokadd(p, '.'); - tokadd(p, c); - is_float++; - seen_point++; - nondigit = 0; - break; - - case 'e': - case 'E': - if (nondigit) { - pushback(p, c); - c = nondigit; - goto decode_num; - } - if (seen_e) { - goto decode_num; - } - tokadd(p, c); - seen_e++; - is_float++; - nondigit = c; - c = nextc(p); - if (c != '-' && c != '+') continue; - tokadd(p, c); - nondigit = c; - break; - - case '_': /* `_' in number just ignored */ - if (nondigit) goto decode_num; - nondigit = c; - break; - - default: - goto decode_num; - } - c = nextc(p); + for (;;) { + switch (c) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + nondigit = 0; + tokadd(p, c); + break; + + case '.': + if (nondigit) goto trailing_uc; + if (seen_point || seen_e) { + goto decode_num; + } + else { + int c0 = nextc(p); + if (c0 < 0 || !ISDIGIT(c0)) { + pushback(p, c0); + goto decode_num; + } + c = c0; + } + tokadd(p, '.'); + tokadd(p, c); + is_float++; + seen_point++; + nondigit = 0; + break; + + case 'e': + case 'E': + if (nondigit) { + pushback(p, c); + c = nondigit; + goto decode_num; + } + if (seen_e) { + goto decode_num; + } + tokadd(p, c); + seen_e++; + is_float++; + nondigit = c; + c = nextc(p); + if (c != '-' && c != '+') continue; + tokadd(p, c); + nondigit = c; + break; + + case '_': /* `_' in number just ignored */ + if (nondigit) goto decode_num; + nondigit = c; + break; + + default: + goto decode_num; } + c = nextc(p); + } decode_num: - pushback(p, c); - if (nondigit) { + pushback(p, c); + if (nondigit) { trailing_uc: - yyerror_i(p, "trailing `%c' in number", nondigit); + yyerror_i(p, "trailing `%c' in number", nondigit); + } + tokfix(p); + if (is_float) { + double d; + char *endp; + + errno = 0; + d = strtod(tok(p), &endp); + if (d == 0 && endp == tok(p)) { + yywarning_s(p, "corrupted float value %s", tok(p)); } - tokfix(p); - if (is_float) { - double d; - char *endp; - - errno = 0; - d = strtod(tok(p), &endp); - if (d == 0 && endp == tok(p)) { - yywarning_s(p, "corrupted float value %s", tok(p)); - } - else if (errno == ERANGE) { - yywarning_s(p, "float %s out of range", tok(p)); - errno = 0; - } - yylval.nd = new_float(p, tok(p)); - return tFLOAT; + else if (errno == ERANGE) { + yywarning_s(p, "float %s out of range", tok(p)); + errno = 0; } - yylval.nd = new_int(p, tok(p), 10); - return tINTEGER; + yylval.nd = new_float(p, tok(p)); + return tFLOAT; } + yylval.nd = new_int(p, tok(p), 10); + return tINTEGER; + } case ')': case ']': @@ -4513,8 +4730,8 @@ parser_yylex(parser_state *p) c = nextc(p); if (c == ':') { if (IS_BEG() || p->lstate == EXPR_CLASS || IS_SPCARG(-1)) { - p->lstate = EXPR_BEG; - return tCOLON3; + p->lstate = EXPR_BEG; + return tCOLON3; } p->lstate = EXPR_DOT; return tCOLON2; @@ -4545,7 +4762,8 @@ parser_yylex(parser_state *p) } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; } return '/'; @@ -4558,7 +4776,8 @@ parser_yylex(parser_state *p) } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; } pushback(p, c); @@ -4575,7 +4794,7 @@ parser_yylex(parser_state *p) case '~': if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { if ((c = nextc(p)) != '@') { - pushback(p, c); + pushback(p, c); } p->lstate = EXPR_ARG; } @@ -4602,11 +4821,11 @@ parser_yylex(parser_state *p) if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; if ((c = nextc(p)) == ']') { - if ((c = nextc(p)) == '=') { - return tASET; - } - pushback(p, c); - return tAREF; + if ((c = nextc(p)) == '=') { + return tASET; + } + pushback(p, c); + return tAREF; } pushback(p, c); return '['; @@ -4659,21 +4878,21 @@ parser_yylex(parser_state *p) int paren; c = nextc(p); - quotation: - if (c == -1 || !ISALNUM(c)) { - term = c; - c = 'Q'; + quotation: + if (c < 0 || !ISALNUM(c)) { + term = c; + c = 'Q'; } else { - term = nextc(p); - if (isalnum(term)) { - yyerror(p, "unknown type of %string"); - return 0; - } + term = nextc(p); + if (isalnum(term)) { + yyerror(p, "unknown type of %string"); + return 0; + } } - if (c == -1 || term == -1) { - yyerror(p, "unterminated quoted string meets end of file"); - return 0; + if (c < 0 || term < 0) { + yyerror(p, "unterminated quoted string meets end of file"); + return 0; } paren = term; if (term == '(') term = ')'; @@ -4684,44 +4903,44 @@ parser_yylex(parser_state *p) switch (c) { case 'Q': - p->lex_strterm = new_strterm(p, str_dquote, term, paren); - return tSTRING_BEG; + p->lex_strterm = new_strterm(p, str_dquote, term, paren); + return tSTRING_BEG; case 'q': - p->lex_strterm = new_strterm(p, str_squote, term, paren); - return parse_string(p); + p->lex_strterm = new_strterm(p, str_squote, term, paren); + return parse_string(p); case 'W': - p->lex_strterm = new_strterm(p, str_dword, term, paren); - return tWORDS_BEG; + p->lex_strterm = new_strterm(p, str_dword, term, paren); + return tWORDS_BEG; case 'w': - p->lex_strterm = new_strterm(p, str_sword, term, paren); - return tWORDS_BEG; + p->lex_strterm = new_strterm(p, str_sword, term, paren); + return tWORDS_BEG; case 'x': - p->lex_strterm = new_strterm(p, str_xquote, term, paren); - return tXSTRING_BEG; + p->lex_strterm = new_strterm(p, str_xquote, term, paren); + return tXSTRING_BEG; case 'r': - p->lex_strterm = new_strterm(p, str_regexp, term, paren); - return tREGEXP_BEG; + p->lex_strterm = new_strterm(p, str_regexp, term, paren); + return tREGEXP_BEG; case 's': - p->lex_strterm = new_strterm(p, str_ssym, term, paren); - return tSYMBEG; + p->lex_strterm = new_strterm(p, str_ssym, term, paren); + return tSYMBEG; case 'I': - p->lex_strterm = new_strterm(p, str_dsymbols, term, paren); - return tSYMBOLS_BEG; + p->lex_strterm = new_strterm(p, str_dsymbols, term, paren); + return tSYMBOLS_BEG; case 'i': - p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); - return tSYMBOLS_BEG; + p->lex_strterm = new_strterm(p, str_ssymbols, term, paren); + return tSYMBOLS_BEG; default: - yyerror(p, "unknown type of %string"); - return 0; + yyerror(p, "unknown type of %string"); + return 0; } } if ((c = nextc(p)) == '=') { @@ -4734,7 +4953,8 @@ parser_yylex(parser_state *p) } if (p->lstate == EXPR_FNAME || p->lstate == EXPR_DOT) { p->lstate = EXPR_ARG; - } else { + } + else { p->lstate = EXPR_BEG; } pushback(p, c); @@ -4744,14 +4964,14 @@ parser_yylex(parser_state *p) p->lstate = EXPR_END; token_column = newtok(p); c = nextc(p); - if (c == -1) { + if (c < 0) { yyerror(p, "incomplete global variable syntax"); return 0; } switch (c) { case '_': /* $_: last read line string */ c = nextc(p); - if (c != -1 && identchar(c)) { /* if there is more after _ it is a variable */ + if (c >= 0 && identchar(c)) { /* if there is more after _ it is a variable */ tokadd(p, '$'); tokadd(p, c); break; @@ -4778,7 +4998,7 @@ parser_yylex(parser_state *p) tokadd(p, '$'); tokadd(p, c); tokfix(p); - yylval.id = intern(tok(p)); + yylval.id = intern_cstr(tok(p)); return tGVAR; case '-': @@ -4786,9 +5006,9 @@ parser_yylex(parser_state *p) tokadd(p, c); c = nextc(p); pushback(p, c); - gvar: + gvar: tokfix(p); - yylval.id = intern(tok(p)); + yylval.id = intern_cstr(tok(p)); return tGVAR; case '&': /* $&: last match */ @@ -4796,9 +5016,9 @@ parser_yylex(parser_state *p) case '\'': /* $': string after last match */ case '+': /* $+: string matches last pattern */ if (last_state == EXPR_FNAME) { - tokadd(p, '$'); - tokadd(p, c); - goto gvar; + tokadd(p, '$'); + tokadd(p, c); + goto gvar; } yylval.nd = new_back_ref(p, c); return tBACK_REF; @@ -4807,9 +5027,9 @@ parser_yylex(parser_state *p) case '4': case '5': case '6': case '7': case '8': case '9': do { - tokadd(p, c); - c = nextc(p); - } while (c != -1 && isdigit(c)); + tokadd(p, c); + c = nextc(p); + } while (c >= 0 && isdigit(c)); pushback(p, c); if (last_state == EXPR_FNAME) goto gvar; tokfix(p); @@ -4818,58 +5038,58 @@ parser_yylex(parser_state *p) default: if (!identchar(c)) { - pushback(p, c); - return '$'; + pushback(p, c); + return '$'; } case '0': tokadd(p, '$'); } break; - case '@': - c = nextc(p); - token_column = newtok(p); - tokadd(p, '@'); - if (c == '@') { - tokadd(p, '@'); + case '@': c = nextc(p); - } - if (c == -1) { - if (p->bidx == 1) { - yyerror(p, "incomplete instance variable syntax"); + token_column = newtok(p); + tokadd(p, '@'); + if (c == '@') { + tokadd(p, '@'); + c = nextc(p); } - else { - yyerror(p, "incomplete class variable syntax"); + if (c < 0) { + if (p->bidx == 1) { + yyerror(p, "incomplete instance variable syntax"); + } + else { + yyerror(p, "incomplete class variable syntax"); + } + return 0; } - return 0; - } - else if (isdigit(c)) { - if (p->bidx == 1) { - yyerror_i(p, "`@%c' is not allowed as an instance variable name", c); + else if (isdigit(c)) { + if (p->bidx == 1) { + yyerror_i(p, "`@%c' is not allowed as an instance variable name", c); + } + else { + yyerror_i(p, "`@@%c' is not allowed as a class variable name", c); + } + return 0; } - else { - yyerror_i(p, "`@@%c' is not allowed as a class variable name", c); + if (!identchar(c)) { + pushback(p, c); + return '@'; } - return 0; - } - if (!identchar(c)) { - pushback(p, c); - return '@'; - } - break; + break; - case '_': - token_column = newtok(p); - break; + case '_': + token_column = newtok(p); + break; - default: - if (!identchar(c)) { - yyerror_i(p, "Invalid char `\\x%02X' in expression", c); - goto retry; - } + default: + if (!identchar(c)) { + yyerror_i(p, "Invalid char `\\x%02X' in expression", c); + goto retry; + } - token_column = newtok(p); - break; + token_column = newtok(p); + break; } do { @@ -4906,104 +5126,104 @@ parser_yylex(parser_state *p) case '@': p->lstate = EXPR_END; if (tok(p)[1] == '@') - result = tCVAR; + result = tCVAR; else - result = tIVAR; + result = tIVAR; break; default: if (toklast(p) == '!' || toklast(p) == '?') { - result = tFID; + result = tFID; } else { - if (p->lstate == EXPR_FNAME) { - if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') && - (!peek(p, '=') || (peek_n(p, '>', 1)))) { - result = tIDENTIFIER; - tokadd(p, c); - tokfix(p); - } - else { - pushback(p, c); - } - } - if (result == 0 && isupper((int)(unsigned char)tok(p)[0])) { - result = tCONSTANT; - } - else { - result = tIDENTIFIER; - } + if (p->lstate == EXPR_FNAME) { + if ((c = nextc(p)) == '=' && !peek(p, '~') && !peek(p, '>') && + (!peek(p, '=') || (peek_n(p, '>', 1)))) { + result = tIDENTIFIER; + tokadd(p, c); + tokfix(p); + } + else { + pushback(p, c); + } + } + if (result == 0 && isupper((int)(unsigned char)tok(p)[0])) { + result = tCONSTANT; + } + else { + result = tIDENTIFIER; + } } if (IS_LABEL_POSSIBLE()) { - if (IS_LABEL_SUFFIX(0)) { - p->lstate = EXPR_BEG; - nextc(p); - tokfix(p); - yylval.id = intern(tok(p)); - return tLABEL; - } + if (IS_LABEL_SUFFIX(0)) { + p->lstate = EXPR_BEG; + nextc(p); + tokfix(p); + yylval.id = intern_cstr(tok(p)); + return tLABEL; + } } if (p->lstate != EXPR_DOT) { - const struct kwtable *kw; - - /* See if it is a reserved word. */ - kw = mrb_reserved_word(tok(p), toklen(p)); - if (kw) { - enum mrb_lex_state_enum state = p->lstate; - p->lstate = kw->state; - if (state == EXPR_FNAME) { - yylval.id = intern(kw->name); - return kw->id[0]; - } - if (p->lstate == EXPR_BEG) { - p->cmd_start = TRUE; - } - if (kw->id[0] == keyword_do) { - if (p->lpar_beg && p->lpar_beg == p->paren_nest) { - p->lpar_beg = 0; - p->paren_nest--; - return keyword_do_LAMBDA; - } - if (COND_P()) return keyword_do_cond; - if (CMDARG_P() && state != EXPR_CMDARG) - return keyword_do_block; - if (state == EXPR_ENDARG || state == EXPR_BEG) - return keyword_do_block; - return keyword_do; - } - if (state == EXPR_BEG || state == EXPR_VALUE) - return kw->id[0]; - else { - if (kw->id[0] != kw->id[1]) - p->lstate = EXPR_BEG; - return kw->id[1]; - } - } + const struct kwtable *kw; + + /* See if it is a reserved word. */ + kw = mrb_reserved_word(tok(p), toklen(p)); + if (kw) { + enum mrb_lex_state_enum state = p->lstate; + p->lstate = kw->state; + if (state == EXPR_FNAME) { + yylval.id = intern_cstr(kw->name); + return kw->id[0]; + } + if (p->lstate == EXPR_BEG) { + p->cmd_start = TRUE; + } + if (kw->id[0] == keyword_do) { + if (p->lpar_beg && p->lpar_beg == p->paren_nest) { + p->lpar_beg = 0; + p->paren_nest--; + return keyword_do_LAMBDA; + } + if (COND_P()) return keyword_do_cond; + if (CMDARG_P() && state != EXPR_CMDARG) + return keyword_do_block; + if (state == EXPR_ENDARG || state == EXPR_BEG) + return keyword_do_block; + return keyword_do; + } + if (state == EXPR_BEG || state == EXPR_VALUE) + return kw->id[0]; + else { + if (kw->id[0] != kw->id[1]) + p->lstate = EXPR_BEG; + return kw->id[1]; + } + } } if (IS_BEG() || p->lstate == EXPR_DOT || IS_ARG()) { - if (cmd_state) { - p->lstate = EXPR_CMDARG; - } - else { - p->lstate = EXPR_ARG; - } + if (cmd_state) { + p->lstate = EXPR_CMDARG; + } + else { + p->lstate = EXPR_ARG; + } } else if (p->lstate == EXPR_FNAME) { - p->lstate = EXPR_ENDFN; + p->lstate = EXPR_ENDFN; } else { - p->lstate = EXPR_END; + p->lstate = EXPR_END; } } { - mrb_sym ident = intern(tok(p)); + mrb_sym ident = intern_cstr(tok(p)); yylval.id = ident; #if 0 if (last_state != EXPR_DOT && islower(tok(p)[0]) && lvar_defined(ident)) { - p->lstate = EXPR_END; + p->lstate = EXPR_END; } #endif } @@ -5027,7 +5247,7 @@ parser_init_cxt(parser_state *p, mrbc_context *cxt) { if (!cxt) return; if (cxt->lineno) p->lineno = cxt->lineno; - if (cxt->filename) p->filename = cxt->filename; + if (cxt->filename) mrb_parser_set_filename(p, cxt->filename); if (cxt->syms) { int i; @@ -5062,21 +5282,19 @@ parser_update_cxt(parser_state *p, mrbc_context *cxt) } } -void codedump_all(mrb_state*, int); -void parser_dump(mrb_state *mrb, node *tree, int offset); +void mrb_codedump_all(mrb_state*, struct RProc*); +void mrb_parser_dump(mrb_state *mrb, node *tree, int offset); void mrb_parser_parse(parser_state *p, mrbc_context *c) { - if (setjmp(p->jmp) != 0) { - yyerror(p, "memory allocation error"); - p->nerr++; - p->tree = 0; - return; - } + struct mrb_jmpbuf buf; + p->jmp = &buf; + + MRB_TRY(p->jmp) { p->cmd_start = TRUE; - p->in_def = p->in_single = FALSE; + p->in_def = p->in_single = 0; p->nerr = p->nwarn = 0; p->lex_strterm = NULL; @@ -5087,8 +5305,17 @@ mrb_parser_parse(parser_state *p, mrbc_context *c) } parser_update_cxt(p, c); if (c && c->dump_result) { - parser_dump(p->mrb, p->tree, 0); + mrb_parser_dump(p->mrb, p->tree, 0); + } + } + MRB_CATCH(p->jmp) { + yyerror(p, "memory allocation error"); + p->nerr++; + p->tree = 0; + return; + } + MRB_END_EXC(p->jmp); } parser_state* @@ -5106,7 +5333,6 @@ mrb_parser_new(mrb_state *mrb) *p = parser_state_zero; p->mrb = mrb; p->pool = pool; - p->in_def = p->in_single = 0; p->s = p->send = NULL; #ifdef ENABLE_STDIO @@ -5114,9 +5340,9 @@ mrb_parser_new(mrb_state *mrb) #endif p->cmd_start = TRUE; - p->in_def = p->in_single = FALSE; + p->in_def = p->in_single = 0; - p->capture_errors = 0; + p->capture_errors = FALSE; p->lineno = 1; p->column = 0; #if defined(PARSER_TEST) || defined(PARSER_DEBUG) @@ -5124,7 +5350,12 @@ mrb_parser_new(mrb_state *mrb) #endif p->lex_strterm = NULL; - p->heredocs = p->parsing_heredoc = NULL; + p->all_heredocs = p->parsing_heredoc = NULL; + p->lex_strterm_before_heredoc = NULL; + + p->current_filename_index = -1; + p->filename_table = NULL; + p->filename_table_length = 0; return p; } @@ -5159,7 +5390,6 @@ mrbc_filename(mrb_state *mrb, mrbc_context *c, const char *s) memcpy(p, s, len + 1); c->filename = p; - c->lineno = 1; } return c->filename; } @@ -5171,6 +5401,41 @@ mrbc_partial_hook(mrb_state *mrb, mrbc_context *c, int (*func)(struct mrb_parser c->partial_data = data; } +void +mrb_parser_set_filename(struct mrb_parser_state *p, const char *f) +{ + mrb_sym sym; + size_t i; + mrb_sym* new_table; + + sym = mrb_intern_cstr(p->mrb, f); + p->filename = mrb_sym2name_len(p->mrb, sym, NULL); + p->lineno = (p->filename_table_length > 0)? 0 : 1; + + for (i = 0; i < p->filename_table_length; ++i) { + if (p->filename_table[i] == sym) { + p->current_filename_index = i; + return; + } + } + + p->current_filename_index = p->filename_table_length++; + + new_table = (mrb_sym*)parser_palloc(p, sizeof(mrb_sym) * p->filename_table_length); + if (p->filename_table) { + memcpy(new_table, p->filename_table, sizeof(mrb_sym) * p->filename_table_length); + } + p->filename_table = new_table; + p->filename_table[p->filename_table_length - 1] = sym; +} + +char const* mrb_parser_get_filename(struct mrb_parser_state* p, uint16_t idx) { + if (idx >= p->filename_table_length) { return NULL; } + else { + return mrb_sym2name_len(p->mrb, p->filename_table[idx], NULL); + } +} + #ifdef ENABLE_STDIO parser_state* mrb_parse_file(mrb_state *mrb, FILE *f, mrbc_context *c) @@ -5212,7 +5477,6 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) { struct RClass *target = mrb->object_class; struct RProc *proc; - int n; mrb_value v; if (!p) { @@ -5221,40 +5485,38 @@ load_exec(mrb_state *mrb, parser_state *p, mrbc_context *c) if (!p->tree || p->nerr) { if (p->capture_errors) { char buf[256]; + int n; n = snprintf(buf, sizeof(buf), "line %d: %s\n", - p->error_buffer[0].lineno, p->error_buffer[0].message); + p->error_buffer[0].lineno, p->error_buffer[0].message); mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, buf, n)); mrb_parser_free(p); return mrb_undef_value(); } else { - static const char msg[] = "syntax error"; - mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SYNTAX_ERROR, msg, sizeof(msg) - 1)); + mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SYNTAX_ERROR, "syntax error")); mrb_parser_free(p); return mrb_undef_value(); } } - n = mrb_generate_code(mrb, p); + proc = mrb_generate_code(mrb, p); mrb_parser_free(p); - if (n < 0) { - static const char msg[] = "codegen error"; - mrb->exc = mrb_obj_ptr(mrb_exc_new(mrb, E_SCRIPT_ERROR, msg, sizeof(msg) - 1)); - return mrb_nil_value(); + if (proc == NULL) { + mrb->exc = mrb_obj_ptr(mrb_exc_new_str_lit(mrb, E_SCRIPT_ERROR, "codegen error")); + return mrb_undef_value(); } if (c) { - if (c->dump_result) codedump_all(mrb, n); - if (c->no_exec) return mrb_fixnum_value(n); + if (c->dump_result) mrb_codedump_all(mrb, proc); + if (c->no_exec) return mrb_obj_value(proc); if (c->target_class) { target = c->target_class; } } - proc = mrb_proc_new(mrb, mrb->irep[n]); proc->target_class = target; if (mrb->c->ci) { mrb->c->ci->target_class = target; } - v = mrb_run(mrb, proc, mrb_top_self(mrb)); + v = mrb_toplevel_run(mrb, proc); if (mrb->exc) return mrb_nil_value(); return v; } @@ -5312,7 +5574,7 @@ static void dump_recur(mrb_state *mrb, node *tree, int offset) { while (tree) { - parser_dump(mrb, tree->car, offset); + mrb_parser_dump(mrb, tree->car, offset); tree = tree->cdr; } } @@ -5320,13 +5582,13 @@ dump_recur(mrb_state *mrb, node *tree, int offset) #endif void -parser_dump(mrb_state *mrb, node *tree, int offset) +mrb_parser_dump(mrb_state *mrb, node *tree, int offset) { #ifdef ENABLE_STDIO int n; if (!tree) return; - again: + again: dump_prefix(offset); n = (int)(intptr_t)tree->car; tree = tree->cdr; @@ -5341,7 +5603,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) if (tree->car) { dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); } tree = tree->cdr; if (tree->car) { @@ -5350,30 +5612,30 @@ parser_dump(mrb_state *mrb, node *tree, int offset) dump_prefix(offset+1); printf("rescue:\n"); while (n2) { - node *n3 = n2->car; - if (n3->car) { - dump_prefix(offset+2); - printf("handle classes:\n"); - dump_recur(mrb, n3->car, offset+3); - } - if (n3->cdr->car) { - dump_prefix(offset+2); - printf("exc_var:\n"); - parser_dump(mrb, n3->cdr->car, offset+3); - } - if (n3->cdr->cdr->car) { - dump_prefix(offset+2); - printf("rescue body:\n"); - parser_dump(mrb, n3->cdr->cdr->car, offset+3); - } - n2 = n2->cdr; + node *n3 = n2->car; + if (n3->car) { + dump_prefix(offset+2); + printf("handle classes:\n"); + dump_recur(mrb, n3->car, offset+3); + } + if (n3->cdr->car) { + dump_prefix(offset+2); + printf("exc_var:\n"); + mrb_parser_dump(mrb, n3->cdr->car, offset+3); + } + if (n3->cdr->cdr->car) { + dump_prefix(offset+2); + printf("rescue body:\n"); + mrb_parser_dump(mrb, n3->cdr->cdr->car, offset+3); + } + n2 = n2->cdr; } } tree = tree->cdr; if (tree->car) { dump_prefix(offset+1); printf("else:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); } break; @@ -5381,10 +5643,10 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_ENSURE:\n"); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("ensure:\n"); - parser_dump(mrb, tree->cdr->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->cdr, offset+2); break; case NODE_LAMBDA: @@ -5392,85 +5654,85 @@ parser_dump(mrb_state *mrb, node *tree, int offset) goto block; case NODE_BLOCK: - block: + block: printf("NODE_BLOCK:\n"); - tree = tree->cdr; - if (tree->car) { - node *n = tree->car; + tree = tree->cdr; + if (tree->car) { + node *n = tree->car; - if (n->car) { - dump_prefix(offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); - } - n = n->cdr; - if (n->car) { - dump_prefix(offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); - } - n = n->cdr; - if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + if (n->car) { + dump_prefix(offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n->car) { + dump_prefix(offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } } } - dump_prefix(offset+1); - printf("body:\n"); - parser_dump(mrb, tree->cdr->car, offset+2); - break; + n = n->cdr; + if (n->car) { + dump_prefix(offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + } + n = n->cdr; + if (n->car) { + dump_prefix(offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); + } + n = n->cdr; + if (n) { + dump_prefix(offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + } + } + dump_prefix(offset+1); + printf("body:\n"); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); + break; case NODE_IF: printf("NODE_IF:\n"); dump_prefix(offset+1); printf("cond:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("then:\n"); - parser_dump(mrb, tree->cdr->car, offset+2); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); if (tree->cdr->cdr->car) { dump_prefix(offset+1); printf("else:\n"); - parser_dump(mrb, tree->cdr->cdr->car, offset+2); + mrb_parser_dump(mrb, tree->cdr->cdr->car, offset+2); } break; case NODE_AND: printf("NODE_AND:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_OR: printf("NODE_OR:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_CASE: printf("NODE_CASE:\n"); if (tree->car) { - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); } tree = tree->cdr; while (tree) { @@ -5479,7 +5741,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) dump_recur(mrb, tree->car->car, offset+2); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); tree = tree->cdr; } break; @@ -5488,20 +5750,20 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_WHILE:\n"); dump_prefix(offset+1); printf("cond:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_UNTIL: printf("NODE_UNTIL:\n"); dump_prefix(offset+1); printf("cond:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_FOR: @@ -5512,35 +5774,35 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2->car) { - dump_prefix(offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); + dump_prefix(offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); } n2 = n2->cdr; if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("rest:\n"); - parser_dump(mrb, n2->car, offset+3); - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } + if (n2->car) { + dump_prefix(offset+2); + printf("rest:\n"); + mrb_parser_dump(mrb, n2->car, offset+3); + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } } } tree = tree->cdr; dump_prefix(offset+1); printf("in:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; dump_prefix(offset+1); printf("do:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); break; case NODE_SCOPE: @@ -5549,17 +5811,17 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2 && (n2->car || n2->cdr)) { - dump_prefix(offset+1); - printf("local variables:\n"); - dump_prefix(offset+2); - while (n2) { - if (n2->car) { - if (n2 != tree->car) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - } - n2 = n2->cdr; - } - printf("\n"); + dump_prefix(offset+1); + printf("local variables:\n"); + dump_prefix(offset+2); + while (n2) { + if (n2->car) { + if (n2 != tree->car) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + } + n2 = n2->cdr; + } + printf("\n"); } } tree = tree->cdr; @@ -5569,39 +5831,39 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_FCALL: case NODE_CALL: printf("NODE_CALL:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); dump_prefix(offset+1); printf("method='%s' (%d)\n", - mrb_sym2name(mrb, sym(tree->cdr->car)), - (int)(intptr_t)tree->cdr->car); + mrb_sym2name(mrb, sym(tree->cdr->car)), + (int)(intptr_t)tree->cdr->car); tree = tree->cdr->cdr->car; if (tree) { dump_prefix(offset+1); printf("args:\n"); dump_recur(mrb, tree->car, offset+2); if (tree->cdr) { - dump_prefix(offset+1); - printf("block:\n"); - parser_dump(mrb, tree->cdr, offset+2); + dump_prefix(offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); } } break; case NODE_DOT2: printf("NODE_DOT2:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_DOT3: printf("NODE_DOT3:\n"); - parser_dump(mrb, tree->car, offset+1); - parser_dump(mrb, tree->cdr, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->cdr, offset+1); break; case NODE_COLON2: printf("NODE_COLON2:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); dump_prefix(offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->cdr))); break; @@ -5622,27 +5884,27 @@ parser_dump(mrb_state *mrb, node *tree, int offset) while (tree) { dump_prefix(offset+1); printf("key:\n"); - parser_dump(mrb, tree->car->car, offset+2); + mrb_parser_dump(mrb, tree->car->car, offset+2); dump_prefix(offset+1); printf("value:\n"); - parser_dump(mrb, tree->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->car->cdr, offset+2); tree = tree->cdr; } break; case NODE_SPLAT: printf("NODE_SPLAT:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_ASGN: printf("NODE_ASGN:\n"); dump_prefix(offset+1); printf("lhs:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); dump_prefix(offset+1); printf("rhs:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_MASGN: @@ -5653,48 +5915,48 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2->car) { - dump_prefix(offset+2); - printf("pre:\n"); - dump_recur(mrb, n2->car, offset+3); + dump_prefix(offset+2); + printf("pre:\n"); + dump_recur(mrb, n2->car, offset+3); } n2 = n2->cdr; if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("rest:\n"); - if (n2->car == (node*)-1) { - dump_prefix(offset+2); - printf("(empty)\n"); - } - else { - parser_dump(mrb, n2->car, offset+3); - } - } - n2 = n2->cdr; - if (n2) { - if (n2->car) { - dump_prefix(offset+2); - printf("post:\n"); - dump_recur(mrb, n2->car, offset+3); - } - } + if (n2->car) { + dump_prefix(offset+2); + printf("rest:\n"); + if (n2->car == (node*)-1) { + dump_prefix(offset+2); + printf("(empty)\n"); + } + else { + mrb_parser_dump(mrb, n2->car, offset+3); + } + } + n2 = n2->cdr; + if (n2) { + if (n2->car) { + dump_prefix(offset+2); + printf("post:\n"); + dump_recur(mrb, n2->car, offset+3); + } + } } } dump_prefix(offset+1); printf("rhs:\n"); - parser_dump(mrb, tree->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr, offset+2); break; case NODE_OP_ASGN: printf("NODE_OP_ASGN:\n"); dump_prefix(offset+1); printf("lhs:\n"); - parser_dump(mrb, tree->car, offset+2); + mrb_parser_dump(mrb, tree->car, offset+2); tree = tree->cdr; dump_prefix(offset+1); printf("op='%s' (%d)\n", mrb_sym2name(mrb, sym(tree->car)), (int)(intptr_t)tree->car); tree = tree->cdr; - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); break; case NODE_SUPER: @@ -5704,9 +5966,9 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("args:\n"); dump_recur(mrb, tree->car, offset+2); if (tree->cdr) { - dump_prefix(offset+1); - printf("block:\n"); - parser_dump(mrb, tree->cdr, offset+2); + dump_prefix(offset+1); + printf("block:\n"); + mrb_parser_dump(mrb, tree->cdr, offset+2); } } break; @@ -5717,7 +5979,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_RETURN: printf("NODE_RETURN:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_YIELD: @@ -5727,12 +5989,12 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_BREAK: printf("NODE_BREAK:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_NEXT: printf("NODE_NEXT:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_REDO: @@ -5767,10 +6029,10 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("NODE_MATCH:\n"); dump_prefix(offset + 1); printf("lhs:\n"); - parser_dump(mrb, tree->car, offset + 2); + mrb_parser_dump(mrb, tree->car, offset + 2); dump_prefix(offset + 1); printf("rhs:\n"); - parser_dump(mrb, tree->cdr, offset + 2); + mrb_parser_dump(mrb, tree->cdr, offset + 2); break; case NODE_BACK_REF: @@ -5787,7 +6049,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_BLOCK_ARG: printf("NODE_BLOCK_ARG:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_INT: @@ -5800,7 +6062,7 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_NEGATE: printf("NODE_NEGATE\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_STR: @@ -5856,8 +6118,8 @@ parser_dump(mrb_state *mrb, node *tree, int offset) case NODE_ALIAS: printf("NODE_ALIAS %s %s:\n", - mrb_sym2name(mrb, sym(tree->car)), - mrb_sym2name(mrb, sym(tree->cdr))); + mrb_sym2name(mrb, sym(tree->car)), + mrb_sym2name(mrb, sym(tree->cdr))); break; case NODE_UNDEF: @@ -5865,8 +6127,8 @@ parser_dump(mrb_state *mrb, node *tree, int offset) { node *t = tree; while (t) { - printf(" %s", mrb_sym2name(mrb, sym(t->car))); - t = t->cdr; + printf(" %s", mrb_sym2name(mrb, sym(t->car))); + t = t->cdr; } } printf(":\n"); @@ -5883,18 +6145,18 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else { - parser_dump(mrb, tree->car->car, offset+1); + mrb_parser_dump(mrb, tree->car->car, offset+1); dump_prefix(offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } if (tree->cdr->car) { dump_prefix(offset+1); printf("super:\n"); - parser_dump(mrb, tree->cdr->car, offset+2); + mrb_parser_dump(mrb, tree->cdr->car, offset+2); } dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->cdr->car->cdr, offset+2); break; case NODE_MODULE: @@ -5908,21 +6170,21 @@ parser_dump(mrb_state *mrb, node *tree, int offset) printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } else { - parser_dump(mrb, tree->car->car, offset+1); + mrb_parser_dump(mrb, tree->car->car, offset+1); dump_prefix(offset+1); printf("::%s\n", mrb_sym2name(mrb, sym(tree->car->cdr))); } dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); break; case NODE_SCLASS: printf("NODE_SCLASS:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); dump_prefix(offset+1); printf("body:\n"); - parser_dump(mrb, tree->cdr->car->cdr, offset+2); + mrb_parser_dump(mrb, tree->cdr->car->cdr, offset+2); break; case NODE_DEF: @@ -5934,17 +6196,17 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n2 = tree->car; if (n2 && (n2->car || n2->cdr)) { - dump_prefix(offset+1); - printf("local variables:\n"); - dump_prefix(offset+2); - while (n2) { - if (n2->car) { - if (n2 != tree->car) printf(", "); - printf("%s", mrb_sym2name(mrb, sym(n2->car))); - } - n2 = n2->cdr; - } - printf("\n"); + dump_prefix(offset+1); + printf("local variables:\n"); + dump_prefix(offset+2); + while (n2) { + if (n2->car) { + if (n2 != tree->car) printf(", "); + printf("%s", mrb_sym2name(mrb, sym(n2->car))); + } + n2 = n2->cdr; + } + printf("\n"); } } tree = tree->cdr; @@ -5952,48 +6214,48 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n = tree->car; if (n->car) { - dump_prefix(offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } + dump_prefix(offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + dump_prefix(offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + dump_prefix(offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); } } - parser_dump(mrb, tree->cdr->car, offset+1); + mrb_parser_dump(mrb, tree->cdr->car, offset+1); break; case NODE_SDEF: printf("NODE_SDEF:\n"); - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); tree = tree->cdr; dump_prefix(offset+1); printf(":%s\n", mrb_sym2name(mrb, sym(tree->car))); @@ -6002,54 +6264,54 @@ parser_dump(mrb_state *mrb, node *tree, int offset) node *n = tree->car; if (n->car) { - dump_prefix(offset+1); - printf("mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("optional args:\n"); - { - node *n2 = n->car; - - while (n2) { - dump_prefix(offset+2); - printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); - parser_dump(mrb, n2->car->cdr, 0); - n2 = n2->cdr; - } - } + dump_prefix(offset+1); + printf("optional args:\n"); + { + node *n2 = n->car; + + while (n2) { + dump_prefix(offset+2); + printf("%s=", mrb_sym2name(mrb, sym(n2->car->car))); + mrb_parser_dump(mrb, n2->car->cdr, 0); + n2 = n2->cdr; + } + } } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); + dump_prefix(offset+1); + printf("rest=*%s\n", mrb_sym2name(mrb, sym(n->car))); } n = n->cdr; if (n->car) { - dump_prefix(offset+1); - printf("post mandatory args:\n"); - dump_recur(mrb, n->car, offset+2); + dump_prefix(offset+1); + printf("post mandatory args:\n"); + dump_recur(mrb, n->car, offset+2); } n = n->cdr; if (n) { - dump_prefix(offset+1); - printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); + dump_prefix(offset+1); + printf("blk=&%s\n", mrb_sym2name(mrb, sym(n))); } } tree = tree->cdr; - parser_dump(mrb, tree->car, offset+1); + mrb_parser_dump(mrb, tree->car, offset+1); break; case NODE_POSTEXE: printf("NODE_POSTEXE:\n"); - parser_dump(mrb, tree, offset+1); + mrb_parser_dump(mrb, tree, offset+1); break; case NODE_HEREDOC: printf("NODE_HEREDOC:\n"); - parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); + mrb_parser_dump(mrb, ((parser_heredoc_info*)tree)->doc, offset+1); break; default: |
