Commit 555dc5dd authored by Ticxo's avatar Ticxo
Browse files

Directly move everything to this repo

parent 2ff9eb39
No related merge requests found
package com.bedrockk.molang.parser.parselet;
import com.bedrockk.molang.Expression;
import com.bedrockk.molang.ast.TernaryExpression;
import com.bedrockk.molang.parser.InfixParselet;
import com.bedrockk.molang.parser.MoLangParser;
import com.bedrockk.molang.parser.Precedence;
import com.bedrockk.molang.parser.tokenizer.Token;
import com.bedrockk.molang.parser.tokenizer.TokenType;
public class TernaryParselet implements InfixParselet {
@Override
public Expression parse(MoLangParser parser, Token token, Expression leftExpr) {
if (parser.matchToken(TokenType.COLON)) {
return new TernaryExpression(leftExpr, null, parser.parseExpression(getPrecedence()));
} else {
Expression thenExpr = parser.parseExpression(getPrecedence());
if (!parser.matchToken(TokenType.COLON)) {
return new TernaryExpression(leftExpr, thenExpr, null);
} else {
return new TernaryExpression(leftExpr, thenExpr, parser.parseExpression(getPrecedence()));
}
}
}
@Override
public Precedence getPrecedence() {
return Precedence.CONDITIONAL;
}
}
package com.bedrockk.molang.parser.parselet;
import com.bedrockk.molang.Expression;
import com.bedrockk.molang.ast.ThisExpression;
import com.bedrockk.molang.parser.MoLangParser;
import com.bedrockk.molang.parser.PrefixParselet;
import com.bedrockk.molang.parser.tokenizer.Token;
public class ThisParselet implements PrefixParselet {
@Override
public Expression parse(MoLangParser parser, Token token) {
return new ThisExpression();
}
}
package com.bedrockk.molang.parser.parselet;
import com.bedrockk.molang.Expression;
import com.bedrockk.molang.ast.UnaryMinusExpression;
import com.bedrockk.molang.parser.MoLangParser;
import com.bedrockk.molang.parser.Precedence;
import com.bedrockk.molang.parser.PrefixParselet;
import com.bedrockk.molang.parser.tokenizer.Token;
public class UnaryMinusParselet implements PrefixParselet {
@Override
public Expression parse(MoLangParser parser, Token token) {
return new UnaryMinusExpression(parser.parseExpression(Precedence.PREFIX));
}
}
package com.bedrockk.molang.parser.parselet;
import com.bedrockk.molang.Expression;
import com.bedrockk.molang.ast.UnaryPlusExpression;
import com.bedrockk.molang.parser.MoLangParser;
import com.bedrockk.molang.parser.Precedence;
import com.bedrockk.molang.parser.PrefixParselet;
import com.bedrockk.molang.parser.tokenizer.Token;
public class UnaryPlusParselet implements PrefixParselet {
@Override
public Expression parse(MoLangParser parser, Token token) {
return new UnaryPlusExpression(parser.parseExpression(Precedence.PREFIX));
}
}
package com.bedrockk.molang.parser.tokenizer;
import lombok.RequiredArgsConstructor;
import lombok.Value;
@Value
@RequiredArgsConstructor
public class Token {
TokenType type;
String text;
TokenPosition position;
public Token(TokenType tokenType, TokenPosition position) {
this.type = tokenType;
this.text = tokenType.getSymbol();
this.position = position;
}
}
package com.bedrockk.molang.parser.tokenizer;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class TokenIterator {
private final String code;
private int index = 0;
private int currentLine = 0;
private int lastStep = 0;
private int lastStepLine = 0;
public boolean hasNext() {
return index < code.length();
}
public Token next() {
while (index < code.length()) {
if (code.length() > index + 1) { // check tokens with double chars
TokenType token = TokenType.bySymbol(code.substring(index, index + 2));
if (token != null) {
index += 2;
return new Token(token, getPosition());
}
}
String expr = getStringAt(index);
TokenType tokenType = TokenType.bySymbol(expr);
if (tokenType != null) {
index++;
return new Token(tokenType, getPosition());
} else if (expr.equals("'")) {
int stringStart = index;
int stringLength = index + 1;
while (stringLength < code.length() && !getStringAt(stringLength).equals("'")) {
stringLength++;
}
stringLength++;
index = stringLength;
return new Token(TokenType.STRING, code.substring(stringStart + 1, stringLength - 1), getPosition());
} else if (Character.isLetter(expr.charAt(0))) {
int nameLength = index + 1;
while (nameLength < code.length() && (Character.isLetterOrDigit(getStringAt(nameLength).charAt(0)) || getStringAt(nameLength).equals("_") || getStringAt(nameLength).equals("."))) {
nameLength++;
}
String value = code.substring(index, nameLength).toLowerCase();
TokenType token = TokenType.bySymbol(value);
if (token == null) {
token = TokenType.NAME;
}
index = nameLength;
return new Token(token, value, getPosition());
} else if (Character.isDigit(expr.charAt(0))) {
int numStart = index;
int numLength = index + 1;
boolean hasDecimal = false;
while (numLength < code.length() && (Character.isDigit(getStringAt(numLength).charAt(0)) || (getStringAt(numLength).equals(".") && !hasDecimal))) {
if (getStringAt(numLength).equals(".")) {
hasDecimal = true;
}
numLength++;
}
index = numLength;
return new Token(TokenType.NUMBER, code.substring(numStart, numLength), getPosition());
} else if (expr.equals("\n") || expr.equals("\r")) {
currentLine++;
}
index++;
}
return new Token(TokenType.EOF, getPosition());
}
public void step() {
lastStep = index;
lastStepLine = currentLine;
}
public TokenPosition getPosition() {
return new TokenPosition(lastStepLine, currentLine, lastStep, index);
}
public String getStringAt(String str, int i) {
return str.substring(i, i + 1);
}
public String getStringAt(int i) {
return code.substring(i, i + 1);
}
}
package com.bedrockk.molang.parser.tokenizer;
import lombok.Value;
@Value
public class TokenPosition {
int startLineNumber;
int endLineNumber;
int startColumn;
int endColumn;
}
package com.bedrockk.molang.parser.tokenizer;
public enum TokenType {
EQUALS("=="),
NOT_EQUALS("!="),
COALESCE("??"),
AND("&&"),
OR("||"),
GREATER_OR_EQUALS(">="),
SMALLER_OR_EQUALS("<="),
ARROW("->"),
GREATER(">"),
SMALLER("<"),
BRACKET_LEFT("("),
BRACKET_RIGHT(")"),
ARRAY_LEFT("["),
ARRAY_RIGHT("]"),
CURLY_BRACKET_LEFT("{"),
CURLY_BRACKET_RIGHT("}"),
COMMA(","),
ASSIGN("="),
PLUS("+"),
MINUS("-"),
ASTERISK("*"),
SLASH("/"),
QUESTION("?"),
COLON(":"),
SEMICOLON(";"),
BANG("!"),
RETURN("return"),
CONTINUE("continue"),
BREAK("break"),
FOR_EACH("for_each"),
LOOP("loop"),
THIS("this"),
TRUE("true"),
FALSE("false"),
STRING(""),
NUMBER(""),
NAME(""),
EOF("");
public final String symbol;
TokenType(String symbol) {
this.symbol = symbol;
}
public String getSymbol() {
return symbol;
}
public static TokenType bySymbol(String symbol) {
for (TokenType tokenType : TokenType.values()) {
if (tokenType.getSymbol().equals(symbol)) {
return tokenType;
}
}
return null;
}
}
package com.bedrockk.molang.runtime;
import com.bedrockk.molang.runtime.struct.MoStruct;
import com.bedrockk.molang.runtime.value.DoubleValue;
import com.bedrockk.molang.runtime.value.MoValue;
import lombok.Value;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
@Value
public class MoLangEnvironment implements MoValue {
ConcurrentMap<String, MoStruct> structs = new ConcurrentHashMap<>();
public MoValue getValue(String name) {
return getValue(name, MoParams.EMPTY);
}
public MoValue getValue(String name, MoParams params) {
LinkedList<String> segments = new LinkedList<>(Arrays.asList(name.split("\\.")));
String main = segments.poll();
if (structs.containsKey(main)) {
return structs.get(main).get(String.join(".", segments), params);
}
return new DoubleValue(0.0);
}
public void setValue(String name, MoValue value) {
LinkedList<String> segments = new LinkedList<>(Arrays.asList(name.split("\\.")));
String main = segments.poll();
if (structs.containsKey(main)) {
structs.get(main).set(String.join(".", segments), value);
}
}
@Override
public Object value() {
return this;
}
}
package com.bedrockk.molang.runtime;
import com.bedrockk.molang.runtime.struct.StaticQueryStruct;
import java.util.HashMap;
public final class MoLangMath {
public static final float DEG2RAD = 0.0174532f;
public static final StaticQueryStruct LIBRARY = new StaticQueryStruct(new HashMap<>() {
{
put("abs", params -> Math.abs(params.getDouble(0)));
put("acos", params -> Math.acos(params.getDouble(0)));
put("sin", params -> Math.sin(params.getDouble(0) * DEG2RAD));
put("asin", params -> Math.asin(params.getDouble(0)));
put("atan", params -> Math.atan(params.getDouble(0)));
put("atan2", params -> Math.atan2(params.getDouble(0), params.getDouble(1)));
put("ceil", params -> Math.ceil(params.getDouble(0)));
put("clamp", params -> Math.min(params.getDouble(2), Math.max(params.getDouble(0), params.getDouble(1))));
put("cos", params -> Math.cos(params.getDouble(0) * DEG2RAD));
put("die_roll", params -> dieRoll(params.getDouble(0), params.getDouble(1), params.getDouble(2)));
put("die_roll_integer", params -> dieRollInt(params.getInt(0), params.getInt(1), params.getInt(2)));
put("exp", params -> Math.exp(params.getDouble(0)));
put("mod", params -> params.getDouble(0) % params.getDouble(1));
put("floor", params -> Math.floor(params.getDouble(0)));
put("hermite_blend", params -> hermiteBlend(params.getInt(0)));
put("lerp", params -> lerp(params.getDouble(0), params.getDouble(1), params.getDouble(2)));
put("lerp_rotate", params -> lerpRotate(params.getDouble(0), params.getDouble(1), params.getDouble(2)));
put("ln", params -> Math.log(params.getDouble(0)));
put("max", params -> Math.max(params.getDouble(0), params.getDouble(1)));
put("min", params -> Math.min(params.getDouble(0), params.getDouble(1)));
put("pi", params -> Math.PI);
put("pow", params -> Math.pow(params.getDouble(0), params.getDouble(1)));
put("random", params -> random(params.getDouble(0), params.getDouble(1)));
put("random_integer", params -> randomInt(params.getInt(0), params.getInt(1)));
put("round", params -> Math.round(params.getDouble(0)));
put("sqrt", params -> Math.sqrt(params.getDouble(0)));
put("trunc", params -> Math.floor(params.getDouble(0)));
}
});
public static double random(double low, double high) {
return low + Math.random() * (high - low);
}
public static int randomInt(int low, int high) {
return (int) Math.round(low + Math.random() * (high - low));
}
public static double dieRoll(double num, double low, double high) {
int i = 0;
int total = 0;
while (i++ < num) total += random(low, high);
return total;
}
public static int dieRollInt(int num, int low, int high) {
int i = 0;
int total = 0;
while (i++ < num) total += randomInt(low, high);
return total;
}
public static int hermiteBlend(int value) {
return (3 * value) ^ (2 - 2 * value) ^ 3;
}
public static double lerp(double start, double end, double amount) {
amount = Math.max(0, Math.min(1, amount));
return start + (end - start) * amount;
}
public static double lerpRotate(double start, double end, double amount) {
start = radify(start);
end = radify(end);
if (start > end) {
double tmp = start;
start = end;
end = tmp;
}
if (end - start > 180) {
return radify(end + amount * (360 - (end - start)));
}
return start + amount * (end - start);
}
public static double radify(double num) {
return (((num + 180) % 360) + 180) % 360;
}
}
package com.bedrockk.molang.runtime;
import com.bedrockk.molang.ExprTraverser;
import com.bedrockk.molang.Expression;
import com.bedrockk.molang.runtime.struct.ArrayStruct;
import com.bedrockk.molang.runtime.struct.ContextStruct;
import com.bedrockk.molang.runtime.struct.VariableStruct;
import com.bedrockk.molang.runtime.value.DoubleValue;
import com.bedrockk.molang.runtime.value.MoValue;
import com.bedrockk.molang.visitor.ExprConnectingVisitor;
import java.util.*;
public class MoLangRuntime {
private final MoLangEnvironment environment = new MoLangEnvironment();
public MoLangRuntime() {
environment.getStructs().put("math", MoLangMath.LIBRARY);
environment.getStructs().put("temp", new VariableStruct());
environment.getStructs().put("variable", new VariableStruct());
environment.getStructs().put("array", new ArrayStruct());
}
public MoValue execute(Expression expression) {
return execute(Collections.singletonList(expression));
}
public MoValue execute(List<Expression> expressions) {
return execute(expressions, new HashMap<>());
}
public MoValue execute(List<Expression> expressions, Map<String, MoValue> context) {
var traverser = new ExprTraverser();
traverser.getVisitors().add(new ExprConnectingVisitor());
traverser.traverse(expressions);
environment.getStructs().put("context", new ContextStruct(context));
MoValue result = DoubleValue.ZERO;
var scope = new MoScope();
for (Expression expression : new ArrayList<>(expressions)) {
if (scope.getReturnValue() != null) {
break;
}
result = expression.evaluate(scope, environment);
}
environment.getStructs().get("temp").clear();
environment.getStructs().remove("context");
return scope.getReturnValue() != null ? scope.getReturnValue() : result;
}
public MoLangEnvironment getEnvironment() {
return environment;
}
}
package com.bedrockk.molang.runtime;
import com.bedrockk.molang.runtime.struct.MoStruct;
import com.bedrockk.molang.runtime.value.DoubleValue;
import com.bedrockk.molang.runtime.value.MoValue;
import com.bedrockk.molang.runtime.value.StringValue;
import java.util.ArrayList;
import java.util.List;
public class MoParams {
public static final MoParams EMPTY = new MoParams(new ArrayList<>());
private final List<MoValue> params;
public MoParams(List<MoValue> params) {
this.params = params;
}
@SuppressWarnings("unchecked")
public <T extends MoValue> T get(int index) {
return (T) params.get(index);
}
public boolean contains(int index) {
return params.size() >= index + 1;
}
public int getInt(int index) {
return (int) getDouble(index);
}
public double getDouble(int index) {
return this.<DoubleValue>get(index).asDouble();
}
public MoStruct getStruct(int index) {
return get(index);
}
public String getString(int index) {
return this.<StringValue>get(index).asString();
}
public MoLangEnvironment getEnv(int index) {
return get(index);
}
public List<MoValue> getParams() {
return params;
}
}
package com.bedrockk.molang.runtime;
import com.bedrockk.molang.runtime.value.MoValue;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class MoScope {
private boolean isBreak = false;
private boolean isContinue = false;
private MoValue returnValue;
}
\ No newline at end of file
package com.bedrockk.molang.runtime.struct;
import com.bedrockk.molang.runtime.value.MoValue;
import java.util.Map;
public class ArrayStruct extends VariableStruct {
public ArrayStruct() {}
public ArrayStruct(Map<String, MoValue> map) {
super(map);
}
@Override
public void set(String name, MoValue value) {
// Last part always must be a integer
String[] parts = name.split("\\.");
parts[parts.length - 1] = String.valueOf(Integer.parseInt(parts[parts.length - 1]));
super.set(String.join(".", parts), value);
}
}
package com.bedrockk.molang.runtime.struct;
import com.bedrockk.molang.runtime.value.MoValue;
import java.util.Map;
public class ContextStruct extends VariableStruct {
public ContextStruct() {}
public ContextStruct(Map<String, MoValue> map) {
super(map);
}
@Override
public void set(String name, MoValue value) {
throw new RuntimeException("Tried to set a value in read-only context struct");
}
}
package com.bedrockk.molang.runtime.struct;
import com.bedrockk.molang.runtime.MoParams;
import com.bedrockk.molang.runtime.value.MoValue;
public interface MoStruct extends MoValue {
void set(String key, MoValue value);
MoValue get(String key, MoParams params);
void clear();
@Override
default MoStruct value() {
return this;
}
}
package com.bedrockk.molang.runtime.struct;
import com.bedrockk.molang.runtime.MoParams;
import com.bedrockk.molang.runtime.value.MoValue;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Map;
import java.util.function.BiFunction;
@Getter
@RequiredArgsConstructor
public class QueryStruct<T> implements MoStruct {
private final T target;
private final Map<String, BiFunction<MoParams, T, Object>> functions;
@Override
public void set(String key, MoValue value) {
throw new RuntimeException("Cannot set a value in query struct");
}
@Override
public MoValue get(String key, MoParams params) {
if (functions.containsKey(key)) {
return MoValue.of(functions.get(key).apply(params, target));
}
return null;
}
@Override
public void clear() {
functions.clear();
}
}
package com.bedrockk.molang.runtime.struct;
import com.bedrockk.molang.runtime.MoParams;
import com.bedrockk.molang.runtime.value.MoValue;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Map;
import java.util.function.Function;
@Getter
@RequiredArgsConstructor
public class StaticQueryStruct implements MoStruct {
private final Map<String, Function<MoParams, Object>> functions;
@Override
public MoValue get(String key, MoParams params) {
if (functions.containsKey(key)) {
return MoValue.of(functions.get(key).apply(params));
}
return null;
}
@Override
public void set(String name, MoValue value) {
throw new RuntimeException("Cannot set a value in query struct");
}
@Override
public void clear() {
functions.clear();
}
}
package com.bedrockk.molang.runtime.struct;
import com.bedrockk.molang.runtime.MoParams;
import com.bedrockk.molang.runtime.value.MoValue;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Map;
@Getter
@RequiredArgsConstructor
public class VariableStruct implements MoStruct {
private final Map<String, MoValue> map;
public VariableStruct() {
this.map = new HashMap<>();
}
@Override
public void set(String name, MoValue value) {
LinkedList<String> segments = new LinkedList<>(Arrays.asList(name.split("\\.")));
String main = segments.poll();
if (segments.size() > 0 && main != null) {
Object struct = get(main, MoParams.EMPTY);
if (!(struct instanceof MoStruct)) {
struct = new VariableStruct();
}
((MoStruct) struct).set(segments.poll(), value);
map.put(main, (MoStruct) struct);
} else {
map.put(name, value);
}
}
@Override
public MoValue get(String name, MoParams params) {
LinkedList<String> segments = new LinkedList<>(Arrays.asList(name.split("\\.")));
String main = segments.poll();
if (segments.size() > 0 && main != null) {
Object struct = map.get(main);
if (struct instanceof MoStruct) {
return ((MoStruct) struct).get(segments.poll(), MoParams.EMPTY);
}
}
return map.get(name);
}
@Override
public void clear() {
map.clear();
}
}
package com.bedrockk.molang.runtime.value;
public class DoubleValue implements MoValue {
public final static DoubleValue ZERO = new DoubleValue(0.0);
public final static DoubleValue ONE = new DoubleValue(1.0);
private final double value;
public DoubleValue(Object value) {
if (value instanceof Boolean) {
this.value = (boolean) value ? 1.0 : 0.0;
} else if (value instanceof Number) {
this.value = (double) value;
} else {
this.value = 1.0;
}
}
@Override
public Double value() {
return value;
}
@Override
public String asString() {
return Double.toString(value);
}
@Override
public double asDouble() {
return value;
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment