From 607b1b3d7628b1f94f086ce1dfe67789179cf906 Mon Sep 17 00:00:00 2001 From: ydah Date: Wed, 6 Nov 2024 12:14:01 +0900 Subject: [PATCH] Implement YIELD NODE locations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 'def foo; yield end' @ ProgramNode (location: (1,0)-(1,18)) +-- locals: [] +-- statements: @ StatementsNode (location: (1,0)-(1,18)) +-- body: (length: 1) +-- @ DefNode (location: (1,0)-(1,18)) +-- name: :foo +-- name_loc: (1,4)-(1,7) = "foo" +-- receiver: nil +-- parameters: nil +-- body: | @ StatementsNode (location: (1,9)-(1,14)) | +-- body: (length: 1) | +-- @ YieldNode (location: (1,9)-(1,14)) | +-- keyword_loc: (1,9)-(1,14) = "yield" ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +-- lparen_loc: nil ^^^^^^^^^^^^^^^^^^^ | +-- arguments: nil | +-- rparen_loc: nil ^^^^^^^^^^^^^^^^^^^ +-- locals: [] +-- def_keyword_loc: (1,0)-(1,3) = "def" +-- operator_loc: nil +-- lparen_loc: nil +-- rparen_loc: nil +-- equal_loc: nil +-- end_keyword_loc: (1,15)-(1,18) = "end" ``` --- ast.c | 6 ++++++ node_dump.c | 5 ++++- parse.y | 23 +++++++++++++---------- rubyparser.h | 3 +++ test/ruby/test_ast.rb | 14 ++++++++++++++ 5 files changed, 40 insertions(+), 11 deletions(-) diff --git a/ast.c b/ast.c index fc524d7c46..861785871a 100644 --- a/ast.c +++ b/ast.c @@ -886,6 +886,12 @@ node_locations(VALUE ast_value, const NODE *node) location_new(nd_code_loc(node)), location_new(&RNODE_UNTIL(node)->keyword_loc), location_new(&RNODE_UNTIL(node)->closing_loc)); + case NODE_YIELD: + return rb_ary_new_from_args(4, + location_new(nd_code_loc(node)), + location_new(&RNODE_YIELD(node)->keyword_loc), + location_new(&RNODE_YIELD(node)->lparen_loc), + location_new(&RNODE_YIELD(node)->rparen_loc)); case NODE_ARGS_AUX: case NODE_LAST: break; diff --git a/node_dump.c b/node_dump.c index 0153296806..cff7cdb433 100644 --- a/node_dump.c +++ b/node_dump.c @@ -697,8 +697,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node) ANN("yield invocation"); ANN("format: yield [nd_head]"); ANN("example: yield 1"); - LAST_NODE; F_NODE(nd_head, RNODE_YIELD, "arguments"); + F_LOC(keyword_loc, RNODE_YIELD); + F_LOC(lparen_loc, RNODE_YIELD); + LAST_NODE; + F_LOC(rparen_loc, RNODE_YIELD); return; case NODE_LVAR: diff --git a/parse.y b/parse.y index f215c62437..75698de666 100644 --- a/parse.y +++ b/parse.y @@ -1101,7 +1101,7 @@ static rb_node_list_t *rb_node_list_new2(struct parser_params *p, NODE *nd_head, static rb_node_zlist_t *rb_node_zlist_new(struct parser_params *p, const YYLTYPE *loc); static rb_node_hash_t *rb_node_hash_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc); static rb_node_return_t *rb_node_return_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, const YYLTYPE *keyword_loc); -static rb_node_yield_t *rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc); +static rb_node_yield_t *rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *lparen_loc, const YYLTYPE *rparen_loc); static rb_node_lvar_t *rb_node_lvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc); static rb_node_dvar_t *rb_node_dvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc); static rb_node_gvar_t *rb_node_gvar_new(struct parser_params *p, ID nd_vid, const YYLTYPE *loc); @@ -1209,7 +1209,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE #define NEW_ZLIST(loc) (NODE *)rb_node_zlist_new(p,loc) #define NEW_HASH(a,loc) (NODE *)rb_node_hash_new(p,a,loc) #define NEW_RETURN(s,loc,k_loc) (NODE *)rb_node_return_new(p,s,loc,k_loc) -#define NEW_YIELD(a,loc) (NODE *)rb_node_yield_new(p,a,loc) +#define NEW_YIELD(a,loc,k_loc,l_loc,r_loc) (NODE *)rb_node_yield_new(p,a,loc,k_loc,l_loc,r_loc) #define NEW_LVAR(v,loc) (NODE *)rb_node_lvar_new(p,v,loc) #define NEW_DVAR(v,loc) (NODE *)rb_node_dvar_new(p,v,loc) #define NEW_GVAR(v,loc) (NODE *)rb_node_gvar_new(p,v,loc) @@ -1438,7 +1438,7 @@ static rb_node_args_t *args_with_numbered(struct parser_params*,rb_node_args_t*, static NODE* negate_lit(struct parser_params*, NODE*); static NODE *ret_args(struct parser_params*,NODE*); static NODE *arg_blk_pass(NODE*,rb_node_block_pass_t*); -static NODE *new_yield(struct parser_params*,NODE*,const YYLTYPE*); +static NODE *new_yield(struct parser_params*,NODE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*,const YYLTYPE*); static NODE *dsym_node(struct parser_params*,NODE*,const YYLTYPE*); static NODE *gettable(struct parser_params*,ID,const YYLTYPE*); @@ -3515,7 +3515,7 @@ command : fcall command_args %prec tLOWEST } | k_yield command_args { - $$ = new_yield(p, $2, &@$); + $$ = new_yield(p, $2, &@$, &@1, &NULL_LOC, &NULL_LOC); fixpos($$, $2); /*% ripper: yield!($:2) %*/ } @@ -4429,17 +4429,17 @@ primary : inline_primary } | k_yield '(' call_args rparen { - $$ = new_yield(p, $3, &@$); + $$ = new_yield(p, $3, &@$, &@1, &@2, &@4); /*% ripper: yield!(paren!($:3)) %*/ } | k_yield '(' rparen { - $$ = NEW_YIELD(0, &@$); + $$ = NEW_YIELD(0, &@$, &@1, &@2, &@3); /*% ripper: yield!(paren!(args_new!)) %*/ } | k_yield { - $$ = NEW_YIELD(0, &@$); + $$ = NEW_YIELD(0, &@$, &@1, &NULL_LOC, &NULL_LOC); /*% ripper: yield0! %*/ } | keyword_defined '\n'? '(' begin_defined expr rparen @@ -11499,10 +11499,13 @@ rb_node_return_new(struct parser_params *p, NODE *nd_stts, const YYLTYPE *loc, c } static rb_node_yield_t * -rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc) +rb_node_yield_new(struct parser_params *p, NODE *nd_head, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *lparen_loc, const YYLTYPE *rparen_loc) { rb_node_yield_t *n = NODE_NEWNODE(NODE_YIELD, rb_node_yield_t, loc); n->nd_head = nd_head; + n->keyword_loc = *keyword_loc; + n->lparen_loc = *lparen_loc; + n->rparen_loc = *rparen_loc; return n; } @@ -14389,11 +14392,11 @@ ret_args(struct parser_params *p, NODE *node) } static NODE * -new_yield(struct parser_params *p, NODE *node, const YYLTYPE *loc) +new_yield(struct parser_params *p, NODE *node, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *lparen_loc, const YYLTYPE *rparen_loc) { if (node) no_blockarg(p, node); - return NEW_YIELD(node, loc); + return NEW_YIELD(node, loc, keyword_loc, lparen_loc, rparen_loc); } static NODE* diff --git a/rubyparser.h b/rubyparser.h index e3c7eae05a..155b8d8760 100644 --- a/rubyparser.h +++ b/rubyparser.h @@ -593,6 +593,9 @@ typedef struct RNode_YIELD { NODE node; struct RNode *nd_head; + rb_code_location_t keyword_loc; + rb_code_location_t lparen_loc; + rb_code_location_t rparen_loc; } rb_node_yield_t; typedef struct RNode_LVAR { diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index 4e449410f1..e456f5b7b5 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -1517,6 +1517,20 @@ dummy assert_locations(node.children[-1].locations, [[1, 0, 1, 9], [1, 2, 1, 7], nil]) end + def test_yield_locations + node = ast_parse("def foo; yield end") + assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 14], [1, 9, 1, 14], nil, nil]) + + node = ast_parse("def foo; yield() end") + assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 16], [1, 9, 1, 14], [1, 14, 1, 15], [1, 15, 1, 16]]) + + node = ast_parse("def foo; yield 1, 2 end") + assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 19], [1, 9, 1, 14], nil, nil]) + + node = ast_parse("def foo; yield(1, 2) end") + assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 9, 1, 20], [1, 9, 1, 14], [1, 14, 1, 15], [1, 19, 1, 20]]) + end + private def ast_parse(src, **options) begin