mirror of
https://github.com/aNNiMON/Own-Programming-Language-Tutorial.git
synced 2024-09-20 08:44:20 +03:00
Merge optimizations-package into latest
This commit is contained in:
commit
46349bdd36
@ -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.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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,20 @@
|
||||
package com.annimon.ownlang.parser.visitors;
|
||||
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;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
@ -28,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
|
@ -0,0 +1,74 @@
|
||||
package com.annimon.ownlang.parser.optimization;
|
||||
|
||||
import com.annimon.ownlang.lib.Types;
|
||||
import com.annimon.ownlang.lib.Value;
|
||||
import com.annimon.ownlang.parser.ast.Node;
|
||||
import com.annimon.ownlang.parser.ast.ValueExpression;
|
||||
import com.annimon.ownlang.parser.ast.VariableExpression;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Performs constant propagation.
|
||||
*/
|
||||
public class ConstantPropagation extends OptimizationVisitor<Map<String, Value>> implements Optimizable {
|
||||
|
||||
private final Map<String, Integer> propagatedVariables;
|
||||
|
||||
public ConstantPropagation() {
|
||||
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();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String summaryInfo() {
|
||||
if (optimizationsCount() == 0) return "";
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (propagatedVariables.size() > 0) {
|
||||
sb.append("\nConstant propagations: ").append(propagatedVariables.size());
|
||||
for (Map.Entry<String, Integer> e : propagatedVariables.entrySet()) {
|
||||
sb.append("\n ").append(e.getKey()).append(": ").append(e.getValue());
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(VariableExpression s, Map<String, Value> 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);
|
||||
}
|
||||
}
|
@ -1,22 +1,27 @@
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
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
|
||||
@ -41,7 +46,7 @@ public class DeadCodeElimination extends OptimizationVisitor<Void> 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 +63,7 @@ public class DeadCodeElimination extends OptimizationVisitor<Void> 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 +75,9 @@ public class DeadCodeElimination extends OptimizationVisitor<Void> 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);
|
||||
}
|
@ -1,12 +1,12 @@
|
||||
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;
|
||||
import com.annimon.ownlang.parser.ast.ConditionalExpression;
|
||||
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;
|
||||
@ -15,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();
|
||||
|
||||
@ -28,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;
|
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();
|
||||
}
|
@ -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;
|
@ -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;
|
||||
}
|
||||
}
|
@ -1,162 +0,0 @@
|
||||
package com.annimon.ownlang.parser.visitors;
|
||||
|
||||
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 {
|
||||
|
||||
private final Map<String, Integer> propagatedVariables;
|
||||
|
||||
public ConstantPropagation() {
|
||||
propagatedVariables = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int optimizationsCount() {
|
||||
return propagatedVariables.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String summaryInfo() {
|
||||
if (optimizationsCount() == 0) return "";
|
||||
final StringBuilder sb = new StringBuilder();
|
||||
if (propagatedVariables.size() > 0) {
|
||||
sb.append("\nConstant propagations: ").append(propagatedVariables.size());
|
||||
for (Map.Entry<String, Integer> e : propagatedVariables.entrySet()) {
|
||||
sb.append("\n ").append(e.getKey()).append(": ").append(e.getValue());
|
||||
}
|
||||
}
|
||||
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;
|
||||
if (t.containsKey(variableName)) {
|
||||
var = t.get(variableName);
|
||||
var.modifications++;
|
||||
} else {
|
||||
var = new VariableInfo();
|
||||
var.modifications = 1;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
final VariableInfo var;
|
||||
if (t.containsKey(variableName)) {
|
||||
var = t.get(variableName);
|
||||
var.modifications++;
|
||||
} else {
|
||||
var = new VariableInfo();
|
||||
var.modifications = 1;
|
||||
}
|
||||
t.put(variableName, var);
|
||||
}
|
||||
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();
|
||||
final VariableInfo var;
|
||||
if (t.containsKey(variableName)) {
|
||||
var = t.get(variableName);
|
||||
var.modifications++;
|
||||
} else {
|
||||
var = new VariableInfo();
|
||||
var.modifications = 1;
|
||||
}
|
||||
t.put(variableName, var);
|
||||
}
|
||||
return super.visit(s, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node visit(MatchExpression s, Map<String, VariableInfo> t) {
|
||||
// no visit match expression
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
private class VariablesPropagator extends OptimizationVisitor<Map<String, Value>> {
|
||||
|
||||
@Override
|
||||
public Node visit(VariableExpression s, Map<String, Value> 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)";
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user