mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Treat "end" as reserved word with consideration of indent
"end" after "." or "::" is treated as local variable or method, see `EXPR_DOT_bit` for detail. However this "changes" where `bar` method is defined. In the example below it is not module Z but class Foo. ``` module Z class Foo foo. end def bar end end ``` [Feature #19013]
This commit is contained in:
parent
342d4c16d9
commit
4f24f3ea94
Notes:
git
2022-10-08 17:59:34 +09:00
2 changed files with 87 additions and 1 deletions
37
parse.y
37
parse.y
|
@ -438,6 +438,13 @@ pop_end_expect_token_localtions(struct parser_params *p)
|
|||
rb_ary_pop(p->end_expect_token_localtions);
|
||||
debug_end_expect_token_localtions(p, "pop_end_expect_token_localtions");
|
||||
}
|
||||
|
||||
static VALUE
|
||||
peek_end_expect_token_localtions(struct parser_params *p)
|
||||
{
|
||||
if(NIL_P(p->end_expect_token_localtions)) return Qnil;
|
||||
return rb_ary_last(0, 0, p->end_expect_token_localtions);
|
||||
}
|
||||
#endif
|
||||
|
||||
RBIMPL_ATTR_NONNULL((1, 2, 3))
|
||||
|
@ -9285,6 +9292,7 @@ parse_ident(struct parser_params *p, int c, int cmd_state)
|
|||
int mb = ENC_CODERANGE_7BIT;
|
||||
const enum lex_state_e last_state = p->lex.state;
|
||||
ID ident;
|
||||
int enforce_keyword_end = 0;
|
||||
|
||||
do {
|
||||
if (!ISASCII(c)) mb = ENC_CODERANGE_UNKNOWN;
|
||||
|
@ -9314,7 +9322,34 @@ parse_ident(struct parser_params *p, int c, int cmd_state)
|
|||
return tLABEL;
|
||||
}
|
||||
}
|
||||
if (mb == ENC_CODERANGE_7BIT && !IS_lex_state(EXPR_DOT)) {
|
||||
|
||||
#ifndef RIPPER
|
||||
if (!NIL_P(peek_end_expect_token_localtions(p))) {
|
||||
VALUE end_loc;
|
||||
int lineno, column;
|
||||
int beg_pos = (int)(p->lex.ptok - p->lex.pbeg);
|
||||
|
||||
end_loc = peek_end_expect_token_localtions(p);
|
||||
lineno = NUM2INT(rb_ary_entry(end_loc, 0));
|
||||
column = NUM2INT(rb_ary_entry(end_loc, 1));
|
||||
|
||||
if (p->debug) {
|
||||
rb_parser_printf(p, "enforce_keyword_end check. current: (%d, %d), peek: (%d, %d)\n",
|
||||
p->ruby_sourceline, beg_pos, lineno, column);
|
||||
}
|
||||
|
||||
if ((p->ruby_sourceline > lineno) && (beg_pos <= column)) {
|
||||
const struct kwtable *kw;
|
||||
|
||||
if ((IS_lex_state(EXPR_DOT)) && (kw = rb_reserved_word(tok(p), toklen(p))) && (kw && kw->id[0] == keyword_end)) {
|
||||
if (p->debug) rb_parser_printf(p, "enforce_keyword_end is enabled\n");
|
||||
enforce_keyword_end = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mb == ENC_CODERANGE_7BIT && (!IS_lex_state(EXPR_DOT) || enforce_keyword_end)) {
|
||||
const struct kwtable *kw;
|
||||
|
||||
/* See if it is a reserved word. */
|
||||
|
|
|
@ -956,4 +956,55 @@ dummy
|
|||
body: (VCALL@2:2-2:3 :a))))
|
||||
EXP
|
||||
end
|
||||
|
||||
def test_error_tolerant_treat_end_as_keyword_based_on_indent
|
||||
node = RubyVM::AbstractSyntaxTree.parse(<<~STR, error_tolerant: true)
|
||||
module Z
|
||||
class Foo
|
||||
foo.
|
||||
end
|
||||
|
||||
def bar
|
||||
end
|
||||
end
|
||||
STR
|
||||
|
||||
str = ""
|
||||
PP.pp(node, str)
|
||||
assert_equal(<<~EXP, str)
|
||||
(SCOPE@1:0-8:3
|
||||
tbl: []
|
||||
args: nil
|
||||
body:
|
||||
(MODULE@1:0-8:3 (COLON2@1:7-1:8 nil :Z)
|
||||
(SCOPE@1:0-8:3
|
||||
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
|
||||
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))))))))
|
||||
EXP
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue