Implement BREAK, NEXT and REDO NODE locations

This commit is contained in:
ydah 2024-09-10 16:41:27 +09:00 коммит произвёл Yuichiro Kaneko
Родитель f7ffa76377
Коммит d03e0d1c35
5 изменённых файлов: 50 добавлений и 16 удалений

12
ast.c
Просмотреть файл

@ -783,10 +783,22 @@ node_locations(VALUE ast_value, const NODE *node)
return rb_ary_new_from_args(2, return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)), location_new(nd_code_loc(node)),
location_new(&RNODE_AND(node)->operator_loc)); location_new(&RNODE_AND(node)->operator_loc));
case NODE_BREAK:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
location_new(&RNODE_BREAK(node)->keyword_loc));
case NODE_NEXT:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
location_new(&RNODE_NEXT(node)->keyword_loc));
case NODE_OR: case NODE_OR:
return rb_ary_new_from_args(2, return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)), location_new(nd_code_loc(node)),
location_new(&RNODE_OR(node)->operator_loc)); location_new(&RNODE_OR(node)->operator_loc));
case NODE_REDO:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
location_new(&RNODE_REDO(node)->keyword_loc));
case NODE_UNDEF: case NODE_UNDEF:
return rb_ary_new_from_args(2, return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)), location_new(nd_code_loc(node)),

Просмотреть файл

@ -352,15 +352,17 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("break statement"); ANN("break statement");
ANN("format: break [nd_stts]"); ANN("format: break [nd_stts]");
ANN("example: break 1"); ANN("example: break 1");
LAST_NODE;
F_NODE(nd_stts, RNODE_BREAK, "value"); F_NODE(nd_stts, RNODE_BREAK, "value");
LAST_NODE;
F_LOC(keyword_loc, RNODE_REDO);
return; return;
case NODE_NEXT: case NODE_NEXT:
ANN("next statement"); ANN("next statement");
ANN("format: next [nd_stts]"); ANN("format: next [nd_stts]");
ANN("example: next 1"); ANN("example: next 1");
LAST_NODE;
F_NODE(nd_stts, RNODE_NEXT, "value"); F_NODE(nd_stts, RNODE_NEXT, "value");
LAST_NODE;
F_LOC(keyword_loc, RNODE_REDO);
return; return;
case NODE_RETURN: case NODE_RETURN:
ANN("return statement"); ANN("return statement");
@ -374,6 +376,7 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("redo statement"); ANN("redo statement");
ANN("format: redo"); ANN("format: redo");
ANN("example: redo"); ANN("example: redo");
F_LOC(keyword_loc, RNODE_REDO);
return; return;
case NODE_RETRY: case NODE_RETRY:

31
parse.y
Просмотреть файл

@ -1313,15 +1313,15 @@ struct RNode_DEF_TEMP {
#define RNODE_DEF_TEMP(node) ((struct RNode_DEF_TEMP *)(node)) #define RNODE_DEF_TEMP(node) ((struct RNode_DEF_TEMP *)(node))
static rb_node_break_t *rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc); static rb_node_break_t *rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
static rb_node_next_t *rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc); static rb_node_next_t *rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
static rb_node_redo_t *rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc); static rb_node_redo_t *rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
static rb_node_def_temp_t *rb_node_def_temp_new(struct parser_params *p, const YYLTYPE *loc); static rb_node_def_temp_t *rb_node_def_temp_new(struct parser_params *p, const YYLTYPE *loc);
static rb_node_def_temp_t *def_head_save(struct parser_params *p, rb_node_def_temp_t *n); static rb_node_def_temp_t *def_head_save(struct parser_params *p, rb_node_def_temp_t *n);
#define NEW_BREAK(s,loc) (NODE *)rb_node_break_new(p,s,loc) #define NEW_BREAK(s,loc,k_loc) (NODE *)rb_node_break_new(p,s,loc,k_loc)
#define NEW_NEXT(s,loc) (NODE *)rb_node_next_new(p,s,loc) #define NEW_NEXT(s,loc,k_loc) (NODE *)rb_node_next_new(p,s,loc,k_loc)
#define NEW_REDO(loc) (NODE *)rb_node_redo_new(p,loc) #define NEW_REDO(loc,k_loc) (NODE *)rb_node_redo_new(p,loc,k_loc)
#define NEW_DEF_TEMP(loc) rb_node_def_temp_new(p,loc) #define NEW_DEF_TEMP(loc) rb_node_def_temp_new(p,loc)
/* Make a new internal node, which should not be appeared in the /* Make a new internal node, which should not be appeared in the
@ -3538,14 +3538,14 @@ command : fcall command_args %prec tLOWEST
{ {
NODE *args = 0; NODE *args = 0;
args = ret_args(p, $2); args = ret_args(p, $2);
$$ = add_block_exit(p, NEW_BREAK(args, &@$)); $$ = add_block_exit(p, NEW_BREAK(args, &@$, &@1));
/*% ripper: break!($:2) %*/ /*% ripper: break!($:2) %*/
} }
| keyword_next call_args | keyword_next call_args
{ {
NODE *args = 0; NODE *args = 0;
args = ret_args(p, $2); args = ret_args(p, $2);
$$ = add_block_exit(p, NEW_NEXT(args, &@$)); $$ = add_block_exit(p, NEW_NEXT(args, &@$, &@1));
/*% ripper: next!($:2) %*/ /*% ripper: next!($:2) %*/
} }
; ;
@ -4701,17 +4701,17 @@ primary : literal
} }
| keyword_break | keyword_break
{ {
$$ = add_block_exit(p, NEW_BREAK(0, &@$)); $$ = add_block_exit(p, NEW_BREAK(0, &@$, &@1));
/*% ripper: break!(args_new!) %*/ /*% ripper: break!(args_new!) %*/
} }
| keyword_next | keyword_next
{ {
$$ = add_block_exit(p, NEW_NEXT(0, &@$)); $$ = add_block_exit(p, NEW_NEXT(0, &@$, &@1));
/*% ripper: next!(args_new!) %*/ /*% ripper: next!(args_new!) %*/
} }
| keyword_redo | keyword_redo
{ {
$$ = add_block_exit(p, NEW_REDO(&@$)); $$ = add_block_exit(p, NEW_REDO(&@$, &@1));
/*% ripper: redo! %*/ /*% ripper: redo! %*/
} }
| keyword_retry | keyword_retry
@ -12468,30 +12468,33 @@ rb_node_error_new(struct parser_params *p, const YYLTYPE *loc)
} }
static rb_node_break_t * static rb_node_break_t *
rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc) rb_node_break_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
{ {
rb_node_break_t *n = NODE_NEWNODE(NODE_BREAK, rb_node_break_t, loc); rb_node_break_t *n = NODE_NEWNODE(NODE_BREAK, rb_node_break_t, loc);
n->nd_stts = nd_stts; n->nd_stts = nd_stts;
n->nd_chain = 0; n->nd_chain = 0;
n->keyword_loc = *keyword_loc;
return n; return n;
} }
static rb_node_next_t * static rb_node_next_t *
rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc) rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
{ {
rb_node_next_t *n = NODE_NEWNODE(NODE_NEXT, rb_node_next_t, loc); rb_node_next_t *n = NODE_NEWNODE(NODE_NEXT, rb_node_next_t, loc);
n->nd_stts = nd_stts; n->nd_stts = nd_stts;
n->nd_chain = 0; n->nd_chain = 0;
n->keyword_loc = *keyword_loc;
return n; return n;
} }
static rb_node_redo_t * static rb_node_redo_t *
rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc) rb_node_redo_new(struct parser_params *p, const YYLTYPE *loc, const YYLTYPE *keyword_loc)
{ {
rb_node_redo_t *n = NODE_NEWNODE(NODE_REDO, rb_node_redo_t, loc); rb_node_redo_t *n = NODE_NEWNODE(NODE_REDO, rb_node_redo_t, loc);
n->nd_chain = 0; n->nd_chain = 0;
n->keyword_loc = *keyword_loc;
return n; return n;
} }

Просмотреть файл

@ -345,6 +345,7 @@ typedef struct RNode_EXITS {
struct RNode *nd_chain; struct RNode *nd_chain;
struct RNode *nd_stts; struct RNode *nd_stts;
rb_code_location_t keyword_loc;
} rb_node_exits_t, rb_node_break_t, rb_node_next_t, rb_node_redo_t; } rb_node_exits_t, rb_node_break_t, rb_node_next_t, rb_node_redo_t;
typedef struct RNode_RETRY { typedef struct RNode_RETRY {

Просмотреть файл

@ -1343,6 +1343,16 @@ dummy
assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]]) assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]])
end end
def test_break_locations
node = RubyVM::AbstractSyntaxTree.parse("loop { break 1 }")
assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 14], [1, 7, 1, 12]])
end
def test_next_locations
node = RubyVM::AbstractSyntaxTree.parse("loop { next 1 }")
assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 13], [1, 7, 1, 11]])
end
def test_or_locations def test_or_locations
node = RubyVM::AbstractSyntaxTree.parse("1 or 2") node = RubyVM::AbstractSyntaxTree.parse("1 or 2")
assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]]) assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]])
@ -1351,6 +1361,11 @@ dummy
assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]]) assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]])
end end
def test_redo_locations
node = RubyVM::AbstractSyntaxTree.parse("loop { redo }")
assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 11], [1, 7, 1, 11]])
end
def test_unless_locations def test_unless_locations
node = RubyVM::AbstractSyntaxTree.parse("unless cond then 1 else 2 end") node = RubyVM::AbstractSyntaxTree.parse("unless cond then 1 else 2 end")
assert_locations(node.children[-1].locations, [[1, 0, 1, 29], [1, 0, 1, 6], [1, 12, 1, 16], [1, 26, 1, 29]]) assert_locations(node.children[-1].locations, [[1, 0, 1, 29], [1, 0, 1, 6], [1, 12, 1, 16], [1, 26, 1, 29]])