From 156675a75f3cffb672ef787c160e008a8e905b5b Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 26 Jun 2016 11:21:24 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../parser/visitors/ConstantPropagation.java | 42 +++++++------------ .../parser/visitors/DeadCodeElimination.java | 15 ++++--- .../ownlang/parser/visitors/VisitorUtils.java | 9 ++++ 3 files changed, 31 insertions(+), 35 deletions(-) diff --git a/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java b/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java index 41fa425..ca31242 100644 --- a/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java +++ b/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java @@ -76,14 +76,7 @@ public class ConstantPropagation implements Optimizer.Info { } final String variableName = ((VariableExpression) s.target).name; - final VariableInfo var; - if (t.containsKey(variableName)) { - var = t.get(variableName); - var.modifications++; - } else { - var = new VariableInfo(); - var.modifications = 1; - } + final VariableInfo var = variableInfo(t, variableName); if (s.operation == null && isValue(s.expression)) { var.value = ((ValueExpression) s.expression).value; @@ -96,16 +89,7 @@ public class ConstantPropagation implements Optimizer.Info { public Node visit(DestructuringAssignmentStatement s, Map t) { for (String variableName : s.variables) { if (variableName == null) continue; - - final VariableInfo var; - if (t.containsKey(variableName)) { - var = t.get(variableName); - var.modifications++; - } else { - var = new VariableInfo(); - var.modifications = 1; - } - t.put(variableName, var); + t.put(variableName, variableInfo(t, variableName)); } return super.visit(s, t); } @@ -114,15 +98,7 @@ public class ConstantPropagation implements Optimizer.Info { public Node visit(FunctionDefineStatement s, Map t) { for (Argument argument : s.arguments) { final String variableName = argument.getName(); - final VariableInfo var; - if (t.containsKey(variableName)) { - var = t.get(variableName); - var.modifications++; - } else { - var = new VariableInfo(); - var.modifications = 1; - } - t.put(variableName, var); + t.put(variableName, variableInfo(t, variableName)); } return super.visit(s, t); } @@ -132,6 +108,18 @@ public class ConstantPropagation implements Optimizer.Info { // no visit match expression return s; } + + private VariableInfo variableInfo(Map t, final String variableName) { + final VariableInfo var; + if (t.containsKey(variableName)) { + var = t.get(variableName); + var.modifications++; + } else { + var = new VariableInfo(); + var.modifications = 1; + } + return var; + } } private class VariablesPropagator extends OptimizationVisitor> { diff --git a/src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java b/src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java index 8ae8855..f40729e 100644 --- a/src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java +++ b/src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java @@ -5,8 +5,9 @@ import com.annimon.ownlang.parser.ast.ExprStatement; import com.annimon.ownlang.parser.ast.IfStatement; import com.annimon.ownlang.parser.ast.Node; import com.annimon.ownlang.parser.ast.TernaryExpression; -import com.annimon.ownlang.parser.ast.ValueExpression; import com.annimon.ownlang.parser.ast.WhileStatement; +import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValue; +import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValueAsInt; /** * Performs dead code elimination. @@ -41,7 +42,7 @@ public class DeadCodeElimination extends OptimizationVisitor implements Op @Override public Node visit(IfStatement s, Void t) { - if (s.expression instanceof ValueExpression) { + if (isValue(s.expression)) { ifStatementEliminatedCount++; // true statement if (s.expression.eval().asInt() != 0) { @@ -58,7 +59,7 @@ public class DeadCodeElimination extends OptimizationVisitor implements Op @Override public Node visit(TernaryExpression s, Void t) { - if (s.condition instanceof ValueExpression) { + if (isValue(s.condition)) { ternaryExpressionEliminatedCount++; if (s.condition.eval().asInt() != 0) { return s.trueExpr; @@ -70,11 +71,9 @@ public class DeadCodeElimination extends OptimizationVisitor implements Op @Override public Node visit(WhileStatement s, Void t) { - if (s.condition instanceof ValueExpression) { - if (s.condition.eval().asInt() == 0) { - whileStatementEliminatedCount++; - return new ExprStatement(s.condition); - } + if (isValueAsInt(s.condition, 0)) { + whileStatementEliminatedCount++; + return new ExprStatement(s.condition); } return super.visit(s, t); } diff --git a/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java b/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java index 50cb9f6..2a8bed0 100644 --- a/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java +++ b/src/com/annimon/ownlang/parser/visitors/VisitorUtils.java @@ -47,6 +47,15 @@ public final class VisitorUtils { return false; } + public static boolean isValueAsInt(Node node, int valueToCheck) { + if (!isValue(node)) return false; + + final Value value = ((ValueExpression) node).value; + if (value.type() != Types.NUMBER) return false; + + return value.asInt() == valueToCheck; + } + public static boolean isSameVariables(Node n1, Node n2) { if (isVariable(n1) && isVariable(n2)) { final VariableExpression v1 = (VariableExpression) n1; From 08b12ff78587114993488a00b49b1087dabaf616 Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 26 Jun 2016 11:26:41 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=9E=D0=BF=D1=82=D0=B8=D0=BC=D0=B8=D0=B7?= =?UTF-8?q?=D0=B0=D1=82=D0=BE=D1=80=D1=8B=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BC?= =?UTF-8?q?=D0=B5=D1=89=D0=B5=D0=BD=D1=8B=20=D0=B2=20=D0=BE=D1=82=D0=B4?= =?UTF-8?q?=D0=B5=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=BF=D0=B0=D0=BA=D0=B5?= =?UTF-8?q?=D1=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/annimon/ownlang/parser/Optimizer.java | 8 ++++---- .../{visitors => optimization}/ConstantFolding.java | 3 ++- .../{visitors => optimization}/ConstantPropagation.java | 2 +- .../{visitors => optimization}/DeadCodeElimination.java | 2 +- .../ExpressionSimplification.java | 3 ++- .../{visitors => optimization}/OptimizationVisitor.java | 2 +- 6 files changed, 11 insertions(+), 9 deletions(-) rename src/com/annimon/ownlang/parser/{visitors => optimization}/ConstantFolding.java (97%) rename src/com/annimon/ownlang/parser/{visitors => optimization}/ConstantPropagation.java (99%) rename src/com/annimon/ownlang/parser/{visitors => optimization}/DeadCodeElimination.java (98%) rename src/com/annimon/ownlang/parser/{visitors => optimization}/ExpressionSimplification.java (97%) rename src/com/annimon/ownlang/parser/{visitors => optimization}/OptimizationVisitor.java (99%) diff --git a/src/com/annimon/ownlang/parser/Optimizer.java b/src/com/annimon/ownlang/parser/Optimizer.java index c753bed..d842c71 100644 --- a/src/com/annimon/ownlang/parser/Optimizer.java +++ b/src/com/annimon/ownlang/parser/Optimizer.java @@ -1,10 +1,10 @@ package com.annimon.ownlang.parser; import com.annimon.ownlang.parser.ast.Statement; -import com.annimon.ownlang.parser.visitors.ConstantFolding; -import com.annimon.ownlang.parser.visitors.ConstantPropagation; -import com.annimon.ownlang.parser.visitors.DeadCodeElimination; -import com.annimon.ownlang.parser.visitors.ExpressionSimplification; +import com.annimon.ownlang.parser.optimization.ConstantFolding; +import com.annimon.ownlang.parser.optimization.ConstantPropagation; +import com.annimon.ownlang.parser.optimization.DeadCodeElimination; +import com.annimon.ownlang.parser.optimization.ExpressionSimplification; public final class Optimizer { diff --git a/src/com/annimon/ownlang/parser/visitors/ConstantFolding.java b/src/com/annimon/ownlang/parser/optimization/ConstantFolding.java similarity index 97% rename from src/com/annimon/ownlang/parser/visitors/ConstantFolding.java rename to src/com/annimon/ownlang/parser/optimization/ConstantFolding.java index 405dec6..6d26ea2 100644 --- a/src/com/annimon/ownlang/parser/visitors/ConstantFolding.java +++ b/src/com/annimon/ownlang/parser/optimization/ConstantFolding.java @@ -1,4 +1,4 @@ -package com.annimon.ownlang.parser.visitors; +package com.annimon.ownlang.parser.optimization; import com.annimon.ownlang.exceptions.OperationIsNotSupportedException; import com.annimon.ownlang.parser.Optimizer; @@ -8,6 +8,7 @@ import com.annimon.ownlang.parser.ast.FunctionDefineStatement; import com.annimon.ownlang.parser.ast.Node; import com.annimon.ownlang.parser.ast.UnaryExpression; import com.annimon.ownlang.parser.ast.ValueExpression; +import com.annimon.ownlang.parser.visitors.VisitorUtils; import java.util.HashSet; import java.util.Set; diff --git a/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java b/src/com/annimon/ownlang/parser/optimization/ConstantPropagation.java similarity index 99% rename from src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java rename to src/com/annimon/ownlang/parser/optimization/ConstantPropagation.java index ca31242..6448d45 100644 --- a/src/com/annimon/ownlang/parser/visitors/ConstantPropagation.java +++ b/src/com/annimon/ownlang/parser/optimization/ConstantPropagation.java @@ -1,4 +1,4 @@ -package com.annimon.ownlang.parser.visitors; +package com.annimon.ownlang.parser.optimization; import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; diff --git a/src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java b/src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java similarity index 98% rename from src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java rename to src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java index f40729e..b1c8ca4 100644 --- a/src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java +++ b/src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java @@ -1,4 +1,4 @@ -package com.annimon.ownlang.parser.visitors; +package com.annimon.ownlang.parser.optimization; import com.annimon.ownlang.parser.Optimizer; import com.annimon.ownlang.parser.ast.ExprStatement; diff --git a/src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java b/src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java similarity index 97% rename from src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java rename to src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java index 67ddfa6..1a41625 100644 --- a/src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java +++ b/src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java @@ -1,4 +1,4 @@ -package com.annimon.ownlang.parser.visitors; +package com.annimon.ownlang.parser.optimization; import com.annimon.ownlang.parser.Optimizer; import com.annimon.ownlang.parser.ast.BinaryExpression; @@ -7,6 +7,7 @@ import com.annimon.ownlang.parser.ast.FunctionDefineStatement; import com.annimon.ownlang.parser.ast.Node; import com.annimon.ownlang.parser.ast.UnaryExpression; import com.annimon.ownlang.parser.ast.ValueExpression; +import com.annimon.ownlang.parser.visitors.VisitorUtils; import static com.annimon.ownlang.parser.visitors.VisitorUtils.isIntegerValue; import static com.annimon.ownlang.parser.visitors.VisitorUtils.isSameVariables; import java.util.HashSet; diff --git a/src/com/annimon/ownlang/parser/visitors/OptimizationVisitor.java b/src/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java similarity index 99% rename from src/com/annimon/ownlang/parser/visitors/OptimizationVisitor.java rename to src/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java index 18efdee..51983c0 100644 --- a/src/com/annimon/ownlang/parser/visitors/OptimizationVisitor.java +++ b/src/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java @@ -1,4 +1,4 @@ -package com.annimon.ownlang.parser.visitors; +package com.annimon.ownlang.parser.optimization; import com.annimon.ownlang.parser.ast.*; import java.util.ArrayList; From 5f10f0befca8dc971f9ed9fbc0ab6ab30520126a Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 26 Jun 2016 11:52:47 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=A0=D0=B5=D1=84=D0=B0=D0=BA=D1=82=D0=BE?= =?UTF-8?q?=D1=80=D0=B8=D0=BD=D0=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/com/annimon/ownlang/parser/Optimizer.java | 37 ++--- .../parser/optimization/ConstantFolding.java | 8 +- .../optimization/ConstantPropagation.java | 138 ++++-------------- .../optimization/DeadCodeElimination.java | 8 +- .../ExpressionSimplification.java | 8 +- .../parser/optimization/Optimizable.java | 12 ++ .../optimization/SummaryOptimization.java | 38 +++++ .../parser/optimization/VariableInfo.java | 13 ++ .../parser/optimization/VariablesGrabber.java | 75 ++++++++++ 9 files changed, 201 insertions(+), 136 deletions(-) create mode 100644 src/com/annimon/ownlang/parser/optimization/Optimizable.java create mode 100644 src/com/annimon/ownlang/parser/optimization/SummaryOptimization.java create mode 100644 src/com/annimon/ownlang/parser/optimization/VariableInfo.java create mode 100644 src/com/annimon/ownlang/parser/optimization/VariablesGrabber.java diff --git a/src/com/annimon/ownlang/parser/Optimizer.java b/src/com/annimon/ownlang/parser/Optimizer.java index d842c71..3fc8580 100644 --- a/src/com/annimon/ownlang/parser/Optimizer.java +++ b/src/com/annimon/ownlang/parser/Optimizer.java @@ -1,40 +1,31 @@ package com.annimon.ownlang.parser; +import com.annimon.ownlang.parser.ast.Node; import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.optimization.ConstantFolding; import com.annimon.ownlang.parser.optimization.ConstantPropagation; import com.annimon.ownlang.parser.optimization.DeadCodeElimination; import com.annimon.ownlang.parser.optimization.ExpressionSimplification; +import com.annimon.ownlang.parser.optimization.Optimizable; +import com.annimon.ownlang.parser.optimization.SummaryOptimization; public final class Optimizer { - public interface Info { - - int optimizationsCount(); - - String summaryInfo(); - } - public static Statement optimize(Statement statement, int level) { if (level == 0) return statement; - - final ConstantFolding constantFolding = new ConstantFolding(); - final ConstantPropagation constantPropagation = new ConstantPropagation(); - final DeadCodeElimination deadCodeElimination = new DeadCodeElimination(); - final ExpressionSimplification expressionSimplification = new ExpressionSimplification(); - Statement result = statement; + final Optimizable optimization = new SummaryOptimization(new Optimizable[] { + new ConstantFolding(), + new ConstantPropagation(), + new DeadCodeElimination(), + new ExpressionSimplification() + }); + + Node result = statement; for (int i = 0; i < level; i++) { - result = (Statement) result.accept(constantFolding, null); - result = (Statement) constantPropagation.visit(result); - result = (Statement) result.accept(deadCodeElimination, null); - result = (Statement) result.accept(expressionSimplification, null); + result = optimization.optimize(result); } - System.out.print(constantFolding.summaryInfo()); - System.out.print(constantPropagation.summaryInfo()); - System.out.print(deadCodeElimination.summaryInfo()); - System.out.print(expressionSimplification.summaryInfo()); - System.out.println(); - return result; + System.out.println(optimization.summaryInfo()); + return (Statement) result; } } diff --git a/src/com/annimon/ownlang/parser/optimization/ConstantFolding.java b/src/com/annimon/ownlang/parser/optimization/ConstantFolding.java index 6d26ea2..c8bad16 100644 --- a/src/com/annimon/ownlang/parser/optimization/ConstantFolding.java +++ b/src/com/annimon/ownlang/parser/optimization/ConstantFolding.java @@ -1,7 +1,6 @@ package com.annimon.ownlang.parser.optimization; import com.annimon.ownlang.exceptions.OperationIsNotSupportedException; -import com.annimon.ownlang.parser.Optimizer; import com.annimon.ownlang.parser.ast.BinaryExpression; import com.annimon.ownlang.parser.ast.ConditionalExpression; import com.annimon.ownlang.parser.ast.FunctionDefineStatement; @@ -15,7 +14,7 @@ import java.util.Set; /** * Performs constant folding optimization. */ -public class ConstantFolding extends OptimizationVisitor implements Optimizer.Info { +public class ConstantFolding extends OptimizationVisitor implements Optimizable { private static final Set OPERATORS = VisitorUtils.operators(); @@ -29,6 +28,11 @@ public class ConstantFolding extends OptimizationVisitor implements Optimi overloadedOperators = new HashSet<>(); } + @Override + public Node optimize(Node node) { + return node.accept(this, null); + } + @Override public int optimizationsCount() { return binaryExpressionFoldingCount diff --git a/src/com/annimon/ownlang/parser/optimization/ConstantPropagation.java b/src/com/annimon/ownlang/parser/optimization/ConstantPropagation.java index 6448d45..f42435c 100644 --- a/src/com/annimon/ownlang/parser/optimization/ConstantPropagation.java +++ b/src/com/annimon/ownlang/parser/optimization/ConstantPropagation.java @@ -2,25 +2,16 @@ package com.annimon.ownlang.parser.optimization; import com.annimon.ownlang.lib.Types; import com.annimon.ownlang.lib.Value; -import com.annimon.ownlang.parser.Optimizer; -import com.annimon.ownlang.parser.ast.Argument; -import com.annimon.ownlang.parser.ast.AssignmentExpression; -import com.annimon.ownlang.parser.ast.DestructuringAssignmentStatement; -import com.annimon.ownlang.parser.ast.FunctionDefineStatement; -import com.annimon.ownlang.parser.ast.MatchExpression; import com.annimon.ownlang.parser.ast.Node; -import com.annimon.ownlang.parser.ast.Statement; import com.annimon.ownlang.parser.ast.ValueExpression; import com.annimon.ownlang.parser.ast.VariableExpression; -import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValue; -import static com.annimon.ownlang.parser.visitors.VisitorUtils.isVariable; import java.util.HashMap; import java.util.Map; /** * Performs constant propagation. */ -public class ConstantPropagation implements Optimizer.Info { +public class ConstantPropagation extends OptimizationVisitor> implements Optimizable { private final Map propagatedVariables; @@ -28,6 +19,28 @@ public class ConstantPropagation implements Optimizer.Info { propagatedVariables = new HashMap<>(); } + @Override + public Node optimize(Node node) { + final Map variables = new HashMap<>(); + // Find variables + node.accept(new VariablesGrabber(), variables); + // Filter only string/number values with 1 modification + final Map candidates = new HashMap<>(); + for (Map.Entry e : variables.entrySet()) { + final VariableInfo info = e.getValue(); + if (info.modifications != 1) continue; + if (info.value == null) continue; + switch (info.value.type()) { + case Types.NUMBER: + case Types.STRING: + candidates.put(e.getKey(), info.value); + break; + } + } + // Replace VariableExpression with ValueExpression + return node.accept(this, candidates); + } + @Override public int optimizationsCount() { return propagatedVariables.size(); @@ -46,105 +59,16 @@ public class ConstantPropagation implements Optimizer.Info { return sb.toString(); } - public Node visit(Statement s) { - final Map variables = new HashMap<>(); - // Find variables - s.accept(new VariablesGrabber(), variables); - // Filter only string/number values with 1 modification - final Map candidates = new HashMap<>(); - for (Map.Entry e : variables.entrySet()) { - final VariableInfo info = e.getValue(); - if (info.modifications != 1) continue; - if (info.value == null) continue; - switch (info.value.type()) { - case Types.NUMBER: - case Types.STRING: - candidates.put(e.getKey(), info.value); - break; - } - } - // Replace VariableExpression with ValueExpression - return s.accept(new VariablesPropagator(), candidates); - } - - private class VariablesGrabber extends OptimizationVisitor> { - - @Override - public Node visit(AssignmentExpression s, Map t) { - if (!isVariable((Node)s.target)) { - return super.visit(s, t); - } - - final String variableName = ((VariableExpression) s.target).name; - final VariableInfo var = variableInfo(t, variableName); - - if (s.operation == null && isValue(s.expression)) { - var.value = ((ValueExpression) s.expression).value; - } - t.put(variableName, var); - return super.visit(s, t); - } - - @Override - public Node visit(DestructuringAssignmentStatement s, Map t) { - for (String variableName : s.variables) { - if (variableName == null) continue; - t.put(variableName, variableInfo(t, variableName)); - } - return super.visit(s, t); - } - - @Override - public Node visit(FunctionDefineStatement s, Map t) { - for (Argument argument : s.arguments) { - final String variableName = argument.getName(); - t.put(variableName, variableInfo(t, variableName)); - } - return super.visit(s, t); - } - - @Override - public Node visit(MatchExpression s, Map t) { - // no visit match expression - return s; - } - - private VariableInfo variableInfo(Map t, final String variableName) { - final VariableInfo var; - if (t.containsKey(variableName)) { - var = t.get(variableName); - var.modifications++; + @Override + public Node visit(VariableExpression s, Map t) { + if (t.containsKey(s.name)) { + if (!propagatedVariables.containsKey(s.name)) { + propagatedVariables.put(s.name, 1); } else { - var = new VariableInfo(); - var.modifications = 1; + propagatedVariables.put(s.name, 1 + propagatedVariables.get(s.name)); } - return var; - } - } - - private class VariablesPropagator extends OptimizationVisitor> { - - @Override - public Node visit(VariableExpression s, Map t) { - if (t.containsKey(s.name)) { - if (!propagatedVariables.containsKey(s.name)) { - propagatedVariables.put(s.name, 1); - } else { - propagatedVariables.put(s.name, 1 + propagatedVariables.get(s.name)); - } - return new ValueExpression(t.get(s.name)); - } - return super.visit(s, t); - } - } - - private static class VariableInfo { - Value value; - int modifications; - - @Override - public String toString() { - return (value == null ? "?" : value) + " (" + modifications + " mods)"; + return new ValueExpression(t.get(s.name)); } + return super.visit(s, t); } } diff --git a/src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java b/src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java index b1c8ca4..97b928e 100644 --- a/src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java +++ b/src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java @@ -1,6 +1,5 @@ package com.annimon.ownlang.parser.optimization; -import com.annimon.ownlang.parser.Optimizer; import com.annimon.ownlang.parser.ast.ExprStatement; import com.annimon.ownlang.parser.ast.IfStatement; import com.annimon.ownlang.parser.ast.Node; @@ -12,12 +11,17 @@ import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValueAsInt; /** * Performs dead code elimination. */ -public class DeadCodeElimination extends OptimizationVisitor implements Optimizer.Info { +public class DeadCodeElimination extends OptimizationVisitor implements Optimizable { private int ifStatementEliminatedCount; private int ternaryExpressionEliminatedCount; private int whileStatementEliminatedCount; + @Override + public Node optimize(Node node) { + return node.accept(this, null); + } + @Override public int optimizationsCount() { return ifStatementEliminatedCount + ternaryExpressionEliminatedCount diff --git a/src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java b/src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java index 1a41625..7e0255e 100644 --- a/src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java +++ b/src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java @@ -1,6 +1,5 @@ package com.annimon.ownlang.parser.optimization; -import com.annimon.ownlang.parser.Optimizer; import com.annimon.ownlang.parser.ast.BinaryExpression; import com.annimon.ownlang.parser.ast.ConditionalExpression; import com.annimon.ownlang.parser.ast.FunctionDefineStatement; @@ -16,7 +15,7 @@ import java.util.Set; /** * Performs expression simplification. */ -public class ExpressionSimplification extends OptimizationVisitor implements Optimizer.Info { +public class ExpressionSimplification extends OptimizationVisitor implements Optimizable { private static final Set OPERATORS = VisitorUtils.operators(); @@ -29,6 +28,11 @@ public class ExpressionSimplification extends OptimizationVisitor implemen overloadedOperators = new HashSet<>(); } + @Override + public Node optimize(Node node) { + return node.accept(this, null); + } + @Override public int optimizationsCount() { return simplificationsCount; diff --git a/src/com/annimon/ownlang/parser/optimization/Optimizable.java b/src/com/annimon/ownlang/parser/optimization/Optimizable.java new file mode 100644 index 0000000..76b552e --- /dev/null +++ b/src/com/annimon/ownlang/parser/optimization/Optimizable.java @@ -0,0 +1,12 @@ +package com.annimon.ownlang.parser.optimization; + +import com.annimon.ownlang.parser.ast.Node; + +public interface Optimizable { + + Node optimize(Node node); + + int optimizationsCount(); + + String summaryInfo(); +} diff --git a/src/com/annimon/ownlang/parser/optimization/SummaryOptimization.java b/src/com/annimon/ownlang/parser/optimization/SummaryOptimization.java new file mode 100644 index 0000000..25f9f0f --- /dev/null +++ b/src/com/annimon/ownlang/parser/optimization/SummaryOptimization.java @@ -0,0 +1,38 @@ +package com.annimon.ownlang.parser.optimization; + +import com.annimon.ownlang.parser.ast.Node; + +public final class SummaryOptimization implements Optimizable { + + private final Optimizable[] optimizations; + + public SummaryOptimization(Optimizable[] optimizations) { + this.optimizations = optimizations; + } + + @Override + public Node optimize(Node node) { + for (Optimizable optimization : optimizations) { + node = optimization.optimize(node); + } + return node; + } + + @Override + public int optimizationsCount() { + int count = 0; + for (Optimizable optimization : optimizations) { + count += optimization.optimizationsCount(); + } + return count; + } + + @Override + public String summaryInfo() { + final StringBuilder sb = new StringBuilder(); + for (Optimizable optimization : optimizations) { + sb.append(optimization.summaryInfo()); + } + return sb.toString(); + } +} diff --git a/src/com/annimon/ownlang/parser/optimization/VariableInfo.java b/src/com/annimon/ownlang/parser/optimization/VariableInfo.java new file mode 100644 index 0000000..665115e --- /dev/null +++ b/src/com/annimon/ownlang/parser/optimization/VariableInfo.java @@ -0,0 +1,13 @@ +package com.annimon.ownlang.parser.optimization; + +import com.annimon.ownlang.lib.Value; + +public final class VariableInfo { + public Value value; + public int modifications; + + @Override + public String toString() { + return (value == null ? "?" : value) + " (" + modifications + " mods)"; + } +} \ No newline at end of file diff --git a/src/com/annimon/ownlang/parser/optimization/VariablesGrabber.java b/src/com/annimon/ownlang/parser/optimization/VariablesGrabber.java new file mode 100644 index 0000000..d46f824 --- /dev/null +++ b/src/com/annimon/ownlang/parser/optimization/VariablesGrabber.java @@ -0,0 +1,75 @@ +package com.annimon.ownlang.parser.optimization; + +import com.annimon.ownlang.parser.ast.Argument; +import com.annimon.ownlang.parser.ast.AssignmentExpression; +import com.annimon.ownlang.parser.ast.DestructuringAssignmentStatement; +import com.annimon.ownlang.parser.ast.FunctionDefineStatement; +import com.annimon.ownlang.parser.ast.MatchExpression; +import com.annimon.ownlang.parser.ast.Node; +import com.annimon.ownlang.parser.ast.ValueExpression; +import com.annimon.ownlang.parser.ast.VariableExpression; +import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValue; +import static com.annimon.ownlang.parser.visitors.VisitorUtils.isVariable; +import java.util.HashMap; +import java.util.Map; + +public class VariablesGrabber extends OptimizationVisitor> { + + public static Map getInfo(Node node) { + Map variableInfos = new HashMap<>(); + node.accept(new VariablesGrabber(), variableInfos); + return variableInfos; + } + + @Override + public Node visit(AssignmentExpression s, Map t) { + if (!isVariable((Node)s.target)) { + return super.visit(s, t); + } + + final String variableName = ((VariableExpression) s.target).name; + final VariableInfo var = variableInfo(t, variableName); + + if (s.operation == null && isValue(s.expression)) { + var.value = ((ValueExpression) s.expression).value; + } + t.put(variableName, var); + return super.visit(s, t); + } + + @Override + public Node visit(DestructuringAssignmentStatement s, Map t) { + for (String variableName : s.variables) { + if (variableName == null) continue; + t.put(variableName, variableInfo(t, variableName)); + } + return super.visit(s, t); + } + + @Override + public Node visit(FunctionDefineStatement s, Map t) { + for (Argument argument : s.arguments) { + final String variableName = argument.getName(); + t.put(variableName, variableInfo(t, variableName)); + } + return super.visit(s, t); + } + + @Override + public Node visit(MatchExpression s, Map t) { + // no visit match expression + return s; + } + + private VariableInfo variableInfo(Map t, final String variableName) { + final VariableInfo var; + if (t.containsKey(variableName)) { + var = t.get(variableName); + var.modifications++; + } else { + var = new VariableInfo(); + var.modifications = 1; + } + return var; + } +} \ No newline at end of file