mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Рефакторинг
This commit is contained in:
parent
08b12ff785
commit
5f10f0befc
@ -1,40 +1,31 @@
|
|||||||
package com.annimon.ownlang.parser;
|
package com.annimon.ownlang.parser;
|
||||||
|
|
||||||
|
import com.annimon.ownlang.parser.ast.Node;
|
||||||
import com.annimon.ownlang.parser.ast.Statement;
|
import com.annimon.ownlang.parser.ast.Statement;
|
||||||
import com.annimon.ownlang.parser.optimization.ConstantFolding;
|
import com.annimon.ownlang.parser.optimization.ConstantFolding;
|
||||||
import com.annimon.ownlang.parser.optimization.ConstantPropagation;
|
import com.annimon.ownlang.parser.optimization.ConstantPropagation;
|
||||||
import com.annimon.ownlang.parser.optimization.DeadCodeElimination;
|
import com.annimon.ownlang.parser.optimization.DeadCodeElimination;
|
||||||
import com.annimon.ownlang.parser.optimization.ExpressionSimplification;
|
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 final class Optimizer {
|
||||||
|
|
||||||
public interface Info {
|
|
||||||
|
|
||||||
int optimizationsCount();
|
|
||||||
|
|
||||||
String summaryInfo();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Statement optimize(Statement statement, int level) {
|
public static Statement optimize(Statement statement, int level) {
|
||||||
if (level == 0) return statement;
|
if (level == 0) return statement;
|
||||||
|
|
||||||
final ConstantFolding constantFolding = new ConstantFolding();
|
final Optimizable optimization = new SummaryOptimization(new Optimizable[] {
|
||||||
final ConstantPropagation constantPropagation = new ConstantPropagation();
|
new ConstantFolding(),
|
||||||
final DeadCodeElimination deadCodeElimination = new DeadCodeElimination();
|
new ConstantPropagation(),
|
||||||
final ExpressionSimplification expressionSimplification = new ExpressionSimplification();
|
new DeadCodeElimination(),
|
||||||
|
new ExpressionSimplification()
|
||||||
|
});
|
||||||
|
|
||||||
Statement result = statement;
|
Node result = statement;
|
||||||
for (int i = 0; i < level; i++) {
|
for (int i = 0; i < level; i++) {
|
||||||
result = (Statement) result.accept(constantFolding, null);
|
result = optimization.optimize(result);
|
||||||
result = (Statement) constantPropagation.visit(result);
|
|
||||||
result = (Statement) result.accept(deadCodeElimination, null);
|
|
||||||
result = (Statement) result.accept(expressionSimplification, null);
|
|
||||||
}
|
}
|
||||||
System.out.print(constantFolding.summaryInfo());
|
System.out.println(optimization.summaryInfo());
|
||||||
System.out.print(constantPropagation.summaryInfo());
|
return (Statement) result;
|
||||||
System.out.print(deadCodeElimination.summaryInfo());
|
|
||||||
System.out.print(expressionSimplification.summaryInfo());
|
|
||||||
System.out.println();
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.annimon.ownlang.parser.optimization;
|
package com.annimon.ownlang.parser.optimization;
|
||||||
|
|
||||||
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
|
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.BinaryExpression;
|
||||||
import com.annimon.ownlang.parser.ast.ConditionalExpression;
|
import com.annimon.ownlang.parser.ast.ConditionalExpression;
|
||||||
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
|
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
|
||||||
@ -15,7 +14,7 @@ import java.util.Set;
|
|||||||
/**
|
/**
|
||||||
* Performs constant folding optimization.
|
* 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();
|
private static final Set<String> OPERATORS = VisitorUtils.operators();
|
||||||
|
|
||||||
@ -29,6 +28,11 @@ public class ConstantFolding extends OptimizationVisitor<Void> implements Optimi
|
|||||||
overloadedOperators = new HashSet<>();
|
overloadedOperators = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node optimize(Node node) {
|
||||||
|
return node.accept(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int optimizationsCount() {
|
public int optimizationsCount() {
|
||||||
return binaryExpressionFoldingCount
|
return binaryExpressionFoldingCount
|
||||||
|
@ -2,25 +2,16 @@ package com.annimon.ownlang.parser.optimization;
|
|||||||
|
|
||||||
import com.annimon.ownlang.lib.Types;
|
import com.annimon.ownlang.lib.Types;
|
||||||
import com.annimon.ownlang.lib.Value;
|
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.Node;
|
||||||
import com.annimon.ownlang.parser.ast.Statement;
|
|
||||||
import com.annimon.ownlang.parser.ast.ValueExpression;
|
import com.annimon.ownlang.parser.ast.ValueExpression;
|
||||||
import com.annimon.ownlang.parser.ast.VariableExpression;
|
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.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs constant propagation.
|
* 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;
|
private final Map<String, Integer> propagatedVariables;
|
||||||
|
|
||||||
@ -28,6 +19,28 @@ public class ConstantPropagation implements Optimizer.Info {
|
|||||||
propagatedVariables = new HashMap<>();
|
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
|
@Override
|
||||||
public int optimizationsCount() {
|
public int optimizationsCount() {
|
||||||
return propagatedVariables.size();
|
return propagatedVariables.size();
|
||||||
@ -46,84 +59,6 @@ public class ConstantPropagation implements Optimizer.Info {
|
|||||||
return sb.toString();
|
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
|
@Override
|
||||||
public Node visit(VariableExpression s, Map<String, Value> t) {
|
public Node visit(VariableExpression s, Map<String, Value> t) {
|
||||||
if (t.containsKey(s.name)) {
|
if (t.containsKey(s.name)) {
|
||||||
@ -137,14 +72,3 @@ public class ConstantPropagation implements Optimizer.Info {
|
|||||||
return super.visit(s, t);
|
return super.visit(s, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class VariableInfo {
|
|
||||||
Value value;
|
|
||||||
int modifications;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return (value == null ? "?" : value) + " (" + modifications + " mods)";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.annimon.ownlang.parser.optimization;
|
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.ExprStatement;
|
||||||
import com.annimon.ownlang.parser.ast.IfStatement;
|
import com.annimon.ownlang.parser.ast.IfStatement;
|
||||||
import com.annimon.ownlang.parser.ast.Node;
|
import com.annimon.ownlang.parser.ast.Node;
|
||||||
@ -12,12 +11,17 @@ import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValueAsInt;
|
|||||||
/**
|
/**
|
||||||
* Performs dead code elimination.
|
* 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 ifStatementEliminatedCount;
|
||||||
private int ternaryExpressionEliminatedCount;
|
private int ternaryExpressionEliminatedCount;
|
||||||
private int whileStatementEliminatedCount;
|
private int whileStatementEliminatedCount;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node optimize(Node node) {
|
||||||
|
return node.accept(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int optimizationsCount() {
|
public int optimizationsCount() {
|
||||||
return ifStatementEliminatedCount + ternaryExpressionEliminatedCount
|
return ifStatementEliminatedCount + ternaryExpressionEliminatedCount
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package com.annimon.ownlang.parser.optimization;
|
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.BinaryExpression;
|
||||||
import com.annimon.ownlang.parser.ast.ConditionalExpression;
|
import com.annimon.ownlang.parser.ast.ConditionalExpression;
|
||||||
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
|
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
|
||||||
@ -16,7 +15,7 @@ import java.util.Set;
|
|||||||
/**
|
/**
|
||||||
* Performs expression simplification.
|
* 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();
|
private static final Set<String> OPERATORS = VisitorUtils.operators();
|
||||||
|
|
||||||
@ -29,6 +28,11 @@ public class ExpressionSimplification extends OptimizationVisitor<Void> implemen
|
|||||||
overloadedOperators = new HashSet<>();
|
overloadedOperators = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Node optimize(Node node) {
|
||||||
|
return node.accept(this, null);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int optimizationsCount() {
|
public int optimizationsCount() {
|
||||||
return simplificationsCount;
|
return simplificationsCount;
|
||||||
|
12
src/com/annimon/ownlang/parser/optimization/Optimizable.java
Normal file
12
src/com/annimon/ownlang/parser/optimization/Optimizable.java
Normal 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();
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
@ -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)";
|
||||||
|
}
|
||||||
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user