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

+ ruby28.y: add right hand assignment #682

Merged
merged 1 commit into from Apr 30, 2020
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
22 changes: 22 additions & 0 deletions doc/AST_FORMAT.md
Expand Up @@ -730,6 +730,28 @@ Format:

~~~

### Right-hand assignment

Format:

~~~
(rasgn (int 1) (lvasgn :a))
"1 => a"
~~~~~~ expression
~~ operator
~~~

#### Multiple right-hand assignment

Format:

~~~
(mrasgn (send (int 13) :divmod (int 5)) (mlhs (lvasgn :a) (lvasgn :b)))
"13.divmod(5) => a,b"
~~~~~~~~~~~~~~~~~~~ expression
^^ operator
~~~

## Class and module definition

### Module
Expand Down
3 changes: 3 additions & 0 deletions lib/parser/ast/processor.rb
Expand Up @@ -75,6 +75,9 @@ def on_op_asgn(node)
alias on_mlhs process_regular_node
alias on_masgn process_regular_node

alias on_rasgn process_regular_node
alias on_mrasgn process_regular_node

def on_const(node)
scope_node, name = *node

Expand Down
9 changes: 9 additions & 0 deletions lib/parser/builders/default.rb
Expand Up @@ -619,6 +619,15 @@ def multi_assign(lhs, eql_t, rhs)
binary_op_map(lhs, eql_t, rhs))
end

def rassign(lhs, assoc_t, rhs)
n(:rasgn, [lhs, rhs], binary_op_map(lhs, assoc_t, rhs))
end

def multi_rassign(lhs, assoc_t, rhs)
n(:mrasgn, [ lhs, rhs ],
binary_op_map(lhs, assoc_t, rhs))
end

#
# Class and module definition
#
Expand Down
2 changes: 1 addition & 1 deletion lib/parser/meta.rb
Expand Up @@ -12,7 +12,7 @@ module Meta
sym dsym xstr regopt regexp array splat
pair kwsplat hash irange erange self
lvar ivar cvar gvar const defined? lvasgn
ivasgn cvasgn gvasgn casgn mlhs masgn
ivasgn cvasgn gvasgn casgn mlhs masgn rasgn mrasgn
op_asgn and_asgn ensure rescue arg_expr
or_asgn back_ref nth_ref
match_with_lvasgn match_current_line
Expand Down
18 changes: 18 additions & 0 deletions lib/parser/ruby28.y
Expand Up @@ -206,8 +206,26 @@ rule
{
result = @builder.multi_assign(val[0], val[1], val[2])
}
| rassign
| expr

rassign: arg_value tASSOC lhs
{
result = @builder.rassign(val[0], val[1], val[2])
}
| arg_value tASSOC mlhs
{
result = @builder.multi_rassign(val[0], val[1], val[2])
}
| rassign tASSOC lhs
{
result = @builder.rassign(val[0], val[1], val[2])
}
| rassign tASSOC mlhs
{
result = @builder.multi_rassign(val[0], val[1], val[2])
}

command_asgn: lhs tEQL command_rhs
{
result = @builder.assign(val[0], val[1], val[2])
Expand Down
50 changes: 50 additions & 0 deletions test/test_parser.rb
Expand Up @@ -9520,6 +9520,56 @@ def test_endless_method_without_brackets
[:error, :unexpected_token, { :token => 'tEQL' }],
%Q{def obj.foo = 42},
%q{ ^ location},
SINCE_2_8
)
end

def test_rasgn
assert_parses(
s(:rasgn,
s(:int, 1), s(:lvasgn, :a)),
%q{1 => a},
%q{~~~~~~ expression
| ^^ operator},
SINCE_2_8)

assert_parses(
s(:rasgn,
s(:send, s(:int, 1), :+, s(:int, 2)),
s(:gvasgn, :$a)),
%q{1 + 2 => $a},
%q{~~~~~~~~~~~ expression
| ^^ operator},
SINCE_2_8)
end

def test_mrasgn
assert_parses(
s(:mrasgn,
s(:send, s(:int, 13), :divmod, s(:int, 5)),
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b))),
%q{13.divmod(5) => a,b},
%q{~~~~~~~~~~~~~~~~~~~ expression
| ^^ operator},
SINCE_2_8)

assert_parses(
s(:mrasgn,
s(:mrasgn,
s(:send, s(:int, 13), :divmod, s(:int, 5)),
s(:mlhs, s(:lvasgn, :a), s(:lvasgn, :b))),
s(:mlhs, s(:lvasgn, :c), s(:lvasgn, :d))),
%q{13.divmod(5) => a,b => c, d},
%q{~~~~~~~~~~~~~~~~~~~ expression (mrasgn)
|~~~~~~~~~~~~~~~~~~~~~~~~~~~ expression},
SINCE_2_8)
end

def test_rasgn_line_continuation
assert_diagnoses(
[:error, :unexpected_token, { :token => 'tASSOC' }],
%Q{13.divmod(5)\n=> a,b; [a, b]},
%{ ^^ location},
SINCE_2_8)
end
end