Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

+ ruby31.y: allow "command" syntax in endless method definition #801

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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