track code location
This commit is contained in:
parent
51cc7e41ab
commit
e652bfe6ba
|
@ -1,12 +1,11 @@
|
|||
package io.gitlab.jfronny.muscript.ast;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.Type;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
|
||||
public abstract non-sealed class BoolExpr extends Expr<Boolean> {
|
||||
protected BoolExpr(Order order, int chStart, int chEnd) {
|
||||
super(order, chStart, chEnd);
|
||||
protected BoolExpr(Order order, CodeLocation location) {
|
||||
super(order, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +18,6 @@ public abstract non-sealed class BoolExpr extends Expr<Boolean> {
|
|||
|
||||
@Override
|
||||
public DynamicExpr asDynamicExpr() {
|
||||
return new DynamicCoerce(chStart, chEnd, this);
|
||||
return new DynamicCoerce(location, this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
package io.gitlab.jfronny.muscript.ast;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
|
||||
import io.gitlab.jfronny.muscript.ast.dynamic.unpack.*;
|
||||
import io.gitlab.jfronny.muscript.compiler.Type;
|
||||
|
||||
public abstract non-sealed class DynamicExpr extends Expr<Dynamic<?>> {
|
||||
protected DynamicExpr(Order order, int chStart, int chEnd) {
|
||||
super(order, chStart, chEnd);
|
||||
protected DynamicExpr(Order order, CodeLocation location) {
|
||||
super(order, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -20,17 +19,17 @@ public abstract non-sealed class DynamicExpr extends Expr<Dynamic<?>> {
|
|||
|
||||
@Override
|
||||
public BoolExpr asBoolExpr() {
|
||||
return new BoolUnpack(chStart, chEnd, this);
|
||||
return new BoolUnpack(location, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringExpr asStringExpr() {
|
||||
return new StringUnpack(chStart, chEnd, this);
|
||||
return new StringUnpack(location, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberExpr asNumberExpr() {
|
||||
return new NumberUnpack(chStart, chEnd, this);
|
||||
return new NumberUnpack(location, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -12,12 +12,10 @@ import io.gitlab.jfronny.muscript.error.TypeMismatchException;
|
|||
@CanThrow
|
||||
public abstract sealed class Expr<T> extends Decompilable
|
||||
permits BoolExpr, DynamicExpr, NullLiteral, NumberExpr, StringExpr {
|
||||
public final int chStart;
|
||||
public final int chEnd;
|
||||
protected Expr(Order order, int chStart, int chEnd) {
|
||||
public final CodeLocation location;
|
||||
protected Expr(Order order, CodeLocation location) {
|
||||
super(order);
|
||||
this.chStart = chStart;
|
||||
this.chEnd = chEnd;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public abstract Type getResultType();
|
||||
|
@ -33,17 +31,17 @@ public abstract sealed class Expr<T> extends Decompilable
|
|||
|
||||
public BoolExpr asBoolExpr() {
|
||||
if (this instanceof BoolExpr e) return e;
|
||||
throw new TypeMismatchException(chStart, chEnd, Type.Boolean, getResultType());
|
||||
throw new TypeMismatchException(location, Type.Boolean, getResultType());
|
||||
}
|
||||
|
||||
public StringExpr asStringExpr() {
|
||||
if (this instanceof StringExpr e) return e;
|
||||
return new StringCoerce(chStart, chEnd, this);
|
||||
return new StringCoerce(location, this);
|
||||
}
|
||||
|
||||
public NumberExpr asNumberExpr() {
|
||||
if (this instanceof NumberExpr e) return e;
|
||||
throw new TypeMismatchException(chStart, chEnd, Type.Number, getResultType());
|
||||
throw new TypeMismatchException(location, Type.Number, getResultType());
|
||||
}
|
||||
|
||||
public abstract DynamicExpr asDynamicExpr();
|
||||
|
@ -53,54 +51,74 @@ public abstract sealed class Expr<T> extends Decompilable
|
|||
}
|
||||
|
||||
public static BoolExpr literal(boolean bool) {
|
||||
return literal(-1, bool);
|
||||
return literal(CodeLocation.NONE, bool);
|
||||
}
|
||||
|
||||
public static StringExpr literal(String string) {
|
||||
return literal(-1, string);
|
||||
return literal(CodeLocation.NONE, string);
|
||||
}
|
||||
|
||||
public static NumberExpr literal(double number) {
|
||||
return literal(-1, number);
|
||||
return literal(CodeLocation.NONE, number);
|
||||
}
|
||||
|
||||
public static NullLiteral literalNull() {
|
||||
return literalNull(-1);
|
||||
return literalNull(CodeLocation.NONE);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static BoolExpr literal(int character, boolean bool) {
|
||||
return literal(character, character, bool);
|
||||
return literal(new CodeLocation(character), bool);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static StringExpr literal(int character, String string) {
|
||||
return literal(character, character, string);
|
||||
return literal(new CodeLocation(character), string);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static NumberExpr literal(int character, double number) {
|
||||
return literal(character, character, number);
|
||||
return literal(new CodeLocation(character), number);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static NullLiteral literalNull(int character) {
|
||||
return literalNull(character, character);
|
||||
return literalNull(new CodeLocation(character));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static BoolExpr literal(int chStart, int chEnd, boolean bool) {
|
||||
return new BoolLiteral(chStart, chEnd, bool);
|
||||
return literal(new CodeLocation(chStart, chEnd), bool);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static StringExpr literal(int chStart, int chEnd, String string) {
|
||||
return new StringLiteral(chStart, chEnd, string);
|
||||
return literal(new CodeLocation(chStart, chEnd), string);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static NumberExpr literal(int chStart, int chEnd, double number) {
|
||||
return new NumberLiteral(chStart, chEnd, number);
|
||||
return literal(new CodeLocation(chStart, chEnd), number);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static NullLiteral literalNull(int chStart, int chEnd) {
|
||||
return new NullLiteral(chStart, chEnd);
|
||||
return literalNull(new CodeLocation(chStart, chEnd));
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,8 @@ import java.io.IOException;
|
|||
|
||||
@CanThrow
|
||||
public final class NullLiteral extends Expr<Object> {
|
||||
public NullLiteral(int chStart, int chEnd) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
public NullLiteral(CodeLocation location) {
|
||||
super(Order.Primary, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -37,22 +37,22 @@ public final class NullLiteral extends Expr<Object> {
|
|||
|
||||
@Override
|
||||
public DynamicExpr asDynamicExpr() {
|
||||
return new DynamicLiteral<>(chStart, chEnd, new DNull());
|
||||
return new DynamicLiteral<>(location, new DNull());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberExpr asNumberExpr() {
|
||||
throw new LocationalException(chStart, chEnd, "Attempted to convert null to a number");
|
||||
throw new LocationalException(location, "Attempted to convert null to a number");
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringExpr asStringExpr() {
|
||||
return literal(chStart, chEnd, "null");
|
||||
return literal(location, "null");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoolExpr asBoolExpr() {
|
||||
throw new LocationalException(chStart, chEnd, "Attempted to convert null to a boolean");
|
||||
throw new LocationalException(location, "Attempted to convert null to a boolean");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package io.gitlab.jfronny.muscript.ast;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.Type;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
|
||||
public abstract non-sealed class NumberExpr extends Expr<Double> {
|
||||
protected NumberExpr(Order order, int chStart, int chEnd) {
|
||||
super(order, chStart, chEnd);
|
||||
protected NumberExpr(Order order, CodeLocation location) {
|
||||
super(order, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +18,6 @@ public abstract non-sealed class NumberExpr extends Expr<Double> {
|
|||
|
||||
@Override
|
||||
public DynamicExpr asDynamicExpr() {
|
||||
return new DynamicCoerce(chStart, chEnd, this);
|
||||
return new DynamicCoerce(location, this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
package io.gitlab.jfronny.muscript.ast;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.dynamic.DynamicCoerce;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.Type;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
|
||||
public abstract non-sealed class StringExpr extends Expr<String> {
|
||||
protected StringExpr(Order order, int chStart, int chEnd) {
|
||||
super(order, chStart, chEnd);
|
||||
protected StringExpr(Order order, CodeLocation location) {
|
||||
super(order, location);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +18,6 @@ public abstract non-sealed class StringExpr extends Expr<String> {
|
|||
|
||||
@Override
|
||||
public DynamicExpr asDynamicExpr() {
|
||||
return new DynamicCoerce(chStart, chEnd, this);
|
||||
return new DynamicCoerce(location, this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.bool;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
|
@ -13,8 +12,8 @@ public class And extends BoolExpr {
|
|||
private final BoolExpr left;
|
||||
private final BoolExpr right;
|
||||
|
||||
public And(int chStart, int chEnd, BoolExpr left, BoolExpr right) {
|
||||
super(Order.And, chStart, chEnd);
|
||||
public And(CodeLocation location, BoolExpr left, BoolExpr right) {
|
||||
super(Order.And, location);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
@ -28,9 +27,9 @@ public class And extends BoolExpr {
|
|||
public BoolExpr optimize() {
|
||||
BoolExpr left = this.left.optimize();
|
||||
BoolExpr right = this.right.optimize();
|
||||
if (left instanceof BoolLiteral literal) return literal.value ? right : Expr.literal(chStart, chEnd, false);
|
||||
if (right instanceof BoolLiteral literal) return literal.value ? left : Expr.literal(chStart, chEnd, false);
|
||||
return new And(chStart, chEnd, left, right);
|
||||
if (left instanceof BoolLiteral literal) return literal.value ? right : literal(location, false);
|
||||
if (right instanceof BoolLiteral literal) return literal.value ? left : literal(location, false);
|
||||
return new And(location, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -3,8 +3,7 @@ package io.gitlab.jfronny.muscript.ast.bool;
|
|||
import io.gitlab.jfronny.muscript.ast.compare.Equal;
|
||||
import io.gitlab.jfronny.muscript.ast.compare.Greater;
|
||||
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
|
@ -15,8 +14,8 @@ import java.io.IOException;
|
|||
public class Not extends BoolExpr {
|
||||
public final BoolExpr inner;
|
||||
|
||||
public Not(int chStart, int chEnd, BoolExpr inner) {
|
||||
super(Order.Unary, chStart, chEnd);
|
||||
public Not(CodeLocation location, BoolExpr inner) {
|
||||
super(Order.Unary, location);
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
|
@ -29,8 +28,8 @@ public class Not extends BoolExpr {
|
|||
public BoolExpr optimize() {
|
||||
BoolExpr inner = this.inner.optimize();
|
||||
if (inner instanceof Not not) return not.inner;
|
||||
if (inner instanceof BoolLiteral literal) return Expr.literal(chStart, chEnd, !literal.value);
|
||||
return new Not(chStart, chEnd, inner);
|
||||
if (inner instanceof BoolLiteral literal) return literal(location, !literal.value);
|
||||
return new Not(location, inner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.bool;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
|
@ -13,8 +12,8 @@ public class Or extends BoolExpr {
|
|||
private final BoolExpr left;
|
||||
private final BoolExpr right;
|
||||
|
||||
public Or(int chStart, int chEnd, BoolExpr left, BoolExpr right) {
|
||||
super(Order.Or, chStart, chEnd);
|
||||
public Or(CodeLocation location, BoolExpr left, BoolExpr right) {
|
||||
super(Order.Or, location);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
@ -28,9 +27,9 @@ public class Or extends BoolExpr {
|
|||
public BoolExpr optimize() {
|
||||
BoolExpr left = this.left.optimize();
|
||||
BoolExpr right = this.right.optimize();
|
||||
if (left instanceof BoolLiteral literal) return literal.value ? Expr.literal(chStart, chEnd, true) : right;
|
||||
if (right instanceof BoolLiteral literal) return literal.value ? Expr.literal(chStart, chEnd, true) : left;
|
||||
return new Or(chStart, chEnd, left, right);
|
||||
if (left instanceof BoolLiteral literal) return literal.value ? literal(location, true) : right;
|
||||
if (right instanceof BoolLiteral literal) return literal.value ? literal(location, true) : left;
|
||||
return new Or(location, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,8 +2,7 @@ package io.gitlab.jfronny.muscript.ast.compare;
|
|||
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
|
||||
|
||||
|
@ -14,8 +13,8 @@ public class Equal extends BoolExpr {
|
|||
public final Expr<?> left;
|
||||
public final Expr<?> right;
|
||||
|
||||
public Equal(int chStart, int chEnd, Expr<?> left, Expr<?> right) {
|
||||
super(Order.Equality, chStart, chEnd);
|
||||
public Equal(CodeLocation location, Expr<?> left, Expr<?> right) {
|
||||
super(Order.Equality, location);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
@ -34,8 +33,8 @@ public class Equal extends BoolExpr {
|
|||
public BoolExpr optimize() {
|
||||
Expr<?> left = this.left.optimize();
|
||||
Expr<?> right = this.right.optimize();
|
||||
if (left.equals(right)) return Expr.literal(chStart, chEnd, true);
|
||||
return new Equal(chStart, chEnd, left, right);
|
||||
if (left.equals(right)) return literal(location, true);
|
||||
return new Equal(location, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.compare;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.*;
|
||||
import io.gitlab.jfronny.muscript.ast.literal.NumberLiteral;
|
||||
|
@ -13,8 +12,8 @@ public class Greater extends BoolExpr {
|
|||
public final NumberExpr left;
|
||||
public final NumberExpr right;
|
||||
|
||||
public Greater(int chStart, int chEnd, NumberExpr left, NumberExpr right) {
|
||||
super(Order.Comparison, chStart, chEnd);
|
||||
public Greater(CodeLocation location, NumberExpr left, NumberExpr right) {
|
||||
super(Order.Comparison, location);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
@ -29,19 +28,19 @@ public class Greater extends BoolExpr {
|
|||
NumberExpr left = this.left.optimize();
|
||||
NumberExpr right = this.right.optimize();
|
||||
if (left instanceof NumberLiteral litL && right instanceof NumberLiteral litR)
|
||||
return Expr.literal(chStart, chEnd, litL.value > litR.value);
|
||||
return literal(location, litL.value > litR.value);
|
||||
if (left instanceof Divide divide)
|
||||
return new Greater(chStart, chEnd, divide.dividend, new Multiply(divide.chStart, divide.chEnd, right, divide.divisor)).optimize();
|
||||
return new Greater(location, divide.dividend, new Multiply(divide.location, right, divide.divisor)).optimize();
|
||||
if (left instanceof Invert invert)
|
||||
return new Greater(chStart, chEnd, new Invert(right.chStart, right.chEnd, right), invert.inner).optimize();
|
||||
return new Greater(location, new Invert(right.location, right), invert.inner).optimize();
|
||||
if (left instanceof Minus minus)
|
||||
return new Greater(chStart, chEnd, minus.minuend, new Plus(minus.chStart, minus.chEnd, minus.subtrahend, right)).optimize();
|
||||
return new Greater(location, minus.minuend, new Plus(minus.location, minus.subtrahend, right)).optimize();
|
||||
// Modulo is left out because it is too complicated for this naive impl
|
||||
// Multiply is left out since it would transform into a division and may be 0
|
||||
if (left instanceof Plus plus)
|
||||
return new Greater(chStart, chEnd, plus.augend, new Minus(plus.chStart, plus.chEnd, plus.addend, right)).optimize();
|
||||
return new Greater(location, plus.augend, new Minus(plus.location, plus.addend, right)).optimize();
|
||||
// Power is left out because it can't be transformed cleanly either
|
||||
return new Greater(chStart, chEnd, left, right);
|
||||
return new Greater(location, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.conditional;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.bool.Not;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.literal.BoolLiteral;
|
||||
|
@ -14,8 +13,8 @@ public class BoolConditional extends BoolExpr {
|
|||
public final BoolExpr trueExpr;
|
||||
public final BoolExpr falseExpr;
|
||||
|
||||
public BoolConditional(int chStart, int chEnd, BoolExpr condition, BoolExpr trueExpr, BoolExpr falseExpr) {
|
||||
super(Order.Conditional, chStart, chEnd);
|
||||
public BoolConditional(CodeLocation location, BoolExpr condition, BoolExpr trueExpr, BoolExpr falseExpr) {
|
||||
super(Order.Conditional, location);
|
||||
this.condition = condition;
|
||||
this.trueExpr = trueExpr;
|
||||
this.falseExpr = falseExpr;
|
||||
|
@ -33,8 +32,8 @@ public class BoolConditional extends BoolExpr {
|
|||
BoolExpr falseExpr = this.falseExpr.optimize();
|
||||
if (condition instanceof BoolLiteral literal) return literal.value ? trueExpr : falseExpr;
|
||||
if (trueExpr.equals(falseExpr)) return trueExpr;
|
||||
if (condition instanceof Not not) return new BoolConditional(chStart, chEnd, not.inner, falseExpr, trueExpr);
|
||||
return new BoolConditional(chStart, chEnd, condition, trueExpr, falseExpr);
|
||||
if (condition instanceof Not not) return new BoolConditional(location, not.inner, falseExpr, trueExpr);
|
||||
return new BoolConditional(location, condition, trueExpr, falseExpr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.conditional;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.bool.Not;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
|
@ -16,8 +15,8 @@ public class DynamicConditional extends DynamicExpr {
|
|||
public final DynamicExpr trueExpr;
|
||||
public final DynamicExpr falseExpr;
|
||||
|
||||
public DynamicConditional(int chStart, int chEnd, BoolExpr condition, DynamicExpr trueExpr, DynamicExpr falseExpr) {
|
||||
super(Order.Conditional, chStart, chEnd);
|
||||
public DynamicConditional(CodeLocation location, BoolExpr condition, DynamicExpr trueExpr, DynamicExpr falseExpr) {
|
||||
super(Order.Conditional, location);
|
||||
this.condition = condition;
|
||||
this.trueExpr = trueExpr;
|
||||
this.falseExpr = falseExpr;
|
||||
|
@ -35,8 +34,8 @@ public class DynamicConditional extends DynamicExpr {
|
|||
DynamicExpr falseExpr = this.falseExpr.optimize();
|
||||
if (condition instanceof BoolLiteral literal) return literal.value ? trueExpr : falseExpr;
|
||||
if (trueExpr.equals(falseExpr)) return trueExpr;
|
||||
if (condition instanceof Not not) return new DynamicConditional(chStart, chEnd, not.inner, falseExpr, trueExpr);
|
||||
return new DynamicConditional(chStart, chEnd, condition, trueExpr, falseExpr);
|
||||
if (condition instanceof Not not) return new DynamicConditional(location, not.inner, falseExpr, trueExpr);
|
||||
return new DynamicConditional(location, condition, trueExpr, falseExpr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.conditional;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.bool.Not;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -15,8 +14,8 @@ public class NumberConditional extends NumberExpr {
|
|||
public final NumberExpr trueExpr;
|
||||
public final NumberExpr falseExpr;
|
||||
|
||||
public NumberConditional(int chStart, int chEnd, BoolExpr condition, NumberExpr trueExpr, NumberExpr falseExpr) {
|
||||
super(Order.Conditional, chStart, chEnd);
|
||||
public NumberConditional(CodeLocation location, BoolExpr condition, NumberExpr trueExpr, NumberExpr falseExpr) {
|
||||
super(Order.Conditional, location);
|
||||
this.condition = condition;
|
||||
this.trueExpr = trueExpr;
|
||||
this.falseExpr = falseExpr;
|
||||
|
@ -34,8 +33,8 @@ public class NumberConditional extends NumberExpr {
|
|||
NumberExpr falseExpr = this.falseExpr.optimize();
|
||||
if (condition instanceof BoolLiteral literal) return literal.value ? trueExpr : falseExpr;
|
||||
if (trueExpr.equals(falseExpr)) return trueExpr;
|
||||
if (condition instanceof Not not) return new NumberConditional(chStart, chEnd, not.inner, falseExpr, trueExpr);
|
||||
return new NumberConditional(chStart, chEnd, condition, trueExpr, falseExpr);
|
||||
if (condition instanceof Not not) return new NumberConditional(location, not.inner, falseExpr, trueExpr);
|
||||
return new NumberConditional(location, condition, trueExpr, falseExpr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.conditional;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.bool.Not;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.StringExpr;
|
||||
|
@ -15,8 +14,8 @@ public class StringConditional extends StringExpr {
|
|||
public final StringExpr trueExpr;
|
||||
public final StringExpr falseExpr;
|
||||
|
||||
public StringConditional(int chStart, int chEnd, BoolExpr condition, StringExpr trueExpr, StringExpr falseExpr) {
|
||||
super(Order.Conditional, chStart, chEnd);
|
||||
public StringConditional(CodeLocation location, BoolExpr condition, StringExpr trueExpr, StringExpr falseExpr) {
|
||||
super(Order.Conditional, location);
|
||||
this.condition = condition;
|
||||
this.trueExpr = trueExpr;
|
||||
this.falseExpr = falseExpr;
|
||||
|
@ -34,8 +33,8 @@ public class StringConditional extends StringExpr {
|
|||
StringExpr falseExpr = this.falseExpr.optimize();
|
||||
if (condition instanceof BoolLiteral literal) return literal.value ? trueExpr : falseExpr;
|
||||
if (trueExpr.equals(falseExpr)) return trueExpr;
|
||||
if (condition instanceof Not not) return new StringConditional(chStart, chEnd, not.inner, falseExpr, trueExpr);
|
||||
return new StringConditional(chStart, chEnd, condition, trueExpr, falseExpr);
|
||||
if (condition instanceof Not not) return new StringConditional(location, not.inner, falseExpr, trueExpr);
|
||||
return new StringConditional(location, condition, trueExpr, falseExpr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -17,8 +17,8 @@ public class UnresolvedConditional extends DynamicExpr {
|
|||
private final Expr<?> trueExpr;
|
||||
private final Expr<?> falseExpr;
|
||||
|
||||
public UnresolvedConditional(int chStart, int chEnd, BoolExpr condition, Expr<?> trueExpr, Expr<?> falseExpr) {
|
||||
super(Order.Conditional, chStart, chEnd);
|
||||
public UnresolvedConditional(CodeLocation location, BoolExpr condition, Expr<?> trueExpr, Expr<?> falseExpr) {
|
||||
super(Order.Conditional, location);
|
||||
this.condition = condition;
|
||||
this.trueExpr = trueExpr;
|
||||
this.falseExpr = falseExpr;
|
||||
|
@ -36,8 +36,8 @@ public class UnresolvedConditional extends DynamicExpr {
|
|||
Expr<?> falseExpr = this.falseExpr.optimize();
|
||||
if (condition instanceof BoolLiteral literal) return literal.value ? trueExpr.asDynamicExpr() : falseExpr.asDynamicExpr();
|
||||
if (trueExpr.equals(falseExpr)) return trueExpr.asDynamicExpr();
|
||||
if (condition instanceof Not not) return new UnresolvedConditional(chStart, chEnd, not.inner, falseExpr, trueExpr);
|
||||
return new UnresolvedConditional(chStart, chEnd, condition, trueExpr, falseExpr);
|
||||
if (condition instanceof Not not) return new UnresolvedConditional(location, not.inner, falseExpr, trueExpr);
|
||||
return new UnresolvedConditional(location, condition, trueExpr, falseExpr);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,22 +60,22 @@ public class UnresolvedConditional extends DynamicExpr {
|
|||
|
||||
@Override
|
||||
public DynamicExpr asDynamicExpr() {
|
||||
return new DynamicConditional(chStart, chEnd, condition, trueExpr.asDynamicExpr(), falseExpr.asDynamicExpr());
|
||||
return new DynamicConditional(location, condition, trueExpr.asDynamicExpr(), falseExpr.asDynamicExpr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoolExpr asBoolExpr() {
|
||||
return new BoolConditional(chStart, chEnd, condition, trueExpr.asBoolExpr(), falseExpr.asBoolExpr());
|
||||
return new BoolConditional(location, condition, trueExpr.asBoolExpr(), falseExpr.asBoolExpr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringExpr asStringExpr() {
|
||||
return new StringConditional(chStart, chEnd, condition, trueExpr.asStringExpr(), falseExpr.asStringExpr());
|
||||
return new StringConditional(location, condition, trueExpr.asStringExpr(), falseExpr.asStringExpr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberExpr asNumberExpr() {
|
||||
return new NumberConditional(chStart, chEnd, condition, trueExpr.asNumberExpr(), falseExpr.asNumberExpr());
|
||||
return new NumberConditional(location, condition, trueExpr.asNumberExpr(), falseExpr.asNumberExpr());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,8 +14,8 @@ public class Bind extends DynamicExpr {
|
|||
public final DynamicExpr callable;
|
||||
public final DynamicExpr parameter;
|
||||
|
||||
public Bind(int chStart, int chEnd, DynamicExpr callable, DynamicExpr parameter) {
|
||||
super(Order.Call, chStart, chEnd);
|
||||
public Bind(CodeLocation location, DynamicExpr callable, DynamicExpr parameter) {
|
||||
super(Order.Call, location);
|
||||
this.callable = callable;
|
||||
this.parameter = parameter;
|
||||
}
|
||||
|
@ -47,6 +47,6 @@ public class Bind extends DynamicExpr {
|
|||
|
||||
@Override
|
||||
public DynamicExpr optimize() {
|
||||
return new Bind(chStart, chEnd, callable.optimize(), parameter.optimize());
|
||||
return new Bind(location, callable.optimize(), parameter.optimize());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,7 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
|
|||
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
|
||||
import io.gitlab.jfronny.muscript.annotations.CanThrow;
|
||||
import io.gitlab.jfronny.muscript.annotations.UncheckedDynamic;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.*;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.additional.DFinal;
|
||||
|
@ -21,8 +20,8 @@ public class Call extends DynamicExpr {
|
|||
public final DynamicExpr left;
|
||||
public final List<Arg> args;
|
||||
|
||||
public Call(int chStart, int chEnd, DynamicExpr left, List<Arg> args) {
|
||||
super(Order.Call, chStart, chEnd);
|
||||
public Call(CodeLocation location, DynamicExpr left, List<Arg> args) {
|
||||
super(Order.Call, location);
|
||||
this.left = left;
|
||||
this.args = args;
|
||||
}
|
||||
|
@ -36,18 +35,18 @@ public class Call extends DynamicExpr {
|
|||
.asCallable();
|
||||
arg = DFinal.of(args.stream().flatMap(e -> e.get(dataRoot)).toArray(Dynamic[]::new));
|
||||
} catch (DynamicTypeConversionException e) {
|
||||
throw e.locational(chStart, chEnd);
|
||||
throw e.locational(location);
|
||||
} catch (RuntimeException e) {
|
||||
throw new LocationalException(chStart, chEnd, "Could not perform call successfully", e);
|
||||
throw new LocationalException(location, "Could not perform call successfully", e);
|
||||
}
|
||||
try {
|
||||
return dc.getValue().apply(arg);
|
||||
} catch (LocationalException le) {
|
||||
throw le.appendStack(new StackFrame.Raw(dc.getName(), left.chStart));
|
||||
throw le.appendStack(new StackFrame.Raw(location.file(), dc.getName(), left.location.chStart()));
|
||||
} catch (DynamicTypeConversionException e) {
|
||||
throw e.locational(chStart, chEnd);
|
||||
throw e.locational(location);
|
||||
} catch (RuntimeException e) {
|
||||
throw new LocationalException(chStart, chEnd, "Could not perform call successfully", e);
|
||||
throw new LocationalException(location, "Could not perform call successfully", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -60,7 +59,7 @@ public class Call extends DynamicExpr {
|
|||
args.add(new Arg(bind.parameter, false));
|
||||
}
|
||||
for (Arg arg : this.args) args.add(arg.optimize());
|
||||
return new Call(chStart, chEnd, left, args);
|
||||
return new Call(location, left, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,12 +19,12 @@ public class Closure extends DynamicExpr {
|
|||
private final DynamicExpr fin;
|
||||
private final boolean variadic;
|
||||
|
||||
public Closure(int chStart, int chEnd, List<String> boundArgs, List<Expr<?>> expressions, boolean variadic) {
|
||||
this(chStart, chEnd, boundArgs, expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr(), variadic);
|
||||
public Closure(CodeLocation location, List<String> boundArgs, List<Expr<?>> expressions, boolean variadic) {
|
||||
this(location, boundArgs, expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr(), variadic);
|
||||
}
|
||||
|
||||
private Closure(int chStart, int chEnd, List<String> boundArgs, List<Expr<?>> steps, DynamicExpr fin, boolean variadic) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
private Closure(CodeLocation location, List<String> boundArgs, List<Expr<?>> steps, DynamicExpr fin, boolean variadic) {
|
||||
super(Order.Primary, location);
|
||||
this.boundArgs = List.copyOf(boundArgs);
|
||||
this.steps = List.copyOf(steps);
|
||||
this.fin = fin;
|
||||
|
@ -37,8 +37,8 @@ public class Closure extends DynamicExpr {
|
|||
int ac = args.size();
|
||||
int ae = boundArgs.size();
|
||||
if (variadic) ae--;
|
||||
if (ac < ae) throw new LocationalException(chStart, chEnd, "Invoked with too few arguments (expected " + ae + " but got " + ac + ")");
|
||||
if (!variadic && ac > ae) throw new LocationalException(chStart, chEnd, "Invoked with too many arguments (expected " + ae + " but got " + ac + ")");
|
||||
if (ac < ae) throw new LocationalException(location, "Invoked with too few arguments (expected " + ae + " but got " + ac + ")");
|
||||
if (!variadic && ac > ae) throw new LocationalException(location, "Invoked with too many arguments (expected " + ae + " but got " + ac + ")");
|
||||
Scope fork = dataRoot.fork();
|
||||
for (int i = 0; i < ae; i++) fork.set(boundArgs.get(i), args.get(i));
|
||||
if (variadic) {
|
||||
|
@ -56,7 +56,7 @@ public class Closure extends DynamicExpr {
|
|||
@Override
|
||||
public DynamicExpr optimize() {
|
||||
// Eliminating side effect free steps might be possible, but would be too much work imo
|
||||
return new Closure(chStart, chEnd, boundArgs, steps.stream().<Expr<?>>map(Expr::optimize).toList(), fin.optimize(), variadic);
|
||||
return new Closure(location, boundArgs, steps.stream().<Expr<?>>map(Expr::optimize).toList(), fin.optimize(), variadic);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.gitlab.jfronny.muscript.ast.dynamic;
|
|||
|
||||
import io.gitlab.jfronny.muscript.ast.*;
|
||||
import io.gitlab.jfronny.muscript.ast.dynamic.unpack.*;
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.*;
|
||||
|
@ -12,8 +13,8 @@ import java.io.IOException;
|
|||
public class DynamicCoerce extends DynamicExpr {
|
||||
public final Expr<?> inner;
|
||||
|
||||
public DynamicCoerce(int chStart, int chEnd, Expr<?> inner) {
|
||||
super(inner.order, chStart, chEnd);
|
||||
public DynamicCoerce(CodeLocation location, Expr<?> inner) {
|
||||
super(inner.order, location);
|
||||
this.inner = inner;
|
||||
if (!(inner instanceof DynamicExpr)
|
||||
&& !(inner instanceof BoolExpr)
|
||||
|
@ -40,7 +41,7 @@ public class DynamicCoerce extends DynamicExpr {
|
|||
if (inner instanceof BoolUnpack unpack) return unpack.inner;
|
||||
if (inner instanceof NumberUnpack unpack) return unpack.inner;
|
||||
if (inner instanceof StringUnpack unpack) return unpack.inner;
|
||||
return new DynamicCoerce(chStart, chEnd, inner);
|
||||
return new DynamicCoerce(location, inner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -18,12 +18,12 @@ public class Get extends DynamicExpr {
|
|||
private final DynamicExpr left;
|
||||
private final Expr<?> name;
|
||||
|
||||
public Get(int chStart, int chEnd, DynamicExpr left, Expr<?> name) {
|
||||
super(Order.Call, chStart, chEnd);
|
||||
public Get(CodeLocation location, DynamicExpr left, Expr<?> name) {
|
||||
super(Order.Call, location);
|
||||
this.left = left;
|
||||
this.name = name;
|
||||
if (name.getResultType() != Type.String && name.getResultType() != Type.Number && name.getResultType() != Type.Dynamic) {
|
||||
throw new TypeMismatchException(chStart, chEnd, Type.String, name.getResultType(), "Name must be either a string or a number");
|
||||
throw new TypeMismatchException(location, Type.String, name.getResultType(), "Name must be either a string or a number");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,14 +35,14 @@ public class Get extends DynamicExpr {
|
|||
} else if (left instanceof DList l) {
|
||||
return l.get(name.asNumberExpr().get(dataRoot).intValue());
|
||||
}
|
||||
throw new DynamicTypeConversionException("object or list", left).locational(chStart, chEnd);
|
||||
throw new DynamicTypeConversionException("object or list", left).locational(location);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DynamicExpr optimize() {
|
||||
DynamicExpr left = this.left.optimize();
|
||||
Expr<?> name = this.name.optimize();
|
||||
return new Get(chStart, chEnd, left, name);
|
||||
return new Get(location, left, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,8 +14,8 @@ import java.util.Map;
|
|||
public class ObjectLiteral extends DynamicExpr {
|
||||
public final Map<String, DynamicExpr> content;
|
||||
|
||||
public ObjectLiteral(int chStart, int chEnd, Map<String, DynamicExpr> content) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
public ObjectLiteral(CodeLocation location, Map<String, DynamicExpr> content) {
|
||||
super(Order.Primary, location);
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
|
@ -37,8 +37,8 @@ public class ObjectLiteral extends DynamicExpr {
|
|||
else literal = false;
|
||||
content.put(entry.getKey(), de);
|
||||
}
|
||||
if (literal) return new DynamicLiteral<>(chStart, chEnd, DFinal.of(literalContent));
|
||||
return new ObjectLiteral(chStart, chEnd, content);
|
||||
if (literal) return new DynamicLiteral<>(location, DFinal.of(literalContent));
|
||||
return new ObjectLiteral(location, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -15,8 +15,8 @@ import java.io.IOException;
|
|||
public class Variable extends DynamicExpr {
|
||||
public final String name;
|
||||
|
||||
public Variable(int chStart, int chEnd, String name) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
public Variable(CodeLocation location, String name) {
|
||||
super(Order.Primary, location);
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,7 @@ public class Variable extends DynamicExpr {
|
|||
public Dynamic<?> get(Scope dataRoot) {
|
||||
if (name.equals("this")) return dataRoot;
|
||||
if (dataRoot.has(name)) return dataRoot.get(name);
|
||||
else throw new LocationalException(chStart, chEnd, "This object doesn't contain '" + name + "'");
|
||||
else throw new LocationalException(location, "This object doesn't contain '" + name + "'");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.dynamic.assign;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.error.LocationalException;
|
||||
|
||||
|
@ -12,9 +11,9 @@ public class BoolAssign extends BoolExpr {
|
|||
private final String name;
|
||||
private final BoolExpr value;
|
||||
|
||||
protected BoolAssign(int chStart, int chEnd, String name, BoolExpr value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
if (name.equals("this")) throw new LocationalException(chStart, chEnd, "Cannot reassign 'this'");
|
||||
protected BoolAssign(CodeLocation location, String name, BoolExpr value) {
|
||||
super(Order.Primary, location);
|
||||
if (name.equals("this")) throw new LocationalException(location, "Cannot reassign 'this'");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
@ -28,7 +27,7 @@ public class BoolAssign extends BoolExpr {
|
|||
|
||||
@Override
|
||||
public BoolExpr optimize() {
|
||||
return new BoolAssign(chStart, chEnd, name, value.optimize());
|
||||
return new BoolAssign(location, name, value.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,9 +13,9 @@ public class DynamicAssign extends DynamicExpr {
|
|||
private final String name;
|
||||
private final DynamicExpr value;
|
||||
|
||||
public DynamicAssign(int chStart, int chEnd, String name, DynamicExpr value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
if (name.equals("this")) throw new LocationalException(chStart, chEnd, "Cannot reassign 'this'");
|
||||
public DynamicAssign(CodeLocation location, String name, DynamicExpr value) {
|
||||
super(Order.Primary, location);
|
||||
if (name.equals("this")) throw new LocationalException(location, "Cannot reassign 'this'");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ public class DynamicAssign extends DynamicExpr {
|
|||
|
||||
@Override
|
||||
public DynamicExpr optimize() {
|
||||
return new DynamicAssign(chStart, chEnd, name, value.optimize());
|
||||
return new DynamicAssign(location, name, value.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -40,17 +40,17 @@ public class DynamicAssign extends DynamicExpr {
|
|||
|
||||
@Override
|
||||
public BoolExpr asBoolExpr() {
|
||||
return new BoolAssign(chStart, chEnd, name, value.asBoolExpr());
|
||||
return new BoolAssign(location, name, value.asBoolExpr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StringExpr asStringExpr() {
|
||||
return new StringAssign(chStart, chEnd, name, value.asStringExpr());
|
||||
return new StringAssign(location, name, value.asStringExpr());
|
||||
}
|
||||
|
||||
@Override
|
||||
public NumberExpr asNumberExpr() {
|
||||
return new NumberAssign(chStart, chEnd, name, value.asNumberExpr());
|
||||
return new NumberAssign(location, name, value.asNumberExpr());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.dynamic.assign;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.error.LocationalException;
|
||||
|
||||
|
@ -12,9 +11,9 @@ public class NumberAssign extends NumberExpr {
|
|||
private final String name;
|
||||
private final NumberExpr value;
|
||||
|
||||
protected NumberAssign(int chStart, int chEnd, String name, NumberExpr value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
if (name.equals("this")) throw new LocationalException(chStart, chEnd, "Cannot reassign 'this'");
|
||||
protected NumberAssign(CodeLocation location, String name, NumberExpr value) {
|
||||
super(Order.Primary, location);
|
||||
if (name.equals("this")) throw new LocationalException(location, "Cannot reassign 'this'");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
@ -28,7 +27,7 @@ public class NumberAssign extends NumberExpr {
|
|||
|
||||
@Override
|
||||
public NumberExpr optimize() {
|
||||
return new NumberAssign(chStart, chEnd, name, value.optimize());
|
||||
return new NumberAssign(location, name, value.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.dynamic.assign;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.StringExpr;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.error.LocationalException;
|
||||
|
||||
|
@ -12,9 +11,9 @@ public class StringAssign extends StringExpr {
|
|||
private final String name;
|
||||
private final StringExpr value;
|
||||
|
||||
protected StringAssign(int chStart, int chEnd, String name, StringExpr value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
if (name.equals("this")) throw new LocationalException(chStart, chEnd, "Cannot reassign 'this'");
|
||||
protected StringAssign(CodeLocation location, String name, StringExpr value) {
|
||||
super(Order.Primary, location);
|
||||
if (name.equals("this")) throw new LocationalException(location, "Cannot reassign 'this'");
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
@ -28,7 +27,7 @@ public class StringAssign extends StringExpr {
|
|||
|
||||
@Override
|
||||
public StringExpr optimize() {
|
||||
return new StringAssign(chStart, chEnd, name, value.optimize());
|
||||
return new StringAssign(location, name, value.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.dynamic.unpack;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.DynamicTypeConversionException;
|
||||
|
@ -16,8 +17,8 @@ import java.io.IOException;
|
|||
public class BoolUnpack extends BoolExpr {
|
||||
public final DynamicExpr inner;
|
||||
|
||||
public BoolUnpack(int chStart, int chEnd, DynamicExpr inner) {
|
||||
super(inner.order, chStart, chEnd);
|
||||
public BoolUnpack(CodeLocation location, DynamicExpr inner) {
|
||||
super(inner.order, location);
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
|
@ -26,7 +27,7 @@ public class BoolUnpack extends BoolExpr {
|
|||
try {
|
||||
return inner.get(dataRoot).asBool().getValue();
|
||||
} catch (DynamicTypeConversionException e) {
|
||||
throw e.locational(chStart, chEnd);
|
||||
throw e.locational(location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +35,7 @@ public class BoolUnpack extends BoolExpr {
|
|||
public BoolExpr optimize() {
|
||||
DynamicExpr inner = this.inner.optimize();
|
||||
if (inner instanceof DynamicCoerce coerce) return coerce.inner.asBoolExpr();
|
||||
return new BoolUnpack(chStart, chEnd, inner);
|
||||
return new BoolUnpack(location, inner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.dynamic.unpack;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.DynamicTypeConversionException;
|
||||
|
@ -16,8 +17,8 @@ import java.io.IOException;
|
|||
public class NumberUnpack extends NumberExpr {
|
||||
public final DynamicExpr inner;
|
||||
|
||||
public NumberUnpack(int chStart, int chEnd, DynamicExpr inner) {
|
||||
super(inner.order, chStart, chEnd);
|
||||
public NumberUnpack(CodeLocation location, DynamicExpr inner) {
|
||||
super(inner.order, location);
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
|
@ -26,7 +27,7 @@ public class NumberUnpack extends NumberExpr {
|
|||
try {
|
||||
return inner.get(dataRoot).asNumber().getValue();
|
||||
} catch (DynamicTypeConversionException e) {
|
||||
throw e.locational(chStart, chEnd);
|
||||
throw e.locational(location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +35,7 @@ public class NumberUnpack extends NumberExpr {
|
|||
public NumberExpr optimize() {
|
||||
DynamicExpr inner = this.inner.optimize();
|
||||
if (inner instanceof DynamicCoerce coerce) return coerce.inner.asNumberExpr();
|
||||
return new NumberUnpack(chStart, chEnd, inner.optimize());
|
||||
return new NumberUnpack(location, inner.optimize());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.dynamic.unpack;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.DynamicTypeConversionException;
|
||||
|
@ -16,8 +17,8 @@ import java.io.IOException;
|
|||
public class StringUnpack extends StringExpr {
|
||||
public final DynamicExpr inner;
|
||||
|
||||
public StringUnpack(int chStart, int chEnd, DynamicExpr inner) {
|
||||
super(inner.order, chStart, chEnd);
|
||||
public StringUnpack(CodeLocation location, DynamicExpr inner) {
|
||||
super(inner.order, location);
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
|
@ -26,7 +27,7 @@ public class StringUnpack extends StringExpr {
|
|||
try {
|
||||
return inner.get(dataRoot).asString().getValue();
|
||||
} catch (DynamicTypeConversionException e) {
|
||||
throw e.locational(chStart, chEnd);
|
||||
throw e.locational(location);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -34,7 +35,7 @@ public class StringUnpack extends StringExpr {
|
|||
public StringExpr optimize() {
|
||||
DynamicExpr inner = this.inner.optimize();
|
||||
if (inner instanceof DynamicCoerce coerce) return coerce.inner.asStringExpr();
|
||||
return new StringUnpack(chStart, chEnd, inner);
|
||||
return new StringUnpack(location, inner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.literal;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.BoolExpr;
|
||||
|
||||
|
@ -10,8 +9,8 @@ import java.io.IOException;
|
|||
public final class BoolLiteral extends BoolExpr {
|
||||
public final boolean value;
|
||||
|
||||
public BoolLiteral(int chStart, int chEnd, boolean value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
public BoolLiteral(CodeLocation location, boolean value) {
|
||||
super(Order.Primary, location);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.literal;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.data.dynamic.Dynamic;
|
||||
import io.gitlab.jfronny.muscript.ast.DynamicExpr;
|
||||
|
@ -11,8 +10,8 @@ import java.io.IOException;
|
|||
public final class DynamicLiteral<T> extends DynamicExpr {
|
||||
public final Dynamic<T> value;
|
||||
|
||||
public DynamicLiteral(int chStart, int chEnd, Dynamic<T> value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
public DynamicLiteral(CodeLocation location, Dynamic<T> value) {
|
||||
super(Order.Primary, location);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.literal;
|
||||
|
||||
import io.gitlab.jfronny.commons.StringFormatter;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
||||
|
@ -11,8 +10,8 @@ import java.io.IOException;
|
|||
public final class NumberLiteral extends NumberExpr {
|
||||
public final double value;
|
||||
|
||||
public NumberLiteral(int chStart, int chEnd, double value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
public NumberLiteral(CodeLocation location, double value) {
|
||||
super(Order.Primary, location);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.literal;
|
||||
|
||||
import io.gitlab.jfronny.muscript.ast.StringExpr;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -10,8 +9,8 @@ import java.io.IOException;
|
|||
public final class StringLiteral extends StringExpr {
|
||||
public final String value;
|
||||
|
||||
public StringLiteral(int chStart, int chEnd, String value) {
|
||||
super(Order.Primary, chStart, chEnd);
|
||||
public StringLiteral(CodeLocation location, String value) {
|
||||
super(Order.Primary, location);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.math;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -13,8 +12,8 @@ public class Divide extends NumberExpr {
|
|||
public final NumberExpr dividend;
|
||||
public final NumberExpr divisor;
|
||||
|
||||
public Divide(int chStart, int chEnd, NumberExpr dividend, NumberExpr divisor) {
|
||||
super(Order.Factor, chStart, chEnd);
|
||||
public Divide(CodeLocation location, NumberExpr dividend, NumberExpr divisor) {
|
||||
super(Order.Factor, location);
|
||||
this.dividend = dividend;
|
||||
this.divisor = divisor;
|
||||
}
|
||||
|
@ -29,10 +28,10 @@ public class Divide extends NumberExpr {
|
|||
NumberExpr dividend = this.dividend.optimize();
|
||||
NumberExpr divisor = this.divisor.optimize();
|
||||
if (dividend instanceof NumberLiteral litL && divisor instanceof NumberLiteral litR)
|
||||
return Expr.literal(chStart, chEnd, litL.value / litR.value);
|
||||
return literal(location, litL.value / litR.value);
|
||||
if (dividend instanceof Divide divide && divide.dividend instanceof NumberLiteral literal)
|
||||
return new Divide(chStart, chEnd, divide.dividend, new Multiply(divide.chStart, dividend.chEnd, divisor, literal)).optimize();
|
||||
return new Divide(chStart, chEnd, dividend, divisor);
|
||||
return new Divide(location, divide.dividend, new Multiply(divide.location, divisor, literal)).optimize();
|
||||
return new Divide(location, dividend, divisor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.math;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -12,8 +11,8 @@ import java.io.IOException;
|
|||
public class Invert extends NumberExpr {
|
||||
public final NumberExpr inner;
|
||||
|
||||
public Invert(int chStart, int chEnd, NumberExpr inner) {
|
||||
super(Order.Unary, chStart, chEnd);
|
||||
public Invert(CodeLocation location, NumberExpr inner) {
|
||||
super(Order.Unary, location);
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
|
@ -26,9 +25,9 @@ public class Invert extends NumberExpr {
|
|||
public NumberExpr optimize() {
|
||||
NumberExpr inner = this.inner.optimize();
|
||||
if (inner instanceof Invert invert) return invert.inner;
|
||||
if (inner instanceof NumberLiteral literal) return Expr.literal(chStart, chEnd, -literal.value);
|
||||
if (inner instanceof Minus minus) return new Minus(chStart, chEnd, minus.subtrahend, minus.minuend).optimize();
|
||||
return new Invert(chStart, chEnd, inner);
|
||||
if (inner instanceof NumberLiteral literal) return Expr.literal(location, -literal.value);
|
||||
if (inner instanceof Minus minus) return new Minus(location, minus.subtrahend, minus.minuend).optimize();
|
||||
return new Invert(location, inner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.math;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -13,8 +12,8 @@ public class Minus extends NumberExpr {
|
|||
public final NumberExpr minuend;
|
||||
public final NumberExpr subtrahend;
|
||||
|
||||
public Minus(int chStart, int chEnd, NumberExpr minuend, NumberExpr subtrahend) {
|
||||
super(Order.Term, chStart, chEnd);
|
||||
public Minus(CodeLocation location, NumberExpr minuend, NumberExpr subtrahend) {
|
||||
super(Order.Term, location);
|
||||
this.minuend = minuend;
|
||||
this.subtrahend = subtrahend;
|
||||
}
|
||||
|
@ -29,10 +28,15 @@ public class Minus extends NumberExpr {
|
|||
NumberExpr minuend = this.minuend.optimize();
|
||||
NumberExpr subtrahend = this.subtrahend.optimize();
|
||||
if (minuend instanceof NumberLiteral litM && subtrahend instanceof NumberLiteral litS)
|
||||
return Expr.literal(chStart, chEnd, litM.value - litS.value);
|
||||
return literal(location, litM.value - litS.value);
|
||||
if (minuend instanceof Minus minus)
|
||||
return new Minus(chStart, chEnd, minus.minuend, new Plus(minus.chStart, minus.chEnd, minus.subtrahend, subtrahend)).optimize();
|
||||
return new Minus(chStart, chEnd, minuend, subtrahend);
|
||||
return new Minus(location, minus.minuend, new Plus(minus.location, minus.subtrahend, subtrahend)).optimize();
|
||||
if (minuend instanceof Invert invM && subtrahend instanceof Invert invS)
|
||||
return new Minus(location, invS.inner, invM.inner);
|
||||
if (minuend instanceof Invert inv)
|
||||
return new Invert(location, new Plus(location, inv.inner, subtrahend)).optimize();
|
||||
if (subtrahend instanceof Invert inv) return new Plus(location, minuend, inv.inner).optimize();
|
||||
return new Minus(location, minuend, subtrahend);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.math;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -13,8 +12,8 @@ public class Modulo extends NumberExpr {
|
|||
private final NumberExpr dividend;
|
||||
private final NumberExpr divisor;
|
||||
|
||||
public Modulo(int chStart, int chEnd, NumberExpr dividend, NumberExpr divisor) {
|
||||
super(Order.Factor, chStart, chEnd);
|
||||
public Modulo(CodeLocation location, NumberExpr dividend, NumberExpr divisor) {
|
||||
super(Order.Factor, location);
|
||||
this.dividend = dividend;
|
||||
this.divisor = divisor;
|
||||
}
|
||||
|
@ -29,8 +28,8 @@ public class Modulo extends NumberExpr {
|
|||
NumberExpr dividend = this.dividend.optimize();
|
||||
NumberExpr divisor = this.divisor.optimize();
|
||||
if (dividend instanceof NumberLiteral litD && divisor instanceof NumberLiteral litS)
|
||||
return Expr.literal(chStart, chEnd, litD.value % litS.value);
|
||||
return new Modulo(chStart, chEnd, dividend, divisor);
|
||||
return Expr.literal(location, litD.value % litS.value);
|
||||
return new Modulo(location, dividend, divisor);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.math;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -13,8 +12,8 @@ public class Multiply extends NumberExpr {
|
|||
public final NumberExpr multiplier;
|
||||
public final NumberExpr multiplicand;
|
||||
|
||||
public Multiply(int chStart, int chEnd, NumberExpr multiplier, NumberExpr multiplicand) {
|
||||
super(Order.Factor, chStart, chEnd);
|
||||
public Multiply(CodeLocation location, NumberExpr multiplier, NumberExpr multiplicand) {
|
||||
super(Order.Factor, location);
|
||||
this.multiplier = multiplier;
|
||||
this.multiplicand = multiplicand;
|
||||
}
|
||||
|
@ -29,8 +28,8 @@ public class Multiply extends NumberExpr {
|
|||
NumberExpr multiplier = this.multiplier.optimize();
|
||||
NumberExpr multiplicand = this.multiplicand.optimize();
|
||||
if (multiplier instanceof NumberLiteral litEr && multiplicand instanceof NumberLiteral litAnd)
|
||||
return Expr.literal(chStart, chEnd, litEr.value * litAnd.value);
|
||||
return new Multiply(chStart, chEnd, multiplier, multiplicand);
|
||||
return literal(location, litEr.value * litAnd.value);
|
||||
return new Multiply(location, multiplier, multiplicand);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.math;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -13,8 +12,8 @@ public class Plus extends NumberExpr {
|
|||
public final NumberExpr augend;
|
||||
public final NumberExpr addend;
|
||||
|
||||
public Plus(int chStart, int chEnd, NumberExpr augend, NumberExpr addend) {
|
||||
super(Order.Term, chStart, chEnd);
|
||||
public Plus(CodeLocation location, NumberExpr augend, NumberExpr addend) {
|
||||
super(Order.Term, location);
|
||||
this.augend = augend;
|
||||
this.addend = addend;
|
||||
}
|
||||
|
@ -29,8 +28,12 @@ public class Plus extends NumberExpr {
|
|||
NumberExpr augend = this.augend.optimize();
|
||||
NumberExpr addend = this.addend.optimize();
|
||||
if (augend instanceof NumberLiteral litU && addend instanceof NumberLiteral litD)
|
||||
return Expr.literal(chStart, chEnd, litU.value + litD.value);
|
||||
return new Plus(chStart, chEnd, augend, addend);
|
||||
return literal(location, litU.value + litD.value);
|
||||
if (augend instanceof Invert invU && addend instanceof Invert invD)
|
||||
return new Invert(location, new Plus(location, invU.inner, invD.inner)).optimize();
|
||||
if (augend instanceof Invert inv) return new Minus(location, addend, inv.inner).optimize();
|
||||
if (addend instanceof Invert inv) return new Minus(location, augend, inv.inner).optimize();
|
||||
return new Plus(location, augend, addend);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.math;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.NumberExpr;
|
||||
|
@ -13,8 +12,8 @@ public class Power extends NumberExpr {
|
|||
private final NumberExpr base;
|
||||
private final NumberExpr exponent;
|
||||
|
||||
public Power(int chStart, int chEnd, NumberExpr base, NumberExpr exponent) {
|
||||
super(Order.Exp, chStart, chEnd);
|
||||
public Power(CodeLocation location, NumberExpr base, NumberExpr exponent) {
|
||||
super(Order.Exp, location);
|
||||
this.base = base;
|
||||
this.exponent = exponent;
|
||||
}
|
||||
|
@ -29,18 +28,18 @@ public class Power extends NumberExpr {
|
|||
NumberExpr base = this.base.optimize();
|
||||
NumberExpr exponent = this.exponent.optimize();
|
||||
if (base instanceof NumberLiteral litB && exponent instanceof NumberLiteral litE)
|
||||
return Expr.literal(chStart, chEnd, Math.pow(litB.value, litE.value));
|
||||
return literal(location, Math.pow(litB.value, litE.value));
|
||||
if (exponent instanceof NumberLiteral exp && base instanceof Multiply multiply) {
|
||||
if (multiply.multiplier instanceof NumberLiteral literal)
|
||||
return new Multiply(multiply.chStart, multiply.chEnd,
|
||||
Expr.literal(chStart, chEnd, Math.pow(literal.value, exp.value)),
|
||||
new Power(chStart, chEnd, multiply.multiplicand, exp));
|
||||
return new Multiply(multiply.location,
|
||||
literal(location, Math.pow(literal.value, exp.value)),
|
||||
new Power(location, multiply.multiplicand, exp));
|
||||
if (multiply.multiplicand instanceof NumberLiteral literal)
|
||||
return new Multiply(multiply.chStart, multiply.chEnd,
|
||||
Expr.literal(chStart, chEnd, Math.pow(literal.value, exp.value)),
|
||||
new Power(chStart, chEnd, multiply.multiplier, exp));
|
||||
return new Multiply(multiply.location,
|
||||
literal(location, Math.pow(literal.value, exp.value)),
|
||||
new Power(location, multiply.multiplier, exp));
|
||||
}
|
||||
return new Power(chStart, chEnd, base, exponent);
|
||||
return new Power(location, base, exponent);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.ast.string;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.compiler.Order;
|
||||
import io.gitlab.jfronny.muscript.compiler.*;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.Expr;
|
||||
import io.gitlab.jfronny.muscript.ast.StringExpr;
|
||||
|
@ -13,8 +12,8 @@ public class Concatenate extends StringExpr {
|
|||
public final StringExpr left;
|
||||
public final StringExpr right;
|
||||
|
||||
public Concatenate(int chStart, int chEnd, StringExpr left, StringExpr right) {
|
||||
super(Order.Concat, chStart, chEnd);
|
||||
public Concatenate(CodeLocation location, StringExpr left, StringExpr right) {
|
||||
super(Order.Concat, location);
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
}
|
||||
|
@ -29,14 +28,14 @@ public class Concatenate extends StringExpr {
|
|||
StringExpr left = this.left.optimize();
|
||||
StringExpr right = this.right.optimize();
|
||||
if (left instanceof StringLiteral litL && right instanceof StringLiteral litR)
|
||||
return Expr.literal(chStart, chEnd, litL.value + litR.value);
|
||||
return literal(location, litL.value + litR.value);
|
||||
if (right instanceof StringLiteral litR && left instanceof Concatenate concatenate && concatenate.right instanceof StringLiteral litL) {
|
||||
return new Concatenate(chStart, chEnd, concatenate.left, Expr.literal(concatenate.chStart, concatenate.chEnd, litL.value + litR.value));
|
||||
return new Concatenate(location, concatenate.left, literal(concatenate.location, litL.value + litR.value));
|
||||
}
|
||||
if (left instanceof StringLiteral litL && right instanceof Concatenate concatenate && concatenate.left instanceof StringLiteral litR) {
|
||||
return new Concatenate(chStart, chEnd, Expr.literal(concatenate.chStart, concatenate.chEnd, litL.value + litR.value), concatenate.right);
|
||||
return new Concatenate(location, literal(concatenate.location, litL.value + litR.value), concatenate.right);
|
||||
}
|
||||
return new Concatenate(chStart, chEnd, left, right);
|
||||
return new Concatenate(location, left, right);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.ast.string;
|
||||
|
||||
import io.gitlab.jfronny.commons.StringFormatter;
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.compiler.ExprWriter;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.ast.*;
|
||||
|
@ -11,8 +12,8 @@ import java.io.IOException;
|
|||
public class StringCoerce extends StringExpr {
|
||||
private final Expr<?> inner;
|
||||
|
||||
public StringCoerce(int chStart, int chEnd, Expr<?> inner) {
|
||||
super(inner.order, chStart, chEnd);
|
||||
public StringCoerce(CodeLocation location, Expr<?> inner) {
|
||||
super(inner.order, location);
|
||||
this.inner = inner;
|
||||
}
|
||||
|
||||
|
@ -24,12 +25,12 @@ public class StringCoerce extends StringExpr {
|
|||
@Override
|
||||
public StringExpr optimize() {
|
||||
Expr<?> inner = this.inner.optimize();
|
||||
if (inner instanceof NullLiteral) return Expr.literal(chStart, chEnd, "null");
|
||||
if (inner instanceof BoolLiteral expr) return Expr.literal(chStart, chEnd, StringFormatter.toString(expr.value));
|
||||
if (inner instanceof DynamicLiteral<?> expr) return Expr.literal(chStart, chEnd, StringFormatter.toString(expr.value));
|
||||
if (inner instanceof NumberLiteral expr) return Expr.literal(chStart, chEnd, StringFormatter.toString(expr.value));
|
||||
if (inner instanceof NullLiteral) return literal(location, "null");
|
||||
if (inner instanceof BoolLiteral expr) return literal(location, StringFormatter.toString(expr.value));
|
||||
if (inner instanceof DynamicLiteral<?> expr) return literal(location, StringFormatter.toString(expr.value));
|
||||
if (inner instanceof NumberLiteral expr) return literal(location, StringFormatter.toString(expr.value));
|
||||
if (inner instanceof StringExpr expr) return expr;
|
||||
return new StringCoerce(chStart, chEnd, inner);
|
||||
return new StringCoerce(location, inner);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package io.gitlab.jfronny.muscript.compiler;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -1,10 +1,13 @@
|
|||
package io.gitlab.jfronny.muscript.compiler;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// Heavily inspired by starscript
|
||||
public class Lexer {
|
||||
public final String file;
|
||||
|
||||
/**
|
||||
* The type of the token
|
||||
*/
|
||||
|
@ -20,7 +23,12 @@ public class Lexer {
|
|||
public int start, current;
|
||||
|
||||
public Lexer(String source) {
|
||||
this.source = source;
|
||||
this(source, null);
|
||||
}
|
||||
|
||||
public Lexer(String source, String file) {
|
||||
this.source = Objects.requireNonNull(source);
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -16,6 +16,7 @@ import io.gitlab.jfronny.muscript.error.*;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class Parser {
|
||||
private final Lexer lexer;
|
||||
|
@ -24,11 +25,56 @@ public class Parser {
|
|||
private final TokenData current = new TokenData();
|
||||
|
||||
public static Expr<?> parse(String source) {
|
||||
return new Parser(new Lexer(source)).parse().optimize();
|
||||
return parse(source, null);
|
||||
}
|
||||
|
||||
public static Expr<?> parse(String source, String file) {
|
||||
return new Parser(new Lexer(source, file)).parse().optimize();
|
||||
}
|
||||
|
||||
public static Script parseScript(String source) {
|
||||
return new Parser(new Lexer(source)).parseScript().optimize();
|
||||
return parseScript(source, null);
|
||||
}
|
||||
|
||||
public static Script parseScript(String source, String file) {
|
||||
return new Parser(new Lexer(source, file)).parseScript().optimize();
|
||||
}
|
||||
|
||||
public static Script parseMultiScript(String startFile, SourceFS filesystem) {
|
||||
return new Script(parseMultiScript(startFile, filesystem, new HashSet<>()).stream().flatMap(Script::stream).toList());
|
||||
}
|
||||
|
||||
private static List<Script> parseMultiScript(String startFile, SourceFS filesystem, Set<String> alreadyIncluded) {
|
||||
alreadyIncluded.add(startFile);
|
||||
boolean isIncludes = true;
|
||||
StringBuilder src = new StringBuilder();
|
||||
List<Script> includes = new LinkedList<>();
|
||||
int row = 0;
|
||||
final String includePrefix = "#include ";
|
||||
for (String s : filesystem.read(startFile).split("\n")) {
|
||||
row++;
|
||||
if (s.isBlank()) {
|
||||
src.append("\n");
|
||||
} else if (s.startsWith(includePrefix)) {
|
||||
if (isIncludes) {
|
||||
String file = s.substring(includePrefix.length());
|
||||
src.append("// include ").append(file).append("\n");
|
||||
if (!alreadyIncluded.contains(file)) {
|
||||
includes.addAll(parseMultiScript(file, filesystem, alreadyIncluded));
|
||||
}
|
||||
} else {
|
||||
throw new ParseException(LocationalError.builder()
|
||||
.setLocation(new LocationalError.Location(s, 0, row), new LocationalError.Location(s, s.length() - 1, row))
|
||||
.setMessage("Includes MUST be located at the top of the file")
|
||||
.build());
|
||||
}
|
||||
} else {
|
||||
isIncludes = false;
|
||||
src.append(s).append("\n");
|
||||
}
|
||||
}
|
||||
includes.add(parseScript(src.toString(), startFile));
|
||||
return includes;
|
||||
}
|
||||
|
||||
public Parser(Lexer lexer) {
|
||||
|
@ -73,7 +119,7 @@ public class Parser {
|
|||
} catch (RuntimeException e) {
|
||||
if (e instanceof ParseException) throw e;
|
||||
else if (e instanceof LocationalException le) {
|
||||
throw new ParseException(le.asPrintable(lexer.source), le.getCause());
|
||||
throw new ParseException(le.asPrintable(), le.getCause());
|
||||
} else throw error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -82,12 +128,11 @@ public class Parser {
|
|||
Expr<?> expr = and();
|
||||
|
||||
if (match(Token.QuestionMark)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
Expr<?> trueExpr = expression();
|
||||
consume(Token.Colon, "Expected ':' after first part of condition");
|
||||
Expr<?> falseExpr = expression();
|
||||
expr = new UnresolvedConditional(start, end, asBool(expr), trueExpr, falseExpr);
|
||||
expr = new UnresolvedConditional(location, asBool(expr), trueExpr, falseExpr);
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -97,10 +142,9 @@ public class Parser {
|
|||
Expr<?> expr = or();
|
||||
|
||||
while (match(Token.And)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
Expr<?> right = or();
|
||||
expr = new And(start, end, asBool(expr), asBool(right));
|
||||
expr = new And(location, asBool(expr), asBool(right));
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -110,10 +154,9 @@ public class Parser {
|
|||
Expr<?> expr = equality();
|
||||
|
||||
while (match(Token.Or)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
Expr<?> right = equality();
|
||||
expr = new Or(start, end, asBool(expr), asBool(right));
|
||||
expr = new Or(location, asBool(expr), asBool(right));
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -124,11 +167,10 @@ public class Parser {
|
|||
|
||||
while (match(Token.EqualEqual, Token.BangEqual)) {
|
||||
Token op = previous.token;
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
Expr<?> right = concat();
|
||||
BoolExpr e = new Equal(start, end, expr, right);
|
||||
if (op == Token.BangEqual) e = new Not(start, end, e);
|
||||
BoolExpr e = new Equal(location, expr, right);
|
||||
if (op == Token.BangEqual) e = new Not(location, e);
|
||||
expr = e;
|
||||
}
|
||||
|
||||
|
@ -139,10 +181,9 @@ public class Parser {
|
|||
Expr<?> expr = comparison();
|
||||
|
||||
while (match(Token.Concat)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
Expr<?> right = comparison();
|
||||
expr = new Concatenate(start, end, asString(expr), asString(right));
|
||||
expr = new Concatenate(location, asString(expr), asString(right));
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -153,14 +194,13 @@ public class Parser {
|
|||
|
||||
while (match(Token.Greater, Token.GreaterEqual, Token.Less, Token.LessEqual)) {
|
||||
Token op = previous.token;
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
NumberExpr right = asNumber(term());
|
||||
expr = switch (op) {
|
||||
case Greater -> new Greater(start, end, asNumber(expr), right);
|
||||
case GreaterEqual -> new Not(start, end, new Greater(start, end, right, asNumber(expr)));
|
||||
case Less -> new Greater(start, end, right, asNumber(expr));
|
||||
case LessEqual -> new Not(start, end, new Greater(start, end, asNumber(expr), right));
|
||||
case Greater -> new Greater(location, asNumber(expr), right);
|
||||
case GreaterEqual -> new Not(location, new Greater(location, right, asNumber(expr)));
|
||||
case Less -> new Greater(location, right, asNumber(expr));
|
||||
case LessEqual -> new Not(location, new Greater(location, asNumber(expr), right));
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
|
@ -173,12 +213,11 @@ public class Parser {
|
|||
|
||||
while (match(Token.Plus, Token.Minus)) {
|
||||
Token op = previous.token;
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
NumberExpr right = asNumber(factor());
|
||||
expr = switch (op) {
|
||||
case Plus -> new Plus(start, end, asNumber(expr), right);
|
||||
case Minus -> new Minus(start, end, asNumber(expr), right);
|
||||
case Plus -> new Plus(location, asNumber(expr), right);
|
||||
case Minus -> new Minus(location, asNumber(expr), right);
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
|
@ -191,13 +230,12 @@ public class Parser {
|
|||
|
||||
while (match(Token.Star, Token.Slash, Token.Percentage)) {
|
||||
Token op = previous.token;
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
NumberExpr right = asNumber(exp());
|
||||
expr = switch (op) {
|
||||
case Star -> new Multiply(start, end, asNumber(expr), right);
|
||||
case Slash -> new Divide(start, end, asNumber(expr), right);
|
||||
case Percentage -> new Modulo(start, end, asNumber(expr), right);
|
||||
case Star -> new Multiply(location, asNumber(expr), right);
|
||||
case Slash -> new Divide(location, asNumber(expr), right);
|
||||
case Percentage -> new Modulo(location, asNumber(expr), right);
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
|
@ -209,10 +247,9 @@ public class Parser {
|
|||
Expr<?> expr = unary();
|
||||
|
||||
while (match(Token.UpArrow)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
NumberExpr right = asNumber(unary());
|
||||
expr = new Power(start, end, asNumber(expr), right);
|
||||
expr = new Power(location, asNumber(expr), right);
|
||||
}
|
||||
|
||||
return expr;
|
||||
|
@ -221,12 +258,11 @@ public class Parser {
|
|||
private Expr<?> unary() {
|
||||
if (match(Token.Bang, Token.Minus)) {
|
||||
Token op = previous.token;
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
Expr<?> right = unary();
|
||||
return switch (op) {
|
||||
case Bang -> new Not(start, end, asBool(right));
|
||||
case Minus -> new Invert(start, end, asNumber(right));
|
||||
case Bang -> new Not(location, asBool(right));
|
||||
case Minus -> new Invert(location, asNumber(right));
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
}
|
||||
|
@ -238,26 +274,25 @@ public class Parser {
|
|||
Expr<?> expr = primary();
|
||||
|
||||
while (match(Token.LeftParen, Token.Dot, Token.LeftBracket, Token.DoubleColon)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
expr = switch (previous.token) {
|
||||
case LeftParen -> finishCall(start, end, expr);
|
||||
case LeftParen -> finishCall(location, expr);
|
||||
case Dot -> {
|
||||
TokenData name = consume(Token.Identifier, "Expected field name after '.'");
|
||||
yield new Get(start, end, asDynamic(expr), Expr.literal(name.start, name.current - 1, name.lexeme));
|
||||
yield new Get(location, asDynamic(expr), Expr.literal(name.location(), name.lexeme));
|
||||
}
|
||||
case DoubleColon -> {
|
||||
DynamicExpr callable;
|
||||
if (match(Token.Identifier)) {
|
||||
callable = new Variable(previous.start, previous.current - 1, previous.lexeme);
|
||||
callable = new Variable(previous.location(), previous.lexeme);
|
||||
} else if (match(Token.LeftParen)) {
|
||||
callable = expression().asDynamicExpr();
|
||||
consume(Token.RightParen, "Expected ')' after expression");
|
||||
} else throw error("Bind operator requires right side to be a literal identifier or to be wrapped in parentheses.");
|
||||
yield new Bind(start, end, callable, expr.asDynamicExpr());
|
||||
yield new Bind(location, callable, expr.asDynamicExpr());
|
||||
}
|
||||
case LeftBracket -> {
|
||||
expr = new Get(start, end, asDynamic(expr), expression());
|
||||
expr = new Get(location, asDynamic(expr), expression());
|
||||
consume(Token.RightBracket, "Expected closing bracket");
|
||||
yield expr;
|
||||
}
|
||||
|
@ -268,7 +303,7 @@ public class Parser {
|
|||
return expr;
|
||||
}
|
||||
|
||||
private Expr<?> finishCall(int start, int end, Expr<?> callee) {
|
||||
private Expr<?> finishCall(CodeLocation location, Expr<?> callee) {
|
||||
List<Call.Arg> args = new ArrayList<>(2);
|
||||
|
||||
if (!check(Token.RightParen)) {
|
||||
|
@ -278,20 +313,19 @@ public class Parser {
|
|||
}
|
||||
|
||||
consume(Token.RightParen, "Expected ')' after function arguments");
|
||||
return new Call(start, end, asDynamic(callee), args);
|
||||
return new Call(location, asDynamic(callee), args);
|
||||
}
|
||||
|
||||
private Expr<?> primary() {
|
||||
if (match(Token.Null)) return Expr.literalNull(previous.start, previous.current - 1);
|
||||
if (match(Token.String)) return Expr.literal(previous.start, previous.current - 1, previous.lexeme);
|
||||
if (match(Token.True, Token.False)) return Expr.literal(previous.start, previous.current - 1, previous.lexeme.equals("true"));
|
||||
if (match(Token.Number)) return Expr.literal(previous.start, previous.current - 1, Double.parseDouble(previous.lexeme));
|
||||
if (match(Token.Null)) return Expr.literalNull(previous.location());
|
||||
if (match(Token.String)) return Expr.literal(previous.location(), previous.lexeme);
|
||||
if (match(Token.True, Token.False)) return Expr.literal(previous.location(), previous.lexeme.equals("true"));
|
||||
if (match(Token.Number)) return Expr.literal(previous.location(), Double.parseDouble(previous.lexeme));
|
||||
if (match(Token.Identifier)) {
|
||||
int start = previous.start;
|
||||
int end = previous.current - 1;
|
||||
CodeLocation location = previous.location();
|
||||
String name = previous.lexeme;
|
||||
if (match(Token.Assign)) return new DynamicAssign(start, end, name, expression().asDynamicExpr());
|
||||
else return new Variable(start, end, name);
|
||||
if (match(Token.Assign)) return new DynamicAssign(location, name, expression().asDynamicExpr());
|
||||
else return new Variable(location, name);
|
||||
}
|
||||
|
||||
if (match(Token.LeftParen)) {
|
||||
|
@ -303,7 +337,7 @@ public class Parser {
|
|||
if (match(Token.LeftBrace)) {
|
||||
int start = previous.start;
|
||||
if (match(Token.Arrow)) return finishClosure(start, null, false);
|
||||
if (match(Token.RightBrace)) return new DynamicLiteral<>(start, previous.start, DFinal.of(Map.of()));
|
||||
if (match(Token.RightBrace)) return new DynamicLiteral<>(location(start, previous.start), DFinal.of(Map.of()));
|
||||
consume(Token.Identifier, "Expected arrow or identifier as first element in closure or object");
|
||||
String first = previous.lexeme;
|
||||
if (check(Token.Arrow)) return finishClosure(start, first, false);
|
||||
|
@ -345,7 +379,7 @@ public class Parser {
|
|||
match(Token.Semicolon); // Consume semicolon if present
|
||||
}
|
||||
int end = previous.start;
|
||||
return new Closure(start, end, boundArgs, expressions, variadic);
|
||||
return new Closure(location(start, end), boundArgs, expressions, variadic);
|
||||
}
|
||||
|
||||
private Expr<?> finishObject(int start, @Nullable String firstArg, @Nullable DynamicExpr firstValue) {
|
||||
|
@ -358,7 +392,7 @@ public class Parser {
|
|||
content.put(name, expression().asDynamicExpr());
|
||||
}
|
||||
consume(Token.RightBrace, "Expected end of object");
|
||||
return new ObjectLiteral(start, previous.start, content);
|
||||
return new ObjectLiteral(location(start, previous.start), content);
|
||||
}
|
||||
|
||||
// Type conversion
|
||||
|
@ -395,12 +429,16 @@ public class Parser {
|
|||
}
|
||||
|
||||
// Helpers
|
||||
private CodeLocation location(int chStart, int chEnd) {
|
||||
return new CodeLocation(chStart, chEnd, lexer.source, lexer.file);
|
||||
}
|
||||
|
||||
private ParseException error(String message) {
|
||||
return new ParseException(LocationalError.create(lexer.source, current.current - 1, message));
|
||||
}
|
||||
|
||||
private ParseException error(String message, Expr<?> expr) {
|
||||
return new ParseException(LocationalError.create(lexer.source, expr.chStart, expr.chEnd, message));
|
||||
return new ParseException(LocationalError.create(expr.location, message));
|
||||
}
|
||||
|
||||
private TokenData consume(Token token, String message) {
|
||||
|
@ -442,7 +480,7 @@ public class Parser {
|
|||
}
|
||||
|
||||
// Token data
|
||||
private static class TokenData {
|
||||
private class TokenData {
|
||||
public Token token;
|
||||
public String lexeme;
|
||||
public int start, current;
|
||||
|
@ -464,6 +502,10 @@ public class Parser {
|
|||
public String toString() {
|
||||
return String.format("%s '%s'", token, lexeme);
|
||||
}
|
||||
|
||||
public CodeLocation location() {
|
||||
return new CodeLocation(start, current - 1, lexer.source, lexer.file);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse Exception
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package io.gitlab.jfronny.muscript.compiler;
|
||||
|
||||
public interface SourceFS {
|
||||
String read(String file);
|
||||
}
|
|
@ -15,15 +15,21 @@ import java.util.stream.Stream;
|
|||
public class Script extends Decompilable {
|
||||
private final List<Expr<?>> steps;
|
||||
private final DynamicExpr fin;
|
||||
private final String file;
|
||||
|
||||
public Script(List<Expr<?>> expressions) {
|
||||
this(expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr());
|
||||
this(expressions, null);
|
||||
}
|
||||
|
||||
private Script(List<Expr<?>> steps, DynamicExpr fin) {
|
||||
public Script(List<Expr<?>> expressions, String file) {
|
||||
this(expressions.subList(0, expressions.size() - 1), expressions.get(expressions.size() - 1).asDynamicExpr(), file);
|
||||
}
|
||||
|
||||
private Script(List<Expr<?>> steps, DynamicExpr fin, String file) {
|
||||
super(Order.Script);
|
||||
this.steps = steps;
|
||||
this.fin = fin;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public Dynamic<?> run(DObject scope) {
|
||||
|
@ -45,11 +51,12 @@ public class Script extends Decompilable {
|
|||
}
|
||||
|
||||
public DynamicExpr asExpr() {
|
||||
return new Call(-1, -1, new Closure(-1, -1, List.of(), stream().toList(), false), List.of());
|
||||
CodeLocation location = CodeLocation.NONE.withFile(file);
|
||||
return new Call(location, new Closure(location, List.of(), stream().toList(), false), List.of());
|
||||
}
|
||||
|
||||
public Script optimize() {
|
||||
return new Script(steps.stream().<Expr<?>>map(Expr::optimize).toList(), fin.optimize());
|
||||
return new Script(steps.stream().<Expr<?>>map(Expr::optimize).toList(), fin.optimize(), file);
|
||||
}
|
||||
|
||||
public Script concat(Script other) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.data.dynamic;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.error.LocationalException;
|
||||
|
||||
public class DynamicTypeConversionException extends RuntimeException {
|
||||
|
@ -14,7 +15,7 @@ public class DynamicTypeConversionException extends RuntimeException {
|
|||
this.actual = dynamic.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public LocationalException locational(int start, int end) {
|
||||
return new LocationalException(start, end, MESSAGE1 + actual + MESSAGE2 + target, this);
|
||||
public LocationalException locational(CodeLocation location) {
|
||||
return new LocationalException(location, MESSAGE1 + actual + MESSAGE2 + target, this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
package io.gitlab.jfronny.muscript.error;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
//TODO maybe this can be eliminated since the source is now included?
|
||||
|
||||
/**
|
||||
* Class for storing errors with code context
|
||||
* Can be generated from a LocationalException with asPrintable
|
||||
|
@ -76,6 +79,17 @@ public record LocationalError(String message, Location start, @Nullable Location
|
|||
return builder().setSource(source).setLocation(start, end).setMessage(message).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an error by getting the relevant data from what is available while lexing/parsing
|
||||
*
|
||||
* @param location The location of the piece of code causing this
|
||||
* @param message The error message
|
||||
* @return An error using the provided information
|
||||
*/
|
||||
public static LocationalError create(CodeLocation location, String message) {
|
||||
return builder().setSource(location.source()).setLocation(location.chStart(), location.chEnd()).setMessage(message).build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts this error to a human-readable error message
|
||||
*
|
||||
|
@ -120,9 +134,7 @@ public record LocationalError(String message, Location start, @Nullable Location
|
|||
}
|
||||
|
||||
public Builder setLocation(int chStart) {
|
||||
start = Location.create(Objects.requireNonNull(source, "source is required to set location"), chStart);
|
||||
end = null;
|
||||
return this;
|
||||
return setLocation(Location.create(Objects.requireNonNull(source, "source is required to set location"), chStart), null);
|
||||
}
|
||||
|
||||
public Builder setLocation(int chStart, int chEnd) {
|
||||
|
@ -133,8 +145,12 @@ public record LocationalError(String message, Location start, @Nullable Location
|
|||
chEnd = chStart;
|
||||
chStart = a;
|
||||
}
|
||||
start = Location.create(source, chStart);
|
||||
end = Location.create(source, chEnd);
|
||||
return setLocation(Location.create(source, chStart), Location.create(source, chEnd));
|
||||
}
|
||||
|
||||
public Builder setLocation(Location start, Location end) {
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package io.gitlab.jfronny.muscript.error;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -8,37 +10,33 @@ import java.util.List;
|
|||
* For use in MuScript, can be converted to a pretty LocationalError with asPrintable
|
||||
*/
|
||||
public class LocationalException extends RuntimeException {
|
||||
private final int start, end;
|
||||
private final CodeLocation location;
|
||||
private final List<StackFrame> callStack = new LinkedList<>();
|
||||
|
||||
public LocationalException(int start, int end) {
|
||||
public LocationalException(CodeLocation location) {
|
||||
super();
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public LocationalException(int start, int end, String message) {
|
||||
public LocationalException(CodeLocation location, String message) {
|
||||
super(message);
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public LocationalException(int start, int end, String message, Throwable cause) {
|
||||
public LocationalException(CodeLocation location, String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public LocationalException(int start, int end, Throwable cause) {
|
||||
public LocationalException(CodeLocation location, Throwable cause) {
|
||||
super(cause);
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
this.location = location;
|
||||
}
|
||||
|
||||
public LocationalError asPrintable(String source) {
|
||||
public LocationalError asPrintable() {
|
||||
return LocationalError.builder()
|
||||
.setSource(source)
|
||||
.setLocation(start, end)
|
||||
.setSource(location.source())
|
||||
.setLocation(location.chStart(), location.chEnd())
|
||||
.setMessage(getLocalizedMessage())
|
||||
.setCallStack(callStack)
|
||||
.build();
|
||||
|
|
|
@ -1,23 +1,23 @@
|
|||
package io.gitlab.jfronny.muscript.error;
|
||||
|
||||
public sealed interface StackFrame {
|
||||
record Raw(String name, int chStart) implements StackFrame {
|
||||
record Raw(String file, String name, int chStart) implements StackFrame {
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (call: character " + chStart + ")";
|
||||
return name + " (call: character " + chStart + (file == null ? ")" : " in " + file + ")");
|
||||
}
|
||||
|
||||
public Lined lined(String source) {
|
||||
int lineStart = source.lastIndexOf('\n', chStart);
|
||||
int lineIndex = lineStart > 0 ? (int) source.substring(0, lineStart).chars().filter(c -> c == '\n').count() : 0;
|
||||
return new Lined(name, lineIndex + 1);
|
||||
return new Lined(file, name, lineIndex + 1);
|
||||
}
|
||||
}
|
||||
|
||||
record Lined(String name, int row) implements StackFrame {
|
||||
record Lined(String file, String name, int row) implements StackFrame {
|
||||
@Override
|
||||
public String toString() {
|
||||
return name + " (call: line " + row + ")";
|
||||
return name + " (call: line " + row + (file == null ? ")" : " in " + file + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package io.gitlab.jfronny.muscript.error;
|
||||
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.compiler.Type;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
@ -11,12 +12,12 @@ public class TypeMismatchException extends LocationalException {
|
|||
private final Type expected;
|
||||
private final @Nullable Type actual;
|
||||
|
||||
public TypeMismatchException(int start, int end, Type expected, @Nullable Type actual) {
|
||||
this(start, end, expected, actual, "Expected " + expected + (actual == null ? "" : " but got " + actual));
|
||||
public TypeMismatchException(CodeLocation location, Type expected, @Nullable Type actual) {
|
||||
this(location, expected, actual, "Expected " + expected + (actual == null ? "" : " but got " + actual));
|
||||
}
|
||||
|
||||
public TypeMismatchException(int start, int end, Type expected, @Nullable Type actual, String message) {
|
||||
super(start, end, message);
|
||||
public TypeMismatchException(CodeLocation location, Type expected, @Nullable Type actual, String message) {
|
||||
super(location, message);
|
||||
this.expected = expected;
|
||||
this.actual = actual;
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package io.gitlab.jfronny.muscript.test;
|
|||
import io.gitlab.jfronny.muscript.ast.StringExpr;
|
||||
import io.gitlab.jfronny.muscript.ast.dynamic.assign.DynamicAssign;
|
||||
import io.gitlab.jfronny.muscript.ast.literal.StringLiteral;
|
||||
import io.gitlab.jfronny.muscript.compiler.CodeLocation;
|
||||
import io.gitlab.jfronny.muscript.compiler.Parser;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.test.util.UnforkableScope;
|
||||
|
@ -15,7 +16,7 @@ class AssignTest {
|
|||
@Test
|
||||
void testAssignSimple() {
|
||||
StringExpr expr = Parser.parse("someval = 'test'").asStringExpr();
|
||||
assertEquals(new DynamicAssign(0, 6, "someval", new StringLiteral(10, 15, "test").asDynamicExpr()).asStringExpr(), expr);
|
||||
assertEquals(new DynamicAssign(new CodeLocation(0, 6), "someval", new StringLiteral(new CodeLocation(10, 15), "test").asDynamicExpr()).asStringExpr(), expr);
|
||||
assertEquals("someval = 'test'", expr.toString());
|
||||
Scope scope = new UnforkableScope();
|
||||
assertEquals("test", expr.get(scope));
|
||||
|
|
|
@ -2,6 +2,7 @@ package io.gitlab.jfronny.muscript.test;
|
|||
|
||||
import io.gitlab.jfronny.muscript.StandardLib;
|
||||
import io.gitlab.jfronny.muscript.compiler.Parser;
|
||||
import io.gitlab.jfronny.muscript.data.Scope;
|
||||
import io.gitlab.jfronny.muscript.error.LocationalException;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -9,9 +10,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
class StackTraceTest {
|
||||
@Test
|
||||
void stackTrace() {
|
||||
String source = """
|
||||
final String source = """
|
||||
someInner = { ->
|
||||
throw()
|
||||
}
|
||||
|
@ -23,18 +22,32 @@ class StackTraceTest {
|
|||
someOuter()
|
||||
""";
|
||||
|
||||
final Scope scope = StandardLib.createScope()
|
||||
.set("throw", args -> {
|
||||
throw new IllegalArgumentException("No");
|
||||
});
|
||||
|
||||
@Test
|
||||
void stackTrace() {
|
||||
assertEquals("""
|
||||
Error at '(' (character 8): Could not perform call successfully
|
||||
1 | throw()
|
||||
^-- Here
|
||||
at someInner (call: line 5)
|
||||
at someOuter (call: line 8)""",
|
||||
assertThrows(LocationalException.class, () -> Parser.parseScript(source)
|
||||
.run(StandardLib.createScope()
|
||||
.set("throw", args -> {
|
||||
throw new IllegalArgumentException("No");
|
||||
})
|
||||
))
|
||||
.asPrintable(source).toString());
|
||||
assertThrows(LocationalException.class, () -> Parser.parseScript(source).run(scope))
|
||||
.asPrintable().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
void stackTrace2() {
|
||||
assertEquals("""
|
||||
Error at '(' (character 8): Could not perform call successfully
|
||||
1 | throw()
|
||||
^-- Here
|
||||
at someInner (call: line 5 in some/file.mu)
|
||||
at someOuter (call: line 8 in some/file.mu)""",
|
||||
assertThrows(LocationalException.class, () -> Parser.parseScript(source, "some/file.mu").run(scope))
|
||||
.asPrintable().toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ class ValidExampleTest {
|
|||
} catch (Throwable t) {
|
||||
assertEquals(expectedResult, StringFormatter.toString(t, e ->
|
||||
e instanceof LocationalException le
|
||||
? le.asPrintable(source).toString()
|
||||
? le.asPrintable().toString()
|
||||
: e.toString()
|
||||
));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user