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,
location_new(nd_code_loc(node)),
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:
return rb_ary_new_from_args(2,
location_new(nd_code_loc(node)),
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:
return rb_ary_new_from_args(2,
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("format: break [nd_stts]");
ANN("example: break 1");
LAST_NODE;
F_NODE(nd_stts, RNODE_BREAK, "value");
LAST_NODE;
F_LOC(keyword_loc, RNODE_REDO);
return;
case NODE_NEXT:
ANN("next statement");
ANN("format: next [nd_stts]");
ANN("example: next 1");
LAST_NODE;
F_NODE(nd_stts, RNODE_NEXT, "value");
LAST_NODE;
F_LOC(keyword_loc, RNODE_REDO);
return;
case NODE_RETURN:
ANN("return statement");
@ -374,6 +376,7 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("redo statement");
ANN("format: redo");
ANN("example: redo");
F_LOC(keyword_loc, RNODE_REDO);
return;
case NODE_RETRY:

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

@ -1313,15 +1313,15 @@ struct RNode_DEF_TEMP {
#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_next_t *rb_node_next_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc);
static rb_node_redo_t *rb_node_redo_new(struct parser_params *p, 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, const YYLTYPE *keyword_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 *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_NEXT(s,loc) (NODE *)rb_node_next_new(p,s,loc)
#define NEW_REDO(loc) (NODE *)rb_node_redo_new(p,loc)
#define NEW_BREAK(s,loc,k_loc) (NODE *)rb_node_break_new(p,s,loc,k_loc)
#define NEW_NEXT(s,loc,k_loc) (NODE *)rb_node_next_new(p,s,loc,k_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)
/* 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;
args = ret_args(p, $2);
$$ = add_block_exit(p, NEW_BREAK(args, &@$));
$$ = add_block_exit(p, NEW_BREAK(args, &@$, &@1));
/*% ripper: break!($:2) %*/
}
| keyword_next call_args
{
NODE *args = 0;
args = ret_args(p, $2);
$$ = add_block_exit(p, NEW_NEXT(args, &@$));
$$ = add_block_exit(p, NEW_NEXT(args, &@$, &@1));
/*% ripper: next!($:2) %*/
}
;
@ -4701,17 +4701,17 @@ primary : literal
}
| keyword_break
{
$$ = add_block_exit(p, NEW_BREAK(0, &@$));
$$ = add_block_exit(p, NEW_BREAK(0, &@$, &@1));
/*% ripper: break!(args_new!) %*/
}
| keyword_next
{
$$ = add_block_exit(p, NEW_NEXT(0, &@$));
$$ = add_block_exit(p, NEW_NEXT(0, &@$, &@1));
/*% ripper: next!(args_new!) %*/
}
| keyword_redo
{
$$ = add_block_exit(p, NEW_REDO(&@$));
$$ = add_block_exit(p, NEW_REDO(&@$, &@1));
/*% ripper: redo! %*/
}
| keyword_retry
@ -12468,30 +12468,33 @@ rb_node_error_new(struct parser_params *p, const YYLTYPE *loc)
}
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);
n->nd_stts = nd_stts;
n->nd_chain = 0;
n->keyword_loc = *keyword_loc;
return n;
}
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);
n->nd_stts = nd_stts;
n->nd_chain = 0;
n->keyword_loc = *keyword_loc;
return n;
}
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);
n->nd_chain = 0;
n->keyword_loc = *keyword_loc;
return n;
}

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

@ -345,6 +345,7 @@ typedef struct RNode_EXITS {
struct RNode *nd_chain;
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;
typedef struct RNode_RETRY {

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

@ -1343,6 +1343,16 @@ dummy
assert_locations(node.children[-1].locations, [[1, 0, 1, 6], [1, 2, 1, 4]])
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
node = RubyVM::AbstractSyntaxTree.parse("1 or 2")
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]])
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
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]])