Рефакторинг

This commit is contained in:
Victor 2016-06-26 11:52:47 +03:00
parent 08b12ff785
commit 5f10f0befc
9 changed files with 201 additions and 136 deletions

View File

@ -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();
final Optimizable optimization = new SummaryOptimization(new Optimizable[] {
new ConstantFolding(),
new ConstantPropagation(),
new DeadCodeElimination(),
new ExpressionSimplification()
});
Statement result = statement;
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;
}
}

View File

@ -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<Void> implements Optimizer.Info {
public class ConstantFolding extends OptimizationVisitor<Void> implements Optimizable {
private static final Set<String> OPERATORS = VisitorUtils.operators();
@ -29,6 +28,11 @@ public class ConstantFolding extends OptimizationVisitor<Void> implements Optimi
overloadedOperators = new HashSet<>();
}
@Override
public Node optimize(Node node) {
return node.accept(this, null);
}
@Override
public int optimizationsCount() {
return binaryExpressionFoldingCount

View File

@ -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<Map<String, Value>> implements Optimizable {
private final Map<String, Integer> propagatedVariables;
@ -28,6 +19,28 @@ public class ConstantPropagation implements Optimizer.Info {
propagatedVariables = new HashMap<>();
}
@Override
public Node optimize(Node node) {
final Map<String, VariableInfo> variables = new HashMap<>();
// Find variables
node.accept(new VariablesGrabber(), variables);
// Filter only string/number values with 1 modification
final Map<String, Value> candidates = new HashMap<>();
for (Map.Entry<String, VariableInfo> 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,84 +59,6 @@ public class ConstantPropagation implements Optimizer.Info {
return sb.toString();
}
public Node visit(Statement s) {
final Map<String, VariableInfo> variables = new HashMap<>();
// Find variables
s.accept(new VariablesGrabber(), variables);
// Filter only string/number values with 1 modification
final Map<String, Value> candidates = new HashMap<>();
for (Map.Entry<String, VariableInfo> 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<Map<String, VariableInfo>> {
@Override
public Node visit(AssignmentExpression s, Map<String, VariableInfo> 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<String, VariableInfo> 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<String, VariableInfo> 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<String, VariableInfo> t) {
// no visit match expression
return s;
}
private VariableInfo variableInfo(Map<String, VariableInfo> 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<Map<String, Value>> {
@Override
public Node visit(VariableExpression s, Map<String, Value> t) {
if (t.containsKey(s.name)) {
@ -137,14 +72,3 @@ public class ConstantPropagation implements Optimizer.Info {
return super.visit(s, t);
}
}
private static class VariableInfo {
Value value;
int modifications;
@Override
public String toString() {
return (value == null ? "?" : value) + " (" + modifications + " mods)";
}
}
}

View File

@ -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<Void> implements Optimizer.Info {
public class DeadCodeElimination extends OptimizationVisitor<Void> 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

View File

@ -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<Void> implements Optimizer.Info {
public class ExpressionSimplification extends OptimizationVisitor<Void> implements Optimizable {
private static final Set<String> OPERATORS = VisitorUtils.operators();
@ -29,6 +28,11 @@ public class ExpressionSimplification extends OptimizationVisitor<Void> implemen
overloadedOperators = new HashSet<>();
}
@Override
public Node optimize(Node node) {
return node.accept(this, null);
}
@Override
public int optimizationsCount() {
return simplificationsCount;

View File

@ -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();
}

View File

@ -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();
}
}

View File

@ -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)";
}
}

View File

@ -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<Map<String, VariableInfo>> {
public static Map<String, VariableInfo> getInfo(Node node) {
Map<String, VariableInfo> variableInfos = new HashMap<>();
node.accept(new VariablesGrabber(), variableInfos);
return variableInfos;
}
@Override
public Node visit(AssignmentExpression s, Map<String, VariableInfo> 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<String, VariableInfo> 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<String, VariableInfo> 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<String, VariableInfo> t) {
// no visit match expression
return s;
}
private VariableInfo variableInfo(Map<String, VariableInfo> 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;
}
}