From 4bfdf6d06ddbcf21345461038f2a9e3012f77268 Mon Sep 17 00:00:00 2001 From: yui-knk Date: Sat, 1 Oct 2022 17:44:28 +0900 Subject: [PATCH] Move `error` from top_stmts and top_stmt to stmt By this change, syntax error is recovered smaller units. In the case below, "DEFN :bar" is same level with "CLASS :Foo" now. ``` module Z class Foo foo. end def bar end end ``` [Feature #19013] --- ast.c | 2 ++ ext/objspace/objspace.c | 1 + node.c | 3 +++ node.h | 2 ++ parse.y | 14 ++++++------- test/irb/test_color.rb | 5 +++++ test/ruby/test_ast.rb | 44 ++++++++++++++++++++--------------------- 7 files changed, 41 insertions(+), 30 deletions(-) diff --git a/ast.c b/ast.c index 67275c47b3..c9d0b41fac 100644 --- a/ast.c +++ b/ast.c @@ -648,6 +648,8 @@ node_children(rb_ast_t *ast, const NODE *node) NEW_CHILD(ast, node->nd_pkwargs), kwrest); } + case NODE_ERROR: + return rb_ary_new_from_node_args(ast, 0); case NODE_ARGS_AUX: case NODE_LAST: break; diff --git a/ext/objspace/objspace.c b/ext/objspace/objspace.c index 0b1b094325..ca08604c95 100644 --- a/ext/objspace/objspace.c +++ b/ext/objspace/objspace.c @@ -493,6 +493,7 @@ count_nodes(int argc, VALUE *argv, VALUE os) COUNT_NODE(NODE_ARYPTN); COUNT_NODE(NODE_FNDPTN); COUNT_NODE(NODE_HSHPTN); + COUNT_NODE(NODE_ERROR); #undef COUNT_NODE case NODE_LAST: break; } diff --git a/node.c b/node.c index 483e7fa8fb..c7469151ec 100644 --- a/node.c +++ b/node.c @@ -1098,6 +1098,9 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node) F_NODE(nd_pkwrestarg, "keyword rest argument"); } return; + case NODE_ERROR: + ANN("Broken input recovered by Error Tolerant mode"); + return; case NODE_ARGS_AUX: case NODE_LAST: diff --git a/node.h b/node.h index d97c333ab5..2a27988ff5 100644 --- a/node.h +++ b/node.h @@ -125,6 +125,7 @@ enum node_type { NODE_ARYPTN, NODE_HSHPTN, NODE_FNDPTN, + NODE_ERROR, NODE_LAST }; @@ -386,6 +387,7 @@ typedef struct RNode { #define NEW_PREEXE(b,loc) NEW_SCOPE(b,loc) #define NEW_POSTEXE(b,loc) NEW_NODE(NODE_POSTEXE,0,b,0,loc) #define NEW_ATTRASGN(r,m,a,loc) NEW_NODE(NODE_ATTRASGN,r,m,a,loc) +#define NEW_ERROR(loc) NEW_NODE(NODE_ERROR,0,0,0,loc) #define NODE_SPECIAL_REQUIRED_KEYWORD ((NODE *)-1) #define NODE_REQUIRED_KEYWORD_P(node) ((node)->nd_value == NODE_SPECIAL_REQUIRED_KEYWORD) diff --git a/parse.y b/parse.y index c0959a5e81..a8eadfebd3 100644 --- a/parse.y +++ b/parse.y @@ -1430,10 +1430,6 @@ top_stmts : none /*% %*/ /*% ripper: stmts_add!($1, $3) %*/ } - | error top_stmt - { - $$ = remove_begin($2); - } ; top_stmt : stmt @@ -1503,10 +1499,6 @@ stmts : none /*% %*/ /*% ripper: stmts_add!($1, $3) %*/ } - | error stmt - { - $$ = remove_begin($2); - } ; stmt_or_begin : stmt @@ -1659,6 +1651,12 @@ stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem /*% ripper: massign!($1, $4) %*/ } | expr + | error + { + /*%%%*/ + $$ = NEW_ERROR(&@$); + /*% %*/ + } ; command_asgn : lhs '=' lex_ctxt command_rhs diff --git a/test/irb/test_color.rb b/test/irb/test_color.rb index dc394f9d68..8de03a5e8e 100644 --- a/test/irb/test_color.rb +++ b/test/irb/test_color.rb @@ -114,6 +114,11 @@ module TestIRB "class bad; end" => "#{GREEN}class#{CLEAR} #{RED}#{REVERSE}bad#{CLEAR}; #{GREEN}end#{CLEAR}", "def req(@a) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}@a#{CLEAR}) #{GREEN}end#{CLEAR}", }) + if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('3.2.0') + tests.merge!({ + "def req(true) end" => "#{GREEN}def#{CLEAR} #{BLUE}#{BOLD}req#{CLEAR}(#{RED}#{REVERSE}true#{CLEAR}#{RED}#{REVERSE})#{CLEAR} #{RED}#{REVERSE}end#{CLEAR}", + }) + end else if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0') tests.merge!({ diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index 033a09b4c0..cda325c1fd 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -981,30 +981,30 @@ dummy tbl: [] args: nil body: - (BLOCK@1:8-8:3 (BEGIN@1:8-1:8 nil) - (CLASS@2:2-8:3 (COLON2@2:8-2:11 nil :Foo) nil - (SCOPE@2:2-8:3 + (BLOCK@1:8-7:5 (BEGIN@1:8-1:8 nil) + (CLASS@2:2-4:5 (COLON2@2:8-2:11 nil :Foo) nil + (SCOPE@2:2-4:5 tbl: [] args: nil - body: - (DEFN@6:2-7:5 - mid: :bar - body: - (SCOPE@6:2-7:5 - tbl: [] - args: - (ARGS@6:9-6:9 - pre_num: 0 - pre_init: nil - opt: nil - first_post: nil - post_num: 0 - post_init: nil - rest: nil - kw: nil - kwrest: nil - block: nil) - body: nil)))))))) + body: (BLOCK@2:11-4:5 (BEGIN@2:11-2:11 nil) (ERROR@3:4-4:5)))) + (DEFN@6:2-7:5 + mid: :bar + body: + (SCOPE@6:2-7:5 + tbl: [] + args: + (ARGS@6:9-6:9 + pre_num: 0 + pre_init: nil + opt: nil + first_post: nil + post_num: 0 + post_init: nil + rest: nil + kw: nil + kwrest: nil + block: nil) + body: nil)))))) EXP end end