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

[Bug #19392] Make args connected with and/or as a body of method #8054

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
19 changes: 15 additions & 4 deletions parse.y
Expand Up @@ -2055,7 +2055,7 @@ get_nd_args(struct parser_params *p, NODE *node)
%type <node> literal numeric simple_numeric ssym dsym symbol cpath
/*ripper*/ %type <node_def_temp> defn_head defs_head k_def
/*ripper*/ %type <node_exits> block_open k_while k_until k_for allow_exits
%type <node> top_compstmt top_stmts top_stmt begin_block endless_arg endless_command
%type <node> top_compstmt top_stmts top_stmt begin_block endless_stmt endless_arg endless_command
%type <node> bodystmt compstmt stmts stmt_or_begin stmt expr arg primary command command_call method_call
%type <node> expr_value expr_value_do arg_value primary_value rel_expr
%type <node_fcall> fcall
Expand Down Expand Up @@ -3502,7 +3502,7 @@ arg : lhs '=' lex_ctxt arg_rhs
/*% %*/
/*% ripper: ifop!($1, $3, $6) %*/
}
| defn_head[head] f_opt_paren_args[args] '=' endless_arg[bodystmt]
| defn_head[head] f_opt_paren_args[args] '=' endless_stmt[bodystmt]
{
endless_method_name(p, get_id($head->nd_mid), &@head);
restore_defun(p, $head);
Expand All @@ -3515,7 +3515,7 @@ arg : lhs '=' lex_ctxt arg_rhs
/*% ripper: def!($head->nd_mid, $args, $bodystmt) %*/
local_pop(p);
}
| defs_head[head] f_opt_paren_args[args] '=' endless_arg[bodystmt]
| defs_head[head] f_opt_paren_args[args] '=' endless_stmt[bodystmt]
{
endless_method_name(p, get_id($head->nd_mid), &@head);
restore_defun(p, $head);
Expand All @@ -3534,7 +3534,7 @@ arg : lhs '=' lex_ctxt arg_rhs
}
;

endless_arg : arg %prec modifier_rescue
endless_stmt : endless_arg %prec tLOWEST
| endless_arg modifier_rescue after_rescue arg
{
p->ctxt.in_rescue = $3.in_rescue;
Expand All @@ -3543,10 +3543,21 @@ endless_arg : arg %prec modifier_rescue
/*% %*/
/*% ripper: rescue_mod!($1, $4) %*/
}
;

endless_arg : arg %prec modifier_rescue
| keyword_not opt_nl endless_arg
{
$$ = call_uni_op(p, method_cond(p, $3, &@3), METHOD_NOT, &@1, &@$);
}
| endless_arg keyword_and endless_arg
{
$$ = logop(p, idAND, $1, $3, &@2, &@$);
}
| endless_arg keyword_or endless_arg
{
$$ = logop(p, idOR, $1, $3, &@2, &@$);
}
;

relop : '>' {$$ = '>';}
Expand Down
45 changes: 45 additions & 0 deletions test/ruby/test_syntax.rb
Expand Up @@ -1595,6 +1595,51 @@ def test_methoddef_endless
assert_equal("class ok", k.rescued("ok"))
assert_equal("instance ok", k.new.rescued("ok"))

k2 = Class.new do
class_eval('def id(x) = x')
class_eval('def and1(x, y) = x and y')
class_eval('def and2(x, y) = id(x) and id(y)')
class_eval('def or1(x, y) = x or y')
class_eval('def or2(x, y) = id(x) or id(y)')
class_eval('def cond_raise(cond, otherwise = nil) = cond ? raise : otherwise')
class_eval('def and_rescued(x, y) = cond_raise(x, true) and cond_raise(y) rescue "ok"')
class_eval('def or_rescued(x, y) = cond_raise(x, false) or cond_raise(y) rescue "ok"')
end
assert_equal("ok", k2.new.and1(true, "ok"))
assert_equal(false, k2.new.and1(false, "ok"))
assert_equal("ok", k2.new.and2(true, "ok"))
assert_equal(false, k2.new.and2(false, "ok"))
assert_equal(true, k2.new.or1(true, "ok"))
assert_equal("ok", k2.new.or1(false, "ok"))
assert_equal(true, k2.new.or2(true, "ok"))
assert_equal("ok", k2.new.or2(false, "ok"))
assert_equal("ok", k2.new.and_rescued(true, false))
assert_equal("ok", k2.new.and_rescued(false, true))
assert_equal("ok", k2.new.or_rescued(true, false))
assert_equal("ok", k2.new.or_rescued(false, true))

obj = Object.new
def obj.id(x) = x
def obj.and1(x, y) = x and y
def obj.and2(x, y) = id(x) and id(y)
def obj.or1(x, y) = x or y
def obj.or2(x, y) = id(x) or id(y)
def obj.cond_raise(cond, otherwise = nil) = cond ? raise : otherwise
def obj.and_rescued(x, y) = cond_raise(x, true) and cond_raise(y) rescue "ok"
def obj.or_rescued(x, y) = cond_raise(x, false) or cond_raise(y) rescue "ok"
assert_equal("ok", obj.and1(true, "ok"))
assert_equal(false, obj.and1(false, "ok"))
assert_equal("ok", obj.and2(true, "ok"))
assert_equal(false, obj.and2(false, "ok"))
assert_equal(true, obj.or1(true, "ok"))
assert_equal("ok", obj.or1(false, "ok"))
assert_equal(true, obj.or2(true, "ok"))
assert_equal("ok", obj.or2(false, "ok"))
assert_equal("ok", obj.and_rescued(true, false))
assert_equal("ok", obj.and_rescued(false, true))
assert_equal("ok", obj.or_rescued(true, false))
assert_equal("ok", obj.or_rescued(false, true))

error = /setter method cannot be defined in an endless method definition/
assert_syntax_error('def foo=() = 42', error)
assert_syntax_error('def obj.foo=() = 42', error)
Expand Down