ruby-changes:20450
From: nobu <ko1@a...>
Date: Sun, 10 Jul 2011 22:38:31 +0900 (JST)
Subject: [ruby-changes:20450] nobu:r32498 (trunk): * parse.y (var_ref): distinguish vcall from local variable
nobu 2011-07-10 22:38:17 +0900 (Sun, 10 Jul 2011) New Revision: 32498 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=32498 Log: * parse.y (var_ref): distinguish vcall from local variable references. based on a patch by Michael Edgar michael.j.edgar AT dartmouth.edu. Bug #5002 Modified files: trunk/ChangeLog trunk/parse.y trunk/test/ripper/test_parser_events.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 32497) +++ ChangeLog (revision 32498) @@ -1,3 +1,9 @@ +Sun Jul 10 22:38:09 2011 Nobuyoshi Nakada <nobu@r...> + + * parse.y (var_ref): distinguish vcall from local variable + references. based on a patch by Michael Edgar michael.j.edgar + AT dartmouth.edu. Bug #5002 + Sun Jul 10 21:51:29 2011 Koichi Sasada <ko1@a...> * internal.h: add comments (cautions). Index: parse.y =================================================================== --- parse.y (revision 32497) +++ parse.y (revision 32498) @@ -426,6 +426,8 @@ #define get_value(val) ripper_get_value(val) static VALUE assignable_gen(struct parser_params*,VALUE); #define assignable(lhs,node) assignable_gen(parser, (lhs)) +static int id_is_var_gen(struct parser_params *parser, ID id); +#define id_is_var(id) id_is_var_gen(parser, (id)) #endif /* !RIPPER */ static ID formal_argument_gen(struct parser_params*, ID); @@ -699,7 +701,7 @@ %type <node> lambda f_larglist lambda_body %type <node> brace_block cmd_brace_block do_block lhs none fitem %type <node> mlhs mlhs_head mlhs_basic mlhs_item mlhs_node mlhs_post mlhs_inner -%type <id> fsym variable sym symbol operation operation2 operation3 +%type <id> fsym keyword_variable user_variable sym symbol operation operation2 operation3 %type <id> cname fname op f_rest_arg f_block_arg opt_f_block_arg f_norm_arg f_bad_arg /*%%%*/ /*% @@ -1601,10 +1603,14 @@ } ; -mlhs_node : variable +mlhs_node : user_variable { $$ = assignable($1, 0); } + | keyword_variable + { + $$ = assignable($1, 0); + } | primary_value '[' opt_call_args rbracket { /*%%%*/ @@ -1671,7 +1677,7 @@ } ; -lhs : variable +lhs : user_variable { $$ = assignable($1, 0); /*%%%*/ @@ -1680,6 +1686,15 @@ $$ = dispatch1(var_field, $$); %*/ } + | keyword_variable + { + $$ = assignable($1, 0); + /*%%%*/ + if (!$$) $$ = NEW_BEGIN(0); + /*% + $$ = dispatch1(var_field, $$); + %*/ + } | primary_value '[' opt_call_args rbracket { /*%%%*/ @@ -4257,12 +4272,14 @@ } ; -variable : tIDENTIFIER +user_variable : tIDENTIFIER | tIVAR | tGVAR | tCONSTANT | tCVAR - | keyword_nil {ifndef_ripper($$ = keyword_nil);} + ; + +keyword_variable: keyword_nil {ifndef_ripper($$ = keyword_nil);} | keyword_self {ifndef_ripper($$ = keyword_self);} | keyword_true {ifndef_ripper($$ = keyword_true);} | keyword_false {ifndef_ripper($$ = keyword_false);} @@ -4271,17 +4288,30 @@ | keyword__ENCODING__ {ifndef_ripper($$ = keyword__ENCODING__);} ; -var_ref : variable +var_ref : user_variable { /*%%%*/ if (!($$ = gettable($1))) $$ = NEW_BEGIN(0); /*% + if (id_is_var(get_id($1))) { + $$ = dispatch1(var_ref, $1); + } + else { + $$ = dispatch1(vcall, $1); + } + %*/ + } + | keyword_variable + { + /*%%%*/ + if (!($$ = gettable($1))) $$ = NEW_BEGIN(0); + /*% $$ = dispatch1(var_ref, $1); %*/ } ; -var_lhs : variable +var_lhs : user_variable { $$ = assignable($1, 0); /*%%%*/ @@ -4289,6 +4319,14 @@ $$ = dispatch1(var_field, $$); %*/ } + | keyword_variable + { + $$ = assignable($1, 0); + /*%%%*/ + /*% + $$ = dispatch1(var_field, $$); + %*/ + } ; backref : tNTH_REF @@ -8242,6 +8280,24 @@ compile_error(PARSER_ARG "identifier %s is not valid to get", rb_id2name(id)); return 0; } +#else /* !RIPPER */ +static int +id_is_var_gen(struct parser_params *parser, ID id) +{ + if (is_notop_id(id)) { + switch (id & ID_SCOPE_MASK) { + case ID_GLOBAL: case ID_INSTANCE: case ID_CONST: case ID_CLASS: + return 1; + case ID_LOCAL: + if (dyna_in_block() && dvar_defined(id)) return 1; + if (local_id(id)) return 1; + /* method call without arguments */ + return 0; + } + } + compile_error(PARSER_ARG "identifier %s is not valid to get", rb_id2name(id)); + return 0; +} #endif /* !RIPPER */ #ifdef RIPPER Index: test/ripper/test_parser_events.rb =================================================================== --- test/ripper/test_parser_events.rb (revision 32497) +++ test/ripper/test_parser_events.rb (revision 32498) @@ -46,11 +46,15 @@ end def test_var_ref - assert_equal '[ref(a)]', parse('a') + assert_equal '[assign(var_field(a),ref(a))]', parse('a=a') assert_equal '[ref(nil)]', parse('nil') assert_equal '[ref(true)]', parse('true') end + def test_vcall + assert_equal '[vcall(a)]', parse('a') + end + def test_BEGIN assert_equal '[BEGIN([void()])]', parse('BEGIN{}') assert_equal '[BEGIN([ref(nil)])]', parse('BEGIN{nil}') @@ -77,15 +81,15 @@ assert_equal '[fcall(m,[])]', parse('m()') assert_equal '[fcall(m,[1])]', parse('m(1)') assert_equal '[fcall(m,[1,2])]', parse('m(1,2)') - assert_equal '[fcall(m,[*ref(r)])]', parse('m(*r)') - assert_equal '[fcall(m,[1,*ref(r)])]', parse('m(1,*r)') - assert_equal '[fcall(m,[1,2,*ref(r)])]', parse('m(1,2,*r)') - assert_equal '[fcall(m,[&ref(r)])]', parse('m(&r)') - assert_equal '[fcall(m,[1,&ref(r)])]', parse('m(1,&r)') - assert_equal '[fcall(m,[1,2,&ref(r)])]', parse('m(1,2,&r)') - assert_equal '[fcall(m,[*ref(a),&ref(b)])]', parse('m(*a,&b)') - assert_equal '[fcall(m,[1,*ref(a),&ref(b)])]', parse('m(1,*a,&b)') - assert_equal '[fcall(m,[1,2,*ref(a),&ref(b)])]', parse('m(1,2,*a,&b)') + assert_equal '[fcall(m,[*vcall(r)])]', parse('m(*r)') + assert_equal '[fcall(m,[1,*vcall(r)])]', parse('m(1,*r)') + assert_equal '[fcall(m,[1,2,*vcall(r)])]', parse('m(1,2,*r)') + assert_equal '[fcall(m,[&vcall(r)])]', parse('m(&r)') + assert_equal '[fcall(m,[1,&vcall(r)])]', parse('m(1,&r)') + assert_equal '[fcall(m,[1,2,&vcall(r)])]', parse('m(1,2,&r)') + assert_equal '[fcall(m,[*vcall(a),&vcall(b)])]', parse('m(*a,&b)') + assert_equal '[fcall(m,[1,*vcall(a),&vcall(b)])]', parse('m(1,*a,&b)') + assert_equal '[fcall(m,[1,2,*vcall(a),&vcall(b)])]', parse('m(1,2,*a,&b)') end def test_args_add @@ -120,8 +124,8 @@ end def test_aref - assert_equal '[aref(ref(v),[1])]', parse('v[1]') - assert_equal '[aref(ref(v),[1,2])]', parse('v[1,2]') + assert_equal '[aref(vcall(v),[1])]', parse('v[1]') + assert_equal '[aref(vcall(v),[1,2])]', parse('v[1,2]') end def test_assoclist_from_args @@ -143,7 +147,7 @@ end def test_aref_field - assert_equal '[assign(aref_field(ref(a),[1]),2)]', parse('a[1]=2') + assert_equal '[assign(aref_field(vcall(a),[1]),2)]', parse('a[1]=2') end def test_arg_ambiguous @@ -323,7 +327,7 @@ tree = parse("foo.()", :on_call) {thru_call = true} } assert_equal true, thru_call - assert_equal "[call(ref(foo),.,call,[])]", tree + assert_equal "[call(vcall(foo),.,call,[])]", tree end def test_excessed_comma -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/