From c84f3709af2fdd2e40fbfc0db1d2564416782d31 Mon Sep 17 00:00:00 2001 From: Vladimir Dementyev Date: Wed, 29 Apr 2020 12:05:45 +0300 Subject: [PATCH] + ruby28.y: add right hand assignment --- doc/AST_FORMAT.md | 22 +++++++++++++++ lib/parser/ast/processor.rb | 3 ++ lib/parser/builders/default.rb | 9 ++++++ lib/parser/meta.rb | 2 +- lib/parser/ruby28.y | 18 ++++++++++++ test/test_parser.rb | 50 ++++++++++++++++++++++++++++++++++ 6 files changed, 103 insertions(+), 1 deletion(-) diff --git a/doc/AST_FORMAT.md b/doc/AST_FORMAT.md index 315b7bf21..41e401659 100644 --- a/doc/AST_FORMAT.md +++ b/doc/AST_FORMAT.md @@ -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 diff --git a/lib/parser/ast/processor.rb b/lib/parser/ast/processor.rb index b3c17bb0d..083c618f3 100644 --- a/lib/parser/ast/processor.rb +++ b/lib/parser/ast/processor.rb @@ -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 diff --git a/lib/parser/builders/default.rb b/lib/parser/builders/default.rb index 832eaafae..9f95fbbb1 100644 --- a/lib/parser/builders/default.rb +++ b/lib/parser/builders/default.rb @@ -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 # diff --git a/lib/parser/meta.rb b/lib/parser/meta.rb index 22d1adb9f..7ec1404a3 100644 --- a/lib/parser/meta.rb +++ b/lib/parser/meta.rb @@ -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 diff --git a/lib/parser/ruby28.y b/lib/parser/ruby28.y index 3bada3375..cdd7eb3cd 100644 --- a/lib/parser/ruby28.y +++ b/lib/parser/ruby28.y @@ -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]) diff --git a/test/test_parser.rb b/test/test_parser.rb index d30c5e2e7..92f6ddfa5 100644 --- a/test/test_parser.rb +++ b/test/test_parser.rb @@ -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