Skip to content

Commit

Permalink
Merge pull request #4 from FxMorin/optimization-pass
Browse files Browse the repository at this point in the history
  • Loading branch information
bernie-g authored Dec 18, 2023
2 parents 87a4dc4 + 87a139b commit bca2d85
Show file tree
Hide file tree
Showing 15 changed files with 227 additions and 90 deletions.
44 changes: 44 additions & 0 deletions src/main/java/com/eliotlash/molang/ConstantFunctions.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.eliotlash.molang;

import com.eliotlash.molang.ast.Expr;
import com.eliotlash.molang.functions.FunctionDefinition;

import java.util.ArrayList;
import java.util.List;

/**
* This holds a list of function that can be compiled without needing a context.
* These functions, if only passed constants, can be compiled ahead of time into a constant.
* <p>
* You are able to add your own functions into this list.
*
* @author FX
*/
public class ConstantFunctions {

private static final List<FunctionDefinition> CONSTANT_FUNCTIONS = new ArrayList<>();

public static boolean isConstant(Expr.Call expr) {
FunctionDefinition functionDefinition = new FunctionDefinition(expr.target(), expr.member());
return isFunctionDefinitionConstant(functionDefinition) && areArgumentsConstant(expr.arguments());
}

public static boolean isFunctionDefinitionConstant(FunctionDefinition functionDefinition) {
return CONSTANT_FUNCTIONS.contains(functionDefinition);
}

public static boolean areArgumentsConstant(List<Expr> arguments) {
for (Expr expr : arguments) {
if (!(expr instanceof Expr.Constant)) {
return false;
}
}
return true;
}

public static void addConstantFunction(FunctionDefinition functionDefinition) {
if (!CONSTANT_FUNCTIONS.contains(functionDefinition)) {
CONSTANT_FUNCTIONS.add(functionDefinition);
}
}
}
9 changes: 1 addition & 8 deletions src/main/java/com/eliotlash/molang/Parser.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class Parser {

private final List<Token> input;
private int current = 0;
private CompileConstants constants = new CompileConstants();
private final CompileConstants constants = new CompileConstants();

public Parser(List<Token> input) {
this.input = input;
Expand Down Expand Up @@ -97,8 +97,6 @@ private Stmt continueStatement() {
}

private Stmt loopStatement() {
var loop = previous();

consume(OPEN_PAREN, "Expect '(' for loop args.");

List<Expr> arguments = arguments();
Expand Down Expand Up @@ -172,8 +170,6 @@ private Expr.Block elseStatement() {
}

private Stmt returnStatement() {
var returnTok = previous();

Expr value = expression();

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

while (match(OR)) {
Token operator = previous();
Expr right = conjunction();
expr = new Expr.BinOp(Operator.OR, expr, right);
}
Expand All @@ -216,7 +211,6 @@ private Expr conjunction() {
var expr = equality();

while (match(AND)) {
Token operator = previous();
Expr right = equality();
expr = new Expr.BinOp(Operator.AND, expr, right);
}
Expand Down Expand Up @@ -251,7 +245,6 @@ private Expr coalesce() {
var expr = term();

while (match(COALESCE)) {
Token coalesce = previous();
Expr right = term();
expr = new Expr.Coalesce(expr, right);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.eliotlash.molang.ast;

import com.eliotlash.molang.ConstantFunctions;

public class ASTTransformation implements Expr.Visitor<Expr>, Stmt.Visitor<Stmt> {

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

@Override
public Expr visitCall(Expr.Call expr) {
return new Expr.Call((Expr.Variable) visit(expr.target()), expr.member(), expr.arguments().stream().map(this::visit).toList());
Expr.Call call = new Expr.Call((Expr.Variable) visit(expr.target()), expr.member(), expr.arguments().stream().map(this::visit).toList());
if (ConstantFunctions.isConstant(call)) {
return new Expr.Constant(Evaluator.getGlobalEvaluator().visitCall(call));
}
return call;
}

@Override
Expand Down
37 changes: 8 additions & 29 deletions src/main/java/com/eliotlash/molang/ast/Evaluatable.java
Original file line number Diff line number Diff line change
@@ -1,43 +1,22 @@
package com.eliotlash.molang.ast;

import java.util.List;
import java.util.Objects;

public class Evaluatable {
private Expr expr = null;
private List<Stmt> stmts = null;
private boolean constant = false;
public interface Evaluatable {

public Evaluatable(Expr expr) {
this.expr = Objects.requireNonNull(expr);
constant = expr instanceof Expr.Constant;
default boolean isConstant() {
return false;
}

public Evaluatable(List<Stmt> stmts) {
this.stmts = Objects.requireNonNull(stmts);
}

public double evaluate(Evaluator evaluator) {
if (stmts != null) {
return evaluator.evaluate(stmts);
}
if (expr != null) {
Double result = evaluator.evaluate(expr);
return result == null ? 0 : result;
}

//should never get here
default double getConstant() {
return 0.0;
}

public boolean isConstant() {
return constant;
static Evaluatable of(Expr expression) {
return new EvaluatableExpr(expression);
}

public double getConstant() {
if(!isConstant()) {
return 0.0;
}
return Evaluator.getGlobalEvaluator().evaluate(expr);
static Evaluatable of(List<Stmt> statements) {
return new EvaluatableStmt(statements);
}
}
30 changes: 30 additions & 0 deletions src/main/java/com/eliotlash/molang/ast/EvaluatableExpr.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.eliotlash.molang.ast;

import java.util.Objects;

public class EvaluatableExpr implements Evaluatable {

private final Expr expr;
private final boolean constant;

public EvaluatableExpr(Expr expr) {
this.expr = Objects.requireNonNull(expr);
this.constant = expr instanceof Expr.Constant;
}

public double evaluate(Evaluator evaluator) {
Double result = evaluator.evaluate(this.expr);
return result == null ? 0 : result;
}

public boolean isConstant() {
return this.constant;
}

public double getConstant() {
if(!isConstant()) {
return 0.0;
}
return Evaluator.getGlobalEvaluator().evaluate(this.expr);
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/eliotlash/molang/ast/EvaluatableStmt.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.eliotlash.molang.ast;

import java.util.List;
import java.util.Objects;

public class EvaluatableStmt implements Evaluatable {

private final List<Stmt> stmts;

public EvaluatableStmt(List<Stmt> stmts) {
this.stmts = Objects.requireNonNull(stmts);
}

public double evaluate(Evaluator evaluator) {
return evaluator.evaluate(this.stmts);
}
}
3 changes: 1 addition & 2 deletions src/main/java/com/eliotlash/molang/ast/Evaluator.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package com.eliotlash.molang.ast;

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

private ExecutionContext context = new ExecutionContext(this);
private ExecutionContext context;

public static Evaluator getGlobalEvaluator() {
return globalEvaluator;
Expand Down
10 changes: 9 additions & 1 deletion src/main/java/com/eliotlash/molang/functions/Function.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.eliotlash.molang.variables.ExecutionContext;

public abstract class Function {
protected String name;
private final String name;

public Function(String name) {
this.name = name;
Expand All @@ -17,6 +17,14 @@ public String getName() {
return this.name;
}

/**
* If all arguments passed are constant,
* will this function always give the same result without the need of a context.
*/
public boolean isConstant() {
return true;
}

/**
* Get minimum count of arguments this function needs
*/
Expand Down
21 changes: 13 additions & 8 deletions src/main/java/com/eliotlash/molang/functions/utility/DiceRoll.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import com.eliotlash.molang.functions.Function;
import com.eliotlash.molang.variables.ExecutionContext;

public class DiceRoll extends Function {
public java.util.Random random;
import java.util.concurrent.ThreadLocalRandom;

public class DiceRoll extends Function {

public DiceRoll(String name){
public DiceRoll(String name) {
super(name);
this.random = new java.util.Random();
}

public boolean isConstant() {
return false;
}

@Override
Expand All @@ -21,11 +24,13 @@ public int getRequiredArguments() {
public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
double returnValue = 0;
double rollCount = this.evaluateArgument(arguments, ctx, 0);
double min = this.evaluateArgument(arguments, ctx, 1);
double max = this.evaluateArgument(arguments, ctx, 2);
if (rollCount > 0) {
double min = this.evaluateArgument(arguments, ctx, 1);
double max = this.evaluateArgument(arguments, ctx, 2);

for (int i = 0; i < rollCount; i++) {
returnValue += this.random.nextDouble() * (max - min) + min;
for (int i = 0; i < rollCount; i++) {
returnValue += ThreadLocalRandom.current().nextDouble() * (max - min) + min;
}
}

return returnValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,16 @@
import com.eliotlash.molang.functions.Function;
import com.eliotlash.molang.variables.ExecutionContext;

public class DiceRollInteger extends Function {
public java.util.Random random;
import java.util.concurrent.ThreadLocalRandom;

public class DiceRollInteger extends Function {

public DiceRollInteger(String name){
public DiceRollInteger(String name) {
super(name);
this.random = new java.util.Random();
}

public boolean isConstant() {
return false;
}

@Override
Expand All @@ -21,11 +24,13 @@ public int getRequiredArguments() {
public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
double returnValue = 0;
double rollCount = this.evaluateArgument(arguments, ctx, 0);
double min = this.evaluateArgument(arguments, ctx, 1);
double max = this.evaluateArgument(arguments, ctx, 2);
if (rollCount > 0) {
double min = this.evaluateArgument(arguments, ctx, 1);
double max = this.evaluateArgument(arguments, ctx, 2);

for (int i = 0; i < rollCount; i++) {
returnValue += Math.round(this.random.nextDouble() * (max - min) + min);
for (int i = 0; i < rollCount; i++) {
returnValue += Math.round(ThreadLocalRandom.current().nextDouble() * (max - min) + min);
}
}

return returnValue;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public Random(String name){
this.random = new java.util.Random();
}

public boolean isConstant() {
return false;
}

public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
double random = 0;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ public RandomInteger(String name){
this.random = new java.util.Random();
}

public boolean isConstant() {
return false;
}

public double _evaluate(Expr[] arguments, ExecutionContext ctx) {
double random = 0;

Expand Down
Loading

0 comments on commit bca2d85

Please sign in to comment.