From 445664d43287a7ed4fafa549200c1dfd4cacbd2d Mon Sep 17 00:00:00 2001 From: Ricardo Costa Date: Wed, 18 Mar 2026 16:01:59 +0000 Subject: [PATCH] Simplify If Expressions --- .../rj_language/opt/ConstantFolding.java | 46 +++++++++++ .../rj_language/opt/ConstantPropagation.java | 5 ++ .../derivation_node/IteDerivationNode.java | 26 +++++++ .../opt/ExpressionSimplifierTest.java | 77 +++++++++++++++++++ 4 files changed, 154 insertions(+) create mode 100644 liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/derivation_node/IteDerivationNode.java diff --git a/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantFolding.java b/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantFolding.java index b52f8eb7..c4211357 100644 --- a/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantFolding.java +++ b/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantFolding.java @@ -3,12 +3,14 @@ import liquidjava.rj_language.ast.BinaryExpression; import liquidjava.rj_language.ast.Expression; import liquidjava.rj_language.ast.GroupExpression; +import liquidjava.rj_language.ast.Ite; import liquidjava.rj_language.ast.LiteralBoolean; import liquidjava.rj_language.ast.LiteralInt; import liquidjava.rj_language.ast.LiteralReal; import liquidjava.rj_language.ast.UnaryExpression; import liquidjava.rj_language.opt.derivation_node.BinaryDerivationNode; import liquidjava.rj_language.opt.derivation_node.DerivationNode; +import liquidjava.rj_language.opt.derivation_node.IteDerivationNode; import liquidjava.rj_language.opt.derivation_node.UnaryDerivationNode; import liquidjava.rj_language.opt.derivation_node.ValDerivationNode; @@ -26,6 +28,9 @@ public static ValDerivationNode fold(ValDerivationNode node) { if (exp instanceof UnaryExpression) return foldUnary(node); + if (exp instanceof Ite) + return foldIte(node); + if (exp instanceof GroupExpression group) { if (group.getChildren().size() == 1) { return fold(new ValDerivationNode(group.getChildren().get(0), node.getOrigin())); @@ -191,4 +196,45 @@ private static ValDerivationNode foldUnary(ValDerivationNode node) { DerivationNode origin = operandNode.getOrigin() != null ? new UnaryDerivationNode(operandNode, operator) : null; return new ValDerivationNode(unaryExp, origin); } + + /** + * Folds ternary expressions by checking if condition is a boolean literal or both branches are the same + */ + private static ValDerivationNode foldIte(ValDerivationNode node) { + Ite iteExp = (Ite) node.getValue(); + + ValDerivationNode condNode = fold(new ValDerivationNode(iteExp.getCondition(), null)); + ValDerivationNode thenNode = fold(new ValDerivationNode(iteExp.getThen(), null)); + ValDerivationNode elseNode = fold(new ValDerivationNode(iteExp.getElse(), null)); + + Expression condition = condNode.getValue(); + Expression thenExp = thenNode.getValue(); + Expression elseExp = elseNode.getValue(); + + iteExp.setChild(0, condition); + iteExp.setChild(1, thenExp); + iteExp.setChild(2, elseExp); + + // if condition is a boolean literal, select the corresponding branch: true ? a : b => a, false ? a : b => b + if (condition instanceof LiteralBoolean boolCond) { + Expression selected = boolCond.isBooleanTrue() ? thenExp : elseExp; + DerivationNode origin = new IteDerivationNode(condNode, thenNode, elseNode); + return new ValDerivationNode(selected, origin); + } + + // if both branches are the same, return one of them (e.g. cond ? b : b => b) + if (thenExp.equals(elseExp)) { + DerivationNode origin = new IteDerivationNode(condNode, thenNode, elseNode); + return new ValDerivationNode(thenExp, origin); + } + + // no folding, but keep track of the folding steps in the origin + DerivationNode origin = hasIteChildOrigin(condNode, thenNode, elseNode) + ? new IteDerivationNode(condNode, thenNode, elseNode) : node.getOrigin(); + return new ValDerivationNode(iteExp, origin); + } + + private static boolean hasIteChildOrigin(ValDerivationNode cond, ValDerivationNode then, ValDerivationNode els) { + return cond.getOrigin() != null || then.getOrigin() != null || els.getOrigin() != null; + } } \ No newline at end of file diff --git a/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantPropagation.java b/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantPropagation.java index 5cc0562e..f91d546f 100644 --- a/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantPropagation.java +++ b/liquidjava-verifier/src/main/java/liquidjava/rj_language/opt/ConstantPropagation.java @@ -6,6 +6,7 @@ import liquidjava.rj_language.ast.Var; import liquidjava.rj_language.opt.derivation_node.BinaryDerivationNode; import liquidjava.rj_language.opt.derivation_node.DerivationNode; +import liquidjava.rj_language.opt.derivation_node.IteDerivationNode; import liquidjava.rj_language.opt.derivation_node.UnaryDerivationNode; import liquidjava.rj_language.opt.derivation_node.ValDerivationNode; import liquidjava.rj_language.opt.derivation_node.VarDerivationNode; @@ -134,6 +135,10 @@ private static void extractVarOrigins(ValDerivationNode node, Map operand"); + } else if (expected instanceof IteDerivationNode expectedIte) { + IteDerivationNode actualIte = (IteDerivationNode) actual; + assertDerivationEquals(expectedIte.getCondition(), actualIte.getCondition(), message + " > condition"); + assertDerivationEquals(expectedIte.getThenBranch(), actualIte.getThenBranch(), message + " > then"); + assertDerivationEquals(expectedIte.getElseBranch(), actualIte.getElseBranch(), message + " > else"); } } }