Skip to content

Commit

Permalink
+ ruby28.y: add find pattern. (#714)
Browse files Browse the repository at this point in the history
This commit tracks upstream commits ruby/ruby@ddded11 and ruby/ruby@f7906a7.
  • Loading branch information
iliabylich committed Jun 17, 2020
1 parent c56ca2f commit f03d763
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 19 deletions.
35 changes: 35 additions & 0 deletions doc/AST_FORMAT.md
Expand Up @@ -2191,6 +2191,24 @@ Format:
~~~ name (match-nil-pattern)
~~~

### Matching using find pattern

Format:

~~~
(find-pattern
(match-rest
(match-var :a))
(int 42)
(match-rest))
"in [*, 42, *]"
~ begin
~ end
~~~~~~~~~~ expression
~~~

Note that it can be used as a top-level pattern only when used in a `case` statement. In that case `begin` and `end` are empty.

### Matching using const pattern

#### With array pattern
Expand Down Expand Up @@ -2246,3 +2264,20 @@ Format:
~ expression (const-pattern.const)
~~ expression (const-pattern.array_pattern)
~~~

#### With find pattern

Format:

~~~
(const-pattern
(const nil :X)
(find-pattern
(match-rest)
(int 42)
(match-rest)))
"in X[*, 42, *]"
~ begin
~ end
~~~~~~~~~~~ expression
~~~
1 change: 1 addition & 0 deletions lib/parser/ast/processor.rb
Expand Up @@ -258,6 +258,7 @@ def on_numblock(node)
alias on_array_pattern_with_tail process_regular_node
alias on_hash_pattern process_regular_node
alias on_const_pattern process_regular_node
alias on_find_pattern process_regular_node

# @private
def process_variable_node(node)
Expand Down
5 changes: 5 additions & 0 deletions lib/parser/builders/default.rb
Expand Up @@ -1400,6 +1400,11 @@ def array_pattern(lbrack_t, elements, rbrack_t)
collection_map(lbrack_t, elements, rbrack_t))
end

def find_pattern(lbrack_t, elements, rbrack_t)
n(:find_pattern, elements,
collection_map(lbrack_t, elements, rbrack_t))
end

def match_with_trailing_comma(match, comma_t)
n(:match_with_trailing_comma, [ match ], expr_map(match.loc.expression.join(loc(comma_t))))
end
Expand Down
2 changes: 1 addition & 1 deletion lib/parser/meta.rb
Expand Up @@ -31,7 +31,7 @@ module class sclass def defs def_e defs_e undef alias args
match_var pin match_alt match_as match_rest
array_pattern match_with_trailing_comma array_pattern_with_tail
hash_pattern const_pattern if_guard unless_guard match_nil_pattern
empty_else
empty_else find_pattern
).map(&:to_sym).to_set.freeze

end # Meta
Expand Down
51 changes: 34 additions & 17 deletions lib/parser/ruby28.y
Expand Up @@ -1883,6 +1883,10 @@ opt_block_args_tail:
{
result = @builder.array_pattern(nil, [val[0]].concat(val[2]), nil)
}
| p_find
{
result = @builder.find_pattern(nil, val[0], nil)
}
| p_args_tail
{
result = @builder.array_pattern(nil, val[0], nil)
Expand Down Expand Up @@ -1925,6 +1929,12 @@ opt_block_args_tail:
pattern = @builder.array_pattern(nil, val[2], nil)
result = @builder.const_pattern(val[0], val[1], pattern, val[3])
}
| p_const p_lparen p_find rparen
{
@pattern_hash_keys.pop
pattern = @builder.find_pattern(nil, val[2], nil)
result = @builder.const_pattern(val[0], val[1], pattern, val[3])
}
| p_const p_lparen p_kwargs rparen
{
@pattern_hash_keys.pop
Expand All @@ -1942,6 +1952,12 @@ opt_block_args_tail:
pattern = @builder.array_pattern(nil, val[2], nil)
result = @builder.const_pattern(val[0], val[1], pattern, val[3])
}
| p_const p_lbracket p_find rbracket
{
@pattern_hash_keys.pop
pattern = @builder.find_pattern(nil, val[2], nil)
result = @builder.const_pattern(val[0], val[1], pattern, val[3])
}
| p_const p_lbracket p_kwargs rbracket
{
@pattern_hash_keys.pop
Expand All @@ -1953,14 +1969,13 @@ opt_block_args_tail:
pattern = @builder.array_pattern(val[1], nil, val[2])
result = @builder.const_pattern(val[0], val[1], pattern, val[2])
}
| tLBRACK
| tLBRACK p_args rbracket
{
@pattern_hash_keys.push
result = @builder.array_pattern(val[0], val[1], val[2])
}
p_args rbracket
| tLBRACK p_find rbracket
{
@pattern_hash_keys.pop
result = @builder.array_pattern(val[0], val[2], val[3])
result = @builder.find_pattern(val[0], val[1], val[2])
}
| tLBRACK rbracket
{
Expand Down Expand Up @@ -2041,25 +2056,27 @@ opt_block_args_tail:
result = [ *val[0], last_item ]
}
p_args_tail: tSTAR tIDENTIFIER
p_args_tail: p_rest
{
match_rest = @builder.match_rest(val[0], val[1])
result = [ match_rest ]
result = [ val[0] ]
}
| tSTAR tIDENTIFIER tCOMMA p_args_post
| p_rest tCOMMA p_args_post
{
match_rest = @builder.match_rest(val[0], val[1])
result = [ match_rest, *val[3] ]
result = [ val[0], *val[2] ]
}
| tSTAR
p_find: p_rest tCOMMA p_args_post tCOMMA p_rest
{
match_rest = @builder.match_rest(val[0])
result = [ match_rest ]
result = [ val[0], *val[2], val[4] ]
}
| tSTAR tCOMMA p_args_post
p_rest: tSTAR tIDENTIFIER
{
result = @builder.match_rest(val[0], val[1])
}
| tSTAR
{
match_rest = @builder.match_rest(val[0])
result = [ match_rest, *val[2] ]
result = @builder.match_rest(val[0])
}
p_args_post: p_arg
Expand Down
64 changes: 63 additions & 1 deletion test/test_parser.rb
Expand Up @@ -8460,7 +8460,7 @@ def assert_parses_pattern_match(ast, code, source_maps = '', versions = SINCE_2_
nil),
"#{case_pre}#{code}; end",
source_maps,
SINCE_2_7
versions
)
end

Expand Down Expand Up @@ -9715,4 +9715,66 @@ def test_rasgn_line_continuation
%{ ^^ location},
SINCE_2_8)
end

def test_find_pattern
assert_parses_pattern_match(
s(:in_pattern,
s(:find_pattern,
s(:match_rest,
s(:match_var, :x)),
s(:match_as,
s(:int, 1),
s(:match_var, :a)),
s(:match_rest,
s(:match_var, :y))),
nil,
s(:true)),
%q{in [*x, 1 => a, *y] then true},
%q{ ~~~~~~~~~~~~~~~~ expression (in_pattern.find_pattern)
| ~ begin (in_pattern.find_pattern)
| ~ end (in_pattern.find_pattern)
| ~~ expression (in_pattern.find_pattern.match_rest/1)
| ~~ expression (in_pattern.find_pattern.match_rest/2)},
SINCE_2_8)

assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :String),
s(:find_pattern,
s(:match_rest),
s(:int, 1),
s(:match_rest))),
nil,
s(:true)),
%q{in String(*, 1, *) then true},
%q{ ~~~~~~~ expression (in_pattern.const_pattern.find_pattern)},
SINCE_2_8)

assert_parses_pattern_match(
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :Array),
s(:find_pattern,
s(:match_rest),
s(:int, 1),
s(:match_rest))),
nil,
s(:true)),
%q{in Array[*, 1, *] then true},
%q{ ~~~~~~~ expression (in_pattern.const_pattern.find_pattern)},
SINCE_2_8)

assert_parses_pattern_match(
s(:in_pattern,
s(:find_pattern,
s(:match_rest),
s(:int, 42),
s(:match_rest)),
nil,
s(:true)),
%q{in *, 42, * then true},
%q{ ~~~~~~~~ expression (in_pattern.find_pattern)},
SINCE_2_8)
end
end

0 comments on commit f03d763

Please sign in to comment.