Skip to content

Commit

Permalink
+ ruby31.y: allow "command" syntax in endless method definition (#801)
Browse files Browse the repository at this point in the history
Fixes #799.
  • Loading branch information
koic committed May 14, 2021
1 parent b69e8e5 commit 7ecddb6
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 0 deletions.
68 changes: 68 additions & 0 deletions lib/parser/ruby31.y
Expand Up @@ -261,6 +261,74 @@ rule
val[0], val[1], val[2]),
val[3], val[4])
}
| defn_head f_opt_paren_args tEQL command
{
_def_t, name_t = val[0]
endless_method_name(name_t)

result = @builder.def_endless_method(*val[0],
val[1], val[2], val[3])

@lexer.cmdarg.pop
@lexer.cond.pop
@static_env.unextend
@context.pop
@current_arg_stack.pop
}
| defn_head f_opt_paren_args tEQL command kRESCUE_MOD arg
{
_def_t, name_t = val[0]
endless_method_name(name_t)

rescue_body = @builder.rescue_body(val[4],
nil, nil, nil,
nil, val[5])

method_body = @builder.begin_body(val[3], [ rescue_body ])

result = @builder.def_endless_method(*val[0],
val[1], val[2], method_body)

@lexer.cmdarg.pop
@lexer.cond.pop
@static_env.unextend
@context.pop
@current_arg_stack.pop
}
| defs_head f_opt_paren_args tEQL command
{
_def_t, _recv, _dot_t, name_t = val[0]
endless_method_name(name_t)

result = @builder.def_endless_singleton(*val[0],
val[1], val[2], val[3])

@lexer.cmdarg.pop
@lexer.cond.pop
@static_env.unextend
@context.pop
@current_arg_stack.pop
}
| defs_head f_opt_paren_args tEQL command kRESCUE_MOD arg
{
_def_t, _recv, _dot_t, name_t = val[0]
endless_method_name(name_t)

rescue_body = @builder.rescue_body(val[4],
nil, nil, nil,
nil, val[5])

method_body = @builder.begin_body(val[3], [ rescue_body ])

result = @builder.def_endless_singleton(*val[0],
val[1], val[2], method_body)

@lexer.cmdarg.pop
@lexer.cond.pop
@static_env.unextend
@context.pop
@current_arg_stack.pop
}
| backref tOP_ASGN command_rhs
{
@builder.op_assign(val[0], val[1], val[2])
Expand Down
160 changes: 160 additions & 0 deletions test/test_parser.rb
Expand Up @@ -9832,6 +9832,166 @@ def test_endless_method_with_rescue_mod
SINCE_3_0)
end

def test_endless_method_command_syntax
assert_parses(
s(:def, :foo,
s(:args),
s(:send, nil, :puts,
s(:str, "Hello"))),
%q{def foo = puts "Hello"},
%q{~~~ keyword
| ~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)

assert_parses(
s(:def, :foo,
s(:args),
s(:send, nil, :puts,
s(:str, "Hello"))),
%q{def foo() = puts "Hello"},
%q{~~~ keyword
| ~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)

assert_parses(
s(:def, :foo,
s(:args,
s(:arg, :x)),
s(:send, nil, :puts,
s(:lvar, :x))),
%q{def foo(x) = puts x},
%q{~~~ keyword
| ~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)

assert_parses(
s(:defs,
s(:send, nil, :obj), :foo,
s(:args),
s(:send, nil, :puts,
s(:str, "Hello"))),
%q{def obj.foo = puts "Hello"},
%q{~~~ keyword
| ^ operator
| ~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)

assert_parses(
s(:defs,
s(:send, nil, :obj), :foo,
s(:args),
s(:send, nil, :puts,
s(:str, "Hello"))),
%q{def obj.foo() = puts "Hello"},
%q{~~~ keyword
| ^ operator
| ~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)

assert_parses(
s(:def, :rescued,
s(:args,
s(:arg, :x)),
s(:rescue,
s(:send, nil, :raise,
s(:str, "to be caught")),
s(:resbody, nil, nil,
s(:dstr,
s(:str, "instance "),
s(:begin,
s(:lvar, :x)))), nil)),
%q{def rescued(x) = raise "to be caught" rescue "instance #{x}"},
%q{~~~ keyword
| ~~~~~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)

assert_parses(
s(:defs,
s(:self), :rescued,
s(:args,
s(:arg, :x)),
s(:rescue,
s(:send, nil, :raise,
s(:str, "to be caught")),
s(:resbody, nil, nil,
s(:dstr,
s(:str, "class "),
s(:begin,
s(:lvar, :x)))), nil)),
%q{def self.rescued(x) = raise "to be caught" rescue "class #{x}"},
%q{~~~ keyword
| ^ operator
| ~~~~~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)

assert_parses(
s(:defs,
s(:send, nil, :obj), :foo,
s(:args,
s(:arg, :x)),
s(:send, nil, :puts,
s(:lvar, :x))),
%q{def obj.foo(x) = puts x},
%q{~~~ keyword
| ^ operator
| ~~~ name
| ^ assignment
|~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_3_1)
end

def test_private_endless_method_command_syntax
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tSTRING' }],
%q{private def foo = puts "Hello"},
%q{ ^^^^^^^ location},
SINCE_3_1)

assert_diagnoses(
[:error, :unexpected_token, { :token => 'tSTRING' }],
%q{private def foo() = puts "Hello"},
%q{ ^^^^^^^ location},
SINCE_3_1)

assert_diagnoses(
[:error, :unexpected_token, { :token => 'tIDENTIFIER' }],
%q{private def foo(x) = puts x},
%q{ ^ location},
SINCE_3_1)

assert_diagnoses(
[:error, :unexpected_token, { :token => 'tSTRING' }],
%q{private def obj.foo = puts "Hello"},
%q{ ^^^^^^^ location},
SINCE_3_1)

assert_diagnoses(
[:error, :unexpected_token, { :token => 'tSTRING' }],
%q{private def obj.foo() = puts "Hello"},
%q{ ^^^^^^^ location},
SINCE_3_1)

assert_diagnoses(
[:error, :unexpected_token, { :token => 'tIDENTIFIER' }],
%q{private def obj.foo(x) = puts x},
%q{ ^ location},
SINCE_3_1)
end

def test_rasgn_line_continuation
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tASSOC' }],
Expand Down

0 comments on commit 7ecddb6

Please sign in to comment.