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]
This commit is contained in:
yui-knk 2022-10-01 17:44:28 +09:00 коммит произвёл Yuichiro Kaneko
Родитель 4f24f3ea94
Коммит 4bfdf6d06d
7 изменённых файлов: 41 добавлений и 30 удалений

2
ast.c
Просмотреть файл

@ -648,6 +648,8 @@ node_children(rb_ast_t *ast, const NODE *node)
NEW_CHILD(ast, node->nd_pkwargs), NEW_CHILD(ast, node->nd_pkwargs),
kwrest); kwrest);
} }
case NODE_ERROR:
return rb_ary_new_from_node_args(ast, 0);
case NODE_ARGS_AUX: case NODE_ARGS_AUX:
case NODE_LAST: case NODE_LAST:
break; break;

Просмотреть файл

@ -493,6 +493,7 @@ count_nodes(int argc, VALUE *argv, VALUE os)
COUNT_NODE(NODE_ARYPTN); COUNT_NODE(NODE_ARYPTN);
COUNT_NODE(NODE_FNDPTN); COUNT_NODE(NODE_FNDPTN);
COUNT_NODE(NODE_HSHPTN); COUNT_NODE(NODE_HSHPTN);
COUNT_NODE(NODE_ERROR);
#undef COUNT_NODE #undef COUNT_NODE
case NODE_LAST: break; case NODE_LAST: break;
} }

3
node.c
Просмотреть файл

@ -1098,6 +1098,9 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
F_NODE(nd_pkwrestarg, "keyword rest argument"); F_NODE(nd_pkwrestarg, "keyword rest argument");
} }
return; return;
case NODE_ERROR:
ANN("Broken input recovered by Error Tolerant mode");
return;
case NODE_ARGS_AUX: case NODE_ARGS_AUX:
case NODE_LAST: case NODE_LAST:

2
node.h
Просмотреть файл

@ -125,6 +125,7 @@ enum node_type {
NODE_ARYPTN, NODE_ARYPTN,
NODE_HSHPTN, NODE_HSHPTN,
NODE_FNDPTN, NODE_FNDPTN,
NODE_ERROR,
NODE_LAST NODE_LAST
}; };
@ -386,6 +387,7 @@ typedef struct RNode {
#define NEW_PREEXE(b,loc) NEW_SCOPE(b,loc) #define NEW_PREEXE(b,loc) NEW_SCOPE(b,loc)
#define NEW_POSTEXE(b,loc) NEW_NODE(NODE_POSTEXE,0,b,0,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_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_SPECIAL_REQUIRED_KEYWORD ((NODE *)-1)
#define NODE_REQUIRED_KEYWORD_P(node) ((node)->nd_value == NODE_SPECIAL_REQUIRED_KEYWORD) #define NODE_REQUIRED_KEYWORD_P(node) ((node)->nd_value == NODE_SPECIAL_REQUIRED_KEYWORD)

14
parse.y
Просмотреть файл

@ -1430,10 +1430,6 @@ top_stmts : none
/*% %*/ /*% %*/
/*% ripper: stmts_add!($1, $3) %*/ /*% ripper: stmts_add!($1, $3) %*/
} }
| error top_stmt
{
$$ = remove_begin($2);
}
; ;
top_stmt : stmt top_stmt : stmt
@ -1503,10 +1499,6 @@ stmts : none
/*% %*/ /*% %*/
/*% ripper: stmts_add!($1, $3) %*/ /*% ripper: stmts_add!($1, $3) %*/
} }
| error stmt
{
$$ = remove_begin($2);
}
; ;
stmt_or_begin : stmt stmt_or_begin : stmt
@ -1659,6 +1651,12 @@ stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem
/*% ripper: massign!($1, $4) %*/ /*% ripper: massign!($1, $4) %*/
} }
| expr | expr
| error
{
/*%%%*/
$$ = NEW_ERROR(&@$);
/*% %*/
}
; ;
command_asgn : lhs '=' lex_ctxt command_rhs command_asgn : lhs '=' lex_ctxt command_rhs

Просмотреть файл

@ -114,6 +114,11 @@ module TestIRB
"class bad; end" => "#{GREEN}class#{CLEAR} #{RED}#{REVERSE}bad#{CLEAR}; #{GREEN}end#{CLEAR}", "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}", "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 else
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0') if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.7.0')
tests.merge!({ tests.merge!({

Просмотреть файл

@ -981,30 +981,30 @@ dummy
tbl: [] tbl: []
args: nil args: nil
body: body:
(BLOCK@1:8-8:3 (BEGIN@1:8-1:8 nil) (BLOCK@1:8-7:5 (BEGIN@1:8-1:8 nil)
(CLASS@2:2-8:3 (COLON2@2:8-2:11 nil :Foo) nil (CLASS@2:2-4:5 (COLON2@2:8-2:11 nil :Foo) nil
(SCOPE@2:2-8:3 (SCOPE@2:2-4:5
tbl: [] tbl: []
args: nil args: nil
body: body: (BLOCK@2:11-4:5 (BEGIN@2:11-2:11 nil) (ERROR@3:4-4:5))))
(DEFN@6:2-7:5 (DEFN@6:2-7:5
mid: :bar mid: :bar
body: body:
(SCOPE@6:2-7:5 (SCOPE@6:2-7:5
tbl: [] tbl: []
args: args:
(ARGS@6:9-6:9 (ARGS@6:9-6:9
pre_num: 0 pre_num: 0
pre_init: nil pre_init: nil
opt: nil opt: nil
first_post: nil first_post: nil
post_num: 0 post_num: 0
post_init: nil post_init: nil
rest: nil rest: nil
kw: nil kw: nil
kwrest: nil kwrest: nil
block: nil) block: nil)
body: nil)))))))) body: nil))))))
EXP EXP
end end
end end