зеркало из https://github.com/github/ruby.git
Implement UNLESS NODE keyword locations
This commit is contained in:
Родитель
f23485a8d6
Коммит
57b11be15a
14
ast.c
14
ast.c
|
@ -747,12 +747,20 @@ ast_node_children(rb_execution_context_t *ec, VALUE self)
|
|||
return node_children(data->ast_value, data->node);
|
||||
}
|
||||
|
||||
static int
|
||||
null_loc_p(rb_code_location_t *loc)
|
||||
{
|
||||
return (loc->beg_pos.lineno == 0 && loc->beg_pos.column == -1 && loc->end_pos.lineno == 0 && loc->end_pos.column == -1);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
location_new(rb_code_location_t *loc)
|
||||
{
|
||||
VALUE obj;
|
||||
struct ASTLocationData *data;
|
||||
|
||||
if (null_loc_p(loc)) return Qnil;
|
||||
|
||||
obj = TypedData_Make_Struct(rb_cLocation, struct ASTLocationData, &rb_location_type, data);
|
||||
data->first_lineno = loc->beg_pos.lineno;
|
||||
data->first_column = loc->beg_pos.column;
|
||||
|
@ -767,6 +775,12 @@ node_locations(VALUE ast_value, const NODE *node)
|
|||
{
|
||||
enum node_type type = nd_type(node);
|
||||
switch (type) {
|
||||
case NODE_UNLESS:
|
||||
return rb_ary_new_from_args(4,
|
||||
location_new(nd_code_loc(node)),
|
||||
location_new(&RNODE_UNLESS(node)->keyword_loc),
|
||||
location_new(&RNODE_UNLESS(node)->then_keyword_loc),
|
||||
location_new(&RNODE_UNLESS(node)->end_keyword_loc));
|
||||
case NODE_ARGS_AUX:
|
||||
case NODE_LAST:
|
||||
break;
|
||||
|
|
10
node_dump.c
10
node_dump.c
|
@ -27,6 +27,10 @@
|
|||
#define A_INT(val) rb_str_catf(buf, "%d", (val))
|
||||
#define A_LONG(val) rb_str_catf(buf, "%ld", (val))
|
||||
#define A_LIT(lit) AR(rb_dump_literal(lit))
|
||||
#define A_LOC(loc) \
|
||||
rb_str_catf(buf, "(%d,%d)-(%d,%d)", \
|
||||
loc.beg_pos.lineno, loc.beg_pos.column, \
|
||||
loc.end_pos.lineno, loc.end_pos.column)
|
||||
#define A_NODE_HEADER(node, term) \
|
||||
rb_str_catf(buf, "@ %s (id: %d, line: %d, location: (%d,%d)-(%d,%d))%s"term, \
|
||||
ruby_node_name(nd_type(node)), nd_node_id(node), nd_line(node), \
|
||||
|
@ -84,6 +88,7 @@
|
|||
#define F_LIT(name, type, ann) SIMPLE_FIELD1(#name, ann) A_LIT(type(node)->name)
|
||||
#define F_VALUE(name, val, ann) SIMPLE_FIELD1(#name, ann) A_LIT(val)
|
||||
#define F_MSG(name, ann, desc) SIMPLE_FIELD1(#name, ann) A(desc)
|
||||
#define F_LOC(name, type) SIMPLE_FIELD1(#name, "") A_LOC(type(node)->name)
|
||||
#define F_SHAREABILITY(name, type, ann) SIMPLE_FIELD1(#name, ann) A_SHAREABILITY(type(node)->name)
|
||||
|
||||
#define F_NODE(name, type, ann) \
|
||||
|
@ -244,8 +249,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
|
|||
ANN("example: unless x == 1 then foo else bar end");
|
||||
F_NODE(nd_cond, RNODE_UNLESS, "condition expr");
|
||||
F_NODE(nd_body, RNODE_UNLESS, "then clause");
|
||||
LAST_NODE;
|
||||
F_NODE(nd_else, RNODE_UNLESS, "else clause");
|
||||
F_LOC(keyword_loc, RNODE_UNLESS);
|
||||
F_LOC(then_keyword_loc, RNODE_UNLESS);
|
||||
LAST_NODE;
|
||||
F_LOC(end_keyword_loc, RNODE_UNLESS);
|
||||
return;
|
||||
|
||||
case NODE_CASE:
|
||||
|
|
21
parse.y
21
parse.y
|
@ -1060,7 +1060,7 @@ static rb_node_scope_t *rb_node_scope_new(struct parser_params *p, rb_node_args_
|
|||
static rb_node_scope_t *rb_node_scope_new2(struct parser_params *p, rb_ast_id_table_t *nd_tbl, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
|
||||
static rb_node_block_t *rb_node_block_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc);
|
||||
static rb_node_if_t *rb_node_if_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc);
|
||||
static rb_node_unless_t *rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc);
|
||||
static rb_node_unless_t *rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *end_keyword_loc);
|
||||
static rb_node_case_t *rb_node_case_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
|
||||
static rb_node_case2_t *rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc);
|
||||
static rb_node_case3_t *rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc);
|
||||
|
@ -1168,7 +1168,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
|
|||
#define NEW_SCOPE2(t,a,b,loc) (NODE *)rb_node_scope_new2(p,t,a,b,loc)
|
||||
#define NEW_BLOCK(a,loc) (NODE *)rb_node_block_new(p,a,loc)
|
||||
#define NEW_IF(c,t,e,loc) (NODE *)rb_node_if_new(p,c,t,e,loc)
|
||||
#define NEW_UNLESS(c,t,e,loc) (NODE *)rb_node_unless_new(p,c,t,e,loc)
|
||||
#define NEW_UNLESS(c,t,e,loc,k_loc,t_loc,e_loc) (NODE *)rb_node_unless_new(p,c,t,e,loc,k_loc,t_loc,e_loc)
|
||||
#define NEW_CASE(h,b,loc) (NODE *)rb_node_case_new(p,h,b,loc)
|
||||
#define NEW_CASE2(b,loc) (NODE *)rb_node_case2_new(p,b,loc)
|
||||
#define NEW_CASE3(h,b,loc) (NODE *)rb_node_case3_new(p,h,b,loc)
|
||||
|
@ -1389,7 +1389,7 @@ static NODE* method_cond(struct parser_params *p, NODE *node, const YYLTYPE *loc
|
|||
#define new_nil(loc) NEW_NIL(loc)
|
||||
static NODE *new_nil_at(struct parser_params *p, const rb_code_position_t *pos);
|
||||
static NODE *new_if(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*);
|
||||
static NODE *new_unless(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*);
|
||||
static NODE *new_unless(struct parser_params*,NODE*,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*);
|
||||
static NODE *logop(struct parser_params*,ID,NODE*,NODE*,const YYLTYPE*,const YYLTYPE*);
|
||||
|
||||
static NODE *newline_node(NODE*);
|
||||
|
@ -3167,7 +3167,7 @@ stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
|
|||
}
|
||||
| stmt modifier_unless expr_value
|
||||
{
|
||||
$$ = new_unless(p, $3, remove_begin($1), 0, &@$);
|
||||
$$ = new_unless(p, $3, remove_begin($1), 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
|
||||
fixpos($$, $3);
|
||||
/*% ripper: unless_mod!($:3, $:1) %*/
|
||||
}
|
||||
|
@ -4516,7 +4516,7 @@ primary : literal
|
|||
opt_else
|
||||
k_end
|
||||
{
|
||||
$$ = new_unless(p, $2, $4, $5, &@$);
|
||||
$$ = new_unless(p, $2, $4, $5, &@$, &@1, &@3, &@6);
|
||||
fixpos($$, $2);
|
||||
/*% ripper: unless!($:2, $:4, $:5) %*/
|
||||
}
|
||||
|
@ -5488,7 +5488,7 @@ p_top_expr : p_top_expr_body
|
|||
}
|
||||
| p_top_expr_body modifier_unless expr_value
|
||||
{
|
||||
$$ = new_unless(p, $3, $1, 0, &@$);
|
||||
$$ = new_unless(p, $3, $1, 0, &@$, &@2, &NULL_LOC, &NULL_LOC);
|
||||
fixpos($$, $3);
|
||||
/*% ripper: unless_mod!($:3, $:1) %*/
|
||||
}
|
||||
|
@ -11530,12 +11530,15 @@ rb_node_if_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_e
|
|||
}
|
||||
|
||||
static rb_node_unless_t *
|
||||
rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc)
|
||||
rb_node_unless_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, NODE *nd_else, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *end_keyword_loc)
|
||||
{
|
||||
rb_node_unless_t *n = NODE_NEWNODE(NODE_UNLESS, rb_node_unless_t, loc);
|
||||
n->nd_cond = nd_cond;
|
||||
n->nd_body = nd_body;
|
||||
n->nd_else = nd_else;
|
||||
n->keyword_loc = *keyword_loc;
|
||||
n->then_keyword_loc = *then_keyword_loc;
|
||||
n->end_keyword_loc = *end_keyword_loc;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -14319,11 +14322,11 @@ new_if(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE
|
|||
}
|
||||
|
||||
static NODE*
|
||||
new_unless(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE *loc)
|
||||
new_unless(struct parser_params *p, NODE *cc, NODE *left, NODE *right, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *end_keyword_loc)
|
||||
{
|
||||
if (!cc) return right;
|
||||
cc = cond0(p, cc, COND_IN_COND, loc, true);
|
||||
return newline_node(NEW_UNLESS(cc, left, right, loc));
|
||||
return newline_node(NEW_UNLESS(cc, left, right, loc, keyword_loc, then_keyword_loc, end_keyword_loc));
|
||||
}
|
||||
|
||||
#define NEW_AND_OR(type, f, s, loc) (type == NODE_AND ? NEW_AND(f,s,loc) : NEW_OR(f,s,loc))
|
||||
|
|
|
@ -273,6 +273,9 @@ typedef struct RNode_UNLESS {
|
|||
struct RNode *nd_cond;
|
||||
struct RNode *nd_body;
|
||||
struct RNode *nd_else;
|
||||
rb_code_location_t keyword_loc;
|
||||
rb_code_location_t then_keyword_loc;
|
||||
rb_code_location_t end_keyword_loc;
|
||||
} rb_node_unless_t;
|
||||
|
||||
typedef struct RNode_CASE {
|
||||
|
|
|
@ -1327,12 +1327,22 @@ dummy
|
|||
class TestLocation < Test::Unit::TestCase
|
||||
def test_lineno_and_column
|
||||
node = RubyVM::AbstractSyntaxTree.parse("1 + 2")
|
||||
location = node.locations[0]
|
||||
assert_locations(node.locations, [[1, 0, 1, 5]])
|
||||
end
|
||||
|
||||
assert_equal(1, location.first_lineno)
|
||||
assert_equal(0, location.first_column)
|
||||
assert_equal(1, location.last_lineno)
|
||||
assert_equal(5, location.last_column)
|
||||
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]])
|
||||
|
||||
node = RubyVM::AbstractSyntaxTree.parse("1 unless 2")
|
||||
assert_locations(node.children[-1].locations, [[1, 0, 1, 10], [1, 2, 1, 8], nil, nil])
|
||||
end
|
||||
|
||||
private
|
||||
def assert_locations(locations, expected)
|
||||
ary = locations.map {|loc| loc && [loc.first_lineno, loc.first_column, loc.last_lineno, loc.last_column] }
|
||||
|
||||
assert_equal(ary, expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче