From 5f10f0befca8dc971f9ed9fbc0ab6ab30520126a Mon Sep 17 00:00:00 2001 From: Victor Date: Sun, 26 Jun 2016 11:52:47 +0300 Subject: [PATCH] =?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