mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
* parse.y (ripper_yylval_id, ripper_get_{id,value}): wrap ID by
NODE to track local variable assignment. * parse.y (lvar_defined_gen, assignable_gen): enable local variable check. [ruby-core:24923] * parse.y (validate): use value only. * test/ripper/test_parser_events.rb (test_local_variables): tests based on a patch from Magnus Holm in [ruby-core:25885]. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@25187 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
e9c728fea3
commit
aec8a4b0a4
4 changed files with 337 additions and 179 deletions
13
ChangeLog
13
ChangeLog
|
@ -1,3 +1,16 @@
|
||||||
|
Fri Oct 2 20:37:37 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* parse.y (ripper_yylval_id, ripper_get_{id,value}): wrap ID by
|
||||||
|
NODE to track local variable assignment.
|
||||||
|
|
||||||
|
* parse.y (lvar_defined_gen, assignable_gen): enable local
|
||||||
|
variable check. [ruby-core:24923]
|
||||||
|
|
||||||
|
* parse.y (validate): use value only.
|
||||||
|
|
||||||
|
* test/ripper/test_parser_events.rb (test_local_variables): tests
|
||||||
|
based on a patch from Magnus Holm in [ruby-core:25885].
|
||||||
|
|
||||||
Fri Oct 2 15:34:15 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
Fri Oct 2 15:34:15 2009 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
* thread.c (ruby_suppress_tracing): get rid of clobbering by
|
* thread.c (ruby_suppress_tracing): get rid of clobbering by
|
||||||
|
|
362
parse.y
362
parse.y
|
@ -105,7 +105,6 @@ struct local_vars {
|
||||||
#define DVARS_SPECIAL_P(tbl) (!POINTER_P(tbl))
|
#define DVARS_SPECIAL_P(tbl) (!POINTER_P(tbl))
|
||||||
#define POINTER_P(val) ((VALUE)(val) & ~(VALUE)3)
|
#define POINTER_P(val) ((VALUE)(val) & ~(VALUE)3)
|
||||||
|
|
||||||
#ifndef RIPPER
|
|
||||||
static int
|
static int
|
||||||
vtable_size(const struct vtable *tbl)
|
vtable_size(const struct vtable *tbl)
|
||||||
{
|
{
|
||||||
|
@ -174,6 +173,7 @@ vtable_included(const struct vtable * tbl, ID id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef RIPPER
|
||||||
typedef struct token_info {
|
typedef struct token_info {
|
||||||
const char *token;
|
const char *token;
|
||||||
int linenum;
|
int linenum;
|
||||||
|
@ -374,8 +374,6 @@ static NODE *call_uni_op_gen(struct parser_params*,NODE*,ID);
|
||||||
|
|
||||||
static NODE *new_args_gen(struct parser_params*,NODE*,NODE*,ID,NODE*,ID);
|
static NODE *new_args_gen(struct parser_params*,NODE*,NODE*,ID,NODE*,ID);
|
||||||
#define new_args(f,o,r,p,b) new_args_gen(parser, f,o,r,p,b)
|
#define new_args(f,o,r,p,b) new_args_gen(parser, f,o,r,p,b)
|
||||||
static void shadowing_lvar_gen(struct parser_params*,ID);
|
|
||||||
#define shadowing_lvar(name) shadowing_lvar_gen(parser, name)
|
|
||||||
|
|
||||||
static NODE *negate_lit(NODE*);
|
static NODE *negate_lit(NODE*);
|
||||||
static NODE *ret_args_gen(struct parser_params*,NODE*);
|
static NODE *ret_args_gen(struct parser_params*,NODE*);
|
||||||
|
@ -388,8 +386,7 @@ static NODE *gettable_gen(struct parser_params*,ID);
|
||||||
#define gettable(id) gettable_gen(parser,id)
|
#define gettable(id) gettable_gen(parser,id)
|
||||||
static NODE *assignable_gen(struct parser_params*,ID,NODE*);
|
static NODE *assignable_gen(struct parser_params*,ID,NODE*);
|
||||||
#define assignable(id,node) assignable_gen(parser, id, node)
|
#define assignable(id,node) assignable_gen(parser, id, node)
|
||||||
static void new_bv_gen(struct parser_params*,ID);
|
|
||||||
#define new_bv(id) new_bv_gen(parser, id)
|
|
||||||
static NODE *aryset_gen(struct parser_params*,NODE*,NODE*);
|
static NODE *aryset_gen(struct parser_params*,NODE*,NODE*);
|
||||||
#define aryset(node1,node2) aryset_gen(parser, node1, node2)
|
#define aryset(node1,node2) aryset_gen(parser, node1, node2)
|
||||||
static NODE *attrset_gen(struct parser_params*,NODE*,ID);
|
static NODE *attrset_gen(struct parser_params*,NODE*,ID);
|
||||||
|
@ -403,32 +400,8 @@ static NODE *node_assign_gen(struct parser_params*,NODE*,NODE*);
|
||||||
static NODE *match_op_gen(struct parser_params*,NODE*,NODE*);
|
static NODE *match_op_gen(struct parser_params*,NODE*,NODE*);
|
||||||
#define match_op(node1,node2) match_op_gen(parser, node1, node2)
|
#define match_op(node1,node2) match_op_gen(parser, node1, node2)
|
||||||
|
|
||||||
static void local_push_gen(struct parser_params*,int);
|
|
||||||
#define local_push(top) local_push_gen(parser,top)
|
|
||||||
static void local_pop_gen(struct parser_params*);
|
|
||||||
#define local_pop() local_pop_gen(parser)
|
|
||||||
static int local_var_gen(struct parser_params*, ID);
|
|
||||||
#define local_var(id) local_var_gen(parser, id);
|
|
||||||
static int arg_var_gen(struct parser_params*, ID);
|
|
||||||
#define arg_var(id) arg_var_gen(parser, id)
|
|
||||||
static int local_id_gen(struct parser_params*, ID);
|
|
||||||
#define local_id(id) local_id_gen(parser, id)
|
|
||||||
static ID *local_tbl_gen(struct parser_params*);
|
static ID *local_tbl_gen(struct parser_params*);
|
||||||
#define local_tbl() local_tbl_gen(parser)
|
#define local_tbl() local_tbl_gen(parser)
|
||||||
static ID internal_id_gen(struct parser_params*);
|
|
||||||
#define internal_id() internal_id_gen(parser)
|
|
||||||
|
|
||||||
static void dyna_push_gen(struct parser_params*);
|
|
||||||
#define dyna_push() dyna_push_gen(parser)
|
|
||||||
static void dyna_pop_gen(struct parser_params*);
|
|
||||||
#define dyna_pop() dyna_pop_gen(parser)
|
|
||||||
static int dyna_in_block_gen(struct parser_params*);
|
|
||||||
#define dyna_in_block() dyna_in_block_gen(parser)
|
|
||||||
#define dyna_var(id) local_var(id)
|
|
||||||
static int dvar_defined_gen(struct parser_params*,ID);
|
|
||||||
#define dvar_defined(id) dvar_defined_gen(parser, id)
|
|
||||||
static int dvar_curr_gen(struct parser_params*,ID);
|
|
||||||
#define dvar_curr(id) dvar_curr_gen(parser, id)
|
|
||||||
|
|
||||||
static void fixup_nodes(NODE **);
|
static void fixup_nodes(NODE **);
|
||||||
|
|
||||||
|
@ -445,9 +418,53 @@ static void reg_fragment_check_gen(struct parser_params*, VALUE, int);
|
||||||
#define reg_fragment_check(str,options) reg_fragment_check_gen(parser, str, options)
|
#define reg_fragment_check(str,options) reg_fragment_check_gen(parser, str, options)
|
||||||
static NODE *reg_named_capture_assign_gen(struct parser_params* parser, VALUE regexp, NODE *match);
|
static NODE *reg_named_capture_assign_gen(struct parser_params* parser, VALUE regexp, NODE *match);
|
||||||
#define reg_named_capture_assign(regexp,match) reg_named_capture_assign_gen(parser,regexp,match)
|
#define reg_named_capture_assign(regexp,match) reg_named_capture_assign_gen(parser,regexp,match)
|
||||||
|
|
||||||
|
#define get_id(id) (id)
|
||||||
|
#define get_value(val) (val)
|
||||||
#else
|
#else
|
||||||
#define remove_begin(node) (node)
|
#define remove_begin(node) (node)
|
||||||
|
#define rb_dvar_defined(id) 0
|
||||||
|
#define rb_local_defined(id) 0
|
||||||
|
static ID ripper_get_id(VALUE);
|
||||||
|
#define get_id(id) ripper_get_id(id)
|
||||||
|
static VALUE ripper_get_value(VALUE);
|
||||||
|
#define get_value(val) ripper_get_value(val)
|
||||||
|
static VALUE assignable_gen(struct parser_params*,VALUE);
|
||||||
|
#define assignable(lhs,node) assignable_gen(parser, lhs)
|
||||||
#endif /* !RIPPER */
|
#endif /* !RIPPER */
|
||||||
|
|
||||||
|
static ID formal_argument_gen(struct parser_params*, ID);
|
||||||
|
#define formal_argument(id) formal_argument_gen(parser, id)
|
||||||
|
static ID shadowing_lvar_gen(struct parser_params*,ID);
|
||||||
|
#define shadowing_lvar(name) shadowing_lvar_gen(parser, name)
|
||||||
|
static void new_bv_gen(struct parser_params*,ID);
|
||||||
|
#define new_bv(id) new_bv_gen(parser, id)
|
||||||
|
|
||||||
|
static void local_push_gen(struct parser_params*,int);
|
||||||
|
#define local_push(top) local_push_gen(parser,top)
|
||||||
|
static void local_pop_gen(struct parser_params*);
|
||||||
|
#define local_pop() local_pop_gen(parser)
|
||||||
|
static int local_var_gen(struct parser_params*, ID);
|
||||||
|
#define local_var(id) local_var_gen(parser, id);
|
||||||
|
static int arg_var_gen(struct parser_params*, ID);
|
||||||
|
#define arg_var(id) arg_var_gen(parser, id)
|
||||||
|
static int local_id_gen(struct parser_params*, ID);
|
||||||
|
#define local_id(id) local_id_gen(parser, id)
|
||||||
|
static ID internal_id_gen(struct parser_params*);
|
||||||
|
#define internal_id() internal_id_gen(parser)
|
||||||
|
|
||||||
|
static void dyna_push_gen(struct parser_params*);
|
||||||
|
#define dyna_push() dyna_push_gen(parser)
|
||||||
|
static void dyna_pop_gen(struct parser_params*);
|
||||||
|
#define dyna_pop() dyna_pop_gen(parser)
|
||||||
|
static int dyna_in_block_gen(struct parser_params*);
|
||||||
|
#define dyna_in_block() dyna_in_block_gen(parser)
|
||||||
|
#define dyna_var(id) local_var(id)
|
||||||
|
static int dvar_defined_gen(struct parser_params*,ID);
|
||||||
|
#define dvar_defined(id) dvar_defined_gen(parser, id)
|
||||||
|
static int dvar_curr_gen(struct parser_params*,ID);
|
||||||
|
#define dvar_curr(id) dvar_curr_gen(parser, id)
|
||||||
|
|
||||||
static int lvar_defined_gen(struct parser_params*, ID);
|
static int lvar_defined_gen(struct parser_params*, ID);
|
||||||
#define lvar_defined(id) lvar_defined_gen(parser, id)
|
#define lvar_defined(id) lvar_defined_gen(parser, id)
|
||||||
|
|
||||||
|
@ -763,6 +780,7 @@ program : {
|
||||||
$<num>$ = compile_for_eval || rb_parse_in_main();
|
$<num>$ = compile_for_eval || rb_parse_in_main();
|
||||||
local_push($<num>$);
|
local_push($<num>$);
|
||||||
/*%
|
/*%
|
||||||
|
local_push(0);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
compstmt
|
compstmt
|
||||||
|
@ -780,11 +798,11 @@ program : {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ruby_eval_tree = NEW_SCOPE(0, block_append(ruby_eval_tree, $2));
|
ruby_eval_tree = NEW_SCOPE(0, block_append(ruby_eval_tree, $2));
|
||||||
local_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
parser->result = dispatch1(program, $$);
|
parser->result = dispatch1(program, $$);
|
||||||
%*/
|
%*/
|
||||||
|
local_pop();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -812,7 +830,7 @@ bodystmt : compstmt
|
||||||
}
|
}
|
||||||
fixpos($$, $1);
|
fixpos($$, $1);
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch4(body_stmt,
|
$$ = dispatch4(bodystmt,
|
||||||
escape_Qundef($1),
|
escape_Qundef($1),
|
||||||
escape_Qundef($2),
|
escape_Qundef($2),
|
||||||
escape_Qundef($3),
|
escape_Qundef($3),
|
||||||
|
@ -1235,8 +1253,8 @@ block_command : block_call
|
||||||
|
|
||||||
cmd_brace_block : tLBRACE_ARG
|
cmd_brace_block : tLBRACE_ARG
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
dyna_push();
|
dyna_push();
|
||||||
|
/*%%%*/
|
||||||
$<num>$ = ruby_sourceline;
|
$<num>$ = ruby_sourceline;
|
||||||
/*%
|
/*%
|
||||||
%*/
|
%*/
|
||||||
|
@ -1248,10 +1266,10 @@ cmd_brace_block : tLBRACE_ARG
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_ITER($3,$4);
|
$$ = NEW_ITER($3,$4);
|
||||||
nd_set_line($$, $<num>2);
|
nd_set_line($$, $<num>2);
|
||||||
dyna_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch2(brace_block, escape_Qundef($3), $4);
|
$$ = dispatch2(brace_block, escape_Qundef($3), $4);
|
||||||
%*/
|
%*/
|
||||||
|
dyna_pop();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -1515,11 +1533,7 @@ mlhs_post : mlhs_item
|
||||||
|
|
||||||
mlhs_node : variable
|
mlhs_node : variable
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
$$ = assignable($1, 0);
|
$$ = assignable($1, 0);
|
||||||
/*%
|
|
||||||
$$ = $1;
|
|
||||||
%*/
|
|
||||||
}
|
}
|
||||||
| primary_value '[' opt_call_args rbracket
|
| primary_value '[' opt_call_args rbracket
|
||||||
{
|
{
|
||||||
|
@ -1589,10 +1603,11 @@ mlhs_node : variable
|
||||||
|
|
||||||
lhs : variable
|
lhs : variable
|
||||||
{
|
{
|
||||||
|
$$ = assignable($1, 0);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
if (!($$ = assignable($1, 0))) $$ = NEW_BEGIN(0);
|
if (!$$) $$ = NEW_BEGIN(0);
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch1(var_field, $1);
|
$$ = dispatch1(var_field, $$);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
| primary_value '[' opt_call_args rbracket
|
| primary_value '[' opt_call_args rbracket
|
||||||
|
@ -2807,8 +2822,8 @@ primary : literal
|
||||||
{
|
{
|
||||||
if (in_def || in_single)
|
if (in_def || in_single)
|
||||||
yyerror("class definition in method body");
|
yyerror("class definition in method body");
|
||||||
/*%%%*/
|
|
||||||
local_push(0);
|
local_push(0);
|
||||||
|
/*%%%*/
|
||||||
$<num>$ = ruby_sourceline;
|
$<num>$ = ruby_sourceline;
|
||||||
/*%
|
/*%
|
||||||
%*/
|
%*/
|
||||||
|
@ -2819,10 +2834,10 @@ primary : literal
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_CLASS($2, $5, $3);
|
$$ = NEW_CLASS($2, $5, $3);
|
||||||
nd_set_line($$, $<num>4);
|
nd_set_line($$, $<num>4);
|
||||||
local_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch3(class, $2, $3, $5);
|
$$ = dispatch3(class, $2, $3, $5);
|
||||||
%*/
|
%*/
|
||||||
|
local_pop();
|
||||||
}
|
}
|
||||||
| k_class tLSHFT expr
|
| k_class tLSHFT expr
|
||||||
{
|
{
|
||||||
|
@ -2833,10 +2848,7 @@ primary : literal
|
||||||
{
|
{
|
||||||
$<num>$ = in_single;
|
$<num>$ = in_single;
|
||||||
in_single = 0;
|
in_single = 0;
|
||||||
/*%%%*/
|
|
||||||
local_push(0);
|
local_push(0);
|
||||||
/*%
|
|
||||||
%*/
|
|
||||||
}
|
}
|
||||||
bodystmt
|
bodystmt
|
||||||
k_end
|
k_end
|
||||||
|
@ -2844,10 +2856,10 @@ primary : literal
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_SCLASS($3, $7);
|
$$ = NEW_SCLASS($3, $7);
|
||||||
fixpos($$, $3);
|
fixpos($$, $3);
|
||||||
local_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch2(sclass, $3, $7);
|
$$ = dispatch2(sclass, $3, $7);
|
||||||
%*/
|
%*/
|
||||||
|
local_pop();
|
||||||
in_def = $<num>4;
|
in_def = $<num>4;
|
||||||
in_single = $<num>6;
|
in_single = $<num>6;
|
||||||
}
|
}
|
||||||
|
@ -2855,8 +2867,8 @@ primary : literal
|
||||||
{
|
{
|
||||||
if (in_def || in_single)
|
if (in_def || in_single)
|
||||||
yyerror("module definition in method body");
|
yyerror("module definition in method body");
|
||||||
/*%%%*/
|
|
||||||
local_push(0);
|
local_push(0);
|
||||||
|
/*%%%*/
|
||||||
$<num>$ = ruby_sourceline;
|
$<num>$ = ruby_sourceline;
|
||||||
/*%
|
/*%
|
||||||
%*/
|
%*/
|
||||||
|
@ -2867,20 +2879,17 @@ primary : literal
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_MODULE($2, $4);
|
$$ = NEW_MODULE($2, $4);
|
||||||
nd_set_line($$, $<num>3);
|
nd_set_line($$, $<num>3);
|
||||||
local_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch2(module, $2, $4);
|
$$ = dispatch2(module, $2, $4);
|
||||||
%*/
|
%*/
|
||||||
|
local_pop();
|
||||||
}
|
}
|
||||||
| k_def fname
|
| k_def fname
|
||||||
{
|
{
|
||||||
$<id>$ = cur_mid;
|
$<id>$ = cur_mid;
|
||||||
cur_mid = $2;
|
cur_mid = $2;
|
||||||
in_def++;
|
in_def++;
|
||||||
/*%%%*/
|
|
||||||
local_push(0);
|
local_push(0);
|
||||||
/*%
|
|
||||||
%*/
|
|
||||||
}
|
}
|
||||||
f_arglist
|
f_arglist
|
||||||
bodystmt
|
bodystmt
|
||||||
|
@ -2891,10 +2900,10 @@ primary : literal
|
||||||
reduce_nodes(&body);
|
reduce_nodes(&body);
|
||||||
$$ = NEW_DEFN($2, $4, body, NOEX_PRIVATE);
|
$$ = NEW_DEFN($2, $4, body, NOEX_PRIVATE);
|
||||||
fixpos($$, $4);
|
fixpos($$, $4);
|
||||||
local_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch3(def, $2, $4, $5);
|
$$ = dispatch3(def, $2, $4, $5);
|
||||||
%*/
|
%*/
|
||||||
|
local_pop();
|
||||||
in_def--;
|
in_def--;
|
||||||
cur_mid = $<id>3;
|
cur_mid = $<id>3;
|
||||||
}
|
}
|
||||||
|
@ -2902,10 +2911,7 @@ primary : literal
|
||||||
{
|
{
|
||||||
in_single++;
|
in_single++;
|
||||||
lex_state = EXPR_END; /* force for args */
|
lex_state = EXPR_END; /* force for args */
|
||||||
/*%%%*/
|
|
||||||
local_push(0);
|
local_push(0);
|
||||||
/*%
|
|
||||||
%*/
|
|
||||||
}
|
}
|
||||||
f_arglist
|
f_arglist
|
||||||
bodystmt
|
bodystmt
|
||||||
|
@ -2916,10 +2922,10 @@ primary : literal
|
||||||
reduce_nodes(&body);
|
reduce_nodes(&body);
|
||||||
$$ = NEW_DEFS($2, $5, $7, body);
|
$$ = NEW_DEFS($2, $5, $7, body);
|
||||||
fixpos($$, $2);
|
fixpos($$, $2);
|
||||||
local_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch5(defs, $2, $3, $5, $7, $8);
|
$$ = dispatch5(defs, $2, $3, $5, $7, $8);
|
||||||
%*/
|
%*/
|
||||||
|
local_pop();
|
||||||
in_single--;
|
in_single--;
|
||||||
}
|
}
|
||||||
| keyword_break
|
| keyword_break
|
||||||
|
@ -3108,10 +3114,10 @@ for_var : lhs
|
||||||
|
|
||||||
f_marg : f_norm_arg
|
f_marg : f_norm_arg
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
$$ = assignable($1, 0);
|
$$ = assignable($1, 0);
|
||||||
|
/*%%%*/
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch1(mlhs_paren, $1);
|
$$ = dispatch1(mlhs_paren, $$);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
| tLPAREN f_margs rparen
|
| tLPAREN f_margs rparen
|
||||||
|
@ -3152,18 +3158,20 @@ f_margs : f_marg_list
|
||||||
}
|
}
|
||||||
| f_marg_list ',' tSTAR f_norm_arg
|
| f_marg_list ',' tSTAR f_norm_arg
|
||||||
{
|
{
|
||||||
|
$$ = assignable($4, 0);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_MASGN($1, assignable($4, 0));
|
$$ = NEW_MASGN($1, $$);
|
||||||
/*%
|
/*%
|
||||||
$$ = mlhs_add_star($1, $4);
|
$$ = mlhs_add_star($1, $$);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
| f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
|
| f_marg_list ',' tSTAR f_norm_arg ',' f_marg_list
|
||||||
{
|
{
|
||||||
|
$$ = assignable($4, 0);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_MASGN($1, NEW_POSTARG(assignable($4, 0), $6));
|
$$ = NEW_MASGN($1, NEW_POSTARG($$, $6));
|
||||||
/*%
|
/*%
|
||||||
$$ = mlhs_add_star($1, $4);
|
$$ = mlhs_add_star($1, $$);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
| f_marg_list ',' tSTAR
|
| f_marg_list ',' tSTAR
|
||||||
|
@ -3184,21 +3192,23 @@ f_margs : f_marg_list
|
||||||
}
|
}
|
||||||
| tSTAR f_norm_arg
|
| tSTAR f_norm_arg
|
||||||
{
|
{
|
||||||
|
$$ = assignable($2, 0);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_MASGN(0, assignable($2, 0));
|
$$ = NEW_MASGN(0, $$);
|
||||||
/*%
|
/*%
|
||||||
$$ = mlhs_add_star(mlhs_new(), $2);
|
$$ = mlhs_add_star(mlhs_new(), $$);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
| tSTAR f_norm_arg ',' f_marg_list
|
| tSTAR f_norm_arg ',' f_marg_list
|
||||||
{
|
{
|
||||||
|
$$ = assignable($2, 0);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_MASGN(0, NEW_POSTARG(assignable($2, 0), $4));
|
$$ = NEW_MASGN(0, NEW_POSTARG($$, $4));
|
||||||
/*%
|
/*%
|
||||||
#if 0
|
#if 0
|
||||||
TODO: Check me
|
TODO: Check me
|
||||||
#endif
|
#endif
|
||||||
$$ = mlhs_add_star($2, $4);
|
$$ = mlhs_add_star($$, $4);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
| tSTAR
|
| tSTAR
|
||||||
|
@ -3407,8 +3417,8 @@ bv_decls : bvar
|
||||||
|
|
||||||
bvar : tIDENTIFIER
|
bvar : tIDENTIFIER
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
new_bv($1);
|
new_bv($1);
|
||||||
|
/*%%%*/
|
||||||
/*%
|
/*%
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
%*/
|
%*/
|
||||||
|
@ -3420,10 +3430,7 @@ bvar : tIDENTIFIER
|
||||||
;
|
;
|
||||||
|
|
||||||
lambda : {
|
lambda : {
|
||||||
/*%%%*/
|
|
||||||
dyna_push();
|
dyna_push();
|
||||||
/*%
|
|
||||||
%*/
|
|
||||||
$<num>$ = lpar_beg;
|
$<num>$ = lpar_beg;
|
||||||
lpar_beg = ++paren_nest;
|
lpar_beg = ++paren_nest;
|
||||||
}
|
}
|
||||||
|
@ -3434,10 +3441,10 @@ lambda : {
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
$$->nd_body = NEW_SCOPE($2->nd_head, $3);
|
$$->nd_body = NEW_SCOPE($2->nd_head, $3);
|
||||||
dyna_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch2(lambda, $2, $3);
|
$$ = dispatch2(lambda, $2, $3);
|
||||||
%*/
|
%*/
|
||||||
|
dyna_pop();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -3471,8 +3478,8 @@ lambda_body : tLAMBEG compstmt '}'
|
||||||
|
|
||||||
do_block : keyword_do_block
|
do_block : keyword_do_block
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
dyna_push();
|
dyna_push();
|
||||||
|
/*%%%*/
|
||||||
$<num>$ = ruby_sourceline;
|
$<num>$ = ruby_sourceline;
|
||||||
/*% %*/
|
/*% %*/
|
||||||
}
|
}
|
||||||
|
@ -3483,10 +3490,10 @@ do_block : keyword_do_block
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_ITER($3,$4);
|
$$ = NEW_ITER($3,$4);
|
||||||
nd_set_line($$, $<num>2);
|
nd_set_line($$, $<num>2);
|
||||||
dyna_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch2(do_block, escape_Qundef($3), $4);
|
$$ = dispatch2(do_block, escape_Qundef($3), $4);
|
||||||
%*/
|
%*/
|
||||||
|
dyna_pop();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -3617,8 +3624,8 @@ method_call : operation paren_args
|
||||||
|
|
||||||
brace_block : '{'
|
brace_block : '{'
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
dyna_push();
|
dyna_push();
|
||||||
|
/*%%%*/
|
||||||
$<num>$ = ruby_sourceline;
|
$<num>$ = ruby_sourceline;
|
||||||
/*%
|
/*%
|
||||||
%*/
|
%*/
|
||||||
|
@ -3629,15 +3636,15 @@ brace_block : '{'
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_ITER($3,$4);
|
$$ = NEW_ITER($3,$4);
|
||||||
nd_set_line($$, $<num>2);
|
nd_set_line($$, $<num>2);
|
||||||
dyna_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch2(brace_block, escape_Qundef($3), $4);
|
$$ = dispatch2(brace_block, escape_Qundef($3), $4);
|
||||||
%*/
|
%*/
|
||||||
|
dyna_pop();
|
||||||
}
|
}
|
||||||
| keyword_do
|
| keyword_do
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
dyna_push();
|
dyna_push();
|
||||||
|
/*%%%*/
|
||||||
$<num>$ = ruby_sourceline;
|
$<num>$ = ruby_sourceline;
|
||||||
/*%
|
/*%
|
||||||
%*/
|
%*/
|
||||||
|
@ -3648,10 +3655,10 @@ brace_block : '{'
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
$$ = NEW_ITER($3,$4);
|
$$ = NEW_ITER($3,$4);
|
||||||
nd_set_line($$, $<num>2);
|
nd_set_line($$, $<num>2);
|
||||||
dyna_pop();
|
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch2(do_block, escape_Qundef($3), $4);
|
$$ = dispatch2(do_block, escape_Qundef($3), $4);
|
||||||
%*/
|
%*/
|
||||||
|
dyna_pop();
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -4127,10 +4134,10 @@ var_ref : variable
|
||||||
|
|
||||||
var_lhs : variable
|
var_lhs : variable
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
$$ = assignable($1, 0);
|
$$ = assignable($1, 0);
|
||||||
|
/*%%%*/
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch1(var_field, $1);
|
$$ = dispatch1(var_field, $$);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -4346,29 +4353,25 @@ f_bad_arg : tCONSTANT
|
||||||
f_norm_arg : f_bad_arg
|
f_norm_arg : f_bad_arg
|
||||||
| tIDENTIFIER
|
| tIDENTIFIER
|
||||||
{
|
{
|
||||||
/*%%%*/
|
formal_argument(get_id($1));
|
||||||
if (!is_local_id($1))
|
|
||||||
yyerror("formal argument must be local variable");
|
|
||||||
shadowing_lvar($1);
|
|
||||||
/*%
|
|
||||||
%*/
|
|
||||||
$$ = $1;
|
$$ = $1;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
f_arg_item : f_norm_arg
|
f_arg_item : f_norm_arg
|
||||||
{
|
{
|
||||||
|
arg_var(get_id($1));
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
arg_var($1);
|
|
||||||
$$ = NEW_ARGS_AUX($1, 1);
|
$$ = NEW_ARGS_AUX($1, 1);
|
||||||
/*%
|
/*%
|
||||||
|
$$ = get_value($1);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
| tLPAREN f_margs rparen
|
| tLPAREN f_margs rparen
|
||||||
{
|
{
|
||||||
/*%%%*/
|
|
||||||
ID tid = internal_id();
|
ID tid = internal_id();
|
||||||
arg_var(tid);
|
arg_var(tid);
|
||||||
|
/*%%%*/
|
||||||
if (dyna_in_block()) {
|
if (dyna_in_block()) {
|
||||||
$2->nd_value = NEW_DVAR(tid);
|
$2->nd_value = NEW_DVAR(tid);
|
||||||
}
|
}
|
||||||
|
@ -4405,28 +4408,24 @@ f_arg : f_arg_item
|
||||||
|
|
||||||
f_opt : tIDENTIFIER '=' arg_value
|
f_opt : tIDENTIFIER '=' arg_value
|
||||||
{
|
{
|
||||||
|
arg_var(formal_argument(get_id($1)));
|
||||||
|
$$ = assignable($1, $3);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
if (!is_local_id($1))
|
$$ = NEW_OPT_ARG(0, $$);
|
||||||
yyerror("formal argument must be local variable");
|
|
||||||
shadowing_lvar($1);
|
|
||||||
arg_var($1);
|
|
||||||
$$ = NEW_OPT_ARG(0, assignable($1, $3));
|
|
||||||
/*%
|
/*%
|
||||||
$$ = rb_assoc_new($1, $3);
|
$$ = rb_assoc_new($$, $3);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
f_block_opt : tIDENTIFIER '=' primary_value
|
f_block_opt : tIDENTIFIER '=' primary_value
|
||||||
{
|
{
|
||||||
|
arg_var(formal_argument(get_id($1)));
|
||||||
|
$$ = assignable($1, $3);
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
if (!is_local_id($1))
|
$$ = NEW_OPT_ARG(0, $$);
|
||||||
yyerror("formal argument must be local variable");
|
|
||||||
shadowing_lvar($1);
|
|
||||||
arg_var($1);
|
|
||||||
$$ = NEW_OPT_ARG(0, assignable($1, $3));
|
|
||||||
/*%
|
/*%
|
||||||
$$ = rb_assoc_new($1, $3);
|
$$ = rb_assoc_new($$, $3);
|
||||||
%*/
|
%*/
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
@ -4488,8 +4487,9 @@ f_rest_arg : restarg_mark tIDENTIFIER
|
||||||
/*%%%*/
|
/*%%%*/
|
||||||
if (!is_local_id($2))
|
if (!is_local_id($2))
|
||||||
yyerror("rest argument must be local variable");
|
yyerror("rest argument must be local variable");
|
||||||
shadowing_lvar($2);
|
/*% %*/
|
||||||
arg_var($2);
|
arg_var(shadowing_lvar(get_id($2)));
|
||||||
|
/*%%%*/
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch1(rest_param, $2);
|
$$ = dispatch1(rest_param, $2);
|
||||||
|
@ -4517,8 +4517,9 @@ f_block_arg : blkarg_mark tIDENTIFIER
|
||||||
yyerror("block argument must be local variable");
|
yyerror("block argument must be local variable");
|
||||||
else if (!dyna_in_block() && local_id($2))
|
else if (!dyna_in_block() && local_id($2))
|
||||||
yyerror("duplicated block argument name");
|
yyerror("duplicated block argument name");
|
||||||
shadowing_lvar($2);
|
/*% %*/
|
||||||
arg_var($2);
|
arg_var(shadowing_lvar(get_id($2)));
|
||||||
|
/*%%%*/
|
||||||
$$ = $2;
|
$$ = $2;
|
||||||
/*%
|
/*%
|
||||||
$$ = dispatch1(blockarg, $2);
|
$$ = dispatch1(blockarg, $2);
|
||||||
|
@ -4719,31 +4720,34 @@ static int parser_here_document(struct parser_params*,NODE*);
|
||||||
# define heredoc_restore(n) parser_heredoc_restore(parser,n)
|
# define heredoc_restore(n) parser_heredoc_restore(parser,n)
|
||||||
# define whole_match_p(e,l,i) parser_whole_match_p(parser,e,l,i)
|
# define whole_match_p(e,l,i) parser_whole_match_p(parser,e,l,i)
|
||||||
|
|
||||||
#ifdef RIPPER
|
|
||||||
/* FIXME */
|
|
||||||
# define local_id(x) 1
|
|
||||||
# define dyna_in_block() 1
|
|
||||||
#endif /* RIPPER */
|
|
||||||
|
|
||||||
#ifndef RIPPER
|
#ifndef RIPPER
|
||||||
# define set_yylval_str(x) yylval.node = NEW_STR(x)
|
# define set_yylval_str(x) yylval.node = NEW_STR(x)
|
||||||
# define set_yylval_num(x) yylval.num = x
|
# define set_yylval_num(x) yylval.num = x
|
||||||
# define set_yylval_id(x) yylval.id = x
|
# define set_yylval_id(x) yylval.id = x
|
||||||
|
# define set_yylval_name(x) yylval.id = x
|
||||||
# define set_yylval_literal(x) yylval.node = NEW_LIT(x)
|
# define set_yylval_literal(x) yylval.node = NEW_LIT(x)
|
||||||
# define set_yylval_node(x) yylval.node = x
|
# define set_yylval_node(x) yylval.node = x
|
||||||
# define yylval_id() yylval.id
|
# define yylval_id() yylval.id
|
||||||
#else
|
#else
|
||||||
|
static inline VALUE
|
||||||
|
ripper_yylval_id(ID x)
|
||||||
|
{
|
||||||
|
return (VALUE)NEW_LASGN(x, ID2SYM(x));
|
||||||
|
}
|
||||||
# define set_yylval_str(x) (void)(x)
|
# define set_yylval_str(x) (void)(x)
|
||||||
# define set_yylval_num(x) (void)(x)
|
# define set_yylval_num(x) (void)(x)
|
||||||
# define set_yylval_id(x) (void)(x)
|
# define set_yylval_id(x) (void)(x)
|
||||||
|
# define set_yylval_name(x) (void)(yylval.val = ripper_yylval_id(x))
|
||||||
# define set_yylval_literal(x) (void)(x)
|
# define set_yylval_literal(x) (void)(x)
|
||||||
# define set_yylval_node(x) (void)(x)
|
# define set_yylval_node(x) (void)(x)
|
||||||
# define yylval_id() SYM2ID(yylval.val)
|
# define yylval_id() yylval.id
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef RIPPER
|
#ifdef RIPPER
|
||||||
#define ripper_flush(p) (p->tokp = p->parser_lex_p)
|
#define ripper_flush(p) (p->tokp = p->parser_lex_p)
|
||||||
|
|
||||||
|
#define yylval_rval *(RB_TYPE_P(yylval.val, T_NODE) ? &yylval.node->nd_rval : &yylval.val)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ripper_dispatch_scan_event(struct parser_params *parser, int t)
|
ripper_dispatch_scan_event(struct parser_params *parser, int t)
|
||||||
{
|
{
|
||||||
|
@ -4752,7 +4756,7 @@ ripper_dispatch_scan_event(struct parser_params *parser, int t)
|
||||||
if (lex_p < parser->tokp) rb_raise(rb_eRuntimeError, "lex_p < tokp");
|
if (lex_p < parser->tokp) rb_raise(rb_eRuntimeError, "lex_p < tokp");
|
||||||
if (lex_p == parser->tokp) return;
|
if (lex_p == parser->tokp) return;
|
||||||
str = STR_NEW(parser->tokp, lex_p - parser->tokp);
|
str = STR_NEW(parser->tokp, lex_p - parser->tokp);
|
||||||
yylval.val = ripper_dispatch1(parser, ripper_token2eventid(t), str);
|
yylval_rval = ripper_dispatch1(parser, ripper_token2eventid(t), str);
|
||||||
ripper_flush(parser);
|
ripper_flush(parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4764,7 +4768,7 @@ ripper_dispatch_delayed_token(struct parser_params *parser, int t)
|
||||||
|
|
||||||
ruby_sourceline = parser->delayed_line;
|
ruby_sourceline = parser->delayed_line;
|
||||||
parser->tokp = lex_pbeg + parser->delayed_col;
|
parser->tokp = lex_pbeg + parser->delayed_col;
|
||||||
yylval.val = ripper_dispatch1(parser, ripper_token2eventid(t), parser->delayed);
|
yylval_rval = ripper_dispatch1(parser, ripper_token2eventid(t), parser->delayed);
|
||||||
parser->delayed = Qnil;
|
parser->delayed = Qnil;
|
||||||
ruby_sourceline = saved_line;
|
ruby_sourceline = saved_line;
|
||||||
parser->tokp = saved_tokp;
|
parser->tokp = saved_tokp;
|
||||||
|
@ -6033,29 +6037,32 @@ parser_here_document(struct parser_params *parser, NODE *here)
|
||||||
|
|
||||||
#include "lex.c"
|
#include "lex.c"
|
||||||
|
|
||||||
|
static void
|
||||||
|
arg_ambiguous_gen(struct parser_params *parser)
|
||||||
|
{
|
||||||
#ifndef RIPPER
|
#ifndef RIPPER
|
||||||
static void
|
|
||||||
arg_ambiguous_gen(struct parser_params *parser)
|
|
||||||
{
|
|
||||||
rb_warning0("ambiguous first argument; put parentheses or even spaces");
|
rb_warning0("ambiguous first argument; put parentheses or even spaces");
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
static void
|
|
||||||
arg_ambiguous_gen(struct parser_params *parser)
|
|
||||||
{
|
|
||||||
dispatch0(arg_ambiguous);
|
dispatch0(arg_ambiguous);
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
#define arg_ambiguous() arg_ambiguous_gen(parser)
|
#define arg_ambiguous() arg_ambiguous_gen(parser)
|
||||||
|
|
||||||
|
static ID
|
||||||
|
formal_argument_gen(struct parser_params *parser, ID lhs)
|
||||||
|
{
|
||||||
|
#ifndef RIPPER
|
||||||
|
if (!is_local_id(lhs))
|
||||||
|
yyerror("formal argument must be local variable");
|
||||||
|
#endif
|
||||||
|
shadowing_lvar(lhs);
|
||||||
|
return lhs;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
lvar_defined_gen(struct parser_params *parser, ID id)
|
lvar_defined_gen(struct parser_params *parser, ID id)
|
||||||
{
|
{
|
||||||
#ifndef RIPPER
|
|
||||||
return (dyna_in_block() && dvar_defined(id)) || local_id(id);
|
return (dyna_in_block() && dvar_defined(id)) || local_id(id);
|
||||||
#else
|
|
||||||
return 0;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* emacsen -*- hack */
|
/* emacsen -*- hack */
|
||||||
|
@ -7385,7 +7392,7 @@ parser_yylex(struct parser_params *parser)
|
||||||
tokadd('$');
|
tokadd('$');
|
||||||
tokadd(c);
|
tokadd(c);
|
||||||
tokfix();
|
tokfix();
|
||||||
set_yylval_id(rb_intern(tok()));
|
set_yylval_name(rb_intern(tok()));
|
||||||
return tGVAR;
|
return tGVAR;
|
||||||
|
|
||||||
case '-':
|
case '-':
|
||||||
|
@ -7400,7 +7407,7 @@ parser_yylex(struct parser_params *parser)
|
||||||
}
|
}
|
||||||
gvar:
|
gvar:
|
||||||
tokfix();
|
tokfix();
|
||||||
set_yylval_id(rb_intern(tok()));
|
set_yylval_name(rb_intern(tok()));
|
||||||
return tGVAR;
|
return tGVAR;
|
||||||
|
|
||||||
case '&': /* $&: last match */
|
case '&': /* $&: last match */
|
||||||
|
@ -7554,7 +7561,7 @@ parser_yylex(struct parser_params *parser)
|
||||||
if (peek(':') && !(lex_p + 1 < lex_pend && lex_p[1] == ':')) {
|
if (peek(':') && !(lex_p + 1 < lex_pend && lex_p[1] == ':')) {
|
||||||
lex_state = EXPR_BEG;
|
lex_state = EXPR_BEG;
|
||||||
nextc();
|
nextc();
|
||||||
set_yylval_id(TOK_INTERN(!ENC_SINGLE(mb)));
|
set_yylval_name(TOK_INTERN(!ENC_SINGLE(mb)));
|
||||||
return tLABEL;
|
return tLABEL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7567,7 +7574,7 @@ parser_yylex(struct parser_params *parser)
|
||||||
enum lex_state_e state = lex_state;
|
enum lex_state_e state = lex_state;
|
||||||
lex_state = kw->state;
|
lex_state = kw->state;
|
||||||
if (state == EXPR_FNAME) {
|
if (state == EXPR_FNAME) {
|
||||||
set_yylval_id(rb_intern(kw->name));
|
set_yylval_name(rb_intern(kw->name));
|
||||||
return kw->id[0];
|
return kw->id[0];
|
||||||
}
|
}
|
||||||
if (kw->id[0] == keyword_do) {
|
if (kw->id[0] == keyword_do) {
|
||||||
|
@ -7611,7 +7618,7 @@ parser_yylex(struct parser_params *parser)
|
||||||
{
|
{
|
||||||
ID ident = TOK_INTERN(!ENC_SINGLE(mb));
|
ID ident = TOK_INTERN(!ENC_SINGLE(mb));
|
||||||
|
|
||||||
set_yylval_id(ident);
|
set_yylval_name(ident);
|
||||||
if (last_state != EXPR_DOT && is_local_id(ident) && lvar_defined(ident)) {
|
if (last_state != EXPR_DOT && is_local_id(ident) && lvar_defined(ident)) {
|
||||||
lex_state = EXPR_END;
|
lex_state = EXPR_END;
|
||||||
}
|
}
|
||||||
|
@ -7994,82 +8001,98 @@ gettable_gen(struct parser_params *parser, ID id)
|
||||||
compile_error(PARSER_ARG "identifier %s is not valid to get", rb_id2name(id));
|
compile_error(PARSER_ARG "identifier %s is not valid to get", rb_id2name(id));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
#endif /* !RIPPER */
|
||||||
|
|
||||||
|
#ifdef RIPPER
|
||||||
|
static VALUE
|
||||||
|
assignable_gen(struct parser_params *parser, VALUE lhs)
|
||||||
|
#else
|
||||||
static NODE*
|
static NODE*
|
||||||
assignable_gen(struct parser_params *parser, ID id, NODE *val)
|
assignable_gen(struct parser_params *parser, ID id, NODE *val)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
if (!id) return 0;
|
#ifdef RIPPER
|
||||||
|
ID id = get_id(lhs);
|
||||||
|
# define RETURN(x) return get_value(lhs)
|
||||||
|
# define ERROR(x) dispatch1(assign_error, lhs)
|
||||||
|
#else
|
||||||
|
# define RETURN(x) return x
|
||||||
|
# define ERROR(x) yyerror(x)
|
||||||
|
#endif
|
||||||
|
if (!id) RETURN(0);
|
||||||
if (id == keyword_self) {
|
if (id == keyword_self) {
|
||||||
yyerror("Can't change the value of self");
|
ERROR("Can't change the value of self");
|
||||||
}
|
}
|
||||||
else if (id == keyword_nil) {
|
else if (id == keyword_nil) {
|
||||||
yyerror("Can't assign to nil");
|
ERROR("Can't assign to nil");
|
||||||
}
|
}
|
||||||
else if (id == keyword_true) {
|
else if (id == keyword_true) {
|
||||||
yyerror("Can't assign to true");
|
ERROR("Can't assign to true");
|
||||||
}
|
}
|
||||||
else if (id == keyword_false) {
|
else if (id == keyword_false) {
|
||||||
yyerror("Can't assign to false");
|
ERROR("Can't assign to false");
|
||||||
}
|
}
|
||||||
else if (id == keyword__FILE__) {
|
else if (id == keyword__FILE__) {
|
||||||
yyerror("Can't assign to __FILE__");
|
ERROR("Can't assign to __FILE__");
|
||||||
}
|
}
|
||||||
else if (id == keyword__LINE__) {
|
else if (id == keyword__LINE__) {
|
||||||
yyerror("Can't assign to __LINE__");
|
ERROR("Can't assign to __LINE__");
|
||||||
}
|
}
|
||||||
else if (id == keyword__ENCODING__) {
|
else if (id == keyword__ENCODING__) {
|
||||||
yyerror("Can't assign to __ENCODING__");
|
ERROR("Can't assign to __ENCODING__");
|
||||||
}
|
}
|
||||||
else if (is_local_id(id)) {
|
else if (is_local_id(id)) {
|
||||||
if (dyna_in_block()) {
|
if (dyna_in_block()) {
|
||||||
if (dvar_curr(id)) {
|
if (dvar_curr(id)) {
|
||||||
return NEW_DASGN_CURR(id, val);
|
RETURN(NEW_DASGN_CURR(id, val));
|
||||||
}
|
}
|
||||||
else if (dvar_defined(id)) {
|
else if (dvar_defined(id)) {
|
||||||
return NEW_DASGN(id, val);
|
RETURN(NEW_DASGN(id, val));
|
||||||
}
|
}
|
||||||
else if (local_id(id)) {
|
else if (local_id(id)) {
|
||||||
return NEW_LASGN(id, val);
|
RETURN(NEW_LASGN(id, val));
|
||||||
}
|
}
|
||||||
else{
|
else {
|
||||||
dyna_var(id);
|
dyna_var(id);
|
||||||
return NEW_DASGN_CURR(id, val);
|
RETURN(NEW_DASGN_CURR(id, val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (!local_id(id)) {
|
if (!local_id(id)) {
|
||||||
local_var(id);
|
local_var(id);
|
||||||
}
|
}
|
||||||
return NEW_LASGN(id, val);
|
RETURN(NEW_LASGN(id, val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (is_global_id(id)) {
|
else if (is_global_id(id)) {
|
||||||
return NEW_GASGN(id, val);
|
RETURN(NEW_GASGN(id, val));
|
||||||
}
|
}
|
||||||
else if (is_instance_id(id)) {
|
else if (is_instance_id(id)) {
|
||||||
return NEW_IASGN(id, val);
|
RETURN(NEW_IASGN(id, val));
|
||||||
}
|
}
|
||||||
else if (is_const_id(id)) {
|
else if (is_const_id(id)) {
|
||||||
if (in_def || in_single)
|
if (!in_def && !in_single)
|
||||||
yyerror("dynamic constant assignment");
|
RETURN(NEW_CDECL(id, val, 0));
|
||||||
return NEW_CDECL(id, val, 0);
|
ERROR("dynamic constant assignment");
|
||||||
}
|
}
|
||||||
else if (is_class_id(id)) {
|
else if (is_class_id(id)) {
|
||||||
return NEW_CVASGN(id, val);
|
RETURN(NEW_CVASGN(id, val));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
compile_error(PARSER_ARG "identifier %s is not valid to set", rb_id2name(id));
|
compile_error(PARSER_ARG "identifier %s is not valid to set", rb_id2name(id));
|
||||||
}
|
}
|
||||||
return 0;
|
RETURN(0);
|
||||||
|
#undef RETURN
|
||||||
|
#undef ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static ID
|
||||||
shadowing_lvar_gen(struct parser_params *parser, ID name)
|
shadowing_lvar_gen(struct parser_params *parser, ID name)
|
||||||
{
|
{
|
||||||
ID uscore;
|
ID uscore;
|
||||||
|
|
||||||
CONST_ID(uscore, "_");
|
CONST_ID(uscore, "_");
|
||||||
if (uscore == name) return;
|
if (uscore == name) return name;
|
||||||
if (dyna_in_block()) {
|
if (dyna_in_block()) {
|
||||||
if (dvar_curr(name)) {
|
if (dvar_curr(name)) {
|
||||||
yyerror("duplicated argument name");
|
yyerror("duplicated argument name");
|
||||||
|
@ -8084,6 +8107,7 @@ shadowing_lvar_gen(struct parser_params *parser, ID name)
|
||||||
yyerror("duplicated argument name");
|
yyerror("duplicated argument name");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -8099,6 +8123,7 @@ new_bv_gen(struct parser_params *parser, ID name)
|
||||||
dyna_var(name);
|
dyna_var(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef RIPPER
|
||||||
static NODE *
|
static NODE *
|
||||||
aryset_gen(struct parser_params *parser, NODE *recv, NODE *idx)
|
aryset_gen(struct parser_params *parser, NODE *recv, NODE *idx)
|
||||||
{
|
{
|
||||||
|
@ -8749,6 +8774,7 @@ new_args_gen(struct parser_params *parser, NODE *m, NODE *o, ID r, NODE *p, ID b
|
||||||
ruby_sourceline = saved_line;
|
ruby_sourceline = saved_line;
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
#endif /* !RIPPER */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
local_push_gen(struct parser_params *parser, int inherit_dvars)
|
local_push_gen(struct parser_params *parser, int inherit_dvars)
|
||||||
|
@ -8772,6 +8798,7 @@ local_pop_gen(struct parser_params *parser)
|
||||||
lvtbl = local;
|
lvtbl = local;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef RIPPER
|
||||||
static ID*
|
static ID*
|
||||||
vtable_tblcpy(ID *buf, const struct vtable *src)
|
vtable_tblcpy(ID *buf, const struct vtable *src)
|
||||||
{
|
{
|
||||||
|
@ -8800,6 +8827,7 @@ local_tbl_gen(struct parser_params *parser)
|
||||||
buf[0] = cnt;
|
buf[0] = cnt;
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static int
|
static int
|
||||||
arg_var_gen(struct parser_params *parser, ID id)
|
arg_var_gen(struct parser_params *parser, ID id)
|
||||||
|
@ -8896,6 +8924,7 @@ dvar_curr_gen(struct parser_params *parser, ID id)
|
||||||
vtable_included(lvtbl->vars, id));
|
vtable_included(lvtbl->vars, id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef RIPPER
|
||||||
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline);
|
VALUE rb_reg_compile(VALUE str, int options, const char *sourcefile, int sourceline);
|
||||||
VALUE rb_reg_check_preprocess(VALUE);
|
VALUE rb_reg_check_preprocess(VALUE);
|
||||||
|
|
||||||
|
@ -9228,6 +9257,7 @@ rb_gc_mark_symbols(void)
|
||||||
rb_gc_mark_locations(global_symbols.op_sym,
|
rb_gc_mark_locations(global_symbols.op_sym,
|
||||||
global_symbols.op_sym + tLAST_TOKEN);
|
global_symbols.op_sym + tLAST_TOKEN);
|
||||||
}
|
}
|
||||||
|
#endif /* !RIPPER */
|
||||||
|
|
||||||
static ID
|
static ID
|
||||||
internal_id_gen(struct parser_params *parser)
|
internal_id_gen(struct parser_params *parser)
|
||||||
|
@ -9237,6 +9267,7 @@ internal_id_gen(struct parser_params *parser)
|
||||||
return ID_INTERNAL | (id << ID_SCOPE_SHIFT);
|
return ID_INTERNAL | (id << ID_SCOPE_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef RIPPER
|
||||||
static int
|
static int
|
||||||
is_special_global_name(const char *m, const char *e, rb_encoding *enc)
|
is_special_global_name(const char *m, const char *e, rb_encoding *enc)
|
||||||
{
|
{
|
||||||
|
@ -9960,7 +9991,10 @@ ripper_validate_object(VALUE self, VALUE x)
|
||||||
case T_FLOAT:
|
case T_FLOAT:
|
||||||
return x;
|
return x;
|
||||||
case T_NODE:
|
case T_NODE:
|
||||||
rb_raise(rb_eArgError, "NODE given: %p", x);
|
if (nd_type(x) != NODE_LASGN) {
|
||||||
|
rb_raise(rb_eArgError, "NODE given: %p", x);
|
||||||
|
}
|
||||||
|
return ((NODE *)x)->nd_rval;
|
||||||
default:
|
default:
|
||||||
rb_raise(rb_eArgError, "wrong type of ruby object: %p (%s)",
|
rb_raise(rb_eArgError, "wrong type of ruby object: %p (%s)",
|
||||||
x, rb_obj_classname(x));
|
x, rb_obj_classname(x));
|
||||||
|
@ -9969,7 +10003,7 @@ ripper_validate_object(VALUE self, VALUE x)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define validate(x)
|
#define validate(x) (x = get_value(x))
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
ripper_dispatch0(struct parser_params *parser, ID mid)
|
ripper_dispatch0(struct parser_params *parser, ID mid)
|
||||||
|
@ -10127,6 +10161,26 @@ ripper_intern(const char *s)
|
||||||
return ID2SYM(rb_intern(s));
|
return ID2SYM(rb_intern(s));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ID
|
||||||
|
ripper_get_id(VALUE v)
|
||||||
|
{
|
||||||
|
NODE *nd;
|
||||||
|
if (!RB_TYPE_P(v, T_NODE)) return 0;
|
||||||
|
nd = (NODE *)v;
|
||||||
|
if (nd_type(nd) != NODE_LASGN) return 0;
|
||||||
|
return nd->nd_vid;
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
ripper_get_value(VALUE v)
|
||||||
|
{
|
||||||
|
NODE *nd;
|
||||||
|
if (!RB_TYPE_P(v, T_NODE)) return v;
|
||||||
|
nd = (NODE *)v;
|
||||||
|
if (nd_type(nd) != NODE_LASGN) return Qnil;
|
||||||
|
return nd->nd_rval;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ripper_compile_error(struct parser_params *parser, const char *fmt, ...)
|
ripper_compile_error(struct parser_params *parser, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
|
|
@ -13,7 +13,15 @@ class Node
|
||||||
attr_reader :children
|
attr_reader :children
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
"#{@name}(#{@children.map {|n| n.to_s }.join(',')})"
|
"#{@name}(#{Node.trim_nil(@children).map {|n| n.to_s }.join(',')})"
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.trim_nil(list)
|
||||||
|
if !list.empty? and list.last.nil?
|
||||||
|
list = list[0...-1]
|
||||||
|
list.pop while !list.empty? and list.last.nil?
|
||||||
|
end
|
||||||
|
list
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -34,14 +42,23 @@ class NodeList
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
'[' + @list.join(',') + ']'
|
"[#{@list.join(',')}]"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
class DummyParser < Ripper
|
class DummyParser < Ripper
|
||||||
|
def hook(name)
|
||||||
|
class << self; self; end.class_eval do
|
||||||
|
define_method(name) do |*a, &b|
|
||||||
|
result = super(*a, &b)
|
||||||
|
yield
|
||||||
|
result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self
|
||||||
|
end
|
||||||
|
|
||||||
def on_program(stmts)
|
def on_program(stmts)
|
||||||
$thru_program = true
|
|
||||||
stmts
|
stmts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -170,8 +187,8 @@ class DummyParser < Ripper
|
||||||
Node.new('binary', a, b, c)
|
Node.new('binary', a, b, c)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_block_var(a)
|
def on_block_var(a, b)
|
||||||
Node.new('block_var', a)
|
Node.new('block_var', a, b)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_bodystmt(a, b, c, d)
|
def on_bodystmt(a, b, c, d)
|
||||||
|
@ -346,8 +363,8 @@ class DummyParser < Ripper
|
||||||
Node.new('param_error', a)
|
Node.new('param_error', a)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_params(a, b, c, d)
|
def on_params(a, b, c, d, e)
|
||||||
Node.new('params', a, b, c, d)
|
Node.new('params', a, b, c, d, e)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_paren(a)
|
def on_paren(a)
|
||||||
|
@ -370,8 +387,8 @@ class DummyParser < Ripper
|
||||||
Node.new('redo')
|
Node.new('redo')
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_regexp_literal(a)
|
def on_regexp_literal(a, b)
|
||||||
Node.new('regexp_literal', a)
|
Node.new('regexp_literal', a, b)
|
||||||
end
|
end
|
||||||
|
|
||||||
def on_rescue(a, b, c, d)
|
def on_rescue(a, b, c, d)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
begin
|
begin
|
||||||
|
|
||||||
require 'dummyparser'
|
require_relative 'dummyparser'
|
||||||
require 'test/unit'
|
require 'test/unit'
|
||||||
|
|
||||||
class TestRipper_ParserEvents < Test::Unit::TestCase
|
class TestRipper_ParserEvents < Test::Unit::TestCase
|
||||||
|
@ -16,15 +16,16 @@ class TestRipper_ParserEvents < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
=end
|
=end
|
||||||
|
|
||||||
def parse(str)
|
def parse(str, nm = nil, &bl)
|
||||||
DummyParser.new(str).parse.to_s
|
dp = DummyParser.new(str)
|
||||||
|
dp.hook(nm, &bl) if nm
|
||||||
|
dp.parse.to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
$thru_program = false
|
|
||||||
|
|
||||||
def test_program
|
def test_program
|
||||||
assert_equal '[void()]', parse('')
|
thru_program = false
|
||||||
assert_equal true, $thru_program
|
assert_equal '[void()]', parse('', :on_program) {thru_program = true}
|
||||||
|
assert_equal true, thru_program
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_stmts_new
|
def test_stmts_new
|
||||||
|
@ -104,11 +105,11 @@ class TestRipper_ParserEvents < Test::Unit::TestCase
|
||||||
assert_equal '[assign(aref_field(ref(a),[1]),2)]', parse('a[1]=2')
|
assert_equal '[assign(aref_field(ref(a),[1]),2)]', parse('a[1]=2')
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
|
||||||
def test_arg_ambiguous
|
def test_arg_ambiguous
|
||||||
assert_equal true, $thru__arg_ambiguous
|
thru_arg_ambiguous = false
|
||||||
|
parse('m //', :on_arg_ambiguous) {thru_arg_ambiguous = true}
|
||||||
|
assert_equal true, thru_arg_ambiguous
|
||||||
end
|
end
|
||||||
=end
|
|
||||||
|
|
||||||
def test_array # array literal
|
def test_array # array literal
|
||||||
assert_equal '[array([1,2,3])]', parse('[1,2,3]')
|
assert_equal '[array([1,2,3])]', parse('[1,2,3]')
|
||||||
|
@ -118,27 +119,89 @@ class TestRipper_ParserEvents < Test::Unit::TestCase
|
||||||
assert_equal '[assign(var_field(v),1)]', parse('v=1')
|
assert_equal '[assign(var_field(v),1)]', parse('v=1')
|
||||||
end
|
end
|
||||||
|
|
||||||
=begin
|
|
||||||
def test_assign_error
|
def test_assign_error
|
||||||
assert_equal true, $thru__assign_error
|
thru_assign_error = false
|
||||||
|
parse('$` = 1', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal true, thru_assign_error
|
||||||
|
thru_assign_error = false
|
||||||
|
parse('$`, _ = 1', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal true, thru_assign_error
|
||||||
|
|
||||||
|
thru_assign_error = false
|
||||||
|
parse('self::X = 1', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal false, thru_assign_error
|
||||||
|
parse('def m\n self::X = 1\nend', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal true, thru_assign_error
|
||||||
|
|
||||||
|
thru_assign_error = false
|
||||||
|
parse('X = 1', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal false, thru_assign_error
|
||||||
|
parse('def m\n X = 1\nend', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal true, thru_assign_error
|
||||||
|
|
||||||
|
thru_assign_error = false
|
||||||
|
parse('::X = 1', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal false, thru_assign_error
|
||||||
|
parse('def m\n ::X = 1\nend', :on_assign_error) {thru_assign_error = true}
|
||||||
|
assert_equal true, thru_assign_error
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_begin
|
def test_begin
|
||||||
assert_equal true, $thru__begin
|
thru_begin = false
|
||||||
|
parse('begin end', :on_begin) {thru_begin = true}
|
||||||
|
assert_equal true, thru_begin
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_binary
|
def test_binary
|
||||||
assert_equal true, $thru__binary
|
thru_binary = nil
|
||||||
|
%w"and or + - * / % ** | ^ & <=> > >= < <= == === != =~ !~ << >> && ||".each do |op|
|
||||||
|
thru_binary = false
|
||||||
|
parse("a #{op} b", :on_binary) {thru_binary = true}
|
||||||
|
assert_equal true, thru_binary
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_block_var
|
def test_block_var
|
||||||
assert_equal true, $thru__block_var
|
thru_block_var = false
|
||||||
|
parse("proc{||}", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc{| |}", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc{|x|}", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc{|;y|}", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc{|x;y|}", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc do || end", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc do | | end", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc do |x| end", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc do |;y| end", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
|
thru_block_var = false
|
||||||
|
parse("proc do |x;y| end", :on_block_var) {thru_block_var = true}
|
||||||
|
assert_equal true, thru_block_var
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_bodystmt
|
def test_bodystmt
|
||||||
assert_equal true, $thru__bodystmt
|
thru_bodystmt = false
|
||||||
|
parse("class X\nend", :on_bodystmt) {thru_bodystmt = true}
|
||||||
|
assert_equal true, thru_bodystmt
|
||||||
end
|
end
|
||||||
|
|
||||||
|
=begin
|
||||||
def test_brace_block
|
def test_brace_block
|
||||||
assert_equal true, $thru__brace_block
|
assert_equal true, $thru__brace_block
|
||||||
end
|
end
|
||||||
|
@ -492,6 +555,17 @@ class TestRipper_ParserEvents < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
=end
|
=end
|
||||||
|
|
||||||
|
def test_local_variables
|
||||||
|
cmd = 'command(w,[regexp_literal(xstring_add(xstring_new(),25 # ),/)])'
|
||||||
|
div = 'binary(ref(w),/,25)'
|
||||||
|
var = 'params(["w"])'
|
||||||
|
bug1939 = '[ruby-core:24923]'
|
||||||
|
|
||||||
|
assert_equal("[#{cmd}]", parse('w /25 # /'), bug1939)
|
||||||
|
assert_equal("[assign(var_field(w),1),#{div}]", parse("w = 1; w /25 # /"), bug1939)
|
||||||
|
assert_equal("[fcall(p,[],&brace_block(block_var(#{var}),[#{div}]))]", parse("p{|w|w /25 # /\n}"), bug1939)
|
||||||
|
assert_equal("[def(p,paren(#{var}),bodystmt([#{div}]))]", parse("def p(w)\nw /25 # /\nend"), bug1939)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
rescue LoadError
|
rescue LoadError
|
||||||
|
|
Loading…
Add table
Reference in a new issue