Skip to content

Commit

Permalink
NestedPatternMatchTest uses IRComparator
Browse files Browse the repository at this point in the history
  • Loading branch information
Akirathan committed Jan 27, 2025
1 parent 824666e commit 24638b7
Show file tree
Hide file tree
Showing 2 changed files with 125 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
import java.util.List;
import java.util.Objects;
import org.enso.compiler.core.IR;
import org.enso.compiler.core.ir.Empty;
import org.enso.compiler.core.ir.Expression;
import org.enso.compiler.core.ir.Name;
import org.enso.test.utils.IRDumperTestWrapper;
import scala.jdk.javaapi.CollectionConverters;

public final class IRComparator {
private final String name;
private final boolean compareMeta;
private final IRDumperTestWrapper dumper = new IRDumperTestWrapper();
private IR expectedRoot;
private IR actualRoot;

private IRComparator(String name, boolean compareMeta) {
this.name = name;
Expand All @@ -24,8 +29,8 @@ public static Builder builder() {

/**
* Compares IRs and dumps the diff the {@code actualIR} IR does not match the {@code expectedIR}
* one. IRs are compared recursively. {@code expectedIR} IR can have {@link SkipIR} nodes. When
* the {@link IRComparator} encounters {@link SkipIR} node in the {@code expectedIR} IR, the
* one. IRs are compared recursively. {@code expectedIR} IR can have {@link org.enso.compiler.core.ir.Empty} nodes. When
* the {@link IRComparator} encounters {@link org.enso.compiler.core.ir.Empty} node in the {@code expectedIR} IR, the
* corresponding subtree in the {@code actualIR} IR is skipped.
*
* <p>Traverses the IRs in the BFS order.
Expand All @@ -37,13 +42,15 @@ public static Builder builder() {
* @param actualIR
*/
public void compare(IR expectedIR, IR actualIR) throws IRComparisonFailure {
expectedRoot = expectedIR;
actualRoot = actualIR;
var nodesToProcess = new ArrayDeque<NodePair>();
nodesToProcess.add(new NodePair(expectedIR, actualIR));
while (!nodesToProcess.isEmpty()) {
var nodePairToProcess = nodesToProcess.poll();
var expected = nodePairToProcess.expected;
var actual = nodePairToProcess.actual;
if (expected instanceof SkipIR) {
if (expected instanceof Empty) {
continue;
}
compareTwoNodes(expected, actual);
Expand Down Expand Up @@ -106,12 +113,39 @@ private static List<NodePair> zipChildren(IR expected, IR actual) {
}

private IRComparisonFailure fail(String msg, IR expected, IR actual) {
dumper.dump(expected, name, "expected");
dumper.dump(actual, name, "actual");
dumper.dump(expectedRoot, name, "expected");
dumper.dump(actualRoot, name, "actual");
System.err.println("Dumped expected and actual IRs to IGV with name " + name);
return new IRComparisonFailure(msg, expected, actual);
}

private IR copyRootWithSwap(IR root, Expression node, Expression replacement) {
var duplRoot = root.duplicate(false, false, false, false);
var nodesToProcess = new ArrayDeque<IR>();
nodesToProcess.add(duplRoot);
while (!nodesToProcess.isEmpty()) {
var nodeToProcess = nodesToProcess.poll();
if (nodeToProcess == node) {

}
}
}

private IR replaceChild(IR node, int childIdx, IR replacement) {
var children = node.children();
var newChildren = new ArrayList<IR>();
for (var i = 0; i < children.size(); i++) {
if (childIdx == i) {
newChildren.add(replacement);
} else {
newChildren.add(children.apply(i));
}
}
// Replace via reflection
var newChildrenList = CollectionConverters.asScala(newChildren).toList();
throw new UnsupportedOperationException("unimplemented");
}

private record NodePair(IR expected, IR actual) {}

public static final class Builder {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package org.enso.compiler.test.pass.desugar
import org.enso.compiler.Passes
import org.enso.compiler.context.{FreshNameSupply, InlineContext, ModuleContext}
import org.enso.compiler.core.ir.expression.Case
import org.enso.compiler.core.ir.{Expression, Literal, Module, Name, Pattern}
import org.enso.compiler.core.ir.{Empty, Expression, Literal, Module, Name, Pattern}
import org.enso.compiler.pass.desugar.NestedPatternMatch
import org.enso.compiler.pass.{PassConfiguration, PassGroup, PassManager}
import org.enso.compiler.test.CompilerTest
import org.enso.compiler.test.ircompare.{IRComparator}
import org.enso.compiler.test.{CompilerTest}

class NestedPatternMatchTest extends CompilerTest {

Expand Down Expand Up @@ -342,4 +343,87 @@ class NestedPatternMatchTest extends CompilerTest {
consANilBranch2Expr.branches.head.terminalBranch shouldBe true
}
}

"Simple nested pattern desugaring" should {
implicit val ctx: InlineContext = mkInlineContext

// IGV graph: https://github.com/user-attachments/assets/b5387e61-e577-4b03-8a4a-ca05e27f2462
"One nested pattern" in {
val ir =
"""
|case x of
| Cons (Nested a) -> num
|""".stripMargin.preprocessExpression.get
val processed = ir.desugar

val expectedIR = Expression.Block(
expressions = List(
Expression.Binding(
name = lit("<internal-0>"),
expression = emptyIR(),
identifiedLocation = null
)
),
returnValue = Case.Expr(
scrutinee = lit("<internal-10>"),
branches = List(
Case.Branch(
pattern = Pattern.Constructor(
constructor = lit("Cons"),
fields = List(
Pattern.Name(lit("<internal-1>"), identifiedLocation = null)
),
identifiedLocation = null
),
expression = Expression.Block(
expressions = List(
Expression.Binding(
name = lit("<internal-2>"),
expression = emptyIR(),
identifiedLocation = null
),
),
returnValue = Case.Expr(
scrutinee = lit("<internal-2>"),
branches = List(
Case.Branch(
pattern = Pattern.Constructor(
constructor = lit("Nested"),
fields = List(
Pattern.Name(lit("a"), identifiedLocation = null)
),
identifiedLocation = null
),
expression = lit("num"),
terminalBranch = true,
identifiedLocation = null
)
),
isNested = true,
identifiedLocation = null
),
identifiedLocation = null
),
identifiedLocation = null,
terminalBranch = false
),
),
isNested = false,
identifiedLocation = null
),
identifiedLocation = null
)

val comparator = IRComparator.builder().name("One nested pattern").build()
comparator.compare(expectedIR, processed)
}
}

private def lit(name: String): Name.Literal = {
Name.Literal(name = name, isMethod = false, identifiedLocation = null)
}

private def emptyIR(): Empty = {
new Empty(null)
}
}

0 comments on commit 24638b7

Please sign in to comment.