Skip to content

Commit bca2d85

Browse files
authored
Merge pull request #4 from FxMorin/optimization-pass
2 parents 87a4dc4 + 87a139b commit bca2d85

File tree

15 files changed

+227
-90
lines changed

15 files changed

+227
-90
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.eliotlash.molang;
2+
3+
import com.eliotlash.molang.ast.Expr;
4+
import com.eliotlash.molang.functions.FunctionDefinition;
5+
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
9+
/**
10+
* This holds a list of function that can be compiled without needing a context.
11+
* These functions, if only passed constants, can be compiled ahead of time into a constant.
12+
* <p>
13+
* You are able to add your own functions into this list.
14+
*
15+
* @author FX
16+
*/
17+
public class ConstantFunctions {
18+
19+
private static final List<FunctionDefinition> CONSTANT_FUNCTIONS = new ArrayList<>();
20+
21+
public static boolean isConstant(Expr.Call expr) {
22+
FunctionDefinition functionDefinition = new FunctionDefinition(expr.target(), expr.member());
23+
return isFunctionDefinitionConstant(functionDefinition) && areArgumentsConstant(expr.arguments());
24+
}
25+
26+
public static boolean isFunctionDefinitionConstant(FunctionDefinition functionDefinition) {
27+
return CONSTANT_FUNCTIONS.contains(functionDefinition);
28+
}
29+
30+
public static boolean areArgumentsConstant(List<Expr> arguments) {
31+
for (Expr expr : arguments) {
32+
if (!(expr instanceof Expr.Constant)) {
33+
return false;
34+
}
35+
}
36+
return true;
37+
}
38+
39+
public static void addConstantFunction(FunctionDefinition functionDefinition) {
40+
if (!CONSTANT_FUNCTIONS.contains(functionDefinition)) {
41+
CONSTANT_FUNCTIONS.add(functionDefinition);
42+
}
43+
}
44+
}

src/main/java/com/eliotlash/molang/Parser.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public class Parser {
1717

1818
private final List<Token> input;
1919
private int current = 0;
20-
private CompileConstants constants = new CompileConstants();
20+
private final CompileConstants constants = new CompileConstants();
2121

2222
public Parser(List<Token> input) {
2323
this.input = input;
@@ -97,8 +97,6 @@ private Stmt continueStatement() {
9797
}
9898

9999
private Stmt loopStatement() {
100-
var loop = previous();
101-
102100
consume(OPEN_PAREN, "Expect '(' for loop args.");
103101

104102
List<Expr> arguments = arguments();
@@ -172,8 +170,6 @@ private Expr.Block elseStatement() {
172170
}
173171

174172
private Stmt returnStatement() {
175-
var returnTok = previous();
176-
177173
Expr value = expression();
178174

179175
consume(SEMICOLON, "Expect ';' after return statement.");
@@ -205,7 +201,6 @@ private Expr disjunction() {
205201
var expr = conjunction();
206202

207203
while (match(OR)) {
208-
Token operator = previous();
209204
Expr right = conjunction();
210205
expr = new Expr.BinOp(Operator.OR, expr, right);
211206
}
@@ -216,7 +211,6 @@ private Expr conjunction() {
216211
var expr = equality();
217212

218213
while (match(AND)) {
219-
Token operator = previous();
220214
Expr right = equality();
221215
expr = new Expr.BinOp(Operator.AND, expr, right);
222216
}
@@ -251,7 +245,6 @@ private Expr coalesce() {
251245
var expr = term();
252246

253247
while (match(COALESCE)) {
254-
Token coalesce = previous();
255248
Expr right = term();
256249
expr = new Expr.Coalesce(expr, right);
257250
}

src/main/java/com/eliotlash/molang/ast/ASTTransformation.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.eliotlash.molang.ast;
22

3+
import com.eliotlash.molang.ConstantFunctions;
4+
35
public class ASTTransformation implements Expr.Visitor<Expr>, Stmt.Visitor<Stmt> {
46

57
@Override
@@ -55,7 +57,11 @@ public Expr visitBlock(Expr.Block expr) {
5557

5658
@Override
5759
public Expr visitCall(Expr.Call expr) {
58-
return new Expr.Call((Expr.Variable) visit(expr.target()), expr.member(), expr.arguments().stream().map(this::visit).toList());
60+
Expr.Call call = new Expr.Call((Expr.Variable) visit(expr.target()), expr.member(), expr.arguments().stream().map(this::visit).toList());
61+
if (ConstantFunctions.isConstant(call)) {
62+
return new Expr.Constant(Evaluator.getGlobalEvaluator().visitCall(call));
63+
}
64+
return call;
5965
}
6066

6167
@Override
Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,22 @@
11
package com.eliotlash.molang.ast;
22

33
import java.util.List;
4-
import java.util.Objects;
54

6-
public class Evaluatable {
7-
private Expr expr = null;
8-
private List<Stmt> stmts = null;
9-
private boolean constant = false;
5+
public interface Evaluatable {
106

11-
public Evaluatable(Expr expr) {
12-
this.expr = Objects.requireNonNull(expr);
13-
constant = expr instanceof Expr.Constant;
7+
default boolean isConstant() {
8+
return false;
149
}
1510

16-
public Evaluatable(List<Stmt> stmts) {
17-
this.stmts = Objects.requireNonNull(stmts);
18-
}
19-
20-
public double evaluate(Evaluator evaluator) {
21-
if (stmts != null) {
22-
return evaluator.evaluate(stmts);
23-
}
24-
if (expr != null) {
25-
Double result = evaluator.evaluate(expr);
26-
return result == null ? 0 : result;
27-
}
28-
29-
//should never get here
11+
default double getConstant() {
3012
return 0.0;
3113
}
3214

33-
public boolean isConstant() {
34-
return constant;
15+
static Evaluatable of(Expr expression) {
16+
return new EvaluatableExpr(expression);
3517
}
3618

37-
public double getConstant() {
38-
if(!isConstant()) {
39-
return 0.0;
40-
}
41-
return Evaluator.getGlobalEvaluator().evaluate(expr);
19+
static Evaluatable of(List<Stmt> statements) {
20+
return new EvaluatableStmt(statements);
4221
}
4322
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.eliotlash.molang.ast;
2+
3+
import java.util.Objects;
4+
5+
public class EvaluatableExpr implements Evaluatable {
6+
7+
private final Expr expr;
8+
private final boolean constant;
9+
10+
public EvaluatableExpr(Expr expr) {
11+
this.expr = Objects.requireNonNull(expr);
12+
this.constant = expr instanceof Expr.Constant;
13+
}
14+
15+
public double evaluate(Evaluator evaluator) {
16+
Double result = evaluator.evaluate(this.expr);
17+
return result == null ? 0 : result;
18+
}
19+
20+
public boolean isConstant() {
21+
return this.constant;
22+
}
23+
24+
public double getConstant() {
25+
if(!isConstant()) {
26+
return 0.0;
27+
}
28+
return Evaluator.getGlobalEvaluator().evaluate(this.expr);
29+
}
30+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.eliotlash.molang.ast;
2+
3+
import java.util.List;
4+
import java.util.Objects;
5+
6+
public class EvaluatableStmt implements Evaluatable {
7+
8+
private final List<Stmt> stmts;
9+
10+
public EvaluatableStmt(List<Stmt> stmts) {
11+
this.stmts = Objects.requireNonNull(stmts);
12+
}
13+
14+
public double evaluate(Evaluator evaluator) {
15+
return evaluator.evaluate(this.stmts);
16+
}
17+
}

src/main/java/com/eliotlash/molang/ast/Evaluator.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.eliotlash.molang.ast;
22

3-
import com.eliotlash.molang.ParseException;
43
import com.eliotlash.molang.functions.Function;
54
import com.eliotlash.molang.functions.FunctionDefinition;
65
import com.eliotlash.molang.utils.MolangUtils;
@@ -22,7 +21,7 @@ public class Evaluator implements Expr.Visitor<Double>, Stmt.Visitor<Void> {
2221
globalEvaluator.setExecutionContext(globalContext);
2322
}
2423

25-
private ExecutionContext context = new ExecutionContext(this);
24+
private ExecutionContext context;
2625

2726
public static Evaluator getGlobalEvaluator() {
2827
return globalEvaluator;

src/main/java/com/eliotlash/molang/functions/Function.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import com.eliotlash.molang.variables.ExecutionContext;
55

66
public abstract class Function {
7-
protected String name;
7+
private final String name;
88

99
public Function(String name) {
1010
this.name = name;
@@ -17,6 +17,14 @@ public String getName() {
1717
return this.name;
1818
}
1919

20+
/**
21+
* If all arguments passed are constant,
22+
* will this function always give the same result without the need of a context.
23+
*/
24+
public boolean isConstant() {
25+
return true;
26+
}
27+
2028
/**
2129
* Get minimum count of arguments this function needs
2230
*/

src/main/java/com/eliotlash/molang/functions/utility/DiceRoll.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
import com.eliotlash.molang.functions.Function;
55
import com.eliotlash.molang.variables.ExecutionContext;
66

7-
public class DiceRoll extends Function {
8-
public java.util.Random random;
7+
import java.util.concurrent.ThreadLocalRandom;
98

9+
public class DiceRoll extends Function {
1010

11-
public DiceRoll(String name){
11+
public DiceRoll(String name) {
1212
super(name);
13-
this.random = new java.util.Random();
13+
}
14+
15+
public boolean isConstant() {
16+
return false;
1417
}
1518

1619
@Override
@@ -21,11 +24,13 @@ public int getRequiredArguments() {
2124
public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
2225
double returnValue = 0;
2326
double rollCount = this.evaluateArgument(arguments, ctx, 0);
24-
double min = this.evaluateArgument(arguments, ctx, 1);
25-
double max = this.evaluateArgument(arguments, ctx, 2);
27+
if (rollCount > 0) {
28+
double min = this.evaluateArgument(arguments, ctx, 1);
29+
double max = this.evaluateArgument(arguments, ctx, 2);
2630

27-
for (int i = 0; i < rollCount; i++) {
28-
returnValue += this.random.nextDouble() * (max - min) + min;
31+
for (int i = 0; i < rollCount; i++) {
32+
returnValue += ThreadLocalRandom.current().nextDouble() * (max - min) + min;
33+
}
2934
}
3035

3136
return returnValue;

src/main/java/com/eliotlash/molang/functions/utility/DiceRollInteger.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@
44
import com.eliotlash.molang.functions.Function;
55
import com.eliotlash.molang.variables.ExecutionContext;
66

7-
public class DiceRollInteger extends Function {
8-
public java.util.Random random;
7+
import java.util.concurrent.ThreadLocalRandom;
98

9+
public class DiceRollInteger extends Function {
1010

11-
public DiceRollInteger(String name){
11+
public DiceRollInteger(String name) {
1212
super(name);
13-
this.random = new java.util.Random();
13+
}
14+
15+
public boolean isConstant() {
16+
return false;
1417
}
1518

1619
@Override
@@ -21,11 +24,13 @@ public int getRequiredArguments() {
2124
public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
2225
double returnValue = 0;
2326
double rollCount = this.evaluateArgument(arguments, ctx, 0);
24-
double min = this.evaluateArgument(arguments, ctx, 1);
25-
double max = this.evaluateArgument(arguments, ctx, 2);
27+
if (rollCount > 0) {
28+
double min = this.evaluateArgument(arguments, ctx, 1);
29+
double max = this.evaluateArgument(arguments, ctx, 2);
2630

27-
for (int i = 0; i < rollCount; i++) {
28-
returnValue += Math.round(this.random.nextDouble() * (max - min) + min);
31+
for (int i = 0; i < rollCount; i++) {
32+
returnValue += Math.round(ThreadLocalRandom.current().nextDouble() * (max - min) + min);
33+
}
2934
}
3035

3136
return returnValue;

src/main/java/com/eliotlash/molang/functions/utility/Random.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public Random(String name){
1313
this.random = new java.util.Random();
1414
}
1515

16+
public boolean isConstant() {
17+
return false;
18+
}
19+
1620
public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
1721
double random = 0;
1822

src/main/java/com/eliotlash/molang/functions/utility/RandomInteger.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ public RandomInteger(String name){
1313
this.random = new java.util.Random();
1414
}
1515

16+
public boolean isConstant() {
17+
return false;
18+
}
19+
1620
public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
1721
double random = 0;
1822

0 commit comments

Comments
 (0)