java-commons/muscript-ast/src/main/java/io/gitlab/jfronny/muscript/ast/context/ExprUtils.java

96 lines
5.6 KiB
Java

package io.gitlab.jfronny.muscript.ast.context;
import io.gitlab.jfronny.commons.StringFormatter;
import io.gitlab.jfronny.muscript.ast.*;
import io.gitlab.jfronny.muscript.ast.bool.BoolAssign;
import io.gitlab.jfronny.muscript.ast.bool.BoolConditional;
import io.gitlab.jfronny.muscript.ast.bool.BoolLiteral;
import io.gitlab.jfronny.muscript.ast.bool.BoolUnpack;
import io.gitlab.jfronny.muscript.ast.dynamic.*;
import io.gitlab.jfronny.muscript.ast.number.NumberAssign;
import io.gitlab.jfronny.muscript.ast.number.NumberConditional;
import io.gitlab.jfronny.muscript.ast.number.NumberLiteral;
import io.gitlab.jfronny.muscript.ast.number.NumberUnpack;
import io.gitlab.jfronny.muscript.ast.string.*;
import java.util.Set;
public class ExprUtils {
public static DynamicExpr asDynamic(Expr expression) {
expression = unpack(expression);
return expression instanceof DynamicExpr dynamic ? dynamic : new DynamicCoerce(expression);
}
public static BoolExpr asBool(Expr expression) {
return switch (unpack(expression)) {
case BoolExpr bool -> bool;
case DynamicConditional(var location, var condition, var ifTrue, var ifFalse) -> new BoolConditional(location, condition, asBool(ifTrue), asBool(ifFalse));
case DynamicAssign(var location, var left, var right) -> new BoolAssign(location, left, asBool(right));
case DynamicExpr dynamic -> new BoolUnpack(dynamic);
case NullLiteral nl -> throw new TypeMismatchException("Expected boolean expression but got null");
case StringExpr string -> throw new TypeMismatchException("Expected boolean expression but got string");
case NumberExpr number -> throw new TypeMismatchException("Expected boolean expression but got number");
};
}
public static NumberExpr asNumber(Expr expression) {
return switch (unpack(expression)) {
case NumberExpr number -> number;
case DynamicConditional(var location, var condition, var ifTrue, var ifFalse) -> new NumberConditional(location, condition, asNumber(ifTrue), asNumber(ifFalse));
case DynamicAssign(var location, var left, var right) -> new NumberAssign(location, left, asNumber(right));
case DynamicExpr dynamic -> new NumberUnpack(dynamic);
case NullLiteral nl -> throw new TypeMismatchException("Expected number expression but got null");
case StringExpr string -> throw new TypeMismatchException("Expected number expression but got string");
case BoolExpr bool -> throw new TypeMismatchException("Expected number expression but got boolean");
};
}
public static StringExpr asString(Expr expression) {
return switch (unpack(expression)) {
case StringExpr string -> string;
case NumberLiteral number -> new StringLiteral(expression.location(), StringFormatter.toStringPrecise(number.value()));
case BoolLiteral bool -> new StringLiteral(expression.location(), bool.value() ? "true" : "false");
case NullLiteral nl -> new StringLiteral(expression.location(), "null");
case DynamicConditional(var location, var condition, var ifTrue, var ifFalse) -> new StringConditional(location, condition, asString(ifTrue), asString(ifFalse));
case BoolConditional(var location, var condition, var ifTrue, var ifFalse) -> new StringConditional(location, condition, asString(ifTrue), asString(ifFalse));
case NumberConditional(var location, var condition, var ifTrue, var ifFalse) -> new StringConditional(location, condition, asString(ifTrue), asString(ifFalse));
case DynamicAssign(var location, var left, var right) -> new StringAssign(location, left, asString(right));
case DynamicExpr dynamic -> new StringUnpack(dynamic);
default -> new StringCoerce(expression);
};
}
public static Expr unpack(Expr expression) {
return switch (expression) {
case null -> throw new NullPointerException();
case BoolUnpack(var inner) -> unpack(inner);
case NumberUnpack(var inner) -> unpack(inner);
case StringUnpack(var inner) -> unpack(inner);
case DynamicCoerce(var inner) -> unpack(inner);
case StringCoerce(var inner) -> unpack(inner);
default -> expression;
};
}
private static final Set<String> allowedVariables = Set.of("date", "time", "enum", "listOf");
public static boolean isDirect(Expr expr) {
return switch (expr) {
case NullLiteral ignored -> true;
case StringLiteral ignored -> true;
case NumberLiteral ignored -> true;
case BoolLiteral ignored -> true;
case DynamicLiteral(var location, var value) -> value.isDirect();
case DynamicCoerce(var inner) -> isDirect(inner);
case ObjectLiteral(var location, var content) -> content.values().stream().allMatch(ExprUtils::isDirect);
case Concatenate(var location, var left, var right) -> isDirect(left) && isDirect(right);
case BoolUnpack(var inner) -> isDirect(inner);
case NumberUnpack(var inner) -> isDirect(inner);
case StringUnpack(var inner) -> isDirect(inner);
case Bind(var location, var callable, var parameter) -> isDirect(callable) && isDirect(parameter);
case Call(var location, var left, var args) -> isDirect(left) && args.stream().allMatch(a -> !a.variadic() && isDirect(a.value()));
case Variable(var location, var name) -> allowedVariables.contains(name);
default -> false;
};
}
}