Implement LAMBDA NODE locations

The following Location information has been added This is the information required for parse.y to be a universal parser:

```
❯ ruby --parser=prism --dump=parsetree -e "-> (a, b) do foo end"
@ ProgramNode (location: (1,0)-(1,20))
+-- locals: []
+-- statements:
    @ StatementsNode (location: (1,0)-(1,20))
    +-- body: (length: 1)
        +-- @ LambdaNode (location: (1,0)-(1,20))
            +-- locals: [:a, :b]
            +-- operator_loc: (1,0)-(1,2) = "->"
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            +-- opening_loc: (1,10)-(1,12) = "do"
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
            +-- closing_loc: (1,17)-(1,20) = "end"
                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: (snip)
```
This commit is contained in:
ydah 2024-11-02 17:21:51 +09:00 committed by Yudai Takada
parent 607b1b3d76
commit fa2517451e
5 changed files with 53 additions and 8 deletions

6
ast.c
View File

@ -812,6 +812,12 @@ node_locations(VALUE ast_value, const NODE *node)
location_new(nd_code_loc(node)),
location_new(&RNODE_EVSTR(node)->opening_loc),
location_new(&RNODE_EVSTR(node)->closing_loc));
case NODE_LAMBDA:
return rb_ary_new_from_args(4,
location_new(nd_code_loc(node)),
location_new(&RNODE_LAMBDA(node)->operator_loc),
location_new(&RNODE_LAMBDA(node)->opening_loc),
location_new(&RNODE_LAMBDA(node)->closing_loc));
case NODE_IF:
return rb_ary_new_from_args(4,
location_new(nd_code_loc(node)),

View File

@ -1113,8 +1113,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
ANN("lambda expression");
ANN("format: -> [nd_body]");
ANN("example: -> { foo }");
LAST_NODE;
F_NODE(nd_body, RNODE_LAMBDA, "lambda clause");
F_LOC(operator_loc, RNODE_LAMBDA);
F_LOC(opening_loc, RNODE_LAMBDA);
LAST_NODE;
F_LOC(closing_loc, RNODE_LAMBDA);
return;
case NODE_OPT_ARG:

39
parse.y
View File

@ -437,6 +437,13 @@ struct local_vars {
NODE *it;
};
typedef struct rb_locations_lambda_body_t {
NODE *node;
YYLTYPE loc;
YYLTYPE opening_loc;
YYLTYPE closing_loc;
} rb_locations_lambda_body_t;
enum {
ORDINAL_PARAM = -1,
NO_PARAM = 0,
@ -1155,7 +1162,7 @@ static rb_node_postexe_t *rb_node_postexe_new(struct parser_params *p, NODE *nd_
static rb_node_sym_t *rb_node_sym_new(struct parser_params *p, VALUE str, const YYLTYPE *loc);
static rb_node_dsym_t *rb_node_dsym_new(struct parser_params *p, rb_parser_string_t *string, long nd_alen, NODE *nd_next, const YYLTYPE *loc);
static rb_node_attrasgn_t *rb_node_attrasgn_new(struct parser_params *p, NODE *nd_recv, ID nd_mid, NODE *nd_args, const YYLTYPE *loc);
static rb_node_lambda_t *rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
static rb_node_lambda_t *rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc);
static rb_node_aryptn_t *rb_node_aryptn_new(struct parser_params *p, NODE *pre_args, NODE *rest_arg, NODE *post_args, const YYLTYPE *loc);
static rb_node_hshptn_t *rb_node_hshptn_new(struct parser_params *p, NODE *nd_pconst, NODE *nd_pkwargs, NODE *nd_pkwrestarg, const YYLTYPE *loc);
static rb_node_fndptn_t *rb_node_fndptn_new(struct parser_params *p, NODE *pre_rest_arg, NODE *args, NODE *post_rest_arg, const YYLTYPE *loc);
@ -1263,7 +1270,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
#define NEW_SYM(str,loc) (NODE *)rb_node_sym_new(p,str,loc)
#define NEW_DSYM(s,l,n,loc) (NODE *)rb_node_dsym_new(p,s,l,n,loc)
#define NEW_ATTRASGN(r,m,a,loc) (NODE *)rb_node_attrasgn_new(p,r,m,a,loc)
#define NEW_LAMBDA(a,b,loc) (NODE *)rb_node_lambda_new(p,a,b,loc)
#define NEW_LAMBDA(a,b,loc,op_loc,o_loc,c_loc) (NODE *)rb_node_lambda_new(p,a,b,loc,op_loc,o_loc,c_loc)
#define NEW_ARYPTN(pre,r,post,loc) (NODE *)rb_node_aryptn_new(p,pre,r,post,loc)
#define NEW_HSHPTN(c,kw,kwrest,loc) (NODE *)rb_node_hshptn_new(p,c,kw,kwrest,loc)
#define NEW_FNDPTN(pre,a,post,loc) (NODE *)rb_node_fndptn_new(p,pre,a,post,loc)
@ -1486,6 +1493,8 @@ static NODE *heredoc_dedent(struct parser_params*,NODE*);
static void check_literal_when(struct parser_params *p, NODE *args, const YYLTYPE *loc);
static rb_locations_lambda_body_t* new_locations_lambda_body(struct parser_params *p, NODE *node, const YYLTYPE *loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc);
#ifdef RIPPER
#define get_value(idx) (rb_ary_entry(p->s_value_stack, idx))
#define set_value(val) (p->s_lvalue = val)
@ -2670,6 +2679,7 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
rb_node_masgn_t *node_masgn;
rb_node_def_temp_t *node_def_temp;
rb_node_exits_t *node_exits;
struct rb_locations_lambda_body_t *locations_lambda_body;
ID id;
int num;
st_table *tbl;
@ -2776,7 +2786,8 @@ rb_parser_ary_free(rb_parser_t *p, rb_parser_ary_t *ary)
%type <node_args> block_param opt_block_param block_param_def
%type <node_kw_arg> f_kw f_block_kw
%type <id> bv_decls opt_bv_decl bvar
%type <node> lambda lambda_body brace_body do_body
%type <node> lambda brace_body do_body
%type <locations_lambda_body> lambda_body
%type <node_args> f_larglist
%type <node> brace_block cmd_brace_block do_block lhs none fitem
%type <node> mlhs_head mlhs_item mlhs_node mlhs_post
@ -5183,7 +5194,7 @@ lambda : tLAMBDA[lpar]
$args = args_with_numbered(p, $args, max_numparam, it_id);
{
YYLTYPE loc = code_loc_gen(&@args, &@body);
$$ = NEW_LAMBDA($args, $body, &loc);
$$ = NEW_LAMBDA($args, $body->node, &loc, &@lpar, &$body->opening_loc, &$body->closing_loc);
nd_set_line(RNODE_LAMBDA($$)->nd_body, @body.end_pos.lineno);
nd_set_line($$, @args.end_pos.lineno);
nd_set_first_loc($$, @1.beg_pos);
@ -5213,7 +5224,7 @@ f_larglist : '(' f_args opt_bv_decl ')'
lambda_body : tLAMBEG compstmt '}'
{
token_info_pop(p, "}", &@3);
$$ = $2;
$$ = new_locations_lambda_body(p, $2, &@2, &@1, &@3);
/*% ripper: $:2 %*/
}
| keyword_do_LAMBDA
@ -5222,7 +5233,7 @@ lambda_body : tLAMBEG compstmt '}'
}
bodystmt k_end
{
$$ = $3;
$$ = new_locations_lambda_body(p, $3, &@3, &@1, &@4);
/*% ripper: $:3 %*/
}
;
@ -11588,12 +11599,15 @@ rb_node_iter_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body
}
static rb_node_lambda_t *
rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc)
rb_node_lambda_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *operator_loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc)
{
/* Keep the order of node creation */
NODE *scope = NEW_SCOPE(nd_args, nd_body, loc);
rb_node_lambda_t *n = NODE_NEWNODE(NODE_LAMBDA, rb_node_lambda_t, loc);
n->nd_body = scope;
n->operator_loc = *operator_loc;
n->opening_loc = *opening_loc;
n->closing_loc = *closing_loc;
return n;
}
@ -12894,6 +12908,17 @@ new_command_qcall(struct parser_params* p, ID atype, NODE *recv, ID mid, NODE *a
return ret;
}
static rb_locations_lambda_body_t*
new_locations_lambda_body(struct parser_params* p, NODE *node, const YYLTYPE *loc, const YYLTYPE *opening_loc, const YYLTYPE *closing_loc)
{
rb_locations_lambda_body_t *body = xcalloc(1, sizeof(rb_locations_lambda_body_t));
body->node = node;
body->loc = *loc;
body->opening_loc = *opening_loc;
body->closing_loc = *closing_loc;
return body;
}
#define nd_once_body(node) (nd_type_p((node), NODE_ONCE) ? RNODE_ONCE(node)->nd_body : node)
static NODE*

View File

@ -968,6 +968,9 @@ typedef struct RNode_LAMBDA {
NODE node;
struct RNode *nd_body;
rb_code_location_t operator_loc;
rb_code_location_t opening_loc;
rb_code_location_t closing_loc;
} rb_node_lambda_t;
typedef struct RNode_ARYPTN {

View File

@ -1384,6 +1384,14 @@ dummy
assert_locations(node.children[-1].children[1].locations, [[1, 0, 1, 5], [1, 1, 1, 2], nil])
end
def test_lambda_locations
node = ast_parse("-> (a, b) { foo }")
assert_locations(node.children[-1].locations, [[1, 0, 1, 17], [1, 0, 1, 2], [1, 10, 1, 11], [1, 16, 1, 17]])
node = ast_parse("-> (a, b) do foo end")
assert_locations(node.children[-1].locations, [[1, 0, 1, 20], [1, 0, 1, 2], [1, 10, 1, 12], [1, 17, 1, 20]])
end
def test_if_locations
node = ast_parse("if cond then 1 else 2 end")
assert_locations(node.children[-1].locations, [[1, 0, 1, 25], [1, 0, 1, 2], [1, 8, 1, 12], [1, 22, 1, 25]])