зеркало из https://github.com/github/ruby.git
Implement BREAK, NEXT and REDO NODE locations
This commit is contained in:
Родитель
f7ffa76377
Коммит
d03e0d1c35
12
ast.c
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
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]])
|
||||||
|
|
Загрузка…
Ссылка в новой задаче