Skip to content

Commit

Permalink
Merge pull request #275 from Shopify/Alex/translate-pattern-vars
Browse files Browse the repository at this point in the history
Implement Prism -> Sorbet translation for variable binding in patterns
  • Loading branch information
amomchilov authored Oct 10, 2024
2 parents cfd8e3e + ee10af4 commit 52a9d72
Show file tree
Hide file tree
Showing 3 changed files with 282 additions and 0 deletions.
15 changes: 15 additions & 0 deletions parser/prism/Translator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1105,6 +1105,14 @@ unique_ptr<parser::Node> Translator::patternTranslate(pm_node_t *node) {

return make_unique<parser::MatchAlt>(location, move(left), move(right));
}
case PM_ASSOC_NODE: { // A key-value pair in a Hash pattern, e.g. the `k: v` in `h in { k: v }
auto assocNode = reinterpret_cast<pm_assoc_node *>(node);

auto key = patternTranslate(assocNode->key);
auto value = patternTranslate(assocNode->value);

return make_unique<parser::Pair>(location, move(key), move(value));
}
case PM_ARRAY_PATTERN_NODE: { // An array pattern such as the `[head, *tail]` in the `a in [head, *tail]`
auto arrayPatternNode = reinterpret_cast<pm_array_pattern_node *>(node);

Expand Down Expand Up @@ -1196,6 +1204,13 @@ unique_ptr<parser::Node> Translator::patternTranslate(pm_node_t *node) {

return make_unique<parser::InPattern>(location, move(sorbetPattern), nullptr, move(statements));
}
case PM_LOCAL_VARIABLE_TARGET_NODE: { // A variable binding in a pattern, like the `head` in `[head, *tail]`
auto localVarTargetNode = reinterpret_cast<pm_local_variable_target_node *>(node);

auto name = parser.resolveConstant(localVarTargetNode->name);

return make_unique<MatchVar>(location, gs.enterNameUTF8(name));
}
default: {
return translate(node);
}
Expand Down
246 changes: 246 additions & 0 deletions test/prism_regression/case_match_variable_binding.parse-tree.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,246 @@
CaseMatch {
expr = Send {
receiver = NULL
method = <U foo>
args = [
]
}
inBodies = [
InPattern {
pattern = ArrayPattern {
elts = [
MatchVar {
name = <U x>
}
]
}
guard = NULL
body = DString {
nodes = [
String {
val = <U An Array-like thing that only contains >
}
Begin {
stmts = [
LVar {
name = <U x>
}
]
}
]
}
}
InPattern {
pattern = HashPattern {
pairs = [
Pair {
key = Symbol {
val = <U k>
}
value = MatchVar {
name = <U x>
}
}
]
}
guard = NULL
body = DString {
nodes = [
String {
val = <U A Hash-like whose key `:k` has value >
}
Begin {
stmts = [
LVar {
name = <U x>
}
]
}
]
}
}
InPattern {
pattern = ArrayPattern {
elts = [
ArrayPattern {
elts = [
MatchVar {
name = <U value>
}
]
}
MatchRest {
var = MatchVar {
name = <U tail>
}
}
]
}
guard = NULL
body = DString {
nodes = [
String {
val = <U An array-like thing that starts with a one-element Array containing >
}
Begin {
stmts = [
LVar {
name = <U value>
}
]
}
String {
val = <U , and ends with >
}
Begin {
stmts = [
LVar {
name = <U tail>
}
]
}
]
}
}
InPattern {
pattern = HashPattern {
pairs = [
Pair {
key = Symbol {
val = <U k>
}
value = ArrayPattern {
elts = [
MatchVar {
name = <U value>
}
]
}
}
]
}
guard = NULL
body = DString {
nodes = [
String {
val = <U A hash-like whose key `:k` has a one-element Array value containing >
}
Begin {
stmts = [
LVar {
name = <U value>
}
]
}
]
}
}
InPattern {
pattern = ArrayPattern {
elts = [
HashPattern {
pairs = [
Pair {
key = Symbol {
val = <U k>
}
value = MatchVar {
name = <U value>
}
}
]
}
MatchRest {
var = MatchVar {
name = <U tail>
}
}
]
}
guard = NULL
body = DString {
nodes = [
String {
val = <U An array-like thing that starts with a one-element Hash containing >
}
Begin {
stmts = [
LVar {
name = <U value>
}
]
}
String {
val = <U , and ends with >
}
Begin {
stmts = [
LVar {
name = <U tail>
}
]
}
]
}
}
InPattern {
pattern = HashPattern {
pairs = [
Pair {
key = Symbol {
val = <U k>
}
value = HashPattern {
pairs = [
Pair {
key = Symbol {
val = <U k2>
}
value = MatchVar {
name = <U value>
}
}
]
}
}
]
}
guard = NULL
body = DString {
nodes = [
String {
val = <U A hash-like whose key `:k` has a one-element Hash value containing k2: >
}
Begin {
stmts = [
LVar {
name = <U value>
}
]
}
]
}
}
InPattern {
pattern = MatchVar {
name = <U x>
}
guard = NULL
body = DString {
nodes = [
String {
val = <U Some other value: >
}
Begin {
stmts = [
LVar {
name = <U x>
}
]
}
]
}
}
]
elseBody = NULL
}
21 changes: 21 additions & 0 deletions test/prism_regression/case_match_variable_binding.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# typed: false

case foo
in [x] # Variable binding nested in an Array pattern
"An Array-like thing that only contains #{x}"
in { k: x } # Variable binding nested in a Hash pattern
"A Hash-like whose key `:k` has value #{x}"

in [[value], *tail] # Array pattern inside an Array pattern
"An array-like thing that starts with a one-element Array containing #{value}, and ends with #{tail}"
in { k: [value] } # Array pattern inside a Hash pattern
"A hash-like whose key `:k` has a one-element Array value containing #{value}"

in [{ k: value }, *tail] # A Hash pattern inside an Array pattern
"An array-like thing that starts with a one-element Hash containing #{value}, and ends with #{tail}"
in { k: { k2: value } } # A Hash pattern inside a Hash pattern
"A hash-like whose key `:k` has a one-element Hash value containing k2: #{value}"

in x
"Some other value: #{x}"
end

0 comments on commit 52a9d72

Please sign in to comment.