Skip to content

Commit 46349bd

Browse files
committed
Merge optimizations-package into latest
2 parents 357813e + 5f10f0b commit 46349bd

12 files changed

+270
-207
lines changed
Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,31 @@
11
package com.annimon.ownlang.parser;
22

3+
import com.annimon.ownlang.parser.ast.Node;
34
import com.annimon.ownlang.parser.ast.Statement;
4-
import com.annimon.ownlang.parser.visitors.ConstantFolding;
5-
import com.annimon.ownlang.parser.visitors.ConstantPropagation;
6-
import com.annimon.ownlang.parser.visitors.DeadCodeElimination;
7-
import com.annimon.ownlang.parser.visitors.ExpressionSimplification;
5+
import com.annimon.ownlang.parser.optimization.ConstantFolding;
6+
import com.annimon.ownlang.parser.optimization.ConstantPropagation;
7+
import com.annimon.ownlang.parser.optimization.DeadCodeElimination;
8+
import com.annimon.ownlang.parser.optimization.ExpressionSimplification;
9+
import com.annimon.ownlang.parser.optimization.Optimizable;
10+
import com.annimon.ownlang.parser.optimization.SummaryOptimization;
811

912
public final class Optimizer {
1013

11-
public interface Info {
12-
13-
int optimizationsCount();
14-
15-
String summaryInfo();
16-
}
17-
1814
public static Statement optimize(Statement statement, int level) {
1915
if (level == 0) return statement;
20-
21-
final ConstantFolding constantFolding = new ConstantFolding();
22-
final ConstantPropagation constantPropagation = new ConstantPropagation();
23-
final DeadCodeElimination deadCodeElimination = new DeadCodeElimination();
24-
final ExpressionSimplification expressionSimplification = new ExpressionSimplification();
2516

26-
Statement result = statement;
17+
final Optimizable optimization = new SummaryOptimization(new Optimizable[] {
18+
new ConstantFolding(),
19+
new ConstantPropagation(),
20+
new DeadCodeElimination(),
21+
new ExpressionSimplification()
22+
});
23+
24+
Node result = statement;
2725
for (int i = 0; i < level; i++) {
28-
result = (Statement) result.accept(constantFolding, null);
29-
result = (Statement) constantPropagation.visit(result);
30-
result = (Statement) result.accept(deadCodeElimination, null);
31-
result = (Statement) result.accept(expressionSimplification, null);
26+
result = optimization.optimize(result);
3227
}
33-
System.out.print(constantFolding.summaryInfo());
34-
System.out.print(constantPropagation.summaryInfo());
35-
System.out.print(deadCodeElimination.summaryInfo());
36-
System.out.print(expressionSimplification.summaryInfo());
37-
System.out.println();
38-
return result;
28+
System.out.println(optimization.summaryInfo());
29+
return (Statement) result;
3930
}
4031
}

src/com/annimon/ownlang/parser/visitors/ConstantFolding.java renamed to src/com/annimon/ownlang/parser/optimization/ConstantFolding.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
package com.annimon.ownlang.parser.visitors;
1+
package com.annimon.ownlang.parser.optimization;
22

33
import com.annimon.ownlang.exceptions.OperationIsNotSupportedException;
4-
import com.annimon.ownlang.parser.Optimizer;
54
import com.annimon.ownlang.parser.ast.BinaryExpression;
65
import com.annimon.ownlang.parser.ast.ConditionalExpression;
76
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
87
import com.annimon.ownlang.parser.ast.Node;
98
import com.annimon.ownlang.parser.ast.UnaryExpression;
109
import com.annimon.ownlang.parser.ast.ValueExpression;
10+
import com.annimon.ownlang.parser.visitors.VisitorUtils;
1111
import java.util.HashSet;
1212
import java.util.Set;
1313

1414
/**
1515
* Performs constant folding optimization.
1616
*/
17-
public class ConstantFolding extends OptimizationVisitor<Void> implements Optimizer.Info {
17+
public class ConstantFolding extends OptimizationVisitor<Void> implements Optimizable {
1818

1919
private static final Set<String> OPERATORS = VisitorUtils.operators();
2020

@@ -28,6 +28,11 @@ public ConstantFolding() {
2828
overloadedOperators = new HashSet<>();
2929
}
3030

31+
@Override
32+
public Node optimize(Node node) {
33+
return node.accept(this, null);
34+
}
35+
3136
@Override
3237
public int optimizationsCount() {
3338
return binaryExpressionFoldingCount
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.annimon.ownlang.parser.optimization;
2+
3+
import com.annimon.ownlang.lib.Types;
4+
import com.annimon.ownlang.lib.Value;
5+
import com.annimon.ownlang.parser.ast.Node;
6+
import com.annimon.ownlang.parser.ast.ValueExpression;
7+
import com.annimon.ownlang.parser.ast.VariableExpression;
8+
import java.util.HashMap;
9+
import java.util.Map;
10+
11+
/**
12+
* Performs constant propagation.
13+
*/
14+
public class ConstantPropagation extends OptimizationVisitor<Map<String, Value>> implements Optimizable {
15+
16+
private final Map<String, Integer> propagatedVariables;
17+
18+
public ConstantPropagation() {
19+
propagatedVariables = new HashMap<>();
20+
}
21+
22+
@Override
23+
public Node optimize(Node node) {
24+
final Map<String, VariableInfo> variables = new HashMap<>();
25+
// Find variables
26+
node.accept(new VariablesGrabber(), variables);
27+
// Filter only string/number values with 1 modification
28+
final Map<String, Value> candidates = new HashMap<>();
29+
for (Map.Entry<String, VariableInfo> e : variables.entrySet()) {
30+
final VariableInfo info = e.getValue();
31+
if (info.modifications != 1) continue;
32+
if (info.value == null) continue;
33+
switch (info.value.type()) {
34+
case Types.NUMBER:
35+
case Types.STRING:
36+
candidates.put(e.getKey(), info.value);
37+
break;
38+
}
39+
}
40+
// Replace VariableExpression with ValueExpression
41+
return node.accept(this, candidates);
42+
}
43+
44+
@Override
45+
public int optimizationsCount() {
46+
return propagatedVariables.size();
47+
}
48+
49+
@Override
50+
public String summaryInfo() {
51+
if (optimizationsCount() == 0) return "";
52+
final StringBuilder sb = new StringBuilder();
53+
if (propagatedVariables.size() > 0) {
54+
sb.append("\nConstant propagations: ").append(propagatedVariables.size());
55+
for (Map.Entry<String, Integer> e : propagatedVariables.entrySet()) {
56+
sb.append("\n ").append(e.getKey()).append(": ").append(e.getValue());
57+
}
58+
}
59+
return sb.toString();
60+
}
61+
62+
@Override
63+
public Node visit(VariableExpression s, Map<String, Value> t) {
64+
if (t.containsKey(s.name)) {
65+
if (!propagatedVariables.containsKey(s.name)) {
66+
propagatedVariables.put(s.name, 1);
67+
} else {
68+
propagatedVariables.put(s.name, 1 + propagatedVariables.get(s.name));
69+
}
70+
return new ValueExpression(t.get(s.name));
71+
}
72+
return super.visit(s, t);
73+
}
74+
}

src/com/annimon/ownlang/parser/visitors/DeadCodeElimination.java renamed to src/com/annimon/ownlang/parser/optimization/DeadCodeElimination.java

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,27 @@
1-
package com.annimon.ownlang.parser.visitors;
1+
package com.annimon.ownlang.parser.optimization;
22

3-
import com.annimon.ownlang.parser.Optimizer;
43
import com.annimon.ownlang.parser.ast.ExprStatement;
54
import com.annimon.ownlang.parser.ast.IfStatement;
65
import com.annimon.ownlang.parser.ast.Node;
76
import com.annimon.ownlang.parser.ast.TernaryExpression;
8-
import com.annimon.ownlang.parser.ast.ValueExpression;
97
import com.annimon.ownlang.parser.ast.WhileStatement;
8+
import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValue;
9+
import static com.annimon.ownlang.parser.visitors.VisitorUtils.isValueAsInt;
1010

1111
/**
1212
* Performs dead code elimination.
1313
*/
14-
public class DeadCodeElimination extends OptimizationVisitor<Void> implements Optimizer.Info {
14+
public class DeadCodeElimination extends OptimizationVisitor<Void> implements Optimizable {
1515

1616
private int ifStatementEliminatedCount;
1717
private int ternaryExpressionEliminatedCount;
1818
private int whileStatementEliminatedCount;
1919

20+
@Override
21+
public Node optimize(Node node) {
22+
return node.accept(this, null);
23+
}
24+
2025
@Override
2126
public int optimizationsCount() {
2227
return ifStatementEliminatedCount + ternaryExpressionEliminatedCount
@@ -41,7 +46,7 @@ public String summaryInfo() {
4146

4247
@Override
4348
public Node visit(IfStatement s, Void t) {
44-
if (s.expression instanceof ValueExpression) {
49+
if (isValue(s.expression)) {
4550
ifStatementEliminatedCount++;
4651
// true statement
4752
if (s.expression.eval().asInt() != 0) {
@@ -58,7 +63,7 @@ public Node visit(IfStatement s, Void t) {
5863

5964
@Override
6065
public Node visit(TernaryExpression s, Void t) {
61-
if (s.condition instanceof ValueExpression) {
66+
if (isValue(s.condition)) {
6267
ternaryExpressionEliminatedCount++;
6368
if (s.condition.eval().asInt() != 0) {
6469
return s.trueExpr;
@@ -70,11 +75,9 @@ public Node visit(TernaryExpression s, Void t) {
7075

7176
@Override
7277
public Node visit(WhileStatement s, Void t) {
73-
if (s.condition instanceof ValueExpression) {
74-
if (s.condition.eval().asInt() == 0) {
75-
whileStatementEliminatedCount++;
76-
return new ExprStatement(s.condition);
77-
}
78+
if (isValueAsInt(s.condition, 0)) {
79+
whileStatementEliminatedCount++;
80+
return new ExprStatement(s.condition);
7881
}
7982
return super.visit(s, t);
8083
}

src/com/annimon/ownlang/parser/visitors/ExpressionSimplification.java renamed to src/com/annimon/ownlang/parser/optimization/ExpressionSimplification.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
package com.annimon.ownlang.parser.visitors;
1+
package com.annimon.ownlang.parser.optimization;
22

3-
import com.annimon.ownlang.parser.Optimizer;
43
import com.annimon.ownlang.parser.ast.BinaryExpression;
54
import com.annimon.ownlang.parser.ast.ConditionalExpression;
65
import com.annimon.ownlang.parser.ast.FunctionDefineStatement;
76
import com.annimon.ownlang.parser.ast.Node;
87
import com.annimon.ownlang.parser.ast.UnaryExpression;
98
import com.annimon.ownlang.parser.ast.ValueExpression;
9+
import com.annimon.ownlang.parser.visitors.VisitorUtils;
1010
import static com.annimon.ownlang.parser.visitors.VisitorUtils.isIntegerValue;
1111
import static com.annimon.ownlang.parser.visitors.VisitorUtils.isSameVariables;
1212
import java.util.HashSet;
@@ -15,7 +15,7 @@
1515
/**
1616
* Performs expression simplification.
1717
*/
18-
public class ExpressionSimplification extends OptimizationVisitor<Void> implements Optimizer.Info {
18+
public class ExpressionSimplification extends OptimizationVisitor<Void> implements Optimizable {
1919

2020
private static final Set<String> OPERATORS = VisitorUtils.operators();
2121

@@ -28,6 +28,11 @@ public ExpressionSimplification() {
2828
overloadedOperators = new HashSet<>();
2929
}
3030

31+
@Override
32+
public Node optimize(Node node) {
33+
return node.accept(this, null);
34+
}
35+
3136
@Override
3237
public int optimizationsCount() {
3338
return simplificationsCount;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.annimon.ownlang.parser.optimization;
2+
3+
import com.annimon.ownlang.parser.ast.Node;
4+
5+
public interface Optimizable {
6+
7+
Node optimize(Node node);
8+
9+
int optimizationsCount();
10+
11+
String summaryInfo();
12+
}

src/com/annimon/ownlang/parser/visitors/OptimizationVisitor.java renamed to src/com/annimon/ownlang/parser/optimization/OptimizationVisitor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.annimon.ownlang.parser.visitors;
1+
package com.annimon.ownlang.parser.optimization;
22

33
import com.annimon.ownlang.parser.ast.*;
44
import java.util.ArrayList;
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.annimon.ownlang.parser.optimization;
2+
3+
import com.annimon.ownlang.parser.ast.Node;
4+
5+
public final class SummaryOptimization implements Optimizable {
6+
7+
private final Optimizable[] optimizations;
8+
9+
public SummaryOptimization(Optimizable[] optimizations) {
10+
this.optimizations = optimizations;
11+
}
12+
13+
@Override
14+
public Node optimize(Node node) {
15+
for (Optimizable optimization : optimizations) {
16+
node = optimization.optimize(node);
17+
}
18+
return node;
19+
}
20+
21+
@Override
22+
public int optimizationsCount() {
23+
int count = 0;
24+
for (Optimizable optimization : optimizations) {
25+
count += optimization.optimizationsCount();
26+
}
27+
return count;
28+
}
29+
30+
@Override
31+
public String summaryInfo() {
32+
final StringBuilder sb = new StringBuilder();
33+
for (Optimizable optimization : optimizations) {
34+
sb.append(optimization.summaryInfo());
35+
}
36+
return sb.toString();
37+
}
38+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.annimon.ownlang.parser.optimization;
2+
3+
import com.annimon.ownlang.lib.Value;
4+
5+
public final class VariableInfo {
6+
public Value value;
7+
public int modifications;
8+
9+
@Override
10+
public String toString() {
11+
return (value == null ? "?" : value) + " (" + modifications + " mods)";
12+
}
13+
}

0 commit comments

Comments
 (0)