Nakada, Nobuyoshi
6/13/2005 9:20:00 AM
Hi,
At Sun, 12 Jun 2005 00:45:56 +0900,
Gavin Kistner wrote in [ruby-talk:145166]:
> Would it be possible to have the parser recognize the single-line 'if/
> unless' case and process the right side before the left side (the
> order in which the code is executed)?
Not impossible, but a dirty hack because current implementation is one
pass parser.
Index: parse.y
===================================================================
RCS file: /cvs/ruby/src/ruby/parse.y,v
retrieving revision 1.387
diff -U2 -p -u -r1.387 parse.y
--- parse.y 12 Jun 2005 16:56:05 -0000 1.387
+++ parse.y 13 Jun 2005 09:11:49 -0000
@@ -150,4 +150,5 @@ struct parser_params {
NODE *parser_eval_tree_begin;
NODE *parser_eval_tree;
+ NODE *vcalls;
#else
/* Ripper only */
@@ -304,8 +305,16 @@ static void top_local_setup_gen _((struc
#else
#define remove_begin(node) (node)
+/* FIXME */
+# define local_cnt(x) 3
+# define local_id(x) 1
+# define dyna_in_block() 1
#endif /* !RIPPER */
static int lvar_defined_gen _((struct parser_params*, ID));
#define lvar_defined(id) lvar_defined_gen(parser, id)
+#define lvar_count() (dyna_in_block() ? lvtbl->dname_size : lvtbl->cnt)
+static void replace_vcall _((struct parser_params *, int));
+static void merge_vcalls _((struct parser_params *));
+
#define RE_OPTION_ONCE 0x80
@@ -678,4 +687,5 @@ stmts : none
/*%%%*/
$$ = block_append($1, newline_node(remove_begin($3)));
+ merge_vcalls(parser);
/*%
$$ = dispatch2(stmts_add, $1, $3);
@@ -733,9 +743,14 @@ stmt : kALIAS fitem {lex_state = EXPR_F
%*/
}
- | stmt kIF_MOD expr_value
+ | stmt kIF_MOD
+ {
+ $<num>$ = lvar_count();
+ }
+ expr_value
{
/*%%%*/
- $$ = NEW_IF(cond($3), $1, 0);
- fixpos($$, $3);
+ replace_vcall(parser, $<num>3);
+ $$ = NEW_IF(cond($4), $1, 0);
+ fixpos($$, $4);
if (cond_negative(&$$->nd_cond)) {
$$->nd_else = $$->nd_body;
@@ -743,12 +758,17 @@ stmt : kALIAS fitem {lex_state = EXPR_F
}
/*%
- $$ = dispatch2(if_mod, $3, $1);
+ $$ = dispatch2(if_mod, $4, $1);
%*/
}
- | stmt kUNLESS_MOD expr_value
+ | stmt kUNLESS_MOD
+ {
+ $<num>$ = lvar_count();
+ }
+ expr_value
{
/*%%%*/
- $$ = NEW_UNLESS(cond($3), $1, 0);
- fixpos($$, $3);
+ replace_vcall(parser, $<num>3);
+ $$ = NEW_UNLESS(cond($4), $1, 0);
+ fixpos($$, $4);
if (cond_negative(&$$->nd_cond)) {
$$->nd_body = $$->nd_else;
@@ -756,15 +776,20 @@ stmt : kALIAS fitem {lex_state = EXPR_F
}
/*%
- $$ = dispatch2(unless_mod, $3, $1);
+ $$ = dispatch2(unless_mod, $4, $1);
%*/
}
- | stmt kWHILE_MOD expr_value
+ | stmt kWHILE_MOD
+ {
+ $<num>$ = lvar_count();
+ }
+ expr_value
{
/*%%%*/
+ replace_vcall(parser, $<num>3);
if ($1 && nd_type($1) == NODE_BEGIN) {
- $$ = NEW_WHILE(cond($3), $1->nd_body, 0);
+ $$ = NEW_WHILE(cond($4), $1->nd_body, 0);
}
else {
- $$ = NEW_WHILE(cond($3), $1, 1);
+ $$ = NEW_WHILE(cond($4), $1, 1);
}
if (cond_negative(&$$->nd_cond)) {
@@ -772,15 +797,20 @@ stmt : kALIAS fitem {lex_state = EXPR_F
}
/*%
- $$ = dispatch2(while_mod, $3, $1);
+ $$ = dispatch2(while_mod, $4, $1);
%*/
}
- | stmt kUNTIL_MOD expr_value
+ | stmt kUNTIL_MOD
+ {
+ $<num>$ = lvar_count();
+ }
+ expr_value
{
/*%%%*/
+ replace_vcall(parser, $<num>3);
if ($1 && nd_type($1) == NODE_BEGIN) {
- $$ = NEW_UNTIL(cond($3), $1->nd_body, 0);
+ $$ = NEW_UNTIL(cond($4), $1->nd_body, 0);
}
else {
- $$ = NEW_UNTIL(cond($3), $1, 1);
+ $$ = NEW_UNTIL(cond($4), $1, 1);
}
if (cond_negative(&$$->nd_cond)) {
@@ -788,5 +818,5 @@ stmt : kALIAS fitem {lex_state = EXPR_F
}
/*%
- $$ = dispatch2(until_mod, $3, $1);
+ $$ = dispatch2(until_mod, $4, $1);
%*/
}
@@ -805,4 +835,5 @@ stmt : kALIAS fitem {lex_state = EXPR_F
yyerror("BEGIN in method");
}
+ $<node>1 = parser->vcalls;
local_push(0);
/*%
@@ -818,4 +849,5 @@ stmt : kALIAS fitem {lex_state = EXPR_F
NEW_PREEXE($4));
local_pop();
+ parser->vcalls = $<node>1;
$$ = 0;
/*%
@@ -2732,4 +2764,5 @@ primary : literal
yyerror("class definition in method body");
class_nest++;
+ $<node>1 = parser->vcalls;
local_push(0);
$<num>$ = ruby_sourceline;
@@ -2747,4 +2780,5 @@ primary : literal
nd_set_line($$, $<num>4);
local_pop();
+ parser->vcalls = $<node>1;
class_nest--;
/*%
@@ -2768,4 +2802,5 @@ primary : literal
in_single = 0;
class_nest++;
+ $<node>1 = parser->vcalls;
local_push(0);
/*%
@@ -2782,4 +2817,5 @@ primary : literal
fixpos($$, $3);
local_pop();
+ parser->vcalls = $<node>1;
class_nest--;
in_def = $<num>4;
@@ -2798,4 +2834,5 @@ primary : literal
yyerror("module definition in method body");
class_nest++;
+ $<node>1 = parser->vcalls;
local_push(0);
$<num>$ = ruby_sourceline;
@@ -2813,4 +2850,5 @@ primary : literal
nd_set_line($$, $<num>3);
local_pop();
+ parser->vcalls = $<node>1;
class_nest--;
/*%
@@ -2825,4 +2863,5 @@ primary : literal
cur_mid = $2;
in_def++;
+ $<node>1 = parser->vcalls;
local_push(0);
/*%
@@ -2842,4 +2881,5 @@ primary : literal
fixpos($$, $4);
local_pop();
+ parser->vcalls = $<node>1;
in_def--;
cur_mid = $<id>3;
@@ -2854,4 +2894,5 @@ primary : literal
/*%%%*/
in_single++;
+ $<node>1 = parser->vcalls;
local_push(0);
lex_state = EXPR_END; /* force for args */
@@ -2871,4 +2912,5 @@ primary : literal
fixpos($$, $2);
local_pop();
+ parser->vcalls = $<node>1;
in_single--;
/*%
@@ -4317,11 +4359,4 @@ static int parser_here_document _((struc
# define whole_match_p(e,l,i) parser_whole_match_p(parser,e,l,i)
-#ifdef RIPPER
-/* FIXME */
-# define local_cnt(x) 3
-# define local_id(x) 1
-# define dyna_in_block() 1
-#endif /* RIPPER */
-
#ifndef RIPPER
# define set_yylval_str(x) yylval.node = NEW_STR(x)
@@ -7105,5 +7140,5 @@ gettable_gen(parser, id)
/* method call without arguments */
dyna_check(id);
- return NEW_VCALL(id);
+ return parser->vcalls = NEW_NODE(NODE_VCALL,0,id,parser->vcalls);
}
else if (is_global_id(id)) {
@@ -7915,4 +7950,6 @@ new_super(a)
}
+#define NEW_VCALL_LIST(n) NEW_NODE(NODE_VCALL,0,0,n)
+
static void
local_push_gen(parser, top)
@@ -7932,4 +7969,5 @@ local_push_gen(parser, top)
local->dyna_vars = ruby_dyna_vars;
lvtbl = local;
+ parser->vcalls = NEW_VCALL_LIST(parser->vcalls);
if (!top) {
/* preserve reference for GC, but link should be cut. */
@@ -7944,4 +7982,5 @@ local_pop_gen(parser)
{
struct local_vars *local = lvtbl->prev;
+ NODE *vcalls = parser->vcalls;
if (lvtbl->tbl) {
@@ -7952,4 +7991,10 @@ local_pop_gen(parser)
xfree(lvtbl->dnames);
}
+ while (vcalls) {
+ NODE *next = vcalls->nd_next;
+ vcalls->nd_next = 0;
+ vcalls = next;
+ }
+ parser->vcalls = 0;
ruby_dyna_vars = lvtbl->dyna_vars;
xfree(lvtbl);
@@ -8155,4 +8200,61 @@ dyna_init_gen(parser, node, pre)
}
+static void
+merge_vcalls(parser)
+ struct parser_params *parser;
+{
+ NODE **prev, *n;
+
+ for (n = *(prev = &parser->vcalls); n != 0; n = n->nd_next) {
+ if (n->nd_mid == 0) {
+ *prev = n->nd_next;
+ n->nd_next = parser->vcalls;
+ parser->vcalls = n;
+ break;
+ }
+ }
+}
+
+static void
+replace_vcall(parser, vcnt)
+ struct parser_params *parser;
+ int vcnt;
+{
+ NODE **prev, *n;
+ ID id, *names;
+ int i, ncnt;
+ enum node_type type;
+
+ if (dyna_in_block()) {
+ if (!(names = lvtbl->dnames)) return;
+ ncnt = lvtbl->dname_size;
+ type = NODE_DVAR;
+ }
+ else {
+ if (!(names = lvtbl->tbl)) return;
+ names++;
+ ncnt = lvtbl->cnt;
+ if (vcnt < 2) vcnt = 2;
+ type = NODE_LVAR;
+ }
+
+ if (vcnt >= ncnt) return;
+ prev = &parser->vcalls;
+ while ((n = *prev) != 0 && (id = n->nd_mid) != 0) {
+ for (i = vcnt; i < ncnt; ++i) {
+ if (id == names[i]) {
+ *prev = n->nd_next;
+ nd_set_type(n, type);
+ n->nd_mid = 0;
+ n->nd_vid = id;
+ n->nd_cnt = (type == NODE_LVAR) ? i : 0;
+ goto skip;
+ }
+ }
+ prev = &n->nd_next;
+ skip:;
+ }
+}
+
void
rb_gc_mark_parser()
@@ -8554,4 +8656,5 @@ parser_initialize(parser)
parser->parser_eval_tree_begin = 0;
parser->parser_eval_tree = 0;
+ parser->vcalls = 0;
#else
parser->parser_ruby_sourcefile = Qnil;
--
Nobu Nakada