From 4775d1ffa8a34f0bca3f6124c98426d56eb8e1b6 Mon Sep 17 00:00:00 2001 From: S-H-GAMELINKS Date: Sun, 10 Aug 2025 21:30:41 +0900 Subject: [PATCH] Add NODE IN locations Add locations to struct `RNode_IN`. memo: ```bash > ruby -e 'case 1; in 2 then 3; end' --parser=prism --dump=parsetree @ ProgramNode (location: (1,0)-(1,24)) +-- locals: [] +-- statements: @ StatementsNode (location: (1,0)-(1,24)) +-- body: (length: 1) +-- @ CaseMatchNode (location: (1,0)-(1,24)) +-- predicate: | @ IntegerNode (location: (1,5)-(1,6)) | +-- IntegerBaseFlags: decimal | +-- value: 1 +-- conditions: (length: 1) | +-- @ InNode (location: (1,8)-(1,19)) | +-- pattern: | | @ IntegerNode (location: (1,11)-(1,12)) | | +-- IntegerBaseFlags: decimal | | +-- value: 2 | +-- statements: | | @ StatementsNode (location: (1,18)-(1,19)) | | +-- body: (length: 1) | | +-- @ IntegerNode (location: (1,18)-(1,19)) | | +-- IntegerBaseFlags: decimal | | +-- value: 3 | +-- in_loc: (1,8)-(1,10) = "in" | +-- then_loc: (1,13)-(1,17) = "then" +-- else_clause: nil +-- case_keyword_loc: (1,0)-(1,4) = "case" +-- end_keyword_loc: (1,21)-(1,24) = "end" ``` --- ast.c | 6 ++++++ node_dump.c | 5 ++++- parse.y | 15 +++++++++------ rubyparser.h | 3 +++ test/ruby/test_ast.rb | 14 ++++++++++++++ 5 files changed, 36 insertions(+), 7 deletions(-) diff --git a/ast.c b/ast.c index bc2adeacd6..04b9543854 100644 --- a/ast.c +++ b/ast.c @@ -866,6 +866,12 @@ node_locations(VALUE ast_value, const NODE *node) location_new(&RNODE_IF(node)->if_keyword_loc), location_new(&RNODE_IF(node)->then_keyword_loc), location_new(&RNODE_IF(node)->end_keyword_loc)); + case NODE_IN: + return rb_ary_new_from_args(4, + location_new(nd_code_loc(node)), + location_new(&RNODE_IN(node)->in_keyword_loc), + location_new(&RNODE_IN(node)->then_keyword_loc), + location_new(&RNODE_IN(node)->operator_loc)); case NODE_MODULE: return rb_ary_new_from_args(3, location_new(nd_code_loc(node)), diff --git a/node_dump.c b/node_dump.c index c318baeeed..18ac3d7b35 100644 --- a/node_dump.c +++ b/node_dump.c @@ -309,8 +309,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node) ANN("example: case x; in 1; foo; in 2; bar; else baz; end"); F_NODE(nd_head, RNODE_IN, "in pattern"); F_NODE(nd_body, RNODE_IN, "in body"); - LAST_NODE; F_NODE(nd_next, RNODE_IN, "next in clause"); + F_LOC(in_keyword_loc, RNODE_IN); + F_LOC(then_keyword_loc, RNODE_IN); + LAST_NODE; + F_LOC(operator_loc, RNODE_IN); return; case NODE_WHILE: diff --git a/parse.y b/parse.y index e77dc790bc..c0f46a395f 100644 --- a/parse.y +++ b/parse.y @@ -1070,7 +1070,7 @@ static rb_node_case_t *rb_node_case_new(struct parser_params *p, NODE *nd_head, static rb_node_case2_t *rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc); static rb_node_case3_t *rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc); static rb_node_when_t *rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc); -static rb_node_in_t *rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc); +static rb_node_in_t *rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *in_keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *operator_loc); static rb_node_while_t *rb_node_while_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc); static rb_node_until_t *rb_node_until_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc); static rb_node_iter_t *rb_node_iter_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc); @@ -1178,7 +1178,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE #define NEW_CASE2(b,loc,ck_loc,ek_loc) (NODE *)rb_node_case2_new(p,b,loc,ck_loc,ek_loc) #define NEW_CASE3(h,b,loc,ck_loc,ek_loc) (NODE *)rb_node_case3_new(p,h,b,loc,ck_loc,ek_loc) #define NEW_WHEN(c,t,e,loc,k_loc,t_loc) (NODE *)rb_node_when_new(p,c,t,e,loc,k_loc,t_loc) -#define NEW_IN(c,t,e,loc) (NODE *)rb_node_in_new(p,c,t,e,loc) +#define NEW_IN(c,t,e,loc,ik_loc,tk_loc,o_loc) (NODE *)rb_node_in_new(p,c,t,e,loc,ik_loc,tk_loc,o_loc) #define NEW_WHILE(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_while_new(p,c,b,n,loc,k_loc,c_loc) #define NEW_UNTIL(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_until_new(p,c,b,n,loc,k_loc,c_loc) #define NEW_ITER(a,b,loc) (NODE *)rb_node_iter_new(p,a,b,loc) @@ -3472,7 +3472,7 @@ expr : command_call pop_pktbl(p, $p_pktbl); pop_pvtbl(p, $p_pvtbl); p->ctxt.in_kwarg = $ctxt.in_kwarg; - $$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body), &@$, &NULL_LOC, &NULL_LOC); + $$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body, &NULL_LOC, &NULL_LOC, &@2), &@$, &NULL_LOC, &NULL_LOC); /*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/ } | arg keyword_in @@ -3485,7 +3485,7 @@ expr : command_call pop_pktbl(p, $p_pktbl); pop_pvtbl(p, $p_pvtbl); p->ctxt.in_kwarg = $ctxt.in_kwarg; - $$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body), &@$, &NULL_LOC, &NULL_LOC); + $$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body, &@keyword_in, &NULL_LOC, &NULL_LOC), &@$, &NULL_LOC, &NULL_LOC); /*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/ } | arg %prec tLBRACE_ARG @@ -5399,7 +5399,7 @@ p_case_body : keyword_in compstmt(stmts) p_cases[cases] { - $$ = NEW_IN($expr, $compstmt, $cases, &@$); + $$ = NEW_IN($expr, $compstmt, $cases, &@$, &@keyword_in, &@then, &NULL_LOC); /*% ripper: in!($:expr, $:compstmt, $:cases) %*/ } ; @@ -11528,12 +11528,15 @@ rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd } static rb_node_in_t * -rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc) +rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *in_keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *operator_loc) { rb_node_in_t *n = NODE_NEWNODE(NODE_IN, rb_node_in_t, loc); n->nd_head = nd_head; n->nd_body = nd_body; n->nd_next = nd_next; + n->in_keyword_loc = *in_keyword_loc; + n->then_keyword_loc = *then_keyword_loc; + n->operator_loc = *operator_loc; return n; } diff --git a/rubyparser.h b/rubyparser.h index e436d1c404..cc63efd3f8 100644 --- a/rubyparser.h +++ b/rubyparser.h @@ -324,6 +324,9 @@ typedef struct RNode_IN { struct RNode *nd_head; struct RNode *nd_body; struct RNode *nd_next; + rb_code_location_t in_keyword_loc; + rb_code_location_t then_keyword_loc; + rb_code_location_t operator_loc; } rb_node_in_t; typedef struct RNode_LOOP { diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index 6372b0d34e..9a7d75c270 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -1514,6 +1514,20 @@ dummy assert_locations(node.children[-1].children[1].children[0].locations, [[1, 11, 1, 17], [1, 13, 1, 15], nil, nil]) end + def test_in_locations + node = ast_parse("case 1; in 2 then 3; end") + assert_locations(node.children[-1].children[1].locations, [[1, 8, 1, 20], [1, 8, 1, 10], [1, 13, 1, 17], nil]) + + node = ast_parse("1 => a") + assert_locations(node.children[-1].children[1].locations, [[1, 5, 1, 6], nil, nil, [1, 2, 1, 4]]) + + node = ast_parse("1 in a") + assert_locations(node.children[-1].children[1].locations, [[1, 5, 1, 6], [1, 2, 1, 4], nil, nil]) + + node = ast_parse("case 1; in 2; 3; end") + assert_locations(node.children[-1].children[1].locations, [[1, 8, 1, 16], [1, 8, 1, 10], [1, 12, 1, 13], nil]) + end + def test_next_locations node = ast_parse("loop { next 1 }") assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 13], [1, 7, 1, 11]])