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

[Ruby 3.0] Add support for find pattern #4364

Merged
merged 2 commits into from Jul 28, 2021
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
20 changes: 20 additions & 0 deletions parser/Builder.cc
Expand Up @@ -779,6 +779,20 @@ class Builder::Impl {
return make_unique<False>(tokLoc(tok));
}

unique_ptr<Node> find_pattern(const token *lbrack_t, sorbet::parser::NodeVec elements, const token *rbrack_t) {
auto loc = collectionLoc(elements);

if (lbrack_t != nullptr) {
loc = tokLoc(lbrack_t).join(loc);
}

if (rbrack_t != nullptr) {
loc = loc.join(tokLoc(rbrack_t));
}

return make_unique<FindPattern>(loc, std::move(elements));
}

unique_ptr<Node> fileLiteral(const token *tok) {
return make_unique<FileLiteral>(tokLoc(tok));
}
Expand Down Expand Up @@ -1846,6 +1860,11 @@ ForeignPtr false_(SelfPtr builder, const token *tok) {
return build->toForeign(build->false_(tok));
}

ForeignPtr find_pattern(SelfPtr builder, const token *lbrack_t, const node_list *elements, const token *rbrack_t) {
auto build = cast_builder(builder);
return build->toForeign(build->find_pattern(lbrack_t, build->convertNodeList(elements), rbrack_t));
}

ForeignPtr fileLiteral(SelfPtr builder, const token *tok) {
auto build = cast_builder(builder);
return build->toForeign(build->fileLiteral(tok));
Expand Down Expand Up @@ -2387,6 +2406,7 @@ struct ruby_parser::builder Builder::interface = {
defSingleton,
encodingLiteral,
false_,
find_pattern,
fileLiteral,
float_,
floatComplex,
Expand Down
6 changes: 6 additions & 0 deletions parser/tools/generate_ast.cc
Expand Up @@ -268,6 +268,12 @@ NodeDef nodes[] = {
"false",
vector<FieldDef>(),
},
// Find pattern
{
"FindPattern",
"find_pattern",
vector<FieldDef>({{"elements", FieldType::NodeVec}}),
},
// __FILE__
{
"FileLiteral",
Expand Down
12 changes: 12 additions & 0 deletions test/whitequark/test_find_pattern_0.parse-tree-whitequark.exp
@@ -0,0 +1,12 @@
s(:case_match,
s(:lvar, :foo),
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)), nil)
3 changes: 3 additions & 0 deletions test/whitequark/test_find_pattern_0.rb
@@ -0,0 +1,3 @@
# typed: true

case foo; in [*x, 1 => a, *y] then true; end
10 changes: 10 additions & 0 deletions test/whitequark/test_find_pattern_1.parse-tree-whitequark.exp
@@ -0,0 +1,10 @@
s(:case_match,
s(:lvar, :foo),
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :String),
s(:find_pattern,
s(:match_rest, nil),
s(:int, "1"),
s(:match_rest, nil))), nil,
s(:true)), nil)
3 changes: 3 additions & 0 deletions test/whitequark/test_find_pattern_1.rb
@@ -0,0 +1,3 @@
# typed: true

case foo; in String(*, 1, *) then true; end
10 changes: 10 additions & 0 deletions test/whitequark/test_find_pattern_2.parse-tree-whitequark.exp
@@ -0,0 +1,10 @@
s(:case_match,
s(:lvar, :foo),
s(:in_pattern,
s(:const_pattern,
s(:const, nil, :Array),
s(:find_pattern,
s(:match_rest, nil),
s(:int, "1"),
s(:match_rest, nil))), nil,
s(:true)), nil)
3 changes: 3 additions & 0 deletions test/whitequark/test_find_pattern_2.rb
@@ -0,0 +1,3 @@
# typed: true

case foo; in Array[*, 1, *] then true; end
@@ -0,0 +1,8 @@
s(:case_match,
s(:lvar, :foo),
s(:in_pattern,
s(:find_pattern,
s(:match_rest, nil),
s(:int, "42"),
s(:match_rest, nil)), nil,
s(:true)), nil)
3 changes: 3 additions & 0 deletions test/whitequark/test_find_pattern_3.rb
@@ -0,0 +1,3 @@
# typed: true

case foo; in *, 42, * then true; end
@@ -1,3 +1,3 @@
# typed: true

1 in a, b # error: unexpected token ","
1 => a, b # error: unexpected token ","
@@ -1,3 +1,3 @@
# typed: true

1 in a: # error: unexpected token tLABEL
1 => a: # error: unexpected token tLABEL
@@ -0,0 +1,6 @@
s(:begin,
s(:match_pattern,
s(:int, "1"),
s(:array_pattern,
s(:match_var, :a))),
s(:lvar, :a))
3 changes: 3 additions & 0 deletions test/whitequark/test_pattern_matching_single_line_0.rb
@@ -0,0 +1,3 @@
# typed: true

1 => [a]; a
@@ -0,0 +1,6 @@
s(:begin,
s(:match_pattern_p,
s(:int, "1"),
s(:array_pattern,
s(:match_var, :a))),
s(:lvar, :a))
3 changes: 3 additions & 0 deletions test/whitequark/test_pattern_matching_single_line_1.rb
@@ -0,0 +1,3 @@
# typed: true

1 in [a]; a
56 changes: 37 additions & 19 deletions third_party/parser/cc/grammars/typedruby.ypp
Expand Up @@ -239,6 +239,7 @@ using namespace std::string_literals;
p_kw
p_kw_label
p_primitive
p_rest
p_top_expr_body
p_var_ref
p_value
Expand Down Expand Up @@ -308,6 +309,7 @@ using namespace std::string_literals;
p_args_head
p_args_post
p_args_tail
p_find
p_kwarg
p_kwargs
p_kwnorest
Expand Down Expand Up @@ -2426,6 +2428,10 @@ opt_block_args_tail:
list->concat($3);
$$ = driver.build.array_pattern(self, nullptr, list, nullptr);
}
| p_find
{
$$ = driver.build.find_pattern(self, nullptr, $1, nullptr);
}
| p_args_tail
{
$$ = driver.build.array_pattern(self, nullptr, $1, nullptr);
Expand Down Expand Up @@ -2462,6 +2468,12 @@ opt_block_args_tail:
auto pattern = driver.build.array_pattern(self, nullptr, $3, nullptr);
$$ = driver.build.const_pattern(self, $1, $2, pattern, $4);
}
| p_const p_lparen p_find rparen
{
driver.pattern_hash_keys.pop();
auto pattern = driver.build.find_pattern(self, nullptr, $3, nullptr);
$$ = driver.build.const_pattern(self, $1, $2, pattern, $4);
}
| p_const p_lparen p_kwargs rparen
{
driver.pattern_hash_keys.pop();
Expand All @@ -2480,6 +2492,12 @@ opt_block_args_tail:
auto pattern = driver.build.array_pattern(self, nullptr, $3, nullptr);
$$ = driver.build.const_pattern(self, $1, $2, pattern, $4);
}
| p_const p_lbracket p_find rbracket
{
driver.pattern_hash_keys.pop();
auto pattern = driver.build.find_pattern(self, nullptr, $3, nullptr);
$$ = driver.build.const_pattern(self, $1, $2, pattern, $4);
}
| p_const p_lbracket p_kwargs rbracket
{
driver.pattern_hash_keys.pop();
Expand All @@ -2492,14 +2510,13 @@ opt_block_args_tail:
auto pattern = driver.build.array_pattern(self, $2, list, nullptr);
$$ = driver.build.const_pattern(self, $1, $2, pattern, $3);
}
| tLBRACK
| tLBRACK p_args rbracket
{
driver.pattern_hash_keys.push();
$$ = driver.build.array_pattern(self, $1, $2, $3);
}
p_args rbracket
| tLBRACK p_find rbracket
{
driver.pattern_hash_keys.pop();
$$ = driver.build.array_pattern(self, $1, $3, $4);
$$ = driver.build.find_pattern(self, $1, $2, $3);
}
| tLBRACK rbracket
{
Expand Down Expand Up @@ -2587,27 +2604,28 @@ opt_block_args_tail:
$$ = $1;
$$->emplace_back(last_item);
}
p_args_tail: tSTAR tIDENTIFIER
p_args_tail: p_rest
{
auto match_rest = driver.build.match_rest(self, $1, $2);
$$ = driver.alloc.node_list(match_rest);
$$ = driver.alloc.node_list($1);
}
| tSTAR tIDENTIFIER tCOMMA p_args_post
| p_rest tCOMMA p_args_post
{
auto match_rest = driver.build.match_rest(self, $1, $2);
$$ = driver.alloc.node_list(match_rest);
$$->concat($4);
$$ = driver.alloc.node_list($1);
$$->concat($3);
}
| tSTAR
p_find: p_rest tCOMMA p_args_post tCOMMA p_rest
{
auto match_rest = driver.build.match_rest(self, $1, nullptr);
$$ = driver.alloc.node_list(match_rest);
$$ = driver.alloc.node_list($1);
$$->concat($3);
$$->emplace_back($5);
}
| tSTAR tCOMMA p_args_post
p_rest: tSTAR tIDENTIFIER
{
auto match_rest = driver.build.match_rest(self, $1, nullptr);
$$ = driver.alloc.node_list(match_rest);
$$->concat($3);
$$ = driver.build.match_rest(self, $1, $2);
}
| tSTAR
{
$$ = driver.build.match_rest(self, $1, nullptr);
}
p_args_post: p_arg
{
Expand Down
2 changes: 1 addition & 1 deletion third_party/parser/cc/lexer.rl
Expand Up @@ -2683,7 +2683,7 @@ void lexer::set_state_expr_value() {
'*' | '=>'
=> {
emit_table(PUNCTUATION);
fgoto expr_value;
fnext expr_value; fbreak;
};

# When '|', '~', '!', '=>' are used as operators
Expand Down
1 change: 1 addition & 0 deletions third_party/parser/include/ruby_parser/builder.hh
Expand Up @@ -56,6 +56,7 @@ struct builder {
ForeignPtr(*defSingleton)(SelfPtr builder, ForeignPtr defHead, ForeignPtr args, ForeignPtr body, const token* end);
ForeignPtr(*encodingLiteral)(SelfPtr builder, const token* tok);
ForeignPtr(*false_)(SelfPtr builder, const token* tok);
ForeignPtr(*find_pattern)(SelfPtr builder, const token* lbrack_t, const node_list* elements, const token* rbrack_t);
ForeignPtr(*fileLiteral)(SelfPtr builder, const token* tok);
ForeignPtr(*float_)(SelfPtr builder, const token* tok);
ForeignPtr(*floatComplex)(SelfPtr builder, const token* tok);
Expand Down