Skip to content

Commit

Permalink
Recursively match array literals against array patterns
Browse files Browse the repository at this point in the history
We can't untag any existing tests because we currently depend upon the
local variable having already been declared, but this now works:

```
>> a = "FIRSTINSTANCE"
=> "FIRSTINSTANCE"

>> case [[1,1,1],[6,6,6]]
   in [[a,1,1],[Integer,Integer,Integer,]]
>> end
=> nil

>> a
=> 1
```
  • Loading branch information
Lillian Zhang authored and tomstuart committed Dec 11, 2020
1 parent 2cc9eb1 commit 49e0b57
Showing 1 changed file with 29 additions and 0 deletions.
29 changes: 29 additions & 0 deletions src/main/java/org/truffleruby/parser/BodyTranslator.java
Original file line number Diff line number Diff line change
Expand Up @@ -880,6 +880,35 @@ private RubyNode case3PatternMatch(ParseNode patternNode, ParseNode expressionNo

switch (patternNode.getNodeType()) {
case ARRAYNODE:
// Pattern-match element-wise recursively if possible.
final int size = ((ArrayParseNode) patternNode).size();
if (expressionNode.getNodeType() == NodeType.ARRAYNODE &&
((ArrayParseNode) expressionNode).size() == size) {
final ParseNode[] patternElements = ((ArrayParseNode) patternNode).children();
final ParseNode[] expressionElements = ((ArrayParseNode) expressionNode).children();

final RubyNode[] matches = new RubyNode[size];

// For each element of the case expression, evaluate and assign it, then run the pattern-matching
// on the element
for (int n = 0; n < size; n++) {
final String tempName = environment.allocateLocalTemp("caseElem" + n);
final ReadLocalNode readTemp = environment.findLocalVarNode(tempName, sourceSection);
final RubyNode assignTemp = readTemp.makeWriteNode(expressionElements[n].accept(this));
matches[n] = sequence(sourceSection, Arrays.asList(
assignTemp,
case3PatternMatch(patternElements[n], expressionElements[n], readTemp, sourceSection)));
}

// Incorporate the element-wise pattern-matching into the AST, with the longer right leg since
// AndNode is visited left to right
RubyNode match = matches[size - 1];
for (int n = size - 2; n >= 0; n--) {
match = new AndNode(matches[n], match);
}
return match;
}

deconstructCallParameters = new RubyCallNodeParameters(
expressionValue,
"deconstruct",
Expand Down

0 comments on commit 49e0b57

Please sign in to comment.