diff options
author | Nobuyoshi Nakada <[email protected]> | 2020-10-26 18:00:24 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2020-10-26 18:00:24 +0900 |
commit | 52c630da004d9273e8e5fc91c6304e9eed902566 (patch) | |
tree | 8414c98aa099355174ca6525757128d560ce5f8a | |
parent | cffdacb15a363321e1c1879aa7d94924acafd1cf (diff) |
Assoc pattern matching (#3703)
[Feature #17260] One-line pattern matching using tASSOC
R-assignment is rejected instead.
Notes
Notes:
Merged-By: nobu <[email protected]>
-rw-r--r-- | parse.y | 37 | ||||
-rw-r--r-- | spec/ruby/command_line/dash_upper_w_spec.rb | 4 | ||||
-rw-r--r-- | spec/ruby/command_line/rubyopt_spec.rb | 4 | ||||
-rw-r--r-- | spec/ruby/core/warning/element_set_spec.rb | 4 | ||||
-rw-r--r-- | spec/ruby/language/pattern_matching_spec.rb | 12 | ||||
-rw-r--r-- | test/ripper/test_sexp.rb | 6 | ||||
-rw-r--r-- | test/ruby/test_pattern_matching.rb | 22 | ||||
-rw-r--r-- | test/ruby/test_syntax.rb | 13 |
8 files changed, 37 insertions, 65 deletions
@@ -1150,7 +1150,7 @@ static int looking_at_eol_p(struct parser_params *p); %type <node> string_contents xstring_contents regexp_contents string_content %type <node> words symbols symbol_list qwords qsymbols word_list qword_list qsym_list word %type <node> literal numeric simple_numeric ssym dsym symbol cpath def_name defn_head defs_head -%type <node> top_compstmt top_stmts top_stmt begin_block rassign +%type <node> top_compstmt top_stmts top_stmt begin_block %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 fcall rel_expr %type <node> if_tail opt_else case_body case_args cases opt_rescue exc_list exc_var opt_ensure @@ -1242,7 +1242,7 @@ static int looking_at_eol_p(struct parser_params *p); %nonassoc tLOWEST %nonassoc tLBRACE_ARG -%nonassoc modifier_if modifier_unless modifier_while modifier_until keyword_in +%nonassoc modifier_if modifier_unless modifier_while modifier_until %left keyword_or keyword_and %right keyword_not %nonassoc keyword_defined @@ -1548,40 +1548,9 @@ stmt : keyword_alias fitem {SET_LEX_STATE(EXPR_FNAME|EXPR_FITEM);} fitem /*% %*/ /*% ripper: massign!($1, $3) %*/ } - | rassign | expr ; -rassign : arg_value tASSOC lhs - { - /*%%%*/ - $$ = node_assign(p, $3, $1, &@$); - /*% %*/ - /*% ripper: assign!($3, $1) %*/ - } - | arg_value tASSOC mlhs - { - /*%%%*/ - $$ = node_assign(p, $3, $1, &@$); - /*% %*/ - /*% ripper: massign!($3, $1) %*/ - } - | rassign tASSOC lhs - { - /*%%%*/ - $$ = node_assign(p, $3, $1, &@$); - /*% %*/ - /*% ripper: assign!($3, $1) %*/ - } - | rassign tASSOC mlhs - { - /*%%%*/ - $$ = node_assign(p, $3, $1, &@$); - /*% %*/ - /*% ripper: massign!($3, $1) %*/ - } - ; - command_asgn : lhs '=' command_rhs { /*%%%*/ @@ -1677,7 +1646,7 @@ expr : command_call { $$ = call_uni_op(p, method_cond(p, $2, &@2), '!', &@1, &@$); } - | arg keyword_in + | arg tASSOC { value_expr($1); SET_LEX_STATE(EXPR_BEG|EXPR_LABEL); diff --git a/spec/ruby/command_line/dash_upper_w_spec.rb b/spec/ruby/command_line/dash_upper_w_spec.rb index 8343bc08e4..2b617f9f7f 100644 --- a/spec/ruby/command_line/dash_upper_w_spec.rb +++ b/spec/ruby/command_line/dash_upper_w_spec.rb @@ -32,10 +32,10 @@ ruby_version_is "2.7" do describe "The -W command line option with :no-experimental" do it "suppresses experimental warnings" do - result = ruby_exe('0 in a', args: '2>&1') + result = ruby_exe('case 0; in a; end', args: '2>&1') result.should =~ /is experimental/ - result = ruby_exe('0 in a', options: '-W:no-experimental', args: '2>&1') + result = ruby_exe('case 0; in a; end', options: '-W:no-experimental', args: '2>&1') result.should == "" end end diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb index ee4e594a1c..a739f23eb8 100644 --- a/spec/ruby/command_line/rubyopt_spec.rb +++ b/spec/ruby/command_line/rubyopt_spec.rb @@ -68,13 +68,13 @@ describe "Processing RUBYOPT" do it "suppresses experimental warnings for '-W:no-experimental'" do ENV["RUBYOPT"] = '-W:no-experimental' - result = ruby_exe('0 in a', args: '2>&1') + result = ruby_exe('case 0; in a; end', args: '2>&1') result.should == "" end it "suppresses deprecation and experimental warnings for '-W:no-deprecated -W:no-experimental'" do ENV["RUBYOPT"] = '-W:no-deprecated -W:no-experimental' - result = ruby_exe('($; = "") in a', args: '2>&1') + result = ruby_exe('case ($; = ""); in a; end', args: '2>&1') result.should == "" end end diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb index ee83656cb4..a6b28282a0 100644 --- a/spec/ruby/core/warning/element_set_spec.rb +++ b/spec/ruby/core/warning/element_set_spec.rb @@ -8,8 +8,8 @@ ruby_version_is '2.7' do end it "emits and suppresses warnings for :experimental" do - ruby_exe('Warning[:experimental] = true; eval("0 in a")', args: "2>&1").should =~ /is experimental/ - ruby_exe('Warning[:experimental] = false; eval("0 in a")', args: "2>&1").should == "" + ruby_exe('Warning[:experimental] = true; eval("case 0; in a; end")', args: "2>&1").should =~ /is experimental/ + ruby_exe('Warning[:experimental] = false; eval("case 0; in a; end")', args: "2>&1").should == "" end it "raises for unknown category" do diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb index 91ad23bf32..2d22ec7e64 100644 --- a/spec/ruby/language/pattern_matching_spec.rb +++ b/spec/ruby/language/pattern_matching_spec.rb @@ -9,11 +9,13 @@ ruby_version_is "2.7" do ScratchPad.record [] end - it "can be standalone in operator that deconstructs value" do - eval(<<-RUBY).should == [0, 1] - [0, 1] in [a, b] - [a, b] - RUBY + ruby_version_is "3.0" do + it "can be standalone assoc operator that deconstructs value" do + eval(<<-RUBY).should == [0, 1] + [0, 1] => [a, b] + [a, b] + RUBY + end end it "extends case expression with case/in construction" do diff --git a/test/ripper/test_sexp.rb b/test/ripper/test_sexp.rb index 47339ba496..87b505a69c 100644 --- a/test/ripper/test_sexp.rb +++ b/test/ripper/test_sexp.rb @@ -412,7 +412,7 @@ eot [:@int, "0", [1, 5]], [:in, [:aryptn, nil, nil, nil, nil], [[:void_stmt]], nil]], - [__LINE__, %q{ 0 in [*, a, *] }] => + [__LINE__, %q{ 0 => [*, a, *] }] => [:case, [:@int, "0", [1, 0]], [:in, @@ -424,7 +424,7 @@ eot nil, nil]], - [__LINE__, %q{ 0 in [*a, b, *c] }] => + [__LINE__, %q{ 0 => [*a, b, *c] }] => [:case, [:@int, "0", [1, 0]], [:in, @@ -436,7 +436,7 @@ eot nil, nil]], - [__LINE__, %q{ 0 in A(*a, b, c, *d) }] => + [__LINE__, %q{ 0 => A(*a, b, c, *d) }] => [:case, [:@int, "0", [1, 0]], [:in, diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb index e5a18c5afe..d4de685495 100644 --- a/test/ruby/test_pattern_matching.rb +++ b/test/ruby/test_pattern_matching.rb @@ -272,7 +272,7 @@ class TestPatternMatching < Test::Unit::TestCase end assert_syntax_error(%q{ - 0 in [a, a] + 0 => [a, a] }, /duplicated variable name/) end @@ -737,10 +737,10 @@ END end def test_find_pattern - [0, 1, 2] in [*, 1 => a, *] + [0, 1, 2] => [*, 1 => a, *] assert_equal(1, a) - [0, 1, 2] in [*a, 1 => b, *c] + [0, 1, 2] => [*a, 1 => b, *c] assert_equal([0], a) assert_equal(1, b) assert_equal([2], c) @@ -763,7 +763,7 @@ END end end - [0, 1, 2] in [*a, 1 => b, 2 => c, *d] + [0, 1, 2] => [*a, 1 => b, 2 => c, *d] assert_equal([0], a) assert_equal(1, b) assert_equal(2, c) @@ -1451,18 +1451,18 @@ END ################################################################ - def test_modifier_in - 1 in a + def test_assoc + 1 => a assert_equal 1, a assert_raise(NoMatchingPatternError) do - {a: 1} in {a: 0} + {a: 1} => {a: 0} end - assert_syntax_error("if {} in {a:}; end", /void value expression/) + assert_syntax_error("if {} => {a:}; end", /void value expression/) assert_syntax_error(%q{ - 1 in a, b + 1 => a, b }, /unexpected/, '[ruby-core:95098]') assert_syntax_error(%q{ - 1 in a: + 1 => a: }, /unexpected/, '[ruby-core:95098]') end @@ -1480,7 +1480,7 @@ END def test_experimental_warning assert_experimental_warning("case 0; in 0; end") - assert_experimental_warning("0 in 0") + assert_experimental_warning("0 => 0") end end END_of_GUARD diff --git a/test/ruby/test_syntax.rb b/test/ruby/test_syntax.rb index 2e0d306c21..0a370d416d 100644 --- a/test/ruby/test_syntax.rb +++ b/test/ruby/test_syntax.rb @@ -1430,8 +1430,6 @@ eom assert_syntax_error('private def obj.foo = 42', /unexpected '='/) assert_valid_syntax('private def obj.foo() = 42') assert_valid_syntax('private def obj.inc(x) = x + 1') - eval('def self.inc(x) = x + 1 => @x') - assert_equal(:inc, @x) k = Class.new do class_eval('def rescued(x) = raise("to be caught") rescue "instance #{x}"') class_eval('def self.rescued(x) = raise("to be caught") rescue "class #{x}"') @@ -1715,10 +1713,13 @@ eom end def test_rightward_assign - assert_equal(1, eval("1 => a")) - assert_equal([2,3], eval("13.divmod(5) => a,b; [a, b]")) - assert_equal([2,3,2,3], eval("13.divmod(5) => a,b => c, d; [a, b, c, d]")) - assert_equal(3, eval("1+2 => a")) + a = b = nil + EnvUtil.suppress_warning {eval("1 => a")} + assert_equal(1, a) + EnvUtil.suppress_warning {eval("13.divmod(5) => [a,b]")} + assert_equal([2,3], [a, b]) + EnvUtil.suppress_warning {eval("1+2 => a")} + assert_equal(3, a) end private |