feat(muscript): add muscript-core for shared code between muscript modules

This commit is contained in:
Johannes Frohnmeyer 2024-04-05 14:19:38 +02:00
parent 62c13cc9ac
commit 27b4d535ff
Signed by: Johannes
GPG Key ID: E76429612C2929F4
63 changed files with 650 additions and 123 deletions

View File

@ -6,6 +6,7 @@ plugins {
dependencies {
implementation(projects.commons)
api(projects.muscriptCore)
testImplementation(libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
@ -24,4 +25,5 @@ publishing {
tasks.javadoc {
linksOffline("https://maven.frohnmeyer-wds.de/javadoc/artifacts/io/gitlab/jfronny/commons/$version/raw", projects.commons)
linksOffline("https://maven.frohnmeyer-wds.de/javadoc/artifacts/io/gitlab/jfronny/muscript-core/$version/raw", projects.muscriptCore)
}

View File

@ -3,9 +3,5 @@ package io.gitlab.jfronny.muscript.ast;
import io.gitlab.jfronny.muscript.ast.dynamic.*;
import io.gitlab.jfronny.muscript.ast.extensible.ExtensibleDynamicExpr;
public sealed interface DynamicExpr extends Expr permits Bind, Closure, DynamicAssign, DynamicCoerce, DynamicConditional, DynamicLiteral, ExprGroup, Get, ListLiteral, ObjectLiteral, This, UnresolvedConditional, Variable, ExtensibleDynamicExpr {
@Override
default DynamicExpr asDynamic() {
return this;
}
public sealed interface DynamicExpr extends Expr permits Bind, Call, Closure, DynamicAssign, DynamicCoerce, DynamicConditional, DynamicLiteral, ExprGroup, Get, ListLiteral, ObjectLiteral, This, Variable, ExtensibleDynamicExpr {
}

View File

@ -1,12 +1,44 @@
package io.gitlab.jfronny.muscript.ast;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
import io.gitlab.jfronny.muscript.ast.bool.BoolLiteral;
import io.gitlab.jfronny.muscript.ast.number.NumberLiteral;
import io.gitlab.jfronny.muscript.ast.string.StringLiteral;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public sealed interface Expr permits BoolExpr, DynamicExpr, NullLiteral, NumberExpr, StringExpr {
ICodeLocation location();
CodeLocation location();
Order order();
default DynamicExpr asDynamic() {
return new DynamicCoerce(this);
public static BoolExpr literal(boolean bool) {
return literal(null, bool);
}
public static StringExpr literal(String string) {
return literal(null, string);
}
public static NumberExpr literal(double number) {
return literal(null, number);
}
public static NullLiteral literalNull() {
return literalNull(null);
}
public static BoolExpr literal(CodeLocation location, boolean bool) {
return new BoolLiteral(location, bool);
}
public static StringExpr literal(CodeLocation location, String string) {
return new StringLiteral(location, string);
}
public static NumberExpr literal(CodeLocation location, double number) {
return new NumberLiteral(location, number);
}
public static NullLiteral literalNull(CodeLocation location) {
return new NullLiteral(location);
}
}

View File

@ -1,6 +1,11 @@
package io.gitlab.jfronny.muscript.ast;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record NullLiteral(ICodeLocation location) implements Expr {
public record NullLiteral(CodeLocation location) implements Expr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.bool;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record And(ICodeLocation location, BoolExpr left, BoolExpr right) implements BoolExpr {
public record And(CodeLocation location, BoolExpr left, BoolExpr right) implements BoolExpr {
@Override
public Order order() {
return Order.And;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.bool;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record BoolAssign(ICodeLocation location, String variable, BoolExpr value) implements BoolExpr {
public record BoolAssign(CodeLocation location, String variable, BoolExpr value) implements BoolExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.bool;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record BoolConditional(ICodeLocation location, BoolExpr condition, BoolExpr trueCase, BoolExpr falseCase) implements BoolExpr {
public record BoolConditional(CodeLocation location, BoolExpr condition, BoolExpr ifTrue, BoolExpr ifFalse) implements BoolExpr {
@Override
public Order order() {
return Order.Conditional;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.bool;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record BoolLiteral(ICodeLocation location, boolean value) implements BoolExpr {
public record BoolLiteral(CodeLocation location, boolean value) implements BoolExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -2,11 +2,17 @@ package io.gitlab.jfronny.muscript.ast.bool;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record BoolUnpack(DynamicExpr inner) implements BoolExpr {
@Override
public ICodeLocation location() {
public CodeLocation location() {
return inner.location();
}
@Override
public Order order() {
return inner.order();
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.bool;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Not(ICodeLocation location, BoolExpr inner) implements BoolExpr {
public record Not(CodeLocation location, BoolExpr inner) implements BoolExpr {
@Override
public Order order() {
return Order.Unary;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.bool;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Or(ICodeLocation location, BoolExpr left, BoolExpr right) implements BoolExpr {
public record Or(CodeLocation location, BoolExpr left, BoolExpr right) implements BoolExpr {
@Override
public Order order() {
return Order.Or;
}
}

View File

@ -0,0 +1,73 @@
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.DynamicAssign;
import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
import io.gitlab.jfronny.muscript.ast.dynamic.DynamicConditional;
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.*;
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.toString(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 BoolUnpack(var inner) -> inner;
case NumberUnpack(var inner) -> inner;
case StringUnpack(var inner) -> inner;
case DynamicCoerce(var inner) -> inner;
case StringCoerce(var inner) -> inner;
default -> expression;
};
}
}

View File

@ -1,8 +0,0 @@
package io.gitlab.jfronny.muscript.ast.context;
/**
* Represents a location in the source code.
* To be implemented by the parser.
*/
public interface ICodeLocation {
}

View File

@ -0,0 +1,13 @@
package io.gitlab.jfronny.muscript.ast.context;
import io.gitlab.jfronny.muscript.ast.Expr;
import java.util.ServiceLoader;
public interface IExprParser {
IExprParser INSTANCE = ServiceLoader.load(IExprParser.class)
.findFirst()
.orElseGet(() -> expr -> { throw new UnsupportedOperationException(); });
Expr parse(String expr);
}

View File

@ -0,0 +1,14 @@
package io.gitlab.jfronny.muscript.ast.context;
import io.gitlab.jfronny.muscript.ast.Expr;
import org.jetbrains.annotations.Nullable;
import java.util.ServiceLoader;
public interface IExprSerializer {
IExprSerializer INSTANCE = ServiceLoader.load(IExprSerializer.class)
.findFirst()
.orElseGet(() -> expr -> null);
@Nullable String serialize(Expr expr);
}

View File

@ -0,0 +1,23 @@
package io.gitlab.jfronny.muscript.ast.context;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.dynamic.ExprGroup;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import java.util.List;
import java.util.stream.Stream;
public record Script(DynamicExpr content) {
public Script(List<Expr> expressions) {
this(new ExprGroup(null, expressions, null, true));
}
public Script(List<Expr> expressions, CodeLocation location) {
this(new ExprGroup(location, expressions, null, true));
}
public Stream<Expr> stream() {
return content instanceof ExprGroup group ? group.stream() : Stream.of(content);
}
}

View File

@ -0,0 +1,7 @@
package io.gitlab.jfronny.muscript.ast.context;
public class TypeMismatchException extends RuntimeException {
public TypeMismatchException(String message) {
super(message);
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Bind(ICodeLocation location, DynamicExpr callable, DynamicExpr parameter) implements DynamicExpr {
public record Bind(CodeLocation location, DynamicExpr callable, DynamicExpr parameter) implements DynamicExpr {
@Override
public Order order() {
return Order.Call;
}
}

View File

@ -1,10 +1,17 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
import java.util.List;
public record Call(DynamicExpr left, List<Arg> args) {
record Arg(DynamicExpr value, boolean variadic) {
public record Call(CodeLocation location, DynamicExpr callable, List<Argument> arguments) implements DynamicExpr {
@Override
public Order order() {
return Order.Call;
}
public record Argument(DynamicExpr value, boolean variadic) {
}
}

View File

@ -2,18 +2,25 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.context.ExprUtils;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
import java.util.List;
import java.util.stream.Stream;
public record Closure(ICodeLocation location, List<String> boundArgs, boolean variadic, List<Expr> steps, DynamicExpr finish) implements DynamicExpr {
public Closure(ICodeLocation location, List<String> boundArgs, boolean variadic, List<Expr> expressions) {
public record Closure(CodeLocation location, List<String> boundArgs, boolean variadic, List<Expr> steps, DynamicExpr finish) implements DynamicExpr {
public Closure(CodeLocation location, List<String> boundArgs, boolean variadic, List<Expr> expressions) {
//TODO use static methods before constructor once available
this(location, boundArgs, variadic, expressions.subList(0, expressions.size() - 1), expressions.getLast().asDynamic());
this(location, boundArgs, variadic, expressions.subList(0, expressions.size() - 1), ExprUtils.asDynamic(expressions.getLast()));
}
public Stream<Expr> stream() {
return Stream.concat(steps.stream(), Stream.of(finish));
}
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record DynamicAssign(ICodeLocation location, String variable, DynamicExpr value) implements DynamicExpr {
public record DynamicAssign(CodeLocation location, String variable, DynamicExpr value) implements DynamicExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -2,11 +2,17 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record DynamicCoerce(Expr inner) implements DynamicExpr {
@Override
public ICodeLocation location() {
public CodeLocation location() {
return inner.location();
}
@Override
public Order order() {
return inner.order();
}
}

View File

@ -2,8 +2,12 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record DynamicConditional(ICodeLocation location, BoolExpr condition, DynamicExpr trueCase, DynamicExpr falseCase) implements DynamicExpr {
public record DynamicConditional(CodeLocation location, BoolExpr condition, DynamicExpr ifTrue, DynamicExpr ifFalse) implements DynamicExpr {
@Override
public Order order() {
return Order.Conditional;
}
}

View File

@ -1,8 +1,13 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.context.IDynamic;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.IDynamic;
import io.gitlab.jfronny.muscript.core.Order;
public record DynamicLiteral(ICodeLocation location, IDynamic content) implements DynamicExpr {
public record DynamicLiteral(CodeLocation location, IDynamic content) implements DynamicExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -2,7 +2,12 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Equals(ICodeLocation location, Expr left, Expr right) implements BoolExpr {
public record Equals(CodeLocation location, Expr left, Expr right) implements BoolExpr {
@Override
public Order order() {
return Order.Equality;
}
}

View File

@ -2,16 +2,28 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.context.ExprUtils;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
import org.jetbrains.annotations.Nullable;
import java.util.List;
import java.util.stream.Stream;
public record ExprGroup(ICodeLocation location, List<Expr> steps, DynamicExpr finish, @Nullable PackedArgs packedArgs, boolean fork) implements DynamicExpr {
public ExprGroup(ICodeLocation location, List<Expr> expressions, @Nullable PackedArgs packedArgs, boolean fork) {
this(location, expressions.subList(0, expressions.size() - 1), expressions.getLast().asDynamic(), packedArgs, fork);
public record ExprGroup(CodeLocation location, List<Expr> steps, DynamicExpr finish, @Nullable PackedArgs packedArgs, boolean fork) implements DynamicExpr {
public ExprGroup(CodeLocation location, List<Expr> expressions, @Nullable PackedArgs packedArgs, boolean fork) {
this(location, expressions.subList(0, expressions.size() - 1), ExprUtils.asDynamic(expressions.getLast()), packedArgs, fork);
}
public record PackedArgs(List<Call.Arg> from, List<String> to, boolean variadic) {
public Stream<Expr> stream() {
return Stream.concat(steps.stream(), Stream.of(finish));
}
@Override
public Order order() {
return Order.Primary;
}
public record PackedArgs(List<Call.Argument> from, List<String> to, boolean variadic) {
}
}

View File

@ -2,7 +2,12 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Get(ICodeLocation location, DynamicExpr left, Expr name) implements DynamicExpr {
public record Get(CodeLocation location, DynamicExpr left, Expr name) implements DynamicExpr {
@Override
public Order order() {
return Order.Call;
}
}

View File

@ -1,9 +1,14 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
import java.util.List;
public record ListLiteral(ICodeLocation location, List<DynamicExpr> elements) implements DynamicExpr {
public record ListLiteral(CodeLocation location, List<DynamicExpr> elements) implements DynamicExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,9 +1,14 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
import java.util.Map;
public record ObjectLiteral(ICodeLocation location, Map<String, DynamicExpr> content) implements DynamicExpr {
public record ObjectLiteral(CodeLocation location, Map<String, DynamicExpr> content) implements DynamicExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record This(ICodeLocation location) implements DynamicExpr {
public record This(CodeLocation location) implements DynamicExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,9 +0,0 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
public record UnresolvedConditional(ICodeLocation location, BoolExpr condition, Expr trueCase, Expr falseCase) implements DynamicExpr {
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.dynamic;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Variable(ICodeLocation location, String name) implements DynamicExpr {
public record Variable(CodeLocation location, String name) implements DynamicExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -2,5 +2,5 @@ package io.gitlab.jfronny.muscript.ast.extensible;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
public non-sealed interface ExtensibleBoolExpr extends BoolExpr {
public non-sealed interface ExtensibleBoolExpr extends BoolExpr, ExtensibleExpr {
}

View File

@ -2,5 +2,5 @@ package io.gitlab.jfronny.muscript.ast.extensible;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
public non-sealed interface ExtensibleDynamicExpr extends DynamicExpr {
public non-sealed interface ExtensibleDynamicExpr extends DynamicExpr, ExtensibleExpr {
}

View File

@ -0,0 +1,7 @@
package io.gitlab.jfronny.muscript.ast.extensible;
import io.gitlab.jfronny.muscript.core.ExprWriter;
public interface ExtensibleExpr {
void decompile(ExprWriter writer);
}

View File

@ -2,5 +2,5 @@ package io.gitlab.jfronny.muscript.ast.extensible;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
public non-sealed interface ExtensibleNumberExpr extends NumberExpr {
public non-sealed interface ExtensibleNumberExpr extends NumberExpr, ExtensibleExpr {
}

View File

@ -2,5 +2,5 @@ package io.gitlab.jfronny.muscript.ast.extensible;
import io.gitlab.jfronny.muscript.ast.StringExpr;
public non-sealed interface ExtensibleStringExpr extends StringExpr {
public non-sealed interface ExtensibleStringExpr extends StringExpr, ExtensibleExpr {
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Add(ICodeLocation location, NumberExpr augend, NumberExpr addend) implements NumberExpr {
public record Add(CodeLocation location, NumberExpr augend, NumberExpr addend) implements NumberExpr {
@Override
public Order order() {
return Order.Term;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Divide(ICodeLocation location, NumberExpr dividend, NumberExpr divisor) implements NumberExpr {
public record Divide(CodeLocation location, NumberExpr dividend, NumberExpr divisor) implements NumberExpr {
@Override
public Order order() {
return Order.Factor;
}
}

View File

@ -2,7 +2,12 @@ package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record GreaterThan(ICodeLocation location, NumberExpr left, NumberExpr right) implements BoolExpr {
public record GreaterThan(CodeLocation location, NumberExpr left, NumberExpr right) implements BoolExpr {
@Override
public Order order() {
return Order.Comparison;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Modulo(ICodeLocation location, NumberExpr dividend, NumberExpr divisor) implements NumberExpr {
public record Modulo(CodeLocation location, NumberExpr dividend, NumberExpr divisor) implements NumberExpr {
@Override
public Order order() {
return Order.Factor;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Multiply(ICodeLocation location, NumberExpr multiplier, NumberExpr multiplicand) implements NumberExpr {
public record Multiply(CodeLocation location, NumberExpr multiplier, NumberExpr multiplicand) implements NumberExpr {
@Override
public Order order() {
return Order.Factor;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Negate(ICodeLocation location, NumberExpr inner) implements NumberExpr {
public record Negate(CodeLocation location, NumberExpr inner) implements NumberExpr {
@Override
public Order order() {
return Order.Unary;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record NumberAssign(ICodeLocation location, String variable, NumberExpr value) implements NumberExpr {
public record NumberAssign(CodeLocation location, String variable, NumberExpr value) implements NumberExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,10 +1,13 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record NumberConditional(ICodeLocation location, BoolExpr condition, NumberExpr trueCase, NumberExpr falseCase) implements NumberExpr {
public record NumberConditional(CodeLocation location, BoolExpr condition, NumberExpr ifTrue, NumberExpr ifFalse) implements NumberExpr {
@Override
public Order order() {
return Order.Conditional;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record NumberLiteral(ICodeLocation location, double value) implements NumberExpr {
public record NumberLiteral(CodeLocation location, double value) implements NumberExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -2,11 +2,17 @@ package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record NumberUnpack(DynamicExpr inner) implements NumberExpr {
@Override
public ICodeLocation location() {
public CodeLocation location() {
return inner.location();
}
@Override
public Order order() {
return inner.order();
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Power(ICodeLocation location, NumberExpr base, NumberExpr exponent) implements NumberExpr {
public record Power(CodeLocation location, NumberExpr base, NumberExpr exponent) implements NumberExpr {
@Override
public Order order() {
return Order.Exp;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.number;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Subtract(ICodeLocation location, NumberExpr minuend, NumberExpr subtrahend) implements NumberExpr {
public record Subtract(CodeLocation location, NumberExpr minuend, NumberExpr subtrahend) implements NumberExpr {
@Override
public Order order() {
return Order.Term;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.string;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record Concatenate(ICodeLocation location, StringExpr left, StringExpr right) implements StringExpr {
public record Concatenate(CodeLocation location, StringExpr left, StringExpr right) implements StringExpr {
@Override
public Order order() {
return Order.Concat;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.string;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record StringAssign(ICodeLocation location, String variable, StringExpr value) implements StringExpr {
public record StringAssign(CodeLocation location, String variable, StringExpr value) implements StringExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -1,12 +1,18 @@
package io.gitlab.jfronny.muscript.ast.string;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record StringCoerce(Expr inner) implements StringExpr {
@Override
public ICodeLocation location() {
public CodeLocation location() {
return inner.location();
}
@Override
public Order order() {
return inner.order();
}
}

View File

@ -1,10 +1,13 @@
package io.gitlab.jfronny.muscript.ast.string;
import io.gitlab.jfronny.muscript.ast.BoolExpr;
import io.gitlab.jfronny.muscript.ast.Expr;
import io.gitlab.jfronny.muscript.ast.NumberExpr;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record StringConditional(ICodeLocation location, BoolExpr condition, StringExpr trueCase, StringExpr falseCase) implements StringExpr {
public record StringConditional(CodeLocation location, BoolExpr condition, StringExpr ifTrue, StringExpr ifFalse) implements StringExpr {
@Override
public Order order() {
return Order.Conditional;
}
}

View File

@ -1,7 +1,12 @@
package io.gitlab.jfronny.muscript.ast.string;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record StringLiteral(ICodeLocation location, String value) implements StringExpr {
public record StringLiteral(CodeLocation location, String value) implements StringExpr {
@Override
public Order order() {
return Order.Primary;
}
}

View File

@ -2,11 +2,17 @@ package io.gitlab.jfronny.muscript.ast.string;
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
import io.gitlab.jfronny.muscript.ast.StringExpr;
import io.gitlab.jfronny.muscript.ast.context.ICodeLocation;
import io.gitlab.jfronny.muscript.core.CodeLocation;
import io.gitlab.jfronny.muscript.core.Order;
public record StringUnpack(DynamicExpr inner) implements StringExpr {
@Override
public ICodeLocation location() {
public CodeLocation location() {
return inner.location();
}
@Override
public Order order() {
return inner.order();
}
}

View File

@ -1,6 +1,9 @@
module io.gitlab.jfronny.commons.muscript.ast {
uses io.gitlab.jfronny.muscript.ast.context.IExprParser;
uses io.gitlab.jfronny.muscript.ast.context.IExprSerializer;
requires io.gitlab.jfronny.commons;
requires static org.jetbrains.annotations;
requires io.gitlab.jfronny.commons.muscript.core;
exports io.gitlab.jfronny.muscript.ast;
exports io.gitlab.jfronny.muscript.ast.extensible;
exports io.gitlab.jfronny.muscript.ast.context;

View File

@ -0,0 +1,27 @@
import io.gitlab.jfronny.scripts.*
plugins {
commons.library
}
dependencies {
implementation(projects.commons)
testImplementation(libs.junit.jupiter.api)
testRuntimeOnly(libs.junit.jupiter.engine)
}
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "io.gitlab.jfronny"
artifactId = "muscript-core"
from(components["java"])
}
}
}
tasks.javadoc {
linksOffline("https://maven.frohnmeyer-wds.de/javadoc/artifacts/io/gitlab/jfronny/commons/$version/raw", projects.commons)
}

View File

@ -0,0 +1,23 @@
package io.gitlab.jfronny.muscript.core;
import org.jetbrains.annotations.Nullable;
public record CodeLocation(int chStart, int chEnd, @Nullable String source, @Nullable String file) {
public static final CodeLocation NONE = new CodeLocation(-1, -1);
public CodeLocation(int chStart, int chEnd) {
this(chStart, chEnd, null, null);
}
public CodeLocation(int ch) {
this(ch, ch);
}
public CodeLocation withSource(String source) {
return new CodeLocation(chStart, chEnd, source, file);
}
public CodeLocation withFile(String file) {
return new CodeLocation(chStart, chEnd, source, file);
}
}

View File

@ -0,0 +1,78 @@
package io.gitlab.jfronny.muscript.core;
import io.gitlab.jfronny.commons.throwable.ThrowingConsumer;
import java.io.Closeable;
import java.io.IOException;
public class ExprWriter implements Appendable, Closeable {
private final Appendable target;
private final boolean compact;
private int indent = 0;
public static String write(ThrowingConsumer<ExprWriter, IOException> consumer, boolean compact) {
StringBuilder sb = new StringBuilder();
try (ExprWriter writer = new ExprWriter(sb, compact)) {
consumer.accept(writer);
} catch (IOException e) {
throw new RuntimeException("Could not write expression", e);
}
return sb.toString();
}
public ExprWriter(Appendable target, boolean compact) {
this.target = target;
this.compact = compact;
}
@Override
public ExprWriter append(CharSequence csq) throws IOException {
target.append(csq.toString().replace("\r", "").replace("\n", compact ? " " : "\n" + indent()));
return this;
}
@Override
public ExprWriter append(CharSequence csq, int start, int end) throws IOException {
return append(csq.subSequence(start, end));
}
@Override
public ExprWriter append(char c) throws IOException {
switch (c) {
case '\r' -> {}
case '\n' -> {
if (compact) target.append(" ");
else target.append("\n").append(indent());
}
default -> target.append(c);
}
return this;
}
public ExprWriter appendLiteral(String s) throws IOException {
if (!MuUtil.isValidId(s)) {
if (s.contains("`")) throw new IllegalArgumentException("Not a valid literal: " + s);
else return append('`').append(s).append('`');
} else return append(s);
}
private String indent() {
return " ".repeat(indent);
}
public ExprWriter increaseIndent() {
indent += 2;
return this;
}
public ExprWriter decreaseIndent() {
if (indent <= 1) throw new IllegalStateException("Attempted to decrease indent lower than 0");
indent -= 2;
return this;
}
@Override
public void close() {
if (indent != 0) throw new IllegalStateException("Attempted to close ExprWriter before end");
}
}

View File

@ -1,4 +1,4 @@
package io.gitlab.jfronny.muscript.ast.context;
package io.gitlab.jfronny.muscript.core;
/**
* Represents a Dynamic in the source code.

View File

@ -0,0 +1,13 @@
package io.gitlab.jfronny.muscript.core;
import java.util.Set;
import java.util.regex.Pattern;
public class MuUtil {
public static final Set<String> RESERVED_IDS = Set.of("null", "true", "false");
public static final Pattern IDENTIFIER = Pattern.compile("[a-zA-Z_$][a-zA-Z_$0-9]*");
public static boolean isValidId(String id) {
return IDENTIFIER.matcher(id).matches() && !RESERVED_IDS.contains(id);
}
}

View File

@ -0,0 +1,17 @@
package io.gitlab.jfronny.muscript.core;
public enum Order {
Script,
Conditional,
And,
Or,
Equality,
Concat,
Comparison,
Term,
Factor,
Exp,
Unary,
Call,
Primary;
}

View File

@ -0,0 +1,5 @@
module io.gitlab.jfronny.commons.muscript.core {
requires io.gitlab.jfronny.commons;
requires static org.jetbrains.annotations;
exports io.gitlab.jfronny.muscript.core;
}