mirror of
https://github.com/PolyhedralDev/Terra.git
synced 2026-05-20 08:40:26 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4917160123 | |||
| d71f7d4c36 | |||
| 84898a7a6b | |||
| 0c1a6efc72 | |||
| 200281f140 | |||
| f1ea8074de | |||
| f896a9a278 | |||
| 79b3b34669 | |||
| 158deaa971 | |||
| e51e025e9c | |||
| 8e0d64dccd | |||
| 23f47de10a | |||
| 89651597c2 | |||
| 5c0c833b70 | |||
| 33d654dc8e | |||
| f0c602d7e7 | |||
| 0e37a839fe | |||
| 3f9ead0d66 | |||
| 5eeb5af6c4 |
@@ -1,4 +1,4 @@
|
||||
version = version("1.1.0")
|
||||
version = version("1.2.0")
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
|
||||
|
||||
+10
@@ -155,6 +155,16 @@ public class NoiseChunkGenerator3D implements ChunkGenerator {
|
||||
return biomeProvider.getBiome(x, y, z, world.getSeed()).getContext().get(paletteInfoPropertyKey).paletteHolder().getPalette(y);
|
||||
}
|
||||
|
||||
public double getSlant(int x, int y, int z, WorldProperties world, BiomeProvider biomeProvider) {
|
||||
int fdX = FastMath.floorMod(x, 16);
|
||||
int fdZ = FastMath.floorMod(z, 16);
|
||||
return biomeProvider.getBiome(x, y, z, world.getSeed())
|
||||
.getContext()
|
||||
.get(paletteInfoPropertyKey)
|
||||
.slantHolder()
|
||||
.calculateSlant(samplerCache.get(x, z, world, biomeProvider), fdX, y, fdZ);
|
||||
}
|
||||
|
||||
public SamplerProvider samplerProvider() {
|
||||
return samplerCache;
|
||||
}
|
||||
|
||||
+6
-1
@@ -14,6 +14,7 @@ import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.addons.noise.config.CubicSplinePointTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.DimensionApplicableNoiseSampler;
|
||||
import com.dfsek.terra.addons.noise.config.templates.BinaryArithmeticTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.DomainWarpTemplate;
|
||||
@@ -32,12 +33,14 @@ import com.dfsek.terra.addons.noise.config.templates.noise.fractal.BrownianMotio
|
||||
import com.dfsek.terra.addons.noise.config.templates.noise.fractal.PingPongTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.noise.fractal.RidgedFractalTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ClampNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.CubicSplineNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ExpressionNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.LinearNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.NormalNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.PosterizationNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ProbabilityNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.config.templates.normalizer.ScaleNormalizerTemplate;
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline;
|
||||
import com.dfsek.terra.addons.noise.samplers.arithmetic.AdditionSampler;
|
||||
import com.dfsek.terra.addons.noise.samplers.arithmetic.DivisionSampler;
|
||||
import com.dfsek.terra.addons.noise.samplers.arithmetic.MaxSampler;
|
||||
@@ -90,7 +93,8 @@ public class NoiseAddon implements AddonInitializer {
|
||||
.applyLoader(DistanceSampler.DistanceFunction.class,
|
||||
(type, o, loader, depthTracker) -> DistanceSampler.DistanceFunction.valueOf((String) o))
|
||||
.applyLoader(DimensionApplicableNoiseSampler.class, DimensionApplicableNoiseSampler::new)
|
||||
.applyLoader(FunctionTemplate.class, FunctionTemplate::new);
|
||||
.applyLoader(FunctionTemplate.class, FunctionTemplate::new)
|
||||
.applyLoader(CubicSpline.Point.class, CubicSplinePointTemplate::new);
|
||||
|
||||
noiseRegistry.register(addon.key("LINEAR"), LinearNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("NORMAL"), NormalNormalizerTemplate::new);
|
||||
@@ -98,6 +102,7 @@ public class NoiseAddon implements AddonInitializer {
|
||||
noiseRegistry.register(addon.key("PROBABILITY"), ProbabilityNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("SCALE"), ScaleNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("POSTERIZATION"), PosterizationNormalizerTemplate::new);
|
||||
noiseRegistry.register(addon.key("CUBIC_SPLINE"), CubicSplineNormalizerTemplate::new);
|
||||
|
||||
noiseRegistry.register(addon.key("IMAGE"), ImageSamplerTemplate::new);
|
||||
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
package com.dfsek.terra.addons.noise.config;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
|
||||
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline.Point;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
|
||||
|
||||
public class CubicSplinePointTemplate implements ObjectTemplate<Point> {
|
||||
|
||||
@Value("from")
|
||||
private @Meta double from;
|
||||
|
||||
@Value("to")
|
||||
private @Meta double to;
|
||||
|
||||
@Value("gradient")
|
||||
private @Meta double gradient;
|
||||
|
||||
@Override
|
||||
public Point get() {
|
||||
return new Point(from, to, gradient);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.dfsek.terra.addons.noise.config.templates.normalizer;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline;
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline.Point;
|
||||
import com.dfsek.terra.addons.noise.normalizer.CubicSplineNoiseSampler;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
import com.dfsek.terra.api.noise.NoiseSampler;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class CubicSplineNormalizerTemplate extends NormalizerTemplate<CubicSplineNoiseSampler> {
|
||||
|
||||
@Value("points")
|
||||
private @Meta List<@Meta Point> points;
|
||||
|
||||
@Override
|
||||
public NoiseSampler get() {
|
||||
return new CubicSplineNoiseSampler(function, new CubicSpline(points));
|
||||
}
|
||||
}
|
||||
+89
@@ -0,0 +1,89 @@
|
||||
package com.dfsek.terra.addons.noise.math;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class CubicSpline {
|
||||
|
||||
private final double[] fromValues;
|
||||
private final double[] toValues;
|
||||
private final double[] gradients;
|
||||
|
||||
public CubicSpline(List<Point> points) {
|
||||
Collections.sort(points);
|
||||
|
||||
this.fromValues = new double[points.size()];
|
||||
this.toValues = new double[points.size()];
|
||||
this.gradients = new double[points.size()];
|
||||
|
||||
for(int i = 0; i < points.size(); i++) {
|
||||
fromValues[i] = points.get(i).from;
|
||||
toValues[i] = points.get(i).to;
|
||||
gradients[i] = points.get(i).gradient;
|
||||
}
|
||||
}
|
||||
|
||||
public double apply(double in) {
|
||||
return calculate(in, fromValues, toValues, gradients);
|
||||
}
|
||||
|
||||
public static double calculate(double in, double[] fromValues, double[] toValues, double[] gradients) {
|
||||
int pointIdx = floorBinarySearch(in, fromValues) - 1;
|
||||
|
||||
int pointIdxLast = fromValues.length - 1;
|
||||
|
||||
if (pointIdx < 0) { // If to left of first point return linear function intersecting said point using point's gradient
|
||||
return gradients[0] * (in - fromValues[0]) + toValues[0];
|
||||
} else if (pointIdx == pointIdxLast) { // Do same if to right of last point
|
||||
return gradients[pointIdxLast] * (in - fromValues[pointIdxLast]) + toValues[pointIdxLast];
|
||||
} else {
|
||||
double fromLeft = fromValues[pointIdx];
|
||||
double fromRight = fromValues[pointIdx + 1];
|
||||
|
||||
double toLeft = toValues[pointIdx];
|
||||
double toRight = toValues[pointIdx + 1];
|
||||
|
||||
double gradientLeft = gradients[pointIdx];
|
||||
double gradientRight = gradients[pointIdx + 1];
|
||||
|
||||
double fromDelta = fromRight - fromLeft;
|
||||
double toDelta = toRight - toLeft;
|
||||
|
||||
double t = (in - fromLeft) / fromDelta;
|
||||
|
||||
return lerp(t, toLeft, toRight) + t * (1.0F - t) * lerp(t, gradientLeft * fromDelta - toDelta, -gradientRight * fromDelta + toDelta);
|
||||
}
|
||||
}
|
||||
|
||||
private static int floorBinarySearch(double targetValue, double[] values) {
|
||||
int left = 0;
|
||||
int right = values.length;
|
||||
int idx = right - left;
|
||||
while (idx > 0) {
|
||||
int halfDelta = idx / 2;
|
||||
int mid = left + halfDelta;
|
||||
if (targetValue < values[mid]) {
|
||||
idx = halfDelta;
|
||||
} else {
|
||||
left = mid + 1;
|
||||
idx -= halfDelta + 1;
|
||||
}
|
||||
}
|
||||
return left;
|
||||
}
|
||||
|
||||
private static double lerp(double t, double a, double b) {
|
||||
return a + t * (b - a);
|
||||
}
|
||||
|
||||
public record Point(double from, double to, double gradient) implements Comparable<Point> {
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull CubicSpline.Point o) {
|
||||
return Double.compare(from, o.from);
|
||||
}
|
||||
}
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package com.dfsek.terra.addons.noise.normalizer;
|
||||
|
||||
import com.dfsek.terra.addons.noise.math.CubicSpline;
|
||||
import com.dfsek.terra.api.noise.NoiseSampler;
|
||||
|
||||
|
||||
public class CubicSplineNoiseSampler extends Normalizer {
|
||||
|
||||
private final CubicSpline spline;
|
||||
|
||||
public CubicSplineNoiseSampler(NoiseSampler sampler, CubicSpline spline) {
|
||||
super(sampler);
|
||||
this.spline = spline;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double normalize(double in) {
|
||||
return spline.apply(in);
|
||||
}
|
||||
}
|
||||
+68
-200
@@ -240,99 +240,37 @@ public class CellularSampler extends NoiseFunction {
|
||||
double centerX = x;
|
||||
double centerY = y;
|
||||
|
||||
switch(distanceFunction) {
|
||||
default:
|
||||
case Euclidean:
|
||||
case EuclideanSq:
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed);
|
||||
int idx = hash & (255 << 1);
|
||||
|
||||
double vecX = (xi - x) + RAND_VECS_2D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_2D[idx | 1] * cellularJitter;
|
||||
|
||||
double newDistance = vecX * vecX + vecY * vecY;
|
||||
|
||||
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_2D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed);
|
||||
int idx = hash & (255 << 1);
|
||||
|
||||
double vecX = (xi - x) + RAND_VECS_2D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_2D[idx | 1] * cellularJitter;
|
||||
|
||||
double newDistance = switch(distanceFunction) {
|
||||
case Manhattan -> fastAbs(vecX) + fastAbs(vecY);
|
||||
case Hybrid -> (fastAbs(vecX) + fastAbs(vecY)) + (vecX * vecX + vecY * vecY);
|
||||
default -> vecX * vecX + vecY * vecY;
|
||||
};
|
||||
|
||||
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_2D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
break;
|
||||
case Manhattan:
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed);
|
||||
int idx = hash & (255 << 1);
|
||||
|
||||
double vecX = (xi - x) + RAND_VECS_2D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_2D[idx | 1] * cellularJitter;
|
||||
|
||||
double newDistance = fastAbs(vecX) + fastAbs(vecY);
|
||||
|
||||
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_2D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
}
|
||||
break;
|
||||
case Hybrid:
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed);
|
||||
int idx = hash & (255 << 1);
|
||||
|
||||
double vecX = (xi - x) + RAND_VECS_2D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_2D[idx | 1] * cellularJitter;
|
||||
|
||||
double newDistance = (fastAbs(vecX) + fastAbs(vecY)) + (vecX * vecX + vecY * vecY);
|
||||
|
||||
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_2D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_2D[idx | 1] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
}
|
||||
break;
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
}
|
||||
|
||||
if(distanceFunction == DistanceFunction.Euclidean && returnType != ReturnType.CellValue) {
|
||||
@@ -351,6 +289,7 @@ public class CellularSampler extends NoiseFunction {
|
||||
case Distance2Mul -> distance1 * distance0 * 0.5 - 1;
|
||||
case Distance2Div -> distance0 / distance1 - 1;
|
||||
case NoiseLookup -> noiseLookup.noise(sl, centerX, centerY);
|
||||
case LocalNoiseLookup -> noiseLookup.noise(sl, x / frequency - centerX, y / frequency - centerY);
|
||||
case Distance3 -> distance2 - 1;
|
||||
case Distance3Add -> (distance2 + distance0) * 0.5 - 1;
|
||||
case Distance3Sub -> distance2 - distance0 - 1;
|
||||
@@ -382,120 +321,47 @@ public class CellularSampler extends NoiseFunction {
|
||||
double centerY = y;
|
||||
double centerZ = z;
|
||||
|
||||
switch(distanceFunction) {
|
||||
case Euclidean:
|
||||
case EuclideanSq:
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int zPrimed = zPrimedBase;
|
||||
|
||||
for(int zi = zr - 1; zi <= zr + 1; zi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
|
||||
int idx = hash & (255 << 2);
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int zPrimed = zPrimedBase;
|
||||
|
||||
for(int zi = zr - 1; zi <= zr + 1; zi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
|
||||
int idx = hash & (255 << 2);
|
||||
|
||||
double vecX = (xi - x) + RAND_VECS_3D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_3D[idx | 1] * cellularJitter;
|
||||
double vecZ = (zi - z) + RAND_VECS_3D[idx | 2] * cellularJitter;
|
||||
|
||||
double newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ;
|
||||
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_3D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / frequency);
|
||||
centerZ = ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
zPrimed += PRIME_Z;
|
||||
}
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
}
|
||||
break;
|
||||
case Manhattan:
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
double vecX = (xi - x) + RAND_VECS_3D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_3D[idx | 1] * cellularJitter;
|
||||
double vecZ = (zi - z) + RAND_VECS_3D[idx | 2] * cellularJitter;
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int zPrimed = zPrimedBase;
|
||||
|
||||
for(int zi = zr - 1; zi <= zr + 1; zi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
|
||||
int idx = hash & (255 << 2);
|
||||
|
||||
double vecX = (xi - x) + RAND_VECS_3D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_3D[idx | 1] * cellularJitter;
|
||||
double vecZ = (zi - z) + RAND_VECS_3D[idx | 2] * cellularJitter;
|
||||
|
||||
double newDistance = fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ);
|
||||
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_3D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / frequency);
|
||||
centerZ = ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
zPrimed += PRIME_Z;
|
||||
}
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
}
|
||||
break;
|
||||
case Hybrid:
|
||||
for(int xi = xr - 1; xi <= xr + 1; xi++) {
|
||||
int yPrimed = yPrimedBase;
|
||||
|
||||
for(int yi = yr - 1; yi <= yr + 1; yi++) {
|
||||
int zPrimed = zPrimedBase;
|
||||
|
||||
for(int zi = zr - 1; zi <= zr + 1; zi++) {
|
||||
int hash = hash(seed, xPrimed, yPrimed, zPrimed);
|
||||
int idx = hash & (255 << 2);
|
||||
|
||||
double vecX = (xi - x) + RAND_VECS_3D[idx] * cellularJitter;
|
||||
double vecY = (yi - y) + RAND_VECS_3D[idx | 1] * cellularJitter;
|
||||
double vecZ = (zi - z) + RAND_VECS_3D[idx | 2] * cellularJitter;
|
||||
|
||||
double newDistance = (fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ)) +
|
||||
(vecX * vecX + vecY * vecY + vecZ * vecZ);
|
||||
|
||||
double newDistance = 0;
|
||||
switch(distanceFunction) {
|
||||
case Euclidean, EuclideanSq -> newDistance = vecX * vecX + vecY * vecY + vecZ * vecZ;
|
||||
case Manhattan -> newDistance = fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ);
|
||||
case Hybrid -> {
|
||||
newDistance = (fastAbs(vecX) + fastAbs(vecY) + fastAbs(vecZ)) + (vecX * vecX + vecY * vecY + vecZ * vecZ);
|
||||
distance1 = fastMax(fastMin(distance1, newDistance), distance0);
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_3D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / frequency);
|
||||
centerZ = ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
zPrimed += PRIME_Z;
|
||||
}
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
|
||||
if(newDistance < distance0) {
|
||||
distance0 = newDistance;
|
||||
closestHash = hash;
|
||||
centerX = ((xi + RAND_VECS_3D[idx] * cellularJitter) / frequency);
|
||||
centerY = ((yi + RAND_VECS_3D[idx | 1] * cellularJitter) / frequency);
|
||||
centerZ = ((zi + RAND_VECS_3D[idx | 2] * cellularJitter) / frequency);
|
||||
} else if(newDistance < distance1) {
|
||||
distance2 = distance1;
|
||||
distance1 = newDistance;
|
||||
} else if(newDistance < distance2) {
|
||||
distance2 = newDistance;
|
||||
}
|
||||
zPrimed += PRIME_Z;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
yPrimed += PRIME_Y;
|
||||
}
|
||||
xPrimed += PRIME_X;
|
||||
}
|
||||
|
||||
if(distanceFunction == DistanceFunction.Euclidean && returnType != ReturnType.CellValue) {
|
||||
@@ -514,6 +380,7 @@ public class CellularSampler extends NoiseFunction {
|
||||
case Distance2Mul -> distance1 * distance0 * 0.5 - 1;
|
||||
case Distance2Div -> distance0 / distance1 - 1;
|
||||
case NoiseLookup -> noiseLookup.noise(sl, centerX, centerY, centerZ);
|
||||
case LocalNoiseLookup -> noiseLookup.noise(sl, x / frequency - centerX, y / frequency - centerY, z / frequency - centerZ);
|
||||
case Distance3 -> distance2 - 1;
|
||||
case Distance3Add -> (distance2 + distance0) * 0.5 - 1;
|
||||
case Distance3Sub -> distance2 - distance0 - 1;
|
||||
@@ -540,6 +407,7 @@ public class CellularSampler extends NoiseFunction {
|
||||
Distance2Mul,
|
||||
Distance2Div,
|
||||
NoiseLookup,
|
||||
LocalNoiseLookup,
|
||||
Distance3,
|
||||
Distance3Add,
|
||||
Distance3Sub,
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2021 Polyhedral Development
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,3 @@
|
||||
# config-ore-v2
|
||||
|
||||
Registers the default configuration for Terra Ores, `ORE`.
|
||||
@@ -0,0 +1,11 @@
|
||||
version = version("1.0.0")
|
||||
|
||||
dependencies {
|
||||
compileOnlyApi(project(":common:addons:manifest-addon-loader"))
|
||||
implementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
|
||||
testImplementation("net.jafama", "jafama", Versions.Libraries.Internal.jafama)
|
||||
}
|
||||
|
||||
tasks.named<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>("shadowJar") {
|
||||
relocate("net.jafama", "com.dfsek.terra.addons.ore.lib.jafama")
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.ore.v2;
|
||||
|
||||
import com.dfsek.terra.addons.manifest.api.AddonInitializer;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.addon.BaseAddon;
|
||||
import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
|
||||
|
||||
public class OreAddon implements AddonInitializer {
|
||||
@Inject
|
||||
private Platform platform;
|
||||
|
||||
@Inject
|
||||
private BaseAddon addon;
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
platform.getEventManager()
|
||||
.getHandler(FunctionalEventHandler.class)
|
||||
.register(addon, ConfigPackPreLoadEvent.class)
|
||||
.then(event -> event.getPack().registerConfigType(new OreConfigType(), addon.key("ORE"), 1))
|
||||
.failThrough();
|
||||
}
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.ore.v2;
|
||||
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.config.ConfigFactory;
|
||||
import com.dfsek.terra.api.config.ConfigPack;
|
||||
import com.dfsek.terra.api.config.ConfigType;
|
||||
import com.dfsek.terra.api.structure.Structure;
|
||||
import com.dfsek.terra.api.util.reflection.TypeKey;
|
||||
|
||||
|
||||
public class OreConfigType implements ConfigType<OreTemplate, Structure> {
|
||||
public static final TypeKey<Structure> ORE_TYPE_TOKEN = new TypeKey<>() {
|
||||
};
|
||||
private final OreFactory factory = new OreFactory();
|
||||
|
||||
@Override
|
||||
public OreTemplate getTemplate(ConfigPack pack, Platform platform) {
|
||||
return new OreTemplate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConfigFactory<OreTemplate, Structure> getFactory() {
|
||||
return factory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeKey<Structure> getTypeKey() {
|
||||
return ORE_TYPE_TOKEN;
|
||||
}
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.ore.v2;
|
||||
|
||||
import com.dfsek.terra.addons.ore.v2.ores.VanillaOre;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.config.ConfigFactory;
|
||||
import com.dfsek.terra.api.structure.Structure;
|
||||
|
||||
|
||||
public class OreFactory implements ConfigFactory<OreTemplate, Structure> {
|
||||
@Override
|
||||
public VanillaOre build(OreTemplate config, Platform platform) {
|
||||
BlockState m = config.getMaterial();
|
||||
return new VanillaOre(m, config.getSize(), config.getReplaceable(), config.doPhysics(), config.isExposed(),
|
||||
config.getMaterialOverrides());
|
||||
}
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.ore.v2;
|
||||
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Default;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Description;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Final;
|
||||
import com.dfsek.tectonic.api.config.template.annotations.Value;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.api.block.BlockType;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.config.AbstractableTemplate;
|
||||
import com.dfsek.terra.api.config.meta.Meta;
|
||||
import com.dfsek.terra.api.util.collection.MaterialSet;
|
||||
|
||||
|
||||
@SuppressWarnings({ "unused", "FieldMayBeFinal" })
|
||||
public class OreTemplate implements AbstractableTemplate {
|
||||
@Value("id")
|
||||
@Final
|
||||
private String id;
|
||||
|
||||
@Value("material")
|
||||
private @Meta BlockState material;
|
||||
|
||||
@Value("material-overrides")
|
||||
@Default
|
||||
private @Meta Map<@Meta BlockType, @Meta BlockState> materials = new HashMap<>();
|
||||
|
||||
@Value("replace")
|
||||
private @Meta MaterialSet replaceable;
|
||||
|
||||
@Value("physics")
|
||||
@Default
|
||||
private @Meta boolean physics = false;
|
||||
|
||||
@Value("size")
|
||||
private @Meta double size;
|
||||
|
||||
@Value("exposed")
|
||||
@Default
|
||||
@Description("The chance that ore blocks bordering air will be discarded as candidates for ore. 0 = 0%, 1 = 100%")
|
||||
private @Meta double exposed = 0.0f;
|
||||
|
||||
public boolean doPhysics() {
|
||||
return physics;
|
||||
}
|
||||
|
||||
public double getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public BlockState getMaterial() {
|
||||
return material;
|
||||
}
|
||||
|
||||
public MaterialSet getReplaceable() {
|
||||
return replaceable;
|
||||
}
|
||||
|
||||
public String getID() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public Map<BlockType, BlockState> getMaterialOverrides() {
|
||||
return materials;
|
||||
}
|
||||
|
||||
public double isExposed() {
|
||||
return exposed;
|
||||
}
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.ore.v2.ores;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import java.util.BitSet;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
|
||||
import com.dfsek.terra.api.block.BlockType;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.structure.Structure;
|
||||
import com.dfsek.terra.api.util.Rotation;
|
||||
import com.dfsek.terra.api.util.collection.MaterialSet;
|
||||
import com.dfsek.terra.api.util.vector.Vector3Int;
|
||||
import com.dfsek.terra.api.world.WritableWorld;
|
||||
|
||||
|
||||
public class VanillaOre implements Structure {
|
||||
|
||||
private final BlockState material;
|
||||
|
||||
private final double size;
|
||||
private final MaterialSet replaceable;
|
||||
private final boolean applyGravity;
|
||||
private final double exposed;
|
||||
private final Map<BlockType, BlockState> materials;
|
||||
|
||||
public VanillaOre(BlockState material, double size, MaterialSet replaceable, boolean applyGravity,
|
||||
double exposed, Map<BlockType, BlockState> materials) {
|
||||
this.material = material;
|
||||
this.size = size;
|
||||
this.replaceable = replaceable;
|
||||
this.applyGravity = applyGravity;
|
||||
this.exposed = exposed;
|
||||
this.materials = materials;
|
||||
}
|
||||
|
||||
protected static boolean shouldNotDiscard(Random random, double chance) {
|
||||
if(chance <= 0.0F) {
|
||||
return true;
|
||||
} else if(chance >= 1.0F) {
|
||||
return false;
|
||||
} else {
|
||||
return random.nextFloat() >= chance;
|
||||
}
|
||||
}
|
||||
|
||||
public static double lerp(double t, double v0, double v1) {
|
||||
return v0 + t * (v1 - v0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
|
||||
float f = random.nextFloat() * (float) Math.PI;
|
||||
double g = size / 8.0F;
|
||||
int i = (int) FastMath.ceil((size / 16.0F * 2.0F + 1.0F) / 2.0F);
|
||||
double startX = (double) location.getX() + FastMath.sin(f) * g;
|
||||
double endX = (double) location.getX() - FastMath.sin(f) * g;
|
||||
double startZ = (double) location.getZ() + FastMath.cos(f) * g;
|
||||
double endZ = (double) location.getZ() - FastMath.cos(f) * g;
|
||||
double startY = location.getY() + random.nextInt(3) - 2;
|
||||
double endY = location.getY() + random.nextInt(3) - 2;
|
||||
int x = (int) (location.getX() - FastMath.ceil(g) - i);
|
||||
int y = location.getY() - 2 - i;
|
||||
int z = (int) (location.getZ() - FastMath.ceil(g) - i);
|
||||
int horizontalSize = (int) (2 * (FastMath.ceil(g) + i));
|
||||
int verticalSize = 2 * (2 + i);
|
||||
|
||||
int i1 = 0;
|
||||
BitSet bitSet = new BitSet(horizontalSize * verticalSize * horizontalSize);
|
||||
|
||||
int j1 = (int) size;
|
||||
double[] ds = new double[j1 * 4];
|
||||
|
||||
for(int k1 = 0; k1 < j1; ++k1) {
|
||||
float f1 = (float) k1 / (float) j1;
|
||||
double d1 = lerp(f1, startX, endX);
|
||||
double e1 = lerp(f1, startY, endY);
|
||||
double g1 = lerp(f1, startZ, endZ);
|
||||
double h1 = random.nextDouble() * (double) j1 / 16.0;
|
||||
double l1 = ((FastMath.sin((float) Math.PI * f1) + 1.0F) * h1 + 1.0) / 2.0;
|
||||
ds[k1 * 4] = d1;
|
||||
ds[k1 * 4 + 1] = e1;
|
||||
ds[k1 * 4 + 2] = g1;
|
||||
ds[k1 * 4 + 3] = l1;
|
||||
}
|
||||
|
||||
for(int k1 = 0; k1 < j1 - 1; ++k1) {
|
||||
if(!(ds[k1 * 4 + 3] <= 0.0)) {
|
||||
for(int m1 = k1 + 1; m1 < j1; ++m1) {
|
||||
if(!(ds[m1 * 4 + 3] <= 0.0)) {
|
||||
double d1 = ds[k1 * 4] - ds[m1 * 4];
|
||||
double e1 = ds[k1 * 4 + 1] - ds[m1 * 4 + 1];
|
||||
double g1 = ds[k1 * 4 + 2] - ds[m1 * 4 + 2];
|
||||
double h1 = ds[k1 * 4 + 3] - ds[m1 * 4 + 3];
|
||||
if(h1 * h1 > d1 * d1 + e1 * e1 + g1 * g1) {
|
||||
if(h1 > 0.0) {
|
||||
ds[m1 * 4 + 3] = -1.0;
|
||||
} else {
|
||||
ds[k1 * 4 + 3] = -1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int m1 = 0; m1 < j1; ++m1) {
|
||||
double d1 = ds[m1 * 4 + 3];
|
||||
if(!(d1 < 0.0)) {
|
||||
double e1 = ds[m1 * 4];
|
||||
double g1 = ds[m1 * 4 + 1];
|
||||
double h1 = ds[m1 * 4 + 2];
|
||||
int n1 = (int) FastMath.max(FastMath.floor(e1 - d1), x);
|
||||
int o1 = (int) FastMath.max(FastMath.floor(g1 - d1), y);
|
||||
int p1 = (int) FastMath.max(FastMath.floor(h1 - d1), z);
|
||||
int q1 = (int) FastMath.max(FastMath.floor(e1 + d1), n1);
|
||||
int r1 = (int) FastMath.max(FastMath.floor(g1 + d1), o1);
|
||||
int s1 = (int) FastMath.max(FastMath.floor(h1 + d1), p1);
|
||||
|
||||
for(int t1 = n1; t1 <= q1; ++t1) {
|
||||
double u1 = ((double) t1 + 0.5 - e1) / d1;
|
||||
if(u1 * u1 < 1.0) {
|
||||
for(int v1 = o1; v1 <= r1; ++v1) {
|
||||
double w1 = ((double) v1 + 0.5 - g1) / d1;
|
||||
if(u1 * u1 + w1 * w1 < 1.0) {
|
||||
for(int aa = p1; aa <= s1; ++aa) {
|
||||
double ab = ((double) aa + 0.5 - h1) / d1;
|
||||
if(u1 * u1 + w1 * w1 + ab * ab < 1.0 && !(v1 < world.getMinHeight() || v1 >= world.getMaxHeight())) {
|
||||
int ac = t1 - x + (v1 - y) * horizontalSize + (aa - z) * horizontalSize * verticalSize;
|
||||
if(!bitSet.get(ac)) {
|
||||
bitSet.set(ac);
|
||||
|
||||
BlockType block = world.getBlockState(x, y, z).getBlockType();
|
||||
|
||||
if(shouldPlace(block, random, world, t1, v1, aa)) {
|
||||
world.setBlockState(t1, v1, aa, getMaterial(block), isApplyGravity());
|
||||
++i1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return i1 > 0;
|
||||
}
|
||||
|
||||
public boolean shouldPlace(BlockType type, Random random, WritableWorld world, int x, int y, int z) {
|
||||
if(!getReplaceable().contains(type)) {
|
||||
return false;
|
||||
} else if(shouldNotDiscard(random, exposed)) {
|
||||
return true;
|
||||
} else {
|
||||
return !(world.getBlockState(x, y, z - 1).isAir() ||
|
||||
world.getBlockState(x, y, z + 1).isAir() ||
|
||||
world.getBlockState(x, y - 1, z).isAir() ||
|
||||
world.getBlockState(x, y + 1, z).isAir() ||
|
||||
world.getBlockState(x - 1, y, z).isAir() ||
|
||||
world.getBlockState(x + 1, y, z).isAir());
|
||||
}
|
||||
}
|
||||
|
||||
public BlockState getMaterial(BlockType replace) {
|
||||
return materials.getOrDefault(replace, material);
|
||||
}
|
||||
|
||||
public MaterialSet getReplaceable() {
|
||||
return replaceable;
|
||||
}
|
||||
|
||||
public boolean isApplyGravity() {
|
||||
return applyGravity;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
schema-version: 1
|
||||
contributors:
|
||||
- Terra contributors
|
||||
id: config-ore-v2
|
||||
version: @VERSION@
|
||||
entrypoints:
|
||||
- "com.dfsek.terra.addons.ore.v2.OreAddon"
|
||||
website:
|
||||
issues: https://github.com/PolyhedralDev/Terra/issues
|
||||
source: https://github.com/PolyhedralDev/Terra
|
||||
docs: https://terra.polydev.org
|
||||
license: MIT License
|
||||
@@ -14,8 +14,13 @@ import com.dfsek.terra.api.event.events.config.pack.ConfigPackPreLoadEvent;
|
||||
import com.dfsek.terra.api.event.functional.FunctionalEventHandler;
|
||||
import com.dfsek.terra.api.inject.annotations.Inject;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
public class OreAddon implements AddonInitializer {
|
||||
private static final Logger logger = LoggerFactory.getLogger(OreAddon.class);
|
||||
|
||||
@Inject
|
||||
private Platform platform;
|
||||
|
||||
@@ -29,5 +34,7 @@ public class OreAddon implements AddonInitializer {
|
||||
.register(addon, ConfigPackPreLoadEvent.class)
|
||||
.then(event -> event.getPack().registerConfigType(new OreConfigType(), addon.key("ORE"), 1))
|
||||
.failThrough();
|
||||
|
||||
logger.warn("The ore-config addon is deprecated and scheduled for removal in Terra 7.0. It is recommended to use the ore-config-v2 addon for future pack development instead.");
|
||||
}
|
||||
}
|
||||
|
||||
-256
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.lexer;
|
||||
|
||||
import com.google.common.collect.Sets;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.Stack;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Token.TokenType;
|
||||
import com.dfsek.terra.addons.terrascript.lexer.exceptions.EOFException;
|
||||
import com.dfsek.terra.addons.terrascript.lexer.exceptions.FormatException;
|
||||
import com.dfsek.terra.addons.terrascript.lexer.exceptions.TokenizerException;
|
||||
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
|
||||
|
||||
|
||||
public class Lexer {
|
||||
public static final Set<Character> syntaxSignificant = Sets.newHashSet(';', '(', ')', '"', ',', '\\', '=', '{', '}', '+', '-', '*', '/',
|
||||
'>', '<', '!'); // Reserved chars
|
||||
private final LookaheadStream reader;
|
||||
private final Stack<Token> bracketStack = new Stack<>();
|
||||
private Token current;
|
||||
|
||||
public Lexer(String data) {
|
||||
reader = new LookaheadStream(data + '\0');
|
||||
current = tokenize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the first token.
|
||||
*
|
||||
* @return First token
|
||||
*
|
||||
* @throws ParseException If token does not exist
|
||||
*/
|
||||
public Token current() {
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume (get and remove) the first token.
|
||||
*
|
||||
* @return First token
|
||||
*
|
||||
* @throws ParseException If token does not exist
|
||||
*/
|
||||
public Token consume(String wrongTypeMessage, TokenType expected, TokenType... more) {
|
||||
if(!current.isType(expected) && Arrays.stream(more).noneMatch(t -> t == current.getType())) throw new ParseException(wrongTypeMessage, current.getPosition());
|
||||
return consumeUnchecked();
|
||||
}
|
||||
|
||||
public Token consumeUnchecked() {
|
||||
if(current.getType() == TokenType.END_OF_FILE) return current;
|
||||
Token temp = current;
|
||||
current = tokenize();
|
||||
return temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this {@code Tokenizer} contains additional tokens.
|
||||
*
|
||||
* @return {@code true} if more tokens are present, otherwise {@code false}
|
||||
*/
|
||||
public boolean hasNext() {
|
||||
return current.getType() != TokenType.END_OF_FILE;
|
||||
}
|
||||
|
||||
private Token tokenize() throws TokenizerException {
|
||||
consumeWhitespace();
|
||||
SourcePosition position = reader.getPosition();
|
||||
|
||||
// Skip line if comment
|
||||
while(reader.matchesString("//", true)) skipLine();
|
||||
|
||||
// Skip multi line comment
|
||||
if(reader.matchesString("/*", true)) skipTo("*/");
|
||||
|
||||
// Reached end of file
|
||||
if(reader.current().isEOF()) {
|
||||
if(!bracketStack.isEmpty()) throw new ParseException("Dangling open brace", bracketStack.peek().getPosition());
|
||||
return new Token(reader.consume().toString(), TokenType.END_OF_FILE, position);
|
||||
}
|
||||
|
||||
// Check if operator token
|
||||
if(reader.matchesString("==", true))
|
||||
return new Token("==", TokenType.EQUALS_EQUALS, position);
|
||||
if(reader.matchesString("!=", true))
|
||||
return new Token("!=", TokenType.BANG_EQUALS, position);
|
||||
if(reader.matchesString(">=", true))
|
||||
return new Token(">=", TokenType.GREATER_EQUAL, position);
|
||||
if(reader.matchesString("<=", true))
|
||||
return new Token("<=", TokenType.LESS_EQUALS, position);
|
||||
if(reader.matchesString(">", true))
|
||||
return new Token(">", TokenType.GREATER, position);
|
||||
if(reader.matchesString("<", true))
|
||||
return new Token("<", TokenType.LESS, position);
|
||||
|
||||
// Check if logical operator
|
||||
if(reader.matchesString("||", true))
|
||||
return new Token("||", TokenType.BOOLEAN_OR, position);
|
||||
if(reader.matchesString("&&", true))
|
||||
return new Token("&&", TokenType.BOOLEAN_AND, position);
|
||||
|
||||
// Check if number
|
||||
if(isNumberStart()) {
|
||||
StringBuilder num = new StringBuilder();
|
||||
while(!reader.current().isEOF() && isNumberLike()) {
|
||||
num.append(reader.consume().getCharacter());
|
||||
}
|
||||
return new Token(num.toString(), TokenType.NUMBER, position);
|
||||
}
|
||||
|
||||
// Check if string literal
|
||||
if(reader.current().is('"')) {
|
||||
reader.consume(); // Consume first quote
|
||||
StringBuilder string = new StringBuilder();
|
||||
boolean ignoreNext = false;
|
||||
while((!reader.current().is('"')) || ignoreNext) {
|
||||
if(reader.current().is('\\') && !ignoreNext) {
|
||||
ignoreNext = true;
|
||||
reader.consume();
|
||||
continue;
|
||||
} else ignoreNext = false;
|
||||
if(reader.current().isEOF())
|
||||
throw new FormatException("No end of string literal found. ", position);
|
||||
string.append(reader.consume());
|
||||
}
|
||||
reader.consume(); // Consume last quote
|
||||
|
||||
return new Token(string.toString(), TokenType.STRING, position);
|
||||
}
|
||||
|
||||
if(reader.current().is('('))
|
||||
return new Token(reader.consume().toString(), TokenType.OPEN_PAREN, position);
|
||||
if(reader.current().is(')'))
|
||||
return new Token(reader.consume().toString(), TokenType.CLOSE_PAREN, position);
|
||||
if(reader.current().is(';'))
|
||||
return new Token(reader.consume().toString(), TokenType.STATEMENT_END, position);
|
||||
if(reader.current().is(','))
|
||||
return new Token(reader.consume().toString(), TokenType.SEPARATOR, position);
|
||||
|
||||
if(reader.current().is('{')) {
|
||||
Token token = new Token(reader.consume().toString(), TokenType.BLOCK_BEGIN, position);
|
||||
bracketStack.push(token);
|
||||
return token;
|
||||
}
|
||||
if(reader.current().is('}')) {
|
||||
if(bracketStack.isEmpty()) throw new ParseException("Dangling close brace", position);
|
||||
bracketStack.pop();
|
||||
return new Token(reader.consume().toString(), TokenType.BLOCK_END, position);
|
||||
}
|
||||
|
||||
if(reader.current().is('='))
|
||||
return new Token(reader.consume().toString(), TokenType.ASSIGNMENT, position);
|
||||
if(reader.current().is('+'))
|
||||
return new Token(reader.consume().toString(), TokenType.PLUS, position);
|
||||
if(reader.current().is('-'))
|
||||
return new Token(reader.consume().toString(), TokenType.MINUS,
|
||||
position);
|
||||
if(reader.current().is('*'))
|
||||
return new Token(reader.consume().toString(), TokenType.STAR,
|
||||
position);
|
||||
if(reader.current().is('/'))
|
||||
return new Token(reader.consume().toString(), TokenType.FORWARD_SLASH, position);
|
||||
if(reader.current().is('%'))
|
||||
return new Token(reader.consume().toString(), TokenType.MODULO_OPERATOR, position);
|
||||
if(reader.current().is('!'))
|
||||
return new Token(reader.consume().toString(), TokenType.BANG, position);
|
||||
|
||||
// Read word
|
||||
StringBuilder token = new StringBuilder();
|
||||
while(!reader.current().isEOF() && !isSyntaxSignificant(reader.current().getCharacter())) {
|
||||
Char c = reader.consume();
|
||||
if(c.isWhitespace()) break;
|
||||
token.append(c.getCharacter());
|
||||
}
|
||||
String tokenString = token.toString();
|
||||
|
||||
// Check if word is a keyword
|
||||
if(tokenString.equals("true"))
|
||||
return new Token(tokenString, TokenType.BOOLEAN, position);
|
||||
if(tokenString.equals("false"))
|
||||
return new Token(tokenString, TokenType.BOOLEAN, position);
|
||||
|
||||
if(tokenString.equals("num"))
|
||||
return new Token(tokenString, TokenType.TYPE_NUMBER, position);
|
||||
if(tokenString.equals("str"))
|
||||
return new Token(tokenString, TokenType.TYPE_STRING, position);
|
||||
if(tokenString.equals("bool"))
|
||||
return new Token(tokenString, TokenType.TYPE_BOOLEAN, position);
|
||||
if(tokenString.equals("void"))
|
||||
return new Token(tokenString, TokenType.TYPE_VOID, position);
|
||||
|
||||
if(tokenString.equals("if"))
|
||||
return new Token(tokenString, TokenType.IF_STATEMENT, position);
|
||||
if(tokenString.equals("else"))
|
||||
return new Token(tokenString, TokenType.ELSE, position);
|
||||
if(tokenString.equals("while"))
|
||||
return new Token(tokenString, TokenType.WHILE_LOOP, position);
|
||||
if(tokenString.equals("for"))
|
||||
return new Token(tokenString, TokenType.FOR_LOOP, position);
|
||||
|
||||
if(tokenString.equals("return"))
|
||||
return new Token(tokenString, TokenType.RETURN, position);
|
||||
if(tokenString.equals("continue"))
|
||||
return new Token(tokenString, TokenType.CONTINUE, position);
|
||||
if(tokenString.equals("break"))
|
||||
return new Token(tokenString, TokenType.BREAK, position);
|
||||
if(tokenString.equals("fail"))
|
||||
return new Token(tokenString, TokenType.FAIL, position);
|
||||
|
||||
// If not keyword, assume it is an identifier
|
||||
return new Token(tokenString, TokenType.IDENTIFIER, position);
|
||||
}
|
||||
|
||||
private void skipLine() {
|
||||
while(!reader.current().isEOF() && !reader.current().isNewLine()) reader.consume();
|
||||
consumeWhitespace();
|
||||
}
|
||||
|
||||
private void consumeWhitespace() {
|
||||
while(!reader.current().isEOF() && reader.current().isWhitespace()) reader.consume(); // Consume whitespace.
|
||||
}
|
||||
|
||||
private void skipTo(String s) throws EOFException {
|
||||
SourcePosition begin = reader.getPosition();
|
||||
while(!reader.current().isEOF()) {
|
||||
if(reader.matchesString(s, true)) {
|
||||
consumeWhitespace();
|
||||
return;
|
||||
}
|
||||
reader.consume();
|
||||
}
|
||||
throw new EOFException("No end of expression found.", begin);
|
||||
}
|
||||
|
||||
private boolean isNumberLike() {
|
||||
return reader.current().isDigit()
|
||||
|| reader.current().is('_', '.', 'E');
|
||||
}
|
||||
|
||||
private boolean isNumberStart() {
|
||||
return reader.current().isDigit()
|
||||
|| reader.current().is('.') && reader.peek().isDigit();
|
||||
}
|
||||
|
||||
public boolean isSyntaxSignificant(char c) {
|
||||
return syntaxSignificant.contains(c);
|
||||
}
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
package com.dfsek.terra.addons.terrascript.lexer;
|
||||
|
||||
|
||||
|
||||
public class LookaheadStream {
|
||||
|
||||
private final String source;
|
||||
|
||||
private int index;
|
||||
|
||||
private SourcePosition position = new SourcePosition(1, 1);
|
||||
|
||||
public LookaheadStream(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current character without consuming it.
|
||||
*
|
||||
* @return current character
|
||||
*/
|
||||
public Char current() {
|
||||
return new Char(source.charAt(index), position);
|
||||
}
|
||||
|
||||
/**
|
||||
* Consume and return one character.
|
||||
*
|
||||
* @return Character that was consumed.
|
||||
*/
|
||||
public Char consume() {
|
||||
Char consumed = current();
|
||||
incrementIndex(1);
|
||||
return consumed;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The next character in sequence.
|
||||
*/
|
||||
public Char peek() {
|
||||
int index = this.index + 1;
|
||||
if (index + 1 >= source.length()) return null;
|
||||
return new Char(source.charAt(index), getPositionAfter(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the contained sequence of characters matches the string
|
||||
*
|
||||
* @param check Input string to check against
|
||||
* @param consumeIfMatched Whether to consume the string if there is a match
|
||||
* @return If the string matches
|
||||
*/
|
||||
public boolean matchesString(String check, boolean consumeIfMatched) {
|
||||
boolean matches = check.equals(source.substring(index, Math.min(index + check.length(), source.length())));
|
||||
if (matches && consumeIfMatched) incrementIndex(check.length());
|
||||
return matches;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current position within the source file
|
||||
*/
|
||||
public SourcePosition getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
private void incrementIndex(int amount) {
|
||||
position = getPositionAfter(amount);
|
||||
index = Math.min(index + amount, source.length() - 1);
|
||||
}
|
||||
|
||||
private SourcePosition getPositionAfter(int chars) {
|
||||
if (chars < 0) throw new IllegalArgumentException("Negative values are not allowed");
|
||||
int line = position.line();
|
||||
int column = position.column();
|
||||
for (int i = index; i < Math.min(index + chars, source.length() - 1); i++) {
|
||||
if (source.charAt(i) == '\n') {
|
||||
line++;
|
||||
column = 0;
|
||||
}
|
||||
column++;
|
||||
}
|
||||
return new SourcePosition(line, column);
|
||||
}
|
||||
}
|
||||
-32
@@ -1,32 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.lexer;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
public record SourcePosition(int line, int column) {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "line " + line + ", column " + column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if(this == o) return true;
|
||||
if(o == null || getClass() != o.getClass()) return false;
|
||||
SourcePosition that = (SourcePosition) o;
|
||||
return line == that.line && column == that.column;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(line, column);
|
||||
}
|
||||
}
|
||||
+324
-380
@@ -9,26 +9,24 @@ package com.dfsek.terra.addons.terrascript.parser;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Lexer;
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Token;
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Token.TokenType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Executable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Item;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.BooleanConstant;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.ConstantExpression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.NumericConstant;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.UserDefinedFunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.BreakKeyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.ContinueKeyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.FailKeyword;
|
||||
@@ -36,6 +34,7 @@ import com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow.ReturnKeywor
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike.ForKeyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike.IfKeyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike.WhileKeyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BooleanAndOperation;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BooleanNotOperation;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BooleanOrOperation;
|
||||
@@ -59,16 +58,30 @@ import com.dfsek.terra.addons.terrascript.parser.lang.variables.assign.VariableA
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.BoolVariableReferenceNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.NumVariableReferenceNode;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.variables.reference.StrVariableReferenceNode;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Token;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Tokenizer;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class Parser {
|
||||
private final String data;
|
||||
private final Map<String, FunctionBuilder<? extends Function<?>>> functions = new HashMap<>();
|
||||
private final List<String> ignoredFunctions = new ArrayList<>();
|
||||
|
||||
private final Lexer lexer;
|
||||
public Parser(String data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public Parser(Lexer lexer) {
|
||||
this.lexer = lexer;
|
||||
public Parser registerFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
|
||||
functions.put(name, functionBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Parser ignoreFunction(String name) {
|
||||
ignoredFunctions.add(name);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -78,447 +91,378 @@ public class Parser {
|
||||
*
|
||||
* @throws ParseException If parsing fails.
|
||||
*/
|
||||
public Executable parse(ScopeBuilder scopeBuilder) {
|
||||
return new Executable(parseBlock(scopeBuilder, ReturnType.VOID), scopeBuilder);
|
||||
public Executable parse() {
|
||||
ScopeBuilder scopeBuilder = new ScopeBuilder();
|
||||
return new Executable(parseBlock(new Tokenizer(data), false, scopeBuilder), scopeBuilder);
|
||||
}
|
||||
|
||||
private WhileKeyword parseWhileLoop(ScopeBuilder scopeBuilder) {
|
||||
SourcePosition start = lexer.consume("Expected 'while' keyword at beginning of while loop", TokenType.WHILE_LOOP).getPosition();
|
||||
lexer.consume("Expected '(' proceeding 'while' keyword", TokenType.OPEN_PAREN);
|
||||
scopeBuilder = scopeBuilder.innerLoopScope();
|
||||
Expression<?> condition = parseExpression(scopeBuilder);
|
||||
ParserUtil.ensureReturnType(condition, Expression.ReturnType.BOOLEAN);
|
||||
lexer.consume("Expected ')' proceeding while loop condition", TokenType.CLOSE_PAREN);
|
||||
return new WhileKeyword(parseStatementBlock(scopeBuilder, ReturnType.VOID), (Expression<Boolean>) condition,
|
||||
start); // While loop
|
||||
}
|
||||
|
||||
private IfKeyword parseIfStatement(ScopeBuilder scopeBuilder) {
|
||||
SourcePosition start = lexer.consume("Expected 'if' keyword at beginning of if statement", TokenType.IF_STATEMENT).getPosition();
|
||||
lexer.consume("Expected '(' proceeding 'if' keyword", TokenType.OPEN_PAREN);
|
||||
Expression<?> condition = parseExpression(scopeBuilder);
|
||||
ParserUtil.ensureReturnType(condition, Expression.ReturnType.BOOLEAN);
|
||||
private Keyword<?> parseLoopLike(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) throws ParseException {
|
||||
|
||||
lexer.consume("Expected ')' proceeding if statement condition", TokenType.CLOSE_PAREN);
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
||||
|
||||
return switch(identifier.getType()) {
|
||||
case FOR_LOOP -> parseForLoop(tokens, identifier.getPosition(), scopeBuilder);
|
||||
case IF_STATEMENT -> parseIfStatement(tokens, identifier.getPosition(), loop, scopeBuilder);
|
||||
case WHILE_LOOP -> parseWhileLoop(tokens, identifier.getPosition(), scopeBuilder);
|
||||
default -> throw new UnsupportedOperationException(
|
||||
"Unknown keyword " + identifier.getContent() + ": " + identifier.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
private WhileKeyword parseWhileLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) {
|
||||
Returnable<?> first = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(first, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
return new WhileKeyword(parseStatementBlock(tokens, true, scopeBuilder), (Returnable<Boolean>) first, start); // While loop
|
||||
}
|
||||
|
||||
private IfKeyword parseIfStatement(Tokenizer tokens, Position start, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
Returnable<?> condition = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(condition, Returnable.ReturnType.BOOLEAN);
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
Block elseBlock = null;
|
||||
Block statement = parseStatementBlock(scopeBuilder, ReturnType.VOID);
|
||||
Block statement = parseStatementBlock(tokens, loop, scopeBuilder);
|
||||
|
||||
List<Pair<Expression<Boolean>, Block>> elseIf = new ArrayList<>();
|
||||
List<Pair<Returnable<Boolean>, Block>> elseIf = new ArrayList<>();
|
||||
|
||||
while(lexer.hasNext() && lexer.current().isType(TokenType.ELSE)) {
|
||||
lexer.consumeUnchecked(); // Consume else.
|
||||
if(lexer.current().isType(TokenType.IF_STATEMENT)) {
|
||||
lexer.consumeUnchecked(); // Consume if.
|
||||
Expression<?> elseCondition = parseExpression(scopeBuilder);
|
||||
ParserUtil.ensureReturnType(elseCondition, Expression.ReturnType.BOOLEAN);
|
||||
elseIf.add(Pair.of((Expression<Boolean>) elseCondition, parseStatementBlock(scopeBuilder, ReturnType.VOID)));
|
||||
while(tokens.hasNext() && tokens.get().getType().equals(Token.Type.ELSE)) {
|
||||
tokens.consume(); // Consume else.
|
||||
if(tokens.get().getType().equals(Token.Type.IF_STATEMENT)) {
|
||||
tokens.consume(); // Consume if.
|
||||
Returnable<?> elseCondition = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(elseCondition, Returnable.ReturnType.BOOLEAN);
|
||||
elseIf.add(Pair.of((Returnable<Boolean>) elseCondition, parseStatementBlock(tokens, loop, scopeBuilder)));
|
||||
} else {
|
||||
elseBlock = parseStatementBlock(scopeBuilder, ReturnType.VOID);
|
||||
elseBlock = parseStatementBlock(tokens, loop, scopeBuilder);
|
||||
break; // Else must be last.
|
||||
}
|
||||
}
|
||||
|
||||
return new IfKeyword(statement, (Expression<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
||||
return new IfKeyword(statement, (Returnable<Boolean>) condition, elseIf, elseBlock, start); // If statement
|
||||
}
|
||||
|
||||
private Block parseStatementBlock(ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||
if(lexer.current().isType(TokenType.BLOCK_BEGIN)) {
|
||||
lexer.consumeUnchecked();
|
||||
Block block = parseBlock(scopeBuilder, blockReturnType);
|
||||
lexer.consume("Expected block end '}' after block statements", TokenType.BLOCK_END);
|
||||
private Block parseStatementBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
|
||||
if(tokens.get().getType().equals(Token.Type.BLOCK_BEGIN)) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_BEGIN);
|
||||
Block block = parseBlock(tokens, loop, scopeBuilder);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.BLOCK_END);
|
||||
return block;
|
||||
} else {
|
||||
SourcePosition position = lexer.current().getPosition();
|
||||
return new Block(Collections.singletonList(parseStatement(scopeBuilder)), position, blockReturnType);
|
||||
Position position = tokens.get().getPosition();
|
||||
Block block = new Block(Collections.singletonList(parseItem(tokens, loop, scopeBuilder)), position);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
return block;
|
||||
}
|
||||
}
|
||||
|
||||
private ForKeyword parseForLoop(ScopeBuilder scopeBuilder) {
|
||||
SourcePosition start = lexer.consume("Expected 'for' keyword at beginning of for loop", TokenType.FOR_LOOP).getPosition();
|
||||
lexer.consume("Expected '(' after 'for' keyword", TokenType.OPEN_PAREN);
|
||||
scopeBuilder = scopeBuilder.innerLoopScope(); // new scope
|
||||
private ForKeyword parseForLoop(Tokenizer tokens, Position start, ScopeBuilder scopeBuilder) {
|
||||
scopeBuilder = scopeBuilder.sub(); // new scope
|
||||
Token f = tokens.get();
|
||||
ParserUtil.checkType(f, Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.IDENTIFIER);
|
||||
Item<?> initializer;
|
||||
if(f.isVariableDeclaration()) {
|
||||
VariableAssignmentNode<?> forVar = parseVariableDeclaration(tokens, scopeBuilder);
|
||||
Token name = tokens.get();
|
||||
if(functions.containsKey(name.getContent()) || scopeBuilder.contains(name.getContent()))
|
||||
throw new ParseException(name.getContent() + " is already defined in this scope", name.getPosition());
|
||||
initializer = forVar;
|
||||
} else initializer = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
Returnable<?> conditional = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(conditional, Returnable.ReturnType.BOOLEAN);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
|
||||
Expression<?> initializer = switch(lexer.current().getType()) {
|
||||
case TYPE_NUMBER, TYPE_STRING, TYPE_BOOLEAN -> {
|
||||
Token type = lexer.consume("Expected type before declaration", TokenType.TYPE_STRING, TokenType.TYPE_NUMBER, TokenType.TYPE_BOOLEAN, TokenType.TYPE_VOID);
|
||||
Token identifier = lexer.consume("Expected identifier after type", TokenType.IDENTIFIER);
|
||||
Expression<?> expr = parseVariableDeclaration(scopeBuilder, type, identifier);
|
||||
lexer.consume("Expected ';' after initializer within for loop", TokenType.STATEMENT_END);
|
||||
yield expr;
|
||||
}
|
||||
case IDENTIFIER -> {
|
||||
Expression<?> expr = parseAssignment(scopeBuilder);
|
||||
lexer.consume("Expected ';' after initializer within for loop", TokenType.STATEMENT_END);
|
||||
yield expr;
|
||||
}
|
||||
case STATEMENT_END -> {
|
||||
lexer.consumeUnchecked();
|
||||
yield Expression.NOOP;
|
||||
}
|
||||
default -> throw new ParseException("Unexpected token '" + lexer.current() + "', expected variable declaration or assignment", lexer.current().getPosition());
|
||||
};
|
||||
Item<?> incrementer;
|
||||
Token token = tokens.get();
|
||||
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
|
||||
incrementer = parseAssignment(tokens, scopeBuilder);
|
||||
} else incrementer = parseFunction(tokens, true, scopeBuilder);
|
||||
|
||||
Expression<?> conditional;
|
||||
if (lexer.current().isType(TokenType.STATEMENT_END)) // If no conditional is provided, conditional defaults to true
|
||||
conditional = new BooleanConstant(true, lexer.current().getPosition());
|
||||
else
|
||||
conditional = parseExpression(scopeBuilder);
|
||||
ParserUtil.ensureReturnType(conditional, Expression.ReturnType.BOOLEAN);
|
||||
lexer.consume("Expected ';' separator after conditional within for loop", TokenType.STATEMENT_END);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
|
||||
Expression<?> incrementer;
|
||||
if(lexer.current().isType(TokenType.CLOSE_PAREN))
|
||||
// If no incrementer is provided, do nothing
|
||||
incrementer = Expression.NOOP;
|
||||
else if(scopeBuilder.containsVariable(lexer.current().getContent())) // Assume variable assignment
|
||||
incrementer = parseAssignment(scopeBuilder);
|
||||
else
|
||||
incrementer = parseFunctionInvocation(lexer.consume("Expected function call within for loop incrementer", TokenType.IDENTIFIER), scopeBuilder);
|
||||
lexer.consume("Expected ')' after for loop incrementer", TokenType.CLOSE_PAREN);
|
||||
|
||||
return new ForKeyword(parseStatementBlock(scopeBuilder, ReturnType.VOID), initializer, (Expression<Boolean>) conditional,
|
||||
incrementer,
|
||||
return new ForKeyword(parseStatementBlock(tokens, true, scopeBuilder), initializer, (Returnable<Boolean>) conditional, incrementer,
|
||||
start);
|
||||
}
|
||||
|
||||
private Expression<?> parseExpression(ScopeBuilder scopeBuilder) {
|
||||
return parseLogicOr(scopeBuilder);
|
||||
}
|
||||
|
||||
private Expression<?> parseLogicOr(ScopeBuilder scopeBuilder) {
|
||||
return parseLeftAssociativeBinaryOperation(this::parseLogicAnd, scopeBuilder, (op) -> {
|
||||
ParserUtil.ensureReturnType(op.left, ReturnType.BOOLEAN);
|
||||
ParserUtil.ensureReturnType(op.right, ReturnType.BOOLEAN);
|
||||
}, Map.of(TokenType.BOOLEAN_OR, (op) -> new BooleanOrOperation((Expression<Boolean>) op.left, (Expression<Boolean>) op.right, op.operator.getPosition())));
|
||||
}
|
||||
|
||||
private Expression<?> parseLogicAnd(ScopeBuilder scopeBuilder) {
|
||||
return parseLeftAssociativeBinaryOperation(this::parseEquality, scopeBuilder, (op) -> {
|
||||
ParserUtil.ensureReturnType(op.left, ReturnType.BOOLEAN);
|
||||
ParserUtil.ensureReturnType(op.right, ReturnType.BOOLEAN);
|
||||
}, Map.of(TokenType.BOOLEAN_AND, (op) -> new BooleanAndOperation((Expression<Boolean>) op.left, (Expression<Boolean>) op.right, op.operator.getPosition())));
|
||||
}
|
||||
|
||||
private Expression<?> parseEquality(ScopeBuilder scopeBuilder) {
|
||||
return parseLeftAssociativeBinaryOperation(this::parseComparison, scopeBuilder, Map.of(
|
||||
TokenType.EQUALS_EQUALS, (op) -> new EqualsStatement((Expression<Object>) op.left, (Expression<Object>) op.right, op.operator.getPosition()),
|
||||
TokenType.BANG_EQUALS, (op) -> new NotEqualsStatement((Expression<Object>) op.left, (Expression<Object>) op.right, op.operator.getPosition())
|
||||
));
|
||||
}
|
||||
|
||||
private Expression<?> parseComparison(ScopeBuilder scopeBuilder) {
|
||||
return parseLeftAssociativeBinaryOperation(this::parseTerm, scopeBuilder, (op) -> {
|
||||
ParserUtil.ensureReturnType(op.left, ReturnType.NUMBER);
|
||||
ParserUtil.ensureReturnType(op.right, ReturnType.NUMBER);
|
||||
}, Map.of(
|
||||
TokenType.LESS, (op) -> new LessThanStatement((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition()),
|
||||
TokenType.LESS_EQUALS, (op) -> new LessThanOrEqualsStatement((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition()),
|
||||
TokenType.GREATER, (op) -> new GreaterThanStatement((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition()),
|
||||
TokenType.GREATER_EQUAL, (op) -> new GreaterOrEqualsThanStatement((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition())
|
||||
));
|
||||
}
|
||||
|
||||
private Expression<?> parseTerm(ScopeBuilder scopeBuilder) {
|
||||
return parseLeftAssociativeBinaryOperation(this::parseFactor, scopeBuilder, Map.of(
|
||||
TokenType.MINUS, (op) -> {
|
||||
ParserUtil.ensureReturnType(op.left, ReturnType.NUMBER);
|
||||
ParserUtil.ensureReturnType(op.right, ReturnType.NUMBER);
|
||||
return new SubtractionOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition());
|
||||
},
|
||||
TokenType.PLUS, (op) -> {
|
||||
if (op.left.returnType() == ReturnType.NUMBER && op.right.returnType() == ReturnType.NUMBER)
|
||||
return new NumberAdditionOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition());
|
||||
else
|
||||
return new ConcatenationOperation((Expression<Object>) op.left, (Expression<Object>) op.right, op.operator.getPosition());
|
||||
}));
|
||||
}
|
||||
|
||||
private Expression<?> parseFactor(ScopeBuilder scopeBuilder) {
|
||||
return parseLeftAssociativeBinaryOperation(this::parseUnary, scopeBuilder, (op) -> {
|
||||
ParserUtil.ensureReturnType(op.left, ReturnType.NUMBER);
|
||||
ParserUtil.ensureReturnType(op.right, ReturnType.NUMBER);
|
||||
}, Map.of(
|
||||
TokenType.STAR, (op) -> new MultiplicationOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition()),
|
||||
TokenType.FORWARD_SLASH, (op) -> new DivisionOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition()),
|
||||
TokenType.MODULO_OPERATOR, (op) -> new ModuloOperation((Expression<Number>) op.left, (Expression<Number>) op.right, op.operator.getPosition())
|
||||
));
|
||||
}
|
||||
|
||||
private Expression<?> parseUnary(ScopeBuilder scopeBuilder) {
|
||||
if (lexer.current().isType(TokenType.BANG, TokenType.MINUS)) {
|
||||
Token operator = lexer.consumeUnchecked();
|
||||
Expression<?> right = parseUnary(scopeBuilder);
|
||||
return switch(operator.getType()) {
|
||||
case BANG -> {
|
||||
ParserUtil.ensureReturnType(right, ReturnType.BOOLEAN);
|
||||
yield new BooleanNotOperation((Expression<Boolean>) right, operator.getPosition());
|
||||
}
|
||||
case MINUS -> {
|
||||
ParserUtil.ensureReturnType(right, ReturnType.NUMBER);
|
||||
yield new NegationOperation((Expression<Number>) right, operator.getPosition());
|
||||
}
|
||||
default -> throw new IllegalStateException();
|
||||
};
|
||||
private Returnable<?> parseExpression(Tokenizer tokens, boolean full, ScopeBuilder scopeBuilder) {
|
||||
boolean booleanInverted = false; // Check for boolean not operator
|
||||
boolean negate = false;
|
||||
if(tokens.get().getType().equals(Token.Type.BOOLEAN_NOT)) {
|
||||
booleanInverted = true;
|
||||
tokens.consume();
|
||||
} else if(tokens.get().getType().equals(Token.Type.SUBTRACTION_OPERATOR)) {
|
||||
negate = true;
|
||||
tokens.consume();
|
||||
}
|
||||
return parsePrimary(scopeBuilder);
|
||||
}
|
||||
|
||||
private Expression<?> parsePrimary(ScopeBuilder scopeBuilder) {
|
||||
Token token = lexer.consumeUnchecked();
|
||||
return switch(token.getType()) {
|
||||
case NUMBER -> {
|
||||
String content = token.getContent();
|
||||
yield new NumericConstant(content.contains(".") ? Double.parseDouble(content) : Integer.parseInt(content), token.getPosition());
|
||||
}
|
||||
case STRING -> new StringConstant(token.getContent(), token.getPosition());
|
||||
case BOOLEAN -> new BooleanConstant(Boolean.parseBoolean(token.getContent()), token.getPosition());
|
||||
case OPEN_PAREN -> {
|
||||
Expression<?> expr = parseExpression(scopeBuilder);
|
||||
lexer.consume("Missing ')' at end of expression group", TokenType.CLOSE_PAREN);
|
||||
yield expr;
|
||||
}
|
||||
case IDENTIFIER -> {
|
||||
if (scopeBuilder.containsFunction(token.getContent()))
|
||||
yield parseFunctionInvocation(token, scopeBuilder);
|
||||
else if (scopeBuilder.containsVariable(token.getContent())) {
|
||||
ReturnType variableType = scopeBuilder.getVaraibleType(token.getContent());
|
||||
yield switch(variableType) {
|
||||
case NUMBER -> new NumVariableReferenceNode(token.getPosition(), variableType, scopeBuilder.getIndex(token.getContent()));
|
||||
case BOOLEAN -> new BoolVariableReferenceNode(token.getPosition(), variableType, scopeBuilder.getIndex(token.getContent()));
|
||||
case STRING -> new StrVariableReferenceNode(token.getPosition(), variableType, scopeBuilder.getIndex(token.getContent()));
|
||||
default -> throw new ParseException("Illegal type for variable reference: " + variableType, token.getPosition());
|
||||
};
|
||||
}
|
||||
throw new ParseException("Identifier '" + token.getContent() + "' is not defined in this scope", token.getPosition());
|
||||
}
|
||||
default -> throw new ParseException("Unexpected token '" + token.getContent() + "' when parsing expression", token.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
private Expression<?> parseLeftAssociativeBinaryOperation(Function<ScopeBuilder, Expression<?>> higherPrecedence, ScopeBuilder scopeBuilder,
|
||||
Consumer<BinaryOperationInfo> init,
|
||||
Map<TokenType, Function<BinaryOperationInfo, Expression<?>>> operators) {
|
||||
Expression<?> expr = higherPrecedence.apply(scopeBuilder);
|
||||
TokenType[] opTypes = operators.keySet().toArray(new TokenType[0]);
|
||||
while (lexer.current().isType(opTypes)) {
|
||||
Token operator = lexer.consumeUnchecked();
|
||||
Expression<?> right = higherPrecedence.apply(scopeBuilder);
|
||||
BinaryOperationInfo op = new BinaryOperationInfo(expr, operator, right);
|
||||
init.accept(op);
|
||||
expr = operators.get(operator.getType()).apply(op);
|
||||
|
||||
Token id = tokens.get();
|
||||
|
||||
ParserUtil.checkType(id, Token.Type.IDENTIFIER, Token.Type.BOOLEAN, Token.Type.STRING, Token.Type.NUMBER, Token.Type.GROUP_BEGIN);
|
||||
|
||||
Returnable<?> expression;
|
||||
if(id.isConstant()) {
|
||||
expression = parseConstantExpression(tokens);
|
||||
} else if(id.getType().equals(Token.Type.GROUP_BEGIN)) { // Parse grouped expression
|
||||
expression = parseGroup(tokens, scopeBuilder);
|
||||
} else {
|
||||
if(functions.containsKey(id.getContent()))
|
||||
expression = parseFunction(tokens, false, scopeBuilder);
|
||||
else if(scopeBuilder.contains(id.getContent())) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.IDENTIFIER);
|
||||
String varId = id.getContent();
|
||||
ReturnType varType = scopeBuilder.getType(varId);
|
||||
expression = switch(varType) {
|
||||
case NUMBER -> new NumVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId));
|
||||
case STRING -> new StrVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId));
|
||||
case BOOLEAN -> new BoolVariableReferenceNode(id.getPosition(), varType, scopeBuilder.getIndex(varId));
|
||||
default -> throw new ParseException("Illegal type for variable reference: " + varType, id.getPosition());
|
||||
};
|
||||
|
||||
} else throw new ParseException("Unexpected token \" " + id.getContent() + "\"", id.getPosition());
|
||||
}
|
||||
return expr;
|
||||
|
||||
if(booleanInverted) { // Invert operation if boolean not detected
|
||||
ParserUtil.checkReturnType(expression, Returnable.ReturnType.BOOLEAN);
|
||||
expression = new BooleanNotOperation((Returnable<Boolean>) expression, expression.getPosition());
|
||||
} else if(negate) {
|
||||
ParserUtil.checkReturnType(expression, Returnable.ReturnType.NUMBER);
|
||||
expression = new NegationOperation((Returnable<Number>) expression, expression.getPosition());
|
||||
}
|
||||
|
||||
if(full && tokens.get().isBinaryOperator()) { // Parse binary operations
|
||||
return parseBinaryOperation(expression, tokens, scopeBuilder);
|
||||
}
|
||||
return expression;
|
||||
}
|
||||
|
||||
private Expression<?> parseLeftAssociativeBinaryOperation(Function<ScopeBuilder, Expression<?>> higherPrecedence, ScopeBuilder scopeBuilder, Map<TokenType, Function<BinaryOperationInfo, Expression<?>>> operators) {
|
||||
return parseLeftAssociativeBinaryOperation(higherPrecedence, scopeBuilder, (op) -> {}, operators);
|
||||
private ConstantExpression<?> parseConstantExpression(Tokenizer tokens) {
|
||||
Token constantToken = tokens.consume();
|
||||
Position position = constantToken.getPosition();
|
||||
switch(constantToken.getType()) {
|
||||
case NUMBER:
|
||||
String content = constantToken.getContent();
|
||||
return new NumericConstant(content.contains(".") ? Double.parseDouble(content) : Integer.parseInt(content), position);
|
||||
case STRING:
|
||||
return new StringConstant(constantToken.getContent(), position);
|
||||
case BOOLEAN:
|
||||
return new BooleanConstant(Boolean.parseBoolean(constantToken.getContent()), position);
|
||||
default:
|
||||
throw new UnsupportedOperationException(
|
||||
"Unsupported constant token: " + constantToken.getType() + " at position: " + position);
|
||||
}
|
||||
}
|
||||
|
||||
private record BinaryOperationInfo(Expression<?> left, Token operator, Expression<?> right) {}
|
||||
|
||||
private Expression<?> parseDeclaration(ScopeBuilder scopeBuilder) {
|
||||
Token type = lexer.consume("Expected type before declaration", TokenType.TYPE_STRING, TokenType.TYPE_NUMBER, TokenType.TYPE_BOOLEAN, TokenType.TYPE_VOID);
|
||||
Token identifier = lexer.consume("Expected identifier after type", TokenType.IDENTIFIER);
|
||||
|
||||
return switch(lexer.current().getType()) {
|
||||
case ASSIGNMENT -> parseVariableDeclaration(scopeBuilder, type, identifier);
|
||||
case OPEN_PAREN -> parseFunctionDeclaration(scopeBuilder, type, identifier);
|
||||
default -> throw new ParseException("Expected '=' for variable assignment or '(' for function declaration after identifier '" + identifier.getContent() + "'", lexer.current().getPosition());
|
||||
};
|
||||
private Returnable<?> parseGroup(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN);
|
||||
Returnable<?> expression = parseExpression(tokens, true, scopeBuilder); // Parse inside of group as a separate expression
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END);
|
||||
return expression;
|
||||
}
|
||||
|
||||
private BinaryOperation<?, ?> parseBinaryOperation(Returnable<?> left, Tokenizer tokens,
|
||||
ScopeBuilder scopeBuilder) {
|
||||
Token binaryOperator = tokens.consume();
|
||||
ParserUtil.checkBinaryOperator(binaryOperator);
|
||||
|
||||
Returnable<?> right = parseExpression(tokens, false, scopeBuilder);
|
||||
|
||||
Token other = tokens.get();
|
||||
if(ParserUtil.hasPrecedence(binaryOperator.getType(), other.getType())) {
|
||||
return assemble(left, parseBinaryOperation(right, tokens, scopeBuilder), binaryOperator);
|
||||
} else if(other.isBinaryOperator()) {
|
||||
return parseBinaryOperation(assemble(left, right, binaryOperator), tokens, scopeBuilder);
|
||||
}
|
||||
return assemble(left, right, binaryOperator);
|
||||
}
|
||||
|
||||
private Expression<?> parseVariableDeclaration(ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||
lexer.consume("Expected '=' after identifier '" + identifier.getContent() + "' for variable declaration", TokenType.ASSIGNMENT);
|
||||
private BinaryOperation<?, ?> assemble(Returnable<?> left, Returnable<?> right, Token binaryOperator) {
|
||||
if(binaryOperator.isStrictNumericOperator())
|
||||
ParserUtil.checkArithmeticOperation(left, right, binaryOperator); // Numeric type checking
|
||||
if(binaryOperator.isStrictBooleanOperator()) ParserUtil.checkBooleanOperation(left, right, binaryOperator); // Boolean type checking
|
||||
switch(binaryOperator.getType()) {
|
||||
case ADDITION_OPERATOR:
|
||||
if(left.returnType().equals(Returnable.ReturnType.NUMBER) && right.returnType().equals(Returnable.ReturnType.NUMBER)) {
|
||||
return new NumberAdditionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
}
|
||||
return new ConcatenationOperation((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
|
||||
case SUBTRACTION_OPERATOR:
|
||||
return new SubtractionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case MULTIPLICATION_OPERATOR:
|
||||
return new MultiplicationOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case DIVISION_OPERATOR:
|
||||
return new DivisionOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case EQUALS_OPERATOR:
|
||||
return new EqualsStatement((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
|
||||
case NOT_EQUALS_OPERATOR:
|
||||
return new NotEqualsStatement((Returnable<Object>) left, (Returnable<Object>) right, binaryOperator.getPosition());
|
||||
case GREATER_THAN_OPERATOR:
|
||||
return new GreaterThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case LESS_THAN_OPERATOR:
|
||||
return new LessThanStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case GREATER_THAN_OR_EQUALS_OPERATOR:
|
||||
return new GreaterOrEqualsThanStatement((Returnable<Number>) left, (Returnable<Number>) right,
|
||||
binaryOperator.getPosition());
|
||||
case LESS_THAN_OR_EQUALS_OPERATOR:
|
||||
return new LessThanOrEqualsStatement((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
case BOOLEAN_AND:
|
||||
return new BooleanAndOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
|
||||
case BOOLEAN_OR:
|
||||
return new BooleanOrOperation((Returnable<Boolean>) left, (Returnable<Boolean>) right, binaryOperator.getPosition());
|
||||
case MODULO_OPERATOR:
|
||||
return new ModuloOperation((Returnable<Number>) left, (Returnable<Number>) right, binaryOperator.getPosition());
|
||||
default:
|
||||
throw new UnsupportedOperationException("Unsupported binary operator: " + binaryOperator.getType());
|
||||
}
|
||||
}
|
||||
|
||||
private VariableAssignmentNode<?> parseVariableDeclaration(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
Token type = tokens.consume();
|
||||
ParserUtil.checkType(type, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.NUMBER_VARIABLE);
|
||||
|
||||
if (!type.isVariableDeclaration()) throw new ParseException("Expected type specification at beginning of variable declaration", type.getPosition());
|
||||
Returnable.ReturnType returnType = ParserUtil.getVariableReturnType(type);
|
||||
|
||||
if(scopeBuilder.containsVariable(identifier.getContent()))
|
||||
ParserUtil.checkVarType(type, returnType); // Check for type mismatch
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER);
|
||||
if(functions.containsKey(identifier.getContent()) || scopeBuilder.contains(identifier.getContent()))
|
||||
throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition());
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
|
||||
|
||||
Expression<?> value = parseExpression(scopeBuilder);
|
||||
ParserUtil.ensureReturnType(value, ParserUtil.getVariableReturnType(type));
|
||||
|
||||
String variableName = identifier.getContent();
|
||||
Returnable<?> value = parseExpression(tokens, true, scopeBuilder);
|
||||
ParserUtil.checkReturnType(value, returnType);
|
||||
|
||||
String id = identifier.getContent();
|
||||
|
||||
return switch(value.returnType()) {
|
||||
case NUMBER -> new NumAssignmentNode((Expression<Number>) value, identifier.getPosition(),
|
||||
scopeBuilder.declareNum(variableName));
|
||||
case STRING -> new StrAssignmentNode((Expression<String>) value, identifier.getPosition(),
|
||||
scopeBuilder.declareStr(variableName));
|
||||
case BOOLEAN -> new BoolAssignmentNode((Expression<Boolean>) value, identifier.getPosition(),
|
||||
scopeBuilder.declareBool(variableName));
|
||||
case NUMBER -> new NumAssignmentNode((Returnable<Number>) value, identifier.getPosition(), scopeBuilder.num(id));
|
||||
case STRING -> new StrAssignmentNode((Returnable<String>) value, identifier.getPosition(), scopeBuilder.str(id));
|
||||
case BOOLEAN -> new BoolAssignmentNode((Returnable<Boolean>) value, identifier.getPosition(), scopeBuilder.bool(id));
|
||||
default -> throw new ParseException("Illegal type for variable declaration: " + type, value.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
private Expression<?> parseFunctionDeclaration(ScopeBuilder scopeBuilder, Token type, Token identifier) {
|
||||
lexer.consume("Expected '(' after identifier '" + identifier.getContent() + "' for function declaration", TokenType.OPEN_PAREN);
|
||||
private Block parseBlock(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
List<Item<?>> parsedItems = new ArrayList<>();
|
||||
|
||||
if(!(type.isType(TokenType.TYPE_STRING, TokenType.TYPE_BOOLEAN, TokenType.TYPE_NUMBER, TokenType.TYPE_VOID)))
|
||||
throw new ParseException("Invalid function declaration return type specification " + type.getType(), type.getPosition());
|
||||
scopeBuilder = scopeBuilder.sub();
|
||||
|
||||
if(scopeBuilder.containsVariable(identifier.getContent()))
|
||||
throw new ParseException(identifier.getContent() + " is already defined in this scope", identifier.getPosition());
|
||||
Token first = tokens.get();
|
||||
|
||||
ReturnType returnType = ParserUtil.getVariableReturnType(type);
|
||||
|
||||
ScopeBuilder functionBodyScope = scopeBuilder.functionScope();
|
||||
|
||||
// Declare parameter names into function body scope
|
||||
List<Pair<Integer, ReturnType>> parameterInfo = getFunctionParameterDeclaration().stream().map(
|
||||
arg -> Pair.of(switch(arg.getRight()) {
|
||||
case NUMBER -> functionBodyScope.declareNum(arg.getLeft());
|
||||
case BOOLEAN -> functionBodyScope.declareBool(arg.getLeft());
|
||||
case STRING -> functionBodyScope.declareStr(arg.getLeft());
|
||||
default -> throw new IllegalArgumentException("Unsupported parameter type: " + arg.getRight());
|
||||
}, arg.getRight())).toList();
|
||||
|
||||
Block body = parseStatementBlock(functionBodyScope, returnType);
|
||||
|
||||
FunctionBuilder<?> functionBuilder = new UserDefinedFunctionBuilder<>(returnType, parameterInfo, body, functionBodyScope);
|
||||
|
||||
scopeBuilder.registerFunction(identifier.getContent(), functionBuilder);
|
||||
return Expression.NOOP;
|
||||
}
|
||||
|
||||
private List<Pair<String, ReturnType>> getFunctionParameterDeclaration() {
|
||||
List<Pair<String, ReturnType>> parameters = new ArrayList<>();
|
||||
while(lexer.current().getType() != TokenType.CLOSE_PAREN) {
|
||||
// Parse parameter type
|
||||
Token typeToken = lexer.consume("Expected function parameter type declaration", TokenType.TYPE_BOOLEAN, TokenType.TYPE_STRING, TokenType.TYPE_NUMBER);
|
||||
ReturnType type = ParserUtil.getVariableReturnType(typeToken);
|
||||
|
||||
// Parse parameter name
|
||||
Token identifierToken = lexer.consume("Expected function parameter identifier", TokenType.IDENTIFIER);
|
||||
String name = identifierToken.getContent();
|
||||
|
||||
parameters.add(Pair.of(name, type));
|
||||
|
||||
// Consume separator if present, trailing separators are allowed
|
||||
if(lexer.current().isType(TokenType.SEPARATOR)) lexer.consumeUnchecked();
|
||||
while(tokens.hasNext()) {
|
||||
Token token = tokens.get();
|
||||
if(token.getType().equals(Token.Type.BLOCK_END)) break; // Stop parsing at block end.
|
||||
Item<?> parsedItem = parseItem(tokens, loop, scopeBuilder);
|
||||
if(parsedItem != Function.NULL) {
|
||||
parsedItems.add(parsedItem);
|
||||
}
|
||||
if(tokens.hasNext() && !token.isLoopLike()) ParserUtil.checkType(tokens.consume(), Token.Type.STATEMENT_END);
|
||||
}
|
||||
lexer.consume("Expected ')' after function parameter declaration", TokenType.CLOSE_PAREN);
|
||||
return parameters;
|
||||
return new Block(parsedItems, first.getPosition());
|
||||
}
|
||||
|
||||
private Block parseBlock(ScopeBuilder scopeBuilder, ReturnType blockReturnType) {
|
||||
List<Expression<?>> expressions = new ArrayList<>();
|
||||
scopeBuilder = scopeBuilder.innerScope(); // Create new inner scope for the block
|
||||
SourcePosition startPosition = lexer.current().getPosition();
|
||||
private Item<?> parseItem(Tokenizer tokens, boolean loop, ScopeBuilder scopeBuilder) {
|
||||
Token token = tokens.get();
|
||||
if(loop) ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
|
||||
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE,
|
||||
Token.Type.RETURN, Token.Type.BREAK, Token.Type.CONTINUE, Token.Type.FAIL);
|
||||
else ParserUtil.checkType(token, Token.Type.IDENTIFIER, Token.Type.IF_STATEMENT, Token.Type.WHILE_LOOP, Token.Type.FOR_LOOP,
|
||||
Token.Type.NUMBER_VARIABLE, Token.Type.STRING_VARIABLE, Token.Type.BOOLEAN_VARIABLE, Token.Type.RETURN,
|
||||
Token.Type.FAIL);
|
||||
|
||||
boolean hasReturn = false;
|
||||
|
||||
// Parse each statement
|
||||
while(lexer.hasNext() && !lexer.current().isType(TokenType.BLOCK_END)) {
|
||||
Expression<?> expression = parseStatement(scopeBuilder);
|
||||
if(expression != Expression.NOOP) {
|
||||
expressions.add(expression);
|
||||
}
|
||||
if(expression instanceof ReturnKeyword returnKeyword) {
|
||||
hasReturn = true;
|
||||
if(returnKeyword.dataReturnType() != blockReturnType)
|
||||
throw new ParseException(
|
||||
"Invalid return type, expected " + blockReturnType + ", found " + returnKeyword.dataReturnType(),
|
||||
expression.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
if(blockReturnType != ReturnType.VOID && !hasReturn)
|
||||
throw new ParseException("Block does not contain a return statement, must return type " + blockReturnType, startPosition);
|
||||
|
||||
return new Block(expressions, startPosition, blockReturnType);
|
||||
if(token.isLoopLike()) { // Parse loop-like tokens (if, while, etc)
|
||||
return parseLoopLike(tokens, loop, scopeBuilder);
|
||||
} else if(token.isIdentifier()) { // Parse identifiers
|
||||
if(scopeBuilder.contains(token.getContent())) { // Assume variable assignment
|
||||
return parseAssignment(tokens, scopeBuilder);
|
||||
} else return parseFunction(tokens, true, scopeBuilder);
|
||||
} else if(token.isVariableDeclaration()) {
|
||||
|
||||
return parseVariableDeclaration(tokens, scopeBuilder);
|
||||
|
||||
} else if(token.getType().equals(Token.Type.RETURN)) return new ReturnKeyword(tokens.consume().getPosition());
|
||||
else if(token.getType().equals(Token.Type.BREAK)) return new BreakKeyword(tokens.consume().getPosition());
|
||||
else if(token.getType().equals(Token.Type.CONTINUE)) return new ContinueKeyword(tokens.consume().getPosition());
|
||||
else if(token.getType().equals(Token.Type.FAIL)) return new FailKeyword(tokens.consume().getPosition());
|
||||
else throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
||||
}
|
||||
|
||||
private Expression<?> parseStatement(ScopeBuilder scopeBuilder) {
|
||||
Token token = lexer.current();
|
||||
Expression<?> expression = switch(token.getType()) {
|
||||
case FOR_LOOP -> parseForLoop(scopeBuilder);
|
||||
case IF_STATEMENT -> parseIfStatement(scopeBuilder);
|
||||
case WHILE_LOOP -> parseWhileLoop(scopeBuilder);
|
||||
case IDENTIFIER -> {
|
||||
if(scopeBuilder.containsVariable(token.getContent())) yield parseAssignment(scopeBuilder); // Assume variable assignment
|
||||
else yield parseFunctionInvocation(lexer.consumeUnchecked(), scopeBuilder);
|
||||
}
|
||||
case TYPE_NUMBER, TYPE_STRING, TYPE_BOOLEAN, TYPE_VOID -> parseDeclaration(scopeBuilder);
|
||||
case RETURN -> parseReturn(scopeBuilder);
|
||||
case BREAK -> {
|
||||
if (!scopeBuilder.isInLoop()) throw new ParseException("Break statements can only be defined inside loops", token.getPosition());
|
||||
yield new BreakKeyword(lexer.consumeUnchecked().getPosition());
|
||||
}
|
||||
case CONTINUE -> {
|
||||
if (!scopeBuilder.isInLoop()) throw new ParseException("Continue statements can only be defined inside loops", token.getPosition());
|
||||
yield new ContinueKeyword(lexer.consumeUnchecked().getPosition());
|
||||
}
|
||||
case FAIL -> new FailKeyword(lexer.consumeUnchecked().getPosition());
|
||||
case STATEMENT_END -> Expression.NOOP;
|
||||
default -> throw new UnsupportedOperationException("Unexpected token " + token.getType() + ": " + token.getPosition());
|
||||
};
|
||||
if(!token.isControlStructure() && expression != Expression.NOOP) lexer.consume("Expected ';' at end of statement", TokenType.STATEMENT_END);
|
||||
return expression;
|
||||
}
|
||||
|
||||
private ReturnKeyword parseReturn(ScopeBuilder scopeBuilder) {
|
||||
Token returnToken = lexer.consume("Expected 'return' keyword at beginning of return statement", TokenType.RETURN);
|
||||
Expression<?> data = null;
|
||||
if(!lexer.current().isType(TokenType.STATEMENT_END)) {
|
||||
data = parseExpression(scopeBuilder);
|
||||
}
|
||||
return new ReturnKeyword(data, returnToken.getPosition());
|
||||
}
|
||||
|
||||
private VariableAssignmentNode<?> parseAssignment(ScopeBuilder scopeBuilder) {
|
||||
Token identifier = lexer.consume("Expected identifier at beginning of assignment", TokenType.IDENTIFIER);
|
||||
private VariableAssignmentNode<?> parseAssignment(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
Token identifier = tokens.consume();
|
||||
|
||||
lexer.consume("Expected '=' after identifier for variable assignment", TokenType.ASSIGNMENT);
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER);
|
||||
|
||||
Expression<?> value = parseExpression(scopeBuilder);
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.ASSIGNMENT);
|
||||
|
||||
Returnable<?> value = parseExpression(tokens, true, scopeBuilder);
|
||||
|
||||
String id = identifier.getContent();
|
||||
|
||||
ParserUtil.ensureReturnType(value, scopeBuilder.getVaraibleType(id));
|
||||
ParserUtil.checkReturnType(value, scopeBuilder.getType(id));
|
||||
|
||||
ReturnType type = value.returnType();
|
||||
|
||||
return switch(type) {
|
||||
case NUMBER -> new NumAssignmentNode((Expression<Number>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
case STRING -> new StrAssignmentNode((Expression<String>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
case BOOLEAN -> new BoolAssignmentNode((Expression<Boolean>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
case NUMBER -> new NumAssignmentNode((Returnable<Number>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
case STRING -> new StrAssignmentNode((Returnable<String>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
case BOOLEAN -> new BoolAssignmentNode((Returnable<Boolean>) value, identifier.getPosition(), scopeBuilder.getIndex(id));
|
||||
default -> throw new ParseException("Illegal type for variable assignment: " + type, value.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
private Expression<?> parseFunctionInvocation(Token identifier, ScopeBuilder scopeBuilder) {
|
||||
if(!scopeBuilder.containsFunction(identifier.getContent()))
|
||||
throw new ParseException("Function '" + identifier.getContent() + "' is not defined in this scope", identifier.getPosition());
|
||||
private Function<?> parseFunction(Tokenizer tokens, boolean fullStatement, ScopeBuilder scopeBuilder) {
|
||||
Token identifier = tokens.consume();
|
||||
ParserUtil.checkType(identifier, Token.Type.IDENTIFIER); // First token must be identifier
|
||||
|
||||
FunctionBuilder<?> builder = scopeBuilder.getFunction(identifier.getContent());
|
||||
if(!functions.containsKey(identifier.getContent()))
|
||||
throw new ParseException("No such function \"" + identifier.getContent() + "\"", identifier.getPosition());
|
||||
|
||||
lexer.consume("Expected '(' after identifier " + identifier.getContent(), TokenType.OPEN_PAREN); // Invocation starts with open paren
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_BEGIN); // Second is body begin
|
||||
|
||||
List<Expression<?>> args = new ArrayList<>();
|
||||
while(!lexer.current().isType(TokenType.CLOSE_PAREN)) {
|
||||
args.add(parseExpression(scopeBuilder));
|
||||
if (lexer.current().isType(TokenType.CLOSE_PAREN)) break;
|
||||
lexer.consume("Expected ',' between function arguments", TokenType.SEPARATOR);
|
||||
}
|
||||
lexer.consume("Expected ')' after function arguments", TokenType.CLOSE_PAREN);
|
||||
|
||||
List<Returnable<?>> args = getArgs(tokens, scopeBuilder); // Extract arguments, consume the rest.
|
||||
|
||||
ParserUtil.checkType(tokens.consume(), Token.Type.GROUP_END); // Remove body end
|
||||
|
||||
if(fullStatement) ParserUtil.checkType(tokens.get(), Token.Type.STATEMENT_END);
|
||||
|
||||
if(ignoredFunctions.contains(identifier.getContent())) {
|
||||
return Expression.NOOP;
|
||||
return Function.NULL;
|
||||
}
|
||||
|
||||
if(builder.argNumber() != -1 && args.size() != builder.argNumber())
|
||||
throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size(), identifier.getPosition());
|
||||
|
||||
for(int i = 0; i < args.size(); i++) {
|
||||
Expression<?> argument = args.get(i);
|
||||
if(builder.getArgument(i) == null)
|
||||
throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.getContent(),
|
||||
identifier.getPosition());
|
||||
ParserUtil.ensureReturnType(argument, builder.getArgument(i));
|
||||
if(functions.containsKey(identifier.getContent())) {
|
||||
FunctionBuilder<?> builder = functions.get(identifier.getContent());
|
||||
|
||||
if(builder.argNumber() != -1 && args.size() != builder.argNumber())
|
||||
throw new ParseException("Expected " + builder.argNumber() + " arguments, found " + args.size(), identifier.getPosition());
|
||||
|
||||
for(int i = 0; i < args.size(); i++) {
|
||||
Returnable<?> argument = args.get(i);
|
||||
if(builder.getArgument(i) == null)
|
||||
throw new ParseException("Unexpected argument at position " + i + " in function " + identifier.getContent(),
|
||||
identifier.getPosition());
|
||||
ParserUtil.checkReturnType(argument, builder.getArgument(i));
|
||||
}
|
||||
return builder.build(args, identifier.getPosition());
|
||||
}
|
||||
return builder.build(args, identifier.getPosition());
|
||||
throw new UnsupportedOperationException("Unsupported function: " + identifier.getContent());
|
||||
}
|
||||
|
||||
private List<Returnable<?>> getArgs(Tokenizer tokens, ScopeBuilder scopeBuilder) {
|
||||
List<Returnable<?>> args = new ArrayList<>();
|
||||
|
||||
while(!tokens.get().getType().equals(Token.Type.GROUP_END)) {
|
||||
args.add(parseExpression(tokens, true, scopeBuilder));
|
||||
ParserUtil.checkType(tokens.get(), Token.Type.SEPARATOR, Token.Type.GROUP_END);
|
||||
if(tokens.get().getType().equals(Token.Type.SEPARATOR)) tokens.consume();
|
||||
}
|
||||
return args;
|
||||
}
|
||||
}
|
||||
|
||||
+87
-15
@@ -12,32 +12,104 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Token;
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Token.TokenType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Token;
|
||||
|
||||
|
||||
public class ParserUtil {
|
||||
|
||||
// public static void ensureType(Token token, TokenType... expected) {
|
||||
// for(TokenType type : expected) if(token.getType().equals(type)) return;
|
||||
// throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition());
|
||||
// }
|
||||
private static final Map<Token.Type, Map<Token.Type, Boolean>> PRECEDENCE = new HashMap<>(); // If second has precedence, true.
|
||||
private static final List<Token.Type> ARITHMETIC = Arrays.asList(Token.Type.ADDITION_OPERATOR, Token.Type.SUBTRACTION_OPERATOR,
|
||||
Token.Type.MULTIPLICATION_OPERATOR, Token.Type.DIVISION_OPERATOR,
|
||||
Token.Type.MODULO_OPERATOR);
|
||||
private static final List<Token.Type> COMPARISON = Arrays.asList(Token.Type.EQUALS_OPERATOR, Token.Type.NOT_EQUALS_OPERATOR,
|
||||
Token.Type.LESS_THAN_OPERATOR, Token.Type.LESS_THAN_OR_EQUALS_OPERATOR,
|
||||
Token.Type.GREATER_THAN_OPERATOR,
|
||||
Token.Type.GREATER_THAN_OR_EQUALS_OPERATOR);
|
||||
|
||||
public static void ensureReturnType(Expression<?> returnable, Expression.ReturnType... types) {
|
||||
for(Expression.ReturnType type : types) if(returnable.returnType().equals(type)) return;
|
||||
throw new ParseException("Invalid type " + returnable.returnType() + ", expected " + (types.length == 1 ? types[0].toString() : "one of " + Arrays.toString(types)), returnable.getPosition());
|
||||
static { // Setup precedence
|
||||
Map<Token.Type, Boolean> add = new HashMap<>(); // Addition/subtraction before Multiplication/division.
|
||||
add.put(Token.Type.MULTIPLICATION_OPERATOR, true);
|
||||
add.put(Token.Type.DIVISION_OPERATOR, true);
|
||||
|
||||
PRECEDENCE.put(Token.Type.ADDITION_OPERATOR, add);
|
||||
PRECEDENCE.put(Token.Type.SUBTRACTION_OPERATOR, add);
|
||||
|
||||
Map<Token.Type, Boolean> numericBoolean = new HashMap<>();
|
||||
|
||||
ARITHMETIC.forEach(op -> numericBoolean.put(op, true)); // Numbers before comparison
|
||||
COMPARISON.forEach(op -> PRECEDENCE.put(op, numericBoolean));
|
||||
|
||||
|
||||
Map<Token.Type, Boolean> booleanOps = new HashMap<>();
|
||||
ARITHMETIC.forEach(op -> booleanOps.put(op, true)); // Everything before boolean
|
||||
COMPARISON.forEach(op -> booleanOps.put(op, true));
|
||||
|
||||
|
||||
PRECEDENCE.put(Token.Type.BOOLEAN_AND, booleanOps);
|
||||
PRECEDENCE.put(Token.Type.BOOLEAN_OR, booleanOps);
|
||||
}
|
||||
|
||||
public static Expression.ReturnType getVariableReturnType(Token varToken) {
|
||||
public static void checkType(Token token, Token.Type... expected) {
|
||||
for(Token.Type type : expected) if(token.getType().equals(type)) return;
|
||||
throw new ParseException("Expected " + Arrays.toString(expected) + " but found " + token.getType(), token.getPosition());
|
||||
}
|
||||
|
||||
public static void checkReturnType(Returnable<?> returnable, Returnable.ReturnType... types) {
|
||||
for(Returnable.ReturnType type : types) if(returnable.returnType().equals(type)) return;
|
||||
throw new ParseException("Expected " + Arrays.toString(types) + " but found " + returnable.returnType(), returnable.getPosition());
|
||||
}
|
||||
|
||||
public static void checkArithmeticOperation(Returnable<?> left, Returnable<?> right, Token operation) {
|
||||
if(!left.returnType().equals(Returnable.ReturnType.NUMBER) || !right.returnType().equals(Returnable.ReturnType.NUMBER)) {
|
||||
throw new ParseException(
|
||||
"Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(),
|
||||
operation.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkBooleanOperation(Returnable<?> left, Returnable<?> right, Token operation) {
|
||||
if(!left.returnType().equals(Returnable.ReturnType.BOOLEAN) || !right.returnType().equals(Returnable.ReturnType.BOOLEAN)) {
|
||||
throw new ParseException(
|
||||
"Operation " + operation.getType() + " not supported between " + left.returnType() + " and " + right.returnType(),
|
||||
operation.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
public static void checkVarType(Token token, Returnable.ReturnType returnType) {
|
||||
if(returnType.equals(Returnable.ReturnType.STRING) && token.getType().equals(Token.Type.STRING_VARIABLE)) return;
|
||||
if(returnType.equals(Returnable.ReturnType.NUMBER) && token.getType().equals(Token.Type.NUMBER_VARIABLE)) return;
|
||||
if(returnType.equals(Returnable.ReturnType.BOOLEAN) && token.getType().equals(Token.Type.BOOLEAN_VARIABLE)) return;
|
||||
throw new ParseException("Type mismatch, cannot convert from " + returnType + " to " + token.getType(), token.getPosition());
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if token is a binary operator
|
||||
*
|
||||
* @param token Token to check
|
||||
*
|
||||
* @throws ParseException If token isn't a binary operator
|
||||
*/
|
||||
public static void checkBinaryOperator(Token token) {
|
||||
if(!token.isBinaryOperator())
|
||||
throw new ParseException("Expected binary operator, found " + token.getType(), token.getPosition());
|
||||
}
|
||||
|
||||
public static Returnable.ReturnType getVariableReturnType(Token varToken) {
|
||||
return switch(varToken.getType()) {
|
||||
case TYPE_NUMBER -> Expression.ReturnType.NUMBER;
|
||||
case TYPE_STRING -> Expression.ReturnType.STRING;
|
||||
case TYPE_BOOLEAN -> Expression.ReturnType.BOOLEAN;
|
||||
case TYPE_VOID -> Expression.ReturnType.VOID;
|
||||
case NUMBER_VARIABLE -> Returnable.ReturnType.NUMBER;
|
||||
case STRING_VARIABLE -> Returnable.ReturnType.STRING;
|
||||
case BOOLEAN_VARIABLE -> Returnable.ReturnType.BOOLEAN;
|
||||
default -> throw new ParseException("Unexpected token " + varToken.getType() + "; expected variable declaration",
|
||||
varToken.getPosition());
|
||||
};
|
||||
}
|
||||
|
||||
public static boolean hasPrecedence(Token.Type first, Token.Type second) {
|
||||
if(!PRECEDENCE.containsKey(first)) return false;
|
||||
Map<Token.Type, Boolean> pre = PRECEDENCE.get(first);
|
||||
if(!pre.containsKey(second)) return false;
|
||||
return pre.get(second);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -9,30 +9,30 @@ package com.dfsek.terra.addons.terrascript.parser.exceptions;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class ParseException extends RuntimeException {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 6744390543046766386L;
|
||||
private final SourcePosition position;
|
||||
private final Position position;
|
||||
|
||||
public ParseException(String message, SourcePosition position) {
|
||||
public ParseException(String message, Position position) {
|
||||
super(message);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
public ParseException(String message, SourcePosition position, Throwable cause) {
|
||||
public ParseException(String message, Position position, Throwable cause) {
|
||||
super(message, cause);
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return "Error at " + position + ": " + super.getMessage();
|
||||
return super.getMessage() + ": " + position;
|
||||
}
|
||||
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
+30
-23
@@ -9,43 +9,35 @@ package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class Block implements Expression<EvaluationInfo<?>> {
|
||||
private final List<Expression<?>> items;
|
||||
private final SourcePosition position;
|
||||
private final ReturnType returnType;
|
||||
public class Block implements Item<Block.ReturnInfo<?>> {
|
||||
private final List<Item<?>> items;
|
||||
private final Position position;
|
||||
|
||||
public Block(List<Expression<?>> items, SourcePosition position, ReturnType returnType) {
|
||||
public Block(List<Item<?>> items, Position position) {
|
||||
this.items = items;
|
||||
this.position = position;
|
||||
this.returnType = returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
for(Expression<?> item : items) {
|
||||
Object result = item.evaluate(implementationArguments, scope);
|
||||
if(result instanceof EvaluationInfo<?> evalInfo) {
|
||||
if(!evalInfo.level().equals(EvaluationLevel.NONE)) return evalInfo;
|
||||
public ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
for(Item<?> item : items) {
|
||||
Object result = item.apply(implementationArguments, scope);
|
||||
if(result instanceof ReturnInfo<?> level) {
|
||||
if(!level.getLevel().equals(ReturnLevel.NONE)) return level;
|
||||
}
|
||||
}
|
||||
return new EvaluationInfo<>(EvaluationLevel.NONE, Expression.NOOP);
|
||||
return new ReturnInfo<>(ReturnLevel.NONE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public enum EvaluationLevel {
|
||||
public enum ReturnLevel {
|
||||
NONE(false),
|
||||
BREAK(false),
|
||||
CONTINUE(false),
|
||||
@@ -54,7 +46,7 @@ public class Block implements Expression<EvaluationInfo<?>> {
|
||||
|
||||
private final boolean returnFast;
|
||||
|
||||
EvaluationLevel(boolean returnFast) {
|
||||
ReturnLevel(boolean returnFast) {
|
||||
this.returnFast = returnFast;
|
||||
}
|
||||
|
||||
@@ -64,6 +56,21 @@ public class Block implements Expression<EvaluationInfo<?>> {
|
||||
}
|
||||
|
||||
|
||||
public record EvaluationInfo<T extends Expression<?>>(EvaluationLevel level, T data) {
|
||||
public static class ReturnInfo<T> {
|
||||
private final ReturnLevel level;
|
||||
private final T data;
|
||||
|
||||
public ReturnInfo(ReturnLevel level, T data) {
|
||||
this.level = level;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public ReturnLevel getLevel() {
|
||||
return level;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -7,13 +7,13 @@ import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||
public class Executable {
|
||||
private final Block script;
|
||||
private final ThreadLocal<Scope> scope;
|
||||
|
||||
|
||||
public Executable(Block script, ScopeBuilder scopeBuilder) {
|
||||
this.script = script;
|
||||
this.scope = ThreadLocal.withInitial(scopeBuilder::build);
|
||||
}
|
||||
|
||||
|
||||
public boolean execute(ImplementationArguments arguments) {
|
||||
return script.evaluate(arguments, scope.get()).level() != Block.EvaluationLevel.FAIL;
|
||||
return script.apply(arguments, scope.get()).getLevel() != Block.ReturnLevel.FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
-63
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
|
||||
|
||||
public interface Expression<T> {
|
||||
Expression<Void> NOOP = new Expression<>() {
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.VOID;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
ReturnType returnType();
|
||||
|
||||
T evaluate(ImplementationArguments implementationArguments, Scope scope);
|
||||
|
||||
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
|
||||
}
|
||||
|
||||
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
|
||||
}
|
||||
|
||||
SourcePosition getPosition();
|
||||
|
||||
|
||||
enum ReturnType {
|
||||
NUMBER(true),
|
||||
STRING(true),
|
||||
BOOLEAN(false),
|
||||
VOID(false),
|
||||
OBJECT(false);
|
||||
|
||||
private final boolean comparable;
|
||||
|
||||
ReturnType(boolean comparable) {
|
||||
this.comparable = comparable;
|
||||
}
|
||||
|
||||
public boolean isComparable() {
|
||||
return comparable;
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
/**
|
||||
* Arguments passed to {@link Expression}s by the implementation
|
||||
* Arguments passed to {@link Item}s by the implementation
|
||||
*/
|
||||
public interface ImplementationArguments {
|
||||
}
|
||||
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public interface Item<T> {
|
||||
T apply(ImplementationArguments implementationArguments, Scope scope);
|
||||
|
||||
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
|
||||
}
|
||||
|
||||
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
throw new UnsupportedOperationException("Cannot apply " + this + " as double");
|
||||
}
|
||||
|
||||
Position getPosition();
|
||||
}
|
||||
+1
-1
@@ -7,5 +7,5 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
public interface Keyword<T> extends Expression<T> {
|
||||
public interface Keyword<T> extends Returnable<T> {
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
public interface Returnable<T> extends Item<T> {
|
||||
ReturnType returnType();
|
||||
|
||||
enum ReturnType {
|
||||
NUMBER(true),
|
||||
STRING(true),
|
||||
BOOLEAN(false),
|
||||
VOID(false),
|
||||
OBJECT(false);
|
||||
|
||||
private final boolean comparable;
|
||||
|
||||
ReturnType(boolean comparable) {
|
||||
this.comparable = comparable;
|
||||
}
|
||||
|
||||
public boolean isComparable() {
|
||||
return comparable;
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-47
@@ -6,9 +6,7 @@ import net.jafama.FastMath;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable.ReturnType;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
|
||||
@@ -48,57 +46,28 @@ public class Scope {
|
||||
}
|
||||
|
||||
public static final class ScopeBuilder {
|
||||
|
||||
private final Map<String, FunctionBuilder<? extends Function<?>>> functions;
|
||||
private final Map<String, Pair<Integer, ReturnType>> indices;
|
||||
private int numSize, boolSize, strSize = 0;
|
||||
private ScopeBuilder parent;
|
||||
|
||||
private boolean inLoop;
|
||||
|
||||
public ScopeBuilder() {
|
||||
this.functions = new HashMap<>();
|
||||
this.indices = new HashMap<>();
|
||||
}
|
||||
|
||||
private ScopeBuilder(ScopeBuilder parent, boolean inLoop) {
|
||||
private ScopeBuilder(ScopeBuilder parent) {
|
||||
this.parent = parent;
|
||||
this.numSize = parent.numSize;
|
||||
this.boolSize = parent.boolSize;
|
||||
this.strSize = parent.strSize;
|
||||
this.functions = new HashMap<>(parent.functions);
|
||||
this.indices = new HashMap<>(parent.indices);
|
||||
this.inLoop = inLoop;
|
||||
}
|
||||
|
||||
private ScopeBuilder(Map<String, FunctionBuilder<? extends Function<?>>> functions) {
|
||||
this.functions = new HashMap<>(functions);
|
||||
this.indices = new HashMap<>();
|
||||
}
|
||||
|
||||
public Scope build() {
|
||||
return new Scope(numSize, boolSize, strSize);
|
||||
}
|
||||
|
||||
public ScopeBuilder innerScope() {
|
||||
return new ScopeBuilder(this, inLoop);
|
||||
}
|
||||
|
||||
public ScopeBuilder innerLoopScope() { return new ScopeBuilder(this, true); }
|
||||
|
||||
public ScopeBuilder functionScope() { return new ScopeBuilder(functions); }
|
||||
|
||||
public ScopeBuilder registerFunction(String name, FunctionBuilder<? extends Function<?>> functionBuilder) {
|
||||
functions.put(name, functionBuilder);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean containsFunction(String functionName) {
|
||||
return functions.containsKey(functionName);
|
||||
}
|
||||
|
||||
public FunctionBuilder<?> getFunction(String functionName) {
|
||||
return functions.get(functionName);
|
||||
public ScopeBuilder sub() {
|
||||
return new ScopeBuilder(this);
|
||||
}
|
||||
|
||||
private String check(String id) {
|
||||
@@ -107,12 +76,8 @@ public class Scope {
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isInLoop() {
|
||||
return inLoop;
|
||||
}
|
||||
|
||||
public int declareNum(String id) {
|
||||
|
||||
public int num(String id) {
|
||||
int num = numSize;
|
||||
indices.put(check(id), Pair.of(num, ReturnType.NUMBER));
|
||||
numSize++;
|
||||
@@ -120,7 +85,7 @@ public class Scope {
|
||||
return num;
|
||||
}
|
||||
|
||||
public int declareStr(String id) {
|
||||
public int str(String id) {
|
||||
int str = strSize;
|
||||
indices.put(check(id), Pair.of(str, ReturnType.STRING));
|
||||
strSize++;
|
||||
@@ -128,7 +93,7 @@ public class Scope {
|
||||
return str;
|
||||
}
|
||||
|
||||
public int declareBool(String id) {
|
||||
public int bool(String id) {
|
||||
int bool = boolSize;
|
||||
indices.put(check(id), Pair.of(bool, ReturnType.BOOLEAN));
|
||||
boolSize++;
|
||||
@@ -142,14 +107,14 @@ public class Scope {
|
||||
parent.updateBoolSize(size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateNumSize(int size) {
|
||||
this.numSize = FastMath.max(numSize, size);
|
||||
if(parent != null) {
|
||||
parent.updateNumSize(size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void updateStrSize(int size) {
|
||||
this.strSize = FastMath.max(strSize, size);
|
||||
if(parent != null) {
|
||||
@@ -161,11 +126,12 @@ public class Scope {
|
||||
return indices.get(id).getLeft();
|
||||
}
|
||||
|
||||
public ReturnType getVaraibleType(String id) {
|
||||
public ReturnType getType(String id) {
|
||||
return indices.get(id).getRight();
|
||||
}
|
||||
|
||||
public boolean containsVariable(String id) {
|
||||
|
||||
public boolean contains(String id) {
|
||||
return indices.containsKey(id);
|
||||
}
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Polyhedral Development
|
||||
*
|
||||
* The Terra Core Addons are licensed under the terms of the MIT License. For more details,
|
||||
* reference the LICENSE file in this module's root directory.
|
||||
*/
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang;
|
||||
|
||||
public interface Statement extends Item<Boolean> {
|
||||
}
|
||||
+3
-3
@@ -7,15 +7,15 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.constants;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BooleanConstant extends ConstantExpression<Boolean> {
|
||||
private final boolean constant;
|
||||
|
||||
public BooleanConstant(Boolean constant, SourcePosition position) {
|
||||
|
||||
public BooleanConstant(Boolean constant, Position position) {
|
||||
super(constant, position);
|
||||
this.constant = constant;
|
||||
}
|
||||
|
||||
+7
-7
@@ -7,28 +7,28 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.constants;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public abstract class ConstantExpression<T> implements Expression<T> {
|
||||
public abstract class ConstantExpression<T> implements Returnable<T> {
|
||||
private final T constant;
|
||||
private final SourcePosition position;
|
||||
private final Position position;
|
||||
|
||||
public ConstantExpression(T constant, SourcePosition position) {
|
||||
public ConstantExpression(T constant, Position position) {
|
||||
this.constant = constant;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public T apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return constant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -7,16 +7,16 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.constants;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NumericConstant extends ConstantExpression<Number> {
|
||||
private final double constant;
|
||||
|
||||
public NumericConstant(Number constant, SourcePosition position) {
|
||||
|
||||
public NumericConstant(Number constant, Position position) {
|
||||
super(constant, position);
|
||||
this.constant = constant.doubleValue();
|
||||
}
|
||||
@@ -27,7 +27,7 @@ public class NumericConstant extends ConstantExpression<Number> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.NUMBER;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.NUMBER;
|
||||
}
|
||||
}
|
||||
|
||||
+5
-5
@@ -7,17 +7,17 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.constants;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class StringConstant extends ConstantExpression<String> {
|
||||
public StringConstant(String constant, SourcePosition position) {
|
||||
public StringConstant(String constant, Position position) {
|
||||
super(constant, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.STRING;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.STRING;
|
||||
}
|
||||
}
|
||||
|
||||
+21
-4
@@ -7,20 +7,37 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.functions;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public interface Function<T> extends Expression<T> {
|
||||
public interface Function<T> extends Returnable<T> {
|
||||
Function<?> NULL = new Function<>() {
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Position getPosition() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
default double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return ((Number) evaluate(implementationArguments, scope)).doubleValue();
|
||||
return ((Number) apply(implementationArguments, scope)).doubleValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
default boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return (Boolean) evaluate(implementationArguments, scope);
|
||||
return (Boolean) apply(implementationArguments, scope);
|
||||
}
|
||||
}
|
||||
|
||||
+4
-7
@@ -9,17 +9,14 @@ package com.dfsek.terra.addons.terrascript.parser.lang.functions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public interface FunctionBuilder<T extends Function<?>> {
|
||||
T build(List<Expression<?>> argumentList, SourcePosition position);
|
||||
T build(List<Returnable<?>> argumentList, Position position);
|
||||
|
||||
/**
|
||||
* @return Number of function arguments, -1 if the function uses a vararg at the end
|
||||
*/
|
||||
int argNumber();
|
||||
|
||||
Expression.ReturnType getArgument(int position);
|
||||
Returnable.ReturnType getArgument(int position);
|
||||
}
|
||||
|
||||
-8
@@ -1,8 +0,0 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.functions;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
|
||||
public record FunctionSignature(ReturnType returnType, Pair<String, ReturnType>[] arguments) {
|
||||
}
|
||||
-74
@@ -1,74 +0,0 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.functions;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression.ReturnType;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
|
||||
public class UserDefinedFunctionBuilder<T extends Function<?>> implements FunctionBuilder<T> {
|
||||
|
||||
private final ReturnType returnType;
|
||||
private final List<Pair<Integer, ReturnType>> parameterInfo;
|
||||
private final ScopeBuilder bodyScopeBuilder;
|
||||
private final Block body;
|
||||
|
||||
public UserDefinedFunctionBuilder(ReturnType returnType, List<Pair<Integer, ReturnType>> parameterInfo, Block body,
|
||||
ScopeBuilder functionBodyScope) {
|
||||
this.returnType = returnType;
|
||||
this.bodyScopeBuilder = functionBodyScope;
|
||||
this.body = body;
|
||||
this.parameterInfo = parameterInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
//noinspection unchecked
|
||||
return (T) new Function() {
|
||||
|
||||
private final ThreadLocal<Scope> threadLocalScope = ThreadLocal.withInitial(bodyScopeBuilder::build);
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
Scope bodyScope = threadLocalScope.get();
|
||||
// Pass arguments into scope of function body
|
||||
for(int i = 0; i < argumentList.size(); i++) {
|
||||
Pair<Integer, ReturnType> paramInfo = parameterInfo.get(i);
|
||||
Expression<?> argExpression = argumentList.get(i);
|
||||
switch(paramInfo.getRight()) {
|
||||
case NUMBER -> bodyScope.setNum(paramInfo.getLeft(), argExpression.applyDouble(implementationArguments, scope));
|
||||
case BOOLEAN -> bodyScope.setBool(paramInfo.getLeft(), argExpression.applyBoolean(implementationArguments, scope));
|
||||
case STRING -> bodyScope.setStr(paramInfo.getLeft(), (String) argExpression.evaluate(implementationArguments, scope));
|
||||
}
|
||||
}
|
||||
return body.evaluate(implementationArguments, bodyScope).data().evaluate(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
return position;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public int argNumber() {
|
||||
return parameterInfo.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType getArgument(int position) {
|
||||
return parameterInfo.get(position).getRight();
|
||||
}
|
||||
}
|
||||
+8
-9
@@ -7,28 +7,27 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BreakKeyword implements Keyword<EvaluationInfo<?>> {
|
||||
private final SourcePosition position;
|
||||
public class BreakKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
private final Position position;
|
||||
|
||||
public BreakKeyword(SourcePosition position) {
|
||||
public BreakKeyword(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new EvaluationInfo<>(EvaluationLevel.BREAK, null);
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new Block.ReturnInfo<>(Block.ReturnLevel.BREAK, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -7,28 +7,27 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class ContinueKeyword implements Keyword<EvaluationInfo<?>> {
|
||||
private final SourcePosition position;
|
||||
public class ContinueKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
private final Position position;
|
||||
|
||||
public ContinueKeyword(SourcePosition position) {
|
||||
public ContinueKeyword(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new EvaluationInfo<>(EvaluationLevel.CONTINUE, null);
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new Block.ReturnInfo<>(Block.ReturnLevel.CONTINUE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+8
-9
@@ -7,28 +7,27 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class FailKeyword implements Keyword<EvaluationInfo<?>> {
|
||||
private final SourcePosition position;
|
||||
public class FailKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
private final Position position;
|
||||
|
||||
public FailKeyword(SourcePosition position) {
|
||||
public FailKeyword(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new EvaluationInfo<>(EvaluationLevel.FAIL, null);
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new Block.ReturnInfo<>(Block.ReturnLevel.FAIL, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+8
-23
@@ -7,34 +7,27 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.flow;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class ReturnKeyword implements Keyword<EvaluationInfo<?>> {
|
||||
private final SourcePosition position;
|
||||
public class ReturnKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
private final Position position;
|
||||
|
||||
private final Expression<?> data;
|
||||
|
||||
public ReturnKeyword(@Nullable Expression<?> data, SourcePosition position) {
|
||||
this.data = data;
|
||||
public ReturnKeyword(Position position) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new EvaluationInfo<>(EvaluationLevel.RETURN, data);
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return new Block.ReturnInfo<>(Block.ReturnLevel.RETURN, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@@ -42,12 +35,4 @@ public class ReturnKeyword implements Keyword<EvaluationInfo<?>> {
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.VOID;
|
||||
}
|
||||
|
||||
public ReturnType dataReturnType() {
|
||||
if(data != null) {
|
||||
return data.returnType();
|
||||
} else {
|
||||
return ReturnType.VOID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-19
@@ -7,24 +7,23 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Item;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class ForKeyword implements Keyword<Block.EvaluationInfo<?>> {
|
||||
public class ForKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
private final Block conditional;
|
||||
private final Expression<?> initializer;
|
||||
private final Expression<Boolean> statement;
|
||||
private final Expression<?> incrementer;
|
||||
private final SourcePosition position;
|
||||
private final Item<?> initializer;
|
||||
private final Returnable<Boolean> statement;
|
||||
private final Item<?> incrementer;
|
||||
private final Position position;
|
||||
|
||||
public ForKeyword(Block conditional, Expression<?> initializer, Expression<Boolean> statement, Expression<?> incrementer,
|
||||
SourcePosition position) {
|
||||
public ForKeyword(Block conditional, Item<?> initializer, Returnable<Boolean> statement, Item<?> incrementer, Position position) {
|
||||
this.conditional = conditional;
|
||||
this.initializer = initializer;
|
||||
this.statement = statement;
|
||||
@@ -33,19 +32,19 @@ public class ForKeyword implements Keyword<Block.EvaluationInfo<?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block.EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
for(initializer.evaluate(implementationArguments, scope);
|
||||
statement.evaluate(implementationArguments, scope);
|
||||
incrementer.evaluate(implementationArguments, scope)) {
|
||||
Block.EvaluationInfo<?> level = conditional.evaluate(implementationArguments, scope);
|
||||
if(level.level().equals(EvaluationLevel.BREAK)) break;
|
||||
if(level.level().isReturnFast()) return level;
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
for(initializer.apply(implementationArguments, scope);
|
||||
statement.apply(implementationArguments, scope);
|
||||
incrementer.apply(implementationArguments, scope)) {
|
||||
Block.ReturnInfo<?> level = conditional.apply(implementationArguments, scope);
|
||||
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
|
||||
if(level.getLevel().isReturnFast()) return level;
|
||||
}
|
||||
return new Block.EvaluationInfo<>(EvaluationLevel.NONE, null);
|
||||
return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+16
-17
@@ -11,25 +11,24 @@ import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.util.generic.pair.Pair;
|
||||
|
||||
|
||||
public class IfKeyword implements Keyword<Block.EvaluationInfo<?>> {
|
||||
public class IfKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
private final Block conditional;
|
||||
private final Expression<Boolean> statement;
|
||||
private final SourcePosition position;
|
||||
private final List<Pair<Expression<Boolean>, Block>> elseIf;
|
||||
private final Returnable<Boolean> statement;
|
||||
private final Position position;
|
||||
private final List<Pair<Returnable<Boolean>, Block>> elseIf;
|
||||
private final Block elseBlock;
|
||||
|
||||
public IfKeyword(Block conditional, Expression<Boolean> statement, List<Pair<Expression<Boolean>, Block>> elseIf,
|
||||
@Nullable Block elseBlock, SourcePosition position) {
|
||||
public IfKeyword(Block conditional, Returnable<Boolean> statement, List<Pair<Returnable<Boolean>, Block>> elseIf,
|
||||
@Nullable Block elseBlock, Position position) {
|
||||
this.conditional = conditional;
|
||||
this.statement = statement;
|
||||
this.position = position;
|
||||
@@ -38,21 +37,21 @@ public class IfKeyword implements Keyword<Block.EvaluationInfo<?>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Block.EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
if(statement.evaluate(implementationArguments, scope)) return conditional.evaluate(implementationArguments, scope);
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
if(statement.apply(implementationArguments, scope)) return conditional.apply(implementationArguments, scope);
|
||||
else {
|
||||
for(Pair<Expression<Boolean>, Block> pair : elseIf) {
|
||||
if(pair.getLeft().evaluate(implementationArguments, scope)) {
|
||||
return pair.getRight().evaluate(implementationArguments, scope);
|
||||
for(Pair<Returnable<Boolean>, Block> pair : elseIf) {
|
||||
if(pair.getLeft().apply(implementationArguments, scope)) {
|
||||
return pair.getRight().apply(implementationArguments, scope);
|
||||
}
|
||||
}
|
||||
if(elseBlock != null) return elseBlock.evaluate(implementationArguments, scope);
|
||||
if(elseBlock != null) return elseBlock.apply(implementationArguments, scope);
|
||||
}
|
||||
return new Block.EvaluationInfo<>(EvaluationLevel.NONE, null);
|
||||
return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+13
-15
@@ -7,39 +7,37 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.keywords.looplike;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationInfo;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Block.EvaluationLevel;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Keyword;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class WhileKeyword implements Keyword<EvaluationInfo<?>> {
|
||||
public class WhileKeyword implements Keyword<Block.ReturnInfo<?>> {
|
||||
private final Block conditional;
|
||||
private final Expression<Boolean> statement;
|
||||
private final SourcePosition position;
|
||||
private final Returnable<Boolean> statement;
|
||||
private final Position position;
|
||||
|
||||
public WhileKeyword(Block conditional, Expression<Boolean> statement, SourcePosition position) {
|
||||
public WhileKeyword(Block conditional, Returnable<Boolean> statement, Position position) {
|
||||
this.conditional = conditional;
|
||||
this.statement = statement;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EvaluationInfo<?> evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
while(statement.evaluate(implementationArguments, scope)) {
|
||||
EvaluationInfo<?> level = conditional.evaluate(implementationArguments, scope);
|
||||
if(level.level().equals(EvaluationLevel.BREAK)) break;
|
||||
if(level.level().isReturnFast()) return level;
|
||||
public Block.ReturnInfo<?> apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
while(statement.apply(implementationArguments, scope)) {
|
||||
Block.ReturnInfo<?> level = conditional.apply(implementationArguments, scope);
|
||||
if(level.getLevel().equals(Block.ReturnLevel.BREAK)) break;
|
||||
if(level.getLevel().isReturnFast()) return level;
|
||||
}
|
||||
return new EvaluationInfo<>(EvaluationLevel.NONE, null);
|
||||
return new Block.ReturnInfo<>(Block.ReturnLevel.NONE, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -7,23 +7,23 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public abstract class BinaryOperation<I, O> implements Expression<O> {
|
||||
protected final Expression<I> left;
|
||||
protected final Expression<I> right;
|
||||
private final SourcePosition start;
|
||||
public abstract class BinaryOperation<I, O> implements Returnable<O> {
|
||||
protected final Returnable<I> left;
|
||||
protected final Returnable<I> right;
|
||||
private final Position start;
|
||||
|
||||
public BinaryOperation(Expression<I> left, Expression<I> right, SourcePosition start) {
|
||||
public BinaryOperation(Returnable<I> left, Returnable<I> right, Position start) {
|
||||
this.left = left;
|
||||
this.right = right;
|
||||
this.start = start;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return start;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -7,14 +7,14 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BooleanAndOperation extends BinaryOperation<Boolean, Boolean> {
|
||||
public BooleanAndOperation(Expression<Boolean> left, Expression<Boolean> right, SourcePosition start) {
|
||||
public BooleanAndOperation(Returnable<Boolean> left, Returnable<Boolean> right, Position start) {
|
||||
super(left, right, start);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class BooleanAndOperation extends BinaryOperation<Boolean, Boolean> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -7,19 +7,19 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BooleanNotOperation extends UnaryOperation<Boolean> {
|
||||
public BooleanNotOperation(Expression<Boolean> input, SourcePosition position) {
|
||||
public BooleanNotOperation(Returnable<Boolean> input, Position position) {
|
||||
super(input, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -7,19 +7,19 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BooleanOrOperation extends BinaryOperation<Boolean, Boolean> {
|
||||
public BooleanOrOperation(Expression<Boolean> left, Expression<Boolean> right, SourcePosition start) {
|
||||
public BooleanOrOperation(Returnable<Boolean> left, Returnable<Boolean> right, Position start) {
|
||||
super(left, right, start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class BooleanOrOperation extends BinaryOperation<Boolean, Boolean> {
|
||||
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return left.applyBoolean(implementationArguments, scope) || right.applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.BOOLEAN;
|
||||
|
||||
+7
-7
@@ -7,14 +7,14 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class ConcatenationOperation extends BinaryOperation<Object, Object> {
|
||||
public ConcatenationOperation(Expression<Object> left, Expression<Object> right, SourcePosition position) {
|
||||
public ConcatenationOperation(Returnable<Object> left, Returnable<Object> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@@ -30,12 +30,12 @@ public class ConcatenationOperation extends BinaryOperation<Object, Object> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.STRING;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return toString(left.evaluate(implementationArguments, scope)) + toString(right.evaluate(implementationArguments, scope));
|
||||
public Object apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return toString(left.apply(implementationArguments, scope)) + toString(right.apply(implementationArguments, scope));
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -7,24 +7,24 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class DivisionOperation extends BinaryOperation<Number, Number> {
|
||||
public DivisionOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public DivisionOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.NUMBER;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -7,19 +7,19 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class ModuloOperation extends BinaryOperation<Number, Number> {
|
||||
public ModuloOperation(Expression<Number> left, Expression<Number> right, SourcePosition start) {
|
||||
public ModuloOperation(Returnable<Number> left, Returnable<Number> right, Position start) {
|
||||
super(left, right, start);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class ModuloOperation extends BinaryOperation<Number, Number> {
|
||||
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return left.applyDouble(implementationArguments, scope) % right.applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
|
||||
+5
-5
@@ -7,19 +7,19 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class MultiplicationOperation extends BinaryOperation<Number, Number> {
|
||||
public MultiplicationOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public MultiplicationOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class MultiplicationOperation extends BinaryOperation<Number, Number> {
|
||||
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return left.applyDouble(implementationArguments, scope) * right.applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
|
||||
+4
-4
@@ -7,14 +7,14 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NegationOperation extends UnaryOperation<Number> {
|
||||
public NegationOperation(Expression<Number> input, SourcePosition position) {
|
||||
public NegationOperation(Returnable<Number> input, Position position) {
|
||||
super(input, position);
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ public class NegationOperation extends UnaryOperation<Number> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -7,19 +7,19 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NumberAdditionOperation extends BinaryOperation<Number, Number> {
|
||||
public NumberAdditionOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public NumberAdditionOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class NumberAdditionOperation extends BinaryOperation<Number, Number> {
|
||||
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return left.applyDouble(implementationArguments, scope) + right.applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
|
||||
+5
-5
@@ -7,19 +7,19 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class SubtractionOperation extends BinaryOperation<Number, Number> {
|
||||
public SubtractionOperation(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public SubtractionOperation(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class SubtractionOperation extends BinaryOperation<Number, Number> {
|
||||
public double applyDouble(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return left.applyDouble(implementationArguments, scope) - right.applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
|
||||
+7
-7
@@ -7,21 +7,21 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public abstract class UnaryOperation<T> implements Expression<T> {
|
||||
protected final Expression<T> input;
|
||||
private final SourcePosition position;
|
||||
public abstract class UnaryOperation<T> implements Returnable<T> {
|
||||
protected final Returnable<T> input;
|
||||
private final Position position;
|
||||
|
||||
public UnaryOperation(Expression<T> input, SourcePosition position) {
|
||||
public UnaryOperation(Returnable<T> input, Position position) {
|
||||
this.input = input;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -9,40 +9,40 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
import static com.dfsek.terra.api.util.MathUtil.EPSILON;
|
||||
|
||||
|
||||
public class EqualsStatement extends BinaryOperation<Object, Boolean> {
|
||||
|
||||
public EqualsStatement(Expression<Object> left, Expression<Object> right, SourcePosition position) {
|
||||
public EqualsStatement(Returnable<Object> left, Returnable<Object> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
Object leftValue = left.evaluate(implementationArguments, scope);
|
||||
Object rightValue = right.evaluate(implementationArguments, scope);
|
||||
Object leftValue = left.apply(implementationArguments, scope);
|
||||
Object rightValue = right.apply(implementationArguments, scope);
|
||||
if(leftValue instanceof Number l && rightValue instanceof Number r) {
|
||||
return FastMath.abs(l.doubleValue() - r.doubleValue()) <= EPSILON;
|
||||
}
|
||||
|
||||
|
||||
return leftValue.equals(rightValue);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -7,25 +7,25 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class GreaterOrEqualsThanStatement extends BinaryOperation<Number, Boolean> {
|
||||
public GreaterOrEqualsThanStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public GreaterOrEqualsThanStatement(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -7,21 +7,21 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class GreaterThanStatement extends BinaryOperation<Number, Boolean> {
|
||||
public GreaterThanStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public GreaterThanStatement(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ public class GreaterThanStatement extends BinaryOperation<Number, Boolean> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -7,21 +7,21 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class LessThanOrEqualsStatement extends BinaryOperation<Number, Boolean> {
|
||||
public LessThanOrEqualsStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public LessThanOrEqualsStatement(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ public class LessThanOrEqualsStatement extends BinaryOperation<Number, Boolean>
|
||||
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return left.applyDouble(implementationArguments, scope) <= right.applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -7,21 +7,21 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class LessThanStatement extends BinaryOperation<Number, Boolean> {
|
||||
public LessThanStatement(Expression<Number> left, Expression<Number> right, SourcePosition position) {
|
||||
public LessThanStatement(Returnable<Number> left, Returnable<Number> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@@ -29,9 +29,9 @@ public class LessThanStatement extends BinaryOperation<Number, Boolean> {
|
||||
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return left.applyDouble(implementationArguments, scope) < right.applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,29 +9,29 @@ package com.dfsek.terra.addons.terrascript.parser.lang.operations.statements;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.operations.BinaryOperation;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
import static com.dfsek.terra.api.util.MathUtil.EPSILON;
|
||||
|
||||
|
||||
public class NotEqualsStatement extends BinaryOperation<Object, Boolean> {
|
||||
public NotEqualsStatement(Expression<Object> left, Expression<Object> right, SourcePosition position) {
|
||||
public NotEqualsStatement(Returnable<Object> left, Returnable<Object> right, Position position) {
|
||||
super(left, right, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyBoolean(ImplementationArguments implementationArguments, Scope scope) {
|
||||
Object leftValue = left.evaluate(implementationArguments, scope);
|
||||
Object rightValue = right.evaluate(implementationArguments, scope);
|
||||
Object leftValue = left.apply(implementationArguments, scope);
|
||||
Object rightValue = right.apply(implementationArguments, scope);
|
||||
if(leftValue instanceof Number l && rightValue instanceof Number r) {
|
||||
return FastMath.abs(l.doubleValue() - r.doubleValue()) > EPSILON;
|
||||
}
|
||||
@@ -40,7 +40,7 @@ public class NotEqualsStatement extends BinaryOperation<Object, Boolean> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType returnType() {
|
||||
return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType returnType() {
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -7,15 +7,15 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BooleanVariable implements Variable<Boolean> {
|
||||
private final SourcePosition position;
|
||||
private final Position position;
|
||||
private Boolean value;
|
||||
|
||||
public BooleanVariable(Boolean value, SourcePosition position) {
|
||||
public BooleanVariable(Boolean value, Position position) {
|
||||
this.value = value;
|
||||
this.position = position;
|
||||
}
|
||||
@@ -31,12 +31,12 @@ public class BooleanVariable implements Variable<Boolean> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getType() {
|
||||
return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType getType() {
|
||||
return Returnable.ReturnType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -7,15 +7,15 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NumberVariable implements Variable<Number> {
|
||||
private final SourcePosition position;
|
||||
private final Position position;
|
||||
private Number value;
|
||||
|
||||
public NumberVariable(Number value, SourcePosition position) {
|
||||
public NumberVariable(Number value, Position position) {
|
||||
this.value = value;
|
||||
this.position = position;
|
||||
}
|
||||
@@ -31,12 +31,12 @@ public class NumberVariable implements Variable<Number> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getType() {
|
||||
return Expression.ReturnType.NUMBER;
|
||||
public Returnable.ReturnType getType() {
|
||||
return Returnable.ReturnType.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -7,15 +7,15 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class StringVariable implements Variable<String> {
|
||||
private final SourcePosition position;
|
||||
private final Position position;
|
||||
private String value;
|
||||
|
||||
public StringVariable(String value, SourcePosition position) {
|
||||
public StringVariable(String value, Position position) {
|
||||
this.value = value;
|
||||
this.position = position;
|
||||
}
|
||||
@@ -31,12 +31,12 @@ public class StringVariable implements Variable<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getType() {
|
||||
return Expression.ReturnType.STRING;
|
||||
public Returnable.ReturnType getType() {
|
||||
return Returnable.ReturnType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -7,8 +7,8 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public interface Variable<T> {
|
||||
@@ -16,7 +16,7 @@ public interface Variable<T> {
|
||||
|
||||
void setValue(T value);
|
||||
|
||||
Expression.ReturnType getType();
|
||||
Returnable.ReturnType getType();
|
||||
|
||||
SourcePosition getPosition();
|
||||
Position getPosition();
|
||||
}
|
||||
|
||||
+4
-9
@@ -1,23 +1,18 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BoolAssignmentNode extends VariableAssignmentNode<Boolean> {
|
||||
public BoolAssignmentNode(Expression<Boolean> value, SourcePosition position, int index) {
|
||||
public BoolAssignmentNode(Returnable<Boolean> value, Position position, int index) {
|
||||
super(value, position, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.BOOLEAN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyBoolean(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
+4
-9
@@ -1,23 +1,18 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NumAssignmentNode extends VariableAssignmentNode<Number> {
|
||||
public NumAssignmentNode(Expression<Number> value, SourcePosition position, int index) {
|
||||
public NumAssignmentNode(Returnable<Number> value, Position position, int index) {
|
||||
super(value, position, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.NUMBER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return applyDouble(implementationArguments, scope);
|
||||
}
|
||||
|
||||
|
||||
+5
-10
@@ -1,24 +1,19 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class StrAssignmentNode extends VariableAssignmentNode<String> {
|
||||
public StrAssignmentNode(Expression<String> value, SourcePosition position, int index) {
|
||||
public StrAssignmentNode(Returnable<String> value, Position position, int index) {
|
||||
super(value, position, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
return ReturnType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
String val = value.evaluate(implementationArguments, scope);
|
||||
public String apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
String val = value.apply(implementationArguments, scope);
|
||||
scope.setStr(index, val);
|
||||
return val;
|
||||
}
|
||||
|
||||
+8
-7
@@ -7,24 +7,25 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.assign;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Item;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public abstract class VariableAssignmentNode<T> implements Expression<T> {
|
||||
protected final Expression<T> value;
|
||||
public abstract class VariableAssignmentNode<T> implements Item<T> {
|
||||
protected final Returnable<T> value;
|
||||
protected final int index;
|
||||
private final SourcePosition position;
|
||||
private final Position position;
|
||||
|
||||
|
||||
public VariableAssignmentNode(Expression<T> value, SourcePosition position, int index) {
|
||||
public VariableAssignmentNode(Returnable<T> value, Position position, int index) {
|
||||
this.value = value;
|
||||
this.index = index;
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -1,17 +1,17 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BoolVariableReferenceNode extends VariableReferenceNode<Boolean> {
|
||||
public BoolVariableReferenceNode(SourcePosition position, ReturnType type, int index) {
|
||||
public BoolVariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
super(position, type, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Boolean evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Boolean apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getBool(index);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,17 +1,17 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class NumVariableReferenceNode extends VariableReferenceNode<Number> {
|
||||
public NumVariableReferenceNode(SourcePosition position, ReturnType type, int index) {
|
||||
public NumVariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
super(position, type, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getNum(index);
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,17 +1,17 @@
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class StrVariableReferenceNode extends VariableReferenceNode<String> {
|
||||
public StrVariableReferenceNode(SourcePosition position, ReturnType type, int index) {
|
||||
public StrVariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
super(position, type, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public String apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return scope.getStr(index);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-6
@@ -7,16 +7,16 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.parser.lang.variables.reference;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public abstract class VariableReferenceNode<T> implements Expression<T> {
|
||||
public abstract class VariableReferenceNode<T> implements Returnable<T> {
|
||||
protected final int index;
|
||||
private final SourcePosition position;
|
||||
private final Position position;
|
||||
private final ReturnType type;
|
||||
|
||||
public VariableReferenceNode(SourcePosition position, ReturnType type, int index) {
|
||||
public VariableReferenceNode(Position position, ReturnType type, int index) {
|
||||
this.position = position;
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
@@ -28,7 +28,7 @@ public abstract class VariableReferenceNode<T> implements Expression<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
}
|
||||
|
||||
+23
-24
@@ -7,8 +7,6 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.script;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.Lexer;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.slf4j.Logger;
|
||||
@@ -21,8 +19,7 @@ import java.util.Random;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.parser.Parser;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Executable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope.ScopeBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.builders.BinaryNumberFunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.builders.BiomeFunctionBuilder;
|
||||
@@ -54,34 +51,32 @@ import com.dfsek.terra.api.world.WritableWorld;
|
||||
|
||||
public class StructureScript implements Structure, Keyed<StructureScript> {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(StructureScript.class);
|
||||
private final Executable executable;
|
||||
private final Executable block;
|
||||
private final RegistryKey id;
|
||||
|
||||
private final String profile;
|
||||
private final Platform platform;
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
public StructureScript(InputStream source, RegistryKey id, Platform platform, Registry<Structure> structureRegistry,
|
||||
public StructureScript(InputStream inputStream, RegistryKey id, Platform platform, Registry<Structure> registry,
|
||||
Registry<LootTable> lootRegistry,
|
||||
Registry<FunctionBuilder> functionRegistry) {
|
||||
Lexer lexer;
|
||||
Parser parser;
|
||||
try {
|
||||
lexer = new Lexer(IOUtils.toString(source, Charset.defaultCharset()));
|
||||
parser = new Parser(IOUtils.toString(inputStream, Charset.defaultCharset()));
|
||||
} catch(IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
Parser parser = new Parser(lexer);
|
||||
this.id = id;
|
||||
this.profile = "terrascript_direct:" + id;
|
||||
|
||||
ScopeBuilder scope = new ScopeBuilder();
|
||||
//noinspection unchecked
|
||||
functionRegistry.forEach((key, function) -> parser.registerFunction(key.getID(), function)); // Register registry functions.
|
||||
|
||||
functionRegistry.forEach((key, function) -> scope.registerFunction(key.getID(), function)); // Register registry functions.
|
||||
|
||||
scope
|
||||
parser
|
||||
.registerFunction("block", new BlockFunctionBuilder(platform))
|
||||
.registerFunction("debugBlock", new BlockFunctionBuilder(platform))
|
||||
.registerFunction("structure", new StructureFunctionBuilder(structureRegistry, platform))
|
||||
.registerFunction("structure", new StructureFunctionBuilder(registry, platform))
|
||||
.registerFunction("randomInt", new RandomFunctionBuilder())
|
||||
.registerFunction("recursions", new RecursionsFunctionBuilder())
|
||||
.registerFunction("setMark", new SetMarkFunctionBuilder())
|
||||
@@ -94,15 +89,15 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
|
||||
.registerFunction("state", new StateFunctionBuilder(platform))
|
||||
.registerFunction("setWaterlog", new UnaryBooleanFunctionBuilder((waterlog, args) -> args.setWaterlog(waterlog)))
|
||||
.registerFunction("originX", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getOrigin().getX(),
|
||||
Expression.ReturnType.NUMBER))
|
||||
Returnable.ReturnType.NUMBER))
|
||||
.registerFunction("originY", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getOrigin().getY(),
|
||||
Expression.ReturnType.NUMBER))
|
||||
Returnable.ReturnType.NUMBER))
|
||||
.registerFunction("originZ", new ZeroArgFunctionBuilder<Number>(arguments -> arguments.getOrigin().getZ(),
|
||||
Expression.ReturnType.NUMBER))
|
||||
Returnable.ReturnType.NUMBER))
|
||||
.registerFunction("rotation", new ZeroArgFunctionBuilder<>(arguments -> arguments.getRotation().toString(),
|
||||
Expression.ReturnType.STRING))
|
||||
Returnable.ReturnType.STRING))
|
||||
.registerFunction("rotationDegrees", new ZeroArgFunctionBuilder<>(arguments -> arguments.getRotation().getDegrees(),
|
||||
Expression.ReturnType.NUMBER))
|
||||
Returnable.ReturnType.NUMBER))
|
||||
.registerFunction("print",
|
||||
new UnaryStringFunctionBuilder(string -> LOGGER.info("[TerraScript:{}] {}", id, string)))
|
||||
.registerFunction("abs", new UnaryNumberFunctionBuilder(number -> FastMath.abs(number.doubleValue())))
|
||||
@@ -125,7 +120,11 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
|
||||
.registerFunction("min", new BinaryNumberFunctionBuilder(
|
||||
(number, number2) -> FastMath.min(number.doubleValue(), number2.doubleValue())));
|
||||
|
||||
executable = parser.parse(scope);
|
||||
if(!platform.getTerraConfig().isDebugScript()) {
|
||||
parser.ignoreFunction("debugBlock");
|
||||
}
|
||||
|
||||
block = parser.parse();
|
||||
this.platform = platform;
|
||||
}
|
||||
|
||||
@@ -133,21 +132,21 @@ public class StructureScript implements Structure, Keyed<StructureScript> {
|
||||
@SuppressWarnings("try")
|
||||
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation) {
|
||||
platform.getProfiler().push(profile);
|
||||
boolean result = execute(new TerraImplementationArguments(location, rotation, random, world, 0));
|
||||
boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, 0));
|
||||
platform.getProfiler().pop(profile);
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean generate(Vector3Int location, WritableWorld world, Random random, Rotation rotation, int recursions) {
|
||||
platform.getProfiler().push(profile);
|
||||
boolean result = execute(new TerraImplementationArguments(location, rotation, random, world, recursions));
|
||||
boolean result = applyBlock(new TerraImplementationArguments(location, rotation, random, world, recursions));
|
||||
platform.getProfiler().pop(profile);
|
||||
return result;
|
||||
}
|
||||
|
||||
private boolean execute(TerraImplementationArguments arguments) {
|
||||
private boolean applyBlock(TerraImplementationArguments arguments) {
|
||||
try {
|
||||
return executable.execute(arguments);
|
||||
return block.execute(arguments);
|
||||
} catch(RuntimeException e) {
|
||||
LOGGER.error("Failed to generate structure at {}", arguments.getOrigin(), e);
|
||||
return false;
|
||||
|
||||
+9
-9
@@ -10,12 +10,12 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class BinaryNumberFunctionBuilder implements FunctionBuilder<Function<Number>> {
|
||||
@@ -27,7 +27,7 @@ public class BinaryNumberFunctionBuilder implements FunctionBuilder<Function<Num
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Number> build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public Function<Number> build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new Function<>() {
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
@@ -36,13 +36,13 @@ public class BinaryNumberFunctionBuilder implements FunctionBuilder<Function<Num
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return function.apply(((Expression<Number>) argumentList.get(0)).evaluate(implementationArguments, scope),
|
||||
((Expression<Number>) argumentList.get(1)).evaluate(implementationArguments, scope));
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return function.apply(((Returnable<Number>) argumentList.get(0)).apply(implementationArguments, scope),
|
||||
((Returnable<Number>) argumentList.get(1)).apply(implementationArguments, scope));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
};
|
||||
@@ -54,8 +54,8 @@ public class BinaryNumberFunctionBuilder implements FunctionBuilder<Function<Num
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
if(position == 0 || position == 1) return Expression.ReturnType.NUMBER;
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
if(position == 0 || position == 1) return Returnable.ReturnType.NUMBER;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+7
-7
@@ -9,10 +9,10 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.BiomeFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ public class BiomeFunctionBuilder implements FunctionBuilder<BiomeFunction> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BiomeFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new BiomeFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), position);
|
||||
public BiomeFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new BiomeFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,9 +36,9 @@ public class BiomeFunctionBuilder implements FunctionBuilder<BiomeFunction> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+16
-14
@@ -9,13 +9,13 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.BooleanConstant;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.BlockFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
|
||||
|
||||
@@ -28,17 +28,19 @@ public class BlockFunctionBuilder implements FunctionBuilder<BlockFunction> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public BlockFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public BlockFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
if(argumentList.size() < 4) throw new ParseException("Expected data", position);
|
||||
Expression<Boolean> booleanReturnable = new BooleanConstant(true, position);
|
||||
if(argumentList.size() == 5) booleanReturnable = (Expression<Boolean>) argumentList.get(4);
|
||||
Returnable<Boolean> overwrite = new BooleanConstant(true, position);
|
||||
if(argumentList.size() >= 5) overwrite = (Returnable<Boolean>) argumentList.get(4);
|
||||
Returnable<Boolean> physics = new BooleanConstant(false, position);
|
||||
if(argumentList.size() == 6) physics = (Returnable<Boolean>) argumentList.get(5);
|
||||
if(argumentList.get(3) instanceof StringConstant) {
|
||||
return new BlockFunction.Constant((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), (StringConstant) argumentList.get(3),
|
||||
booleanReturnable, platform, position);
|
||||
return new BlockFunction.Constant((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), (StringConstant) argumentList.get(3),
|
||||
overwrite, physics, platform, position);
|
||||
}
|
||||
return new BlockFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), booleanReturnable,
|
||||
return new BlockFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), overwrite, physics,
|
||||
platform, position);
|
||||
}
|
||||
|
||||
@@ -48,11 +50,11 @@ public class BlockFunctionBuilder implements FunctionBuilder<BlockFunction> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 3 -> Expression.ReturnType.STRING;
|
||||
case 4 -> Expression.ReturnType.BOOLEAN;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
case 3 -> Returnable.ReturnType.STRING;
|
||||
case 4, 5 -> Returnable.ReturnType.BOOLEAN;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+7
-7
@@ -9,18 +9,18 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.CheckBlockFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class CheckBlockFunctionBuilder implements FunctionBuilder<CheckBlockFunction> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public CheckBlockFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new CheckBlockFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), position);
|
||||
public CheckBlockFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new CheckBlockFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -29,9 +29,9 @@ public class CheckBlockFunctionBuilder implements FunctionBuilder<CheckBlockFunc
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,10 +9,10 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.EntityFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ public class EntityFunctionBuilder implements FunctionBuilder<EntityFunction> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public EntityFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new EntityFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), platform, position);
|
||||
public EntityFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new EntityFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), platform, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,10 +36,10 @@ public class EntityFunctionBuilder implements FunctionBuilder<EntityFunction> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 3 -> Expression.ReturnType.STRING;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
case 3 -> Returnable.ReturnType.STRING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+7
-7
@@ -9,10 +9,10 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.GetMarkFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class GetMarkFunctionBuilder implements FunctionBuilder<GetMarkFunction> {
|
||||
@@ -22,9 +22,9 @@ public class GetMarkFunctionBuilder implements FunctionBuilder<GetMarkFunction>
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public GetMarkFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new GetMarkFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), position);
|
||||
public GetMarkFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new GetMarkFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,9 +33,9 @@ public class GetMarkFunctionBuilder implements FunctionBuilder<GetMarkFunction>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,11 +9,11 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.StructureScript;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.LootFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
import com.dfsek.terra.api.structure.LootTable;
|
||||
@@ -32,9 +32,9 @@ public class LootFunctionBuilder implements FunctionBuilder<LootFunction> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public LootFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new LootFunction(registry, (Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), platform, position,
|
||||
public LootFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new LootFunction(registry, (Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), platform, position,
|
||||
script);
|
||||
}
|
||||
|
||||
@@ -44,10 +44,10 @@ public class LootFunctionBuilder implements FunctionBuilder<LootFunction> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 3 -> Expression.ReturnType.STRING;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
case 3 -> Returnable.ReturnType.STRING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,10 +9,10 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.PullFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
|
||||
|
||||
@@ -25,9 +25,9 @@ public class PullFunctionBuilder implements FunctionBuilder<PullFunction> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public PullFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new PullFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), platform, position);
|
||||
public PullFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new PullFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), platform, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,10 +36,10 @@ public class PullFunctionBuilder implements FunctionBuilder<PullFunction> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 3 -> Expression.ReturnType.STRING;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
case 3 -> Returnable.ReturnType.STRING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+6
-6
@@ -9,17 +9,17 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.RandomFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class RandomFunctionBuilder implements FunctionBuilder<RandomFunction> {
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public RandomFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new RandomFunction((Expression<Number>) argumentList.get(0), position);
|
||||
public RandomFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new RandomFunction((Returnable<Number>) argumentList.get(0), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -28,8 +28,8 @@ public class RandomFunctionBuilder implements FunctionBuilder<RandomFunction> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Expression.ReturnType.NUMBER;
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Returnable.ReturnType.NUMBER;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -9,15 +9,15 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.RecursionsFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class RecursionsFunctionBuilder implements FunctionBuilder<RecursionsFunction> {
|
||||
@Override
|
||||
public RecursionsFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public RecursionsFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new RecursionsFunction(position);
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ public class RecursionsFunctionBuilder implements FunctionBuilder<RecursionsFunc
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,10 +9,10 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.SetMarkFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class SetMarkFunctionBuilder implements FunctionBuilder<SetMarkFunction> {
|
||||
@@ -22,9 +22,9 @@ public class SetMarkFunctionBuilder implements FunctionBuilder<SetMarkFunction>
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public SetMarkFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
return new SetMarkFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), position);
|
||||
public SetMarkFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new SetMarkFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,10 +33,10 @@ public class SetMarkFunctionBuilder implements FunctionBuilder<SetMarkFunction>
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 3 -> Expression.ReturnType.STRING;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
case 3 -> Returnable.ReturnType.STRING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,11 +9,11 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.StateFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
|
||||
|
||||
@@ -26,10 +26,10 @@ public class StateFunctionBuilder implements FunctionBuilder<StateFunction> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public StateFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public StateFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
if(argumentList.size() < 4) throw new ParseException("Expected data", position);
|
||||
return new StateFunction((Expression<Number>) argumentList.get(0), (Expression<Number>) argumentList.get(1),
|
||||
(Expression<Number>) argumentList.get(2), (Expression<String>) argumentList.get(3), position);
|
||||
return new StateFunction((Returnable<Number>) argumentList.get(0), (Returnable<Number>) argumentList.get(1),
|
||||
(Returnable<Number>) argumentList.get(2), (Returnable<String>) argumentList.get(3), position);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -38,10 +38,10 @@ public class StateFunctionBuilder implements FunctionBuilder<StateFunction> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
case 3 -> Expression.ReturnType.STRING;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
case 3 -> Returnable.ReturnType.STRING;
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
+9
-9
@@ -10,11 +10,11 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.functions.StructureFunction;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.registry.Registry;
|
||||
import com.dfsek.terra.api.structure.Structure;
|
||||
@@ -31,12 +31,12 @@ public class StructureFunctionBuilder implements FunctionBuilder<StructureFuncti
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public StructureFunction build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public StructureFunction build(List<Returnable<?>> argumentList, Position position) {
|
||||
if(argumentList.size() < 5) throw new ParseException("Expected rotations", position);
|
||||
|
||||
return new StructureFunction((Expression<Number>) argumentList.remove(0), (Expression<Number>) argumentList.remove(0),
|
||||
(Expression<Number>) argumentList.remove(0), (Expression<String>) argumentList.remove(0),
|
||||
argumentList.stream().map(item -> ((Expression<String>) item)).collect(Collectors.toList()), registry,
|
||||
return new StructureFunction((Returnable<Number>) argumentList.remove(0), (Returnable<Number>) argumentList.remove(0),
|
||||
(Returnable<Number>) argumentList.remove(0), (Returnable<String>) argumentList.remove(0),
|
||||
argumentList.stream().map(item -> ((Returnable<String>) item)).collect(Collectors.toList()), registry,
|
||||
position, platform);
|
||||
}
|
||||
|
||||
@@ -46,10 +46,10 @@ public class StructureFunctionBuilder implements FunctionBuilder<StructureFuncti
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
return switch(position) {
|
||||
case 0, 1, 2 -> Expression.ReturnType.NUMBER;
|
||||
default -> Expression.ReturnType.STRING;
|
||||
case 0, 1, 2 -> Returnable.ReturnType.NUMBER;
|
||||
default -> Returnable.ReturnType.STRING;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -10,13 +10,13 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Void>> {
|
||||
@@ -28,7 +28,7 @@ public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Voi
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Void> build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public Function<Void> build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new Function<>() {
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
@@ -37,14 +37,14 @@ public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Voi
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
function.accept(((Expression<Boolean>) argumentList.get(0)).evaluate(implementationArguments, scope),
|
||||
public Void apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
function.accept(((Returnable<Boolean>) argumentList.get(0)).apply(implementationArguments, scope),
|
||||
(TerraImplementationArguments) implementationArguments);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
};
|
||||
@@ -56,8 +56,8 @@ public class UnaryBooleanFunctionBuilder implements FunctionBuilder<Function<Voi
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Expression.ReturnType.BOOLEAN;
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Returnable.ReturnType.BOOLEAN;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,12 +9,12 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class UnaryNumberFunctionBuilder implements FunctionBuilder<Function<Number>> {
|
||||
@@ -26,7 +26,7 @@ public class UnaryNumberFunctionBuilder implements FunctionBuilder<Function<Numb
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Number> build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public Function<Number> build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new Function<>() {
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
@@ -35,12 +35,12 @@ public class UnaryNumberFunctionBuilder implements FunctionBuilder<Function<Numb
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Number evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return function.apply(((Expression<Number>) argumentList.get(0)).evaluate(implementationArguments, scope));
|
||||
public Number apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return function.apply(((Returnable<Number>) argumentList.get(0)).apply(implementationArguments, scope));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
};
|
||||
@@ -52,8 +52,8 @@ public class UnaryNumberFunctionBuilder implements FunctionBuilder<Function<Numb
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Expression.ReturnType.NUMBER;
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Returnable.ReturnType.NUMBER;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,12 +9,12 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class UnaryStringFunctionBuilder implements FunctionBuilder<Function<Void>> {
|
||||
@@ -26,7 +26,7 @@ public class UnaryStringFunctionBuilder implements FunctionBuilder<Function<Void
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Void> build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public Function<Void> build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new Function<>() {
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
@@ -35,13 +35,13 @@ public class UnaryStringFunctionBuilder implements FunctionBuilder<Function<Void
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
function.accept(((Expression<String>) argumentList.get(0)).evaluate(implementationArguments, scope));
|
||||
public Void apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
function.accept(((Returnable<String>) argumentList.get(0)).apply(implementationArguments, scope));
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
};
|
||||
@@ -53,8 +53,8 @@ public class UnaryStringFunctionBuilder implements FunctionBuilder<Function<Void
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Expression.ReturnType.STRING;
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
if(position == 0) return Returnable.ReturnType.STRING;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
+8
-8
@@ -9,26 +9,26 @@ package com.dfsek.terra.addons.terrascript.script.builders;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.FunctionBuilder;
|
||||
import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
|
||||
|
||||
public class ZeroArgFunctionBuilder<T> implements FunctionBuilder<Function<T>> {
|
||||
private final java.util.function.Function<TerraImplementationArguments, T> function;
|
||||
private final Expression.ReturnType type;
|
||||
private final Returnable.ReturnType type;
|
||||
|
||||
public ZeroArgFunctionBuilder(java.util.function.Function<TerraImplementationArguments, T> function, Expression.ReturnType type) {
|
||||
public ZeroArgFunctionBuilder(java.util.function.Function<TerraImplementationArguments, T> function, Returnable.ReturnType type) {
|
||||
this.function = function;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<T> build(List<Expression<?>> argumentList, SourcePosition position) {
|
||||
public Function<T> build(List<Returnable<?>> argumentList, Position position) {
|
||||
return new Function<>() {
|
||||
@Override
|
||||
public ReturnType returnType() {
|
||||
@@ -36,12 +36,12 @@ public class ZeroArgFunctionBuilder<T> implements FunctionBuilder<Function<T>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public T apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
return function.apply((TerraImplementationArguments) implementationArguments);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
};
|
||||
@@ -53,7 +53,7 @@ public class ZeroArgFunctionBuilder<T> implements FunctionBuilder<Function<T>> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Expression.ReturnType getArgument(int position) {
|
||||
public Returnable.ReturnType getArgument(int position) {
|
||||
if(position == 0) return type;
|
||||
return null;
|
||||
}
|
||||
|
||||
+10
-10
@@ -9,12 +9,12 @@ package com.dfsek.terra.addons.terrascript.script.functions;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.util.RotationUtil;
|
||||
import com.dfsek.terra.api.util.vector.Vector2;
|
||||
import com.dfsek.terra.api.util.vector.Vector3;
|
||||
@@ -22,11 +22,11 @@ import com.dfsek.terra.api.world.biome.generation.BiomeProvider;
|
||||
|
||||
|
||||
public class BiomeFunction implements Function<String> {
|
||||
private final Expression<Number> x, y, z;
|
||||
private final SourcePosition position;
|
||||
private final Returnable<Number> x, y, z;
|
||||
private final Position position;
|
||||
|
||||
|
||||
public BiomeFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, SourcePosition position) {
|
||||
public BiomeFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Position position) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
@@ -35,11 +35,11 @@ public class BiomeFunction implements Function<String> {
|
||||
|
||||
|
||||
@Override
|
||||
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public String apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
|
||||
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
|
||||
z.evaluate(implementationArguments, scope).doubleValue()),
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(),
|
||||
z.apply(implementationArguments, scope).doubleValue()),
|
||||
arguments.getRotation());
|
||||
|
||||
|
||||
@@ -49,12 +49,12 @@ public class BiomeFunction implements Function<String> {
|
||||
.toVector3()
|
||||
.mutable()
|
||||
.add(Vector3.of(FastMath.roundToInt(xz.getX()),
|
||||
y.evaluate(implementationArguments, scope).intValue(),
|
||||
y.apply(implementationArguments, scope).intValue(),
|
||||
FastMath.roundToInt(xz.getZ()))).immutable(), arguments.getWorld().getSeed()).getID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+21
-20
@@ -14,13 +14,13 @@ import org.slf4j.LoggerFactory;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.StringConstant;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.block.state.BlockState;
|
||||
import com.dfsek.terra.api.util.RotationUtil;
|
||||
@@ -30,15 +30,16 @@ import com.dfsek.terra.api.util.vector.Vector3;
|
||||
|
||||
public class BlockFunction implements Function<Void> {
|
||||
private static final Logger logger = LoggerFactory.getLogger(BlockFunction.class);
|
||||
protected final Expression<Number> x, y, z;
|
||||
protected final Expression<String> blockData;
|
||||
protected final Returnable<Number> x, y, z;
|
||||
protected final Returnable<String> blockData;
|
||||
protected final Platform platform;
|
||||
private final Map<String, BlockState> data = new HashMap<>();
|
||||
private final Expression<Boolean> overwrite;
|
||||
private final SourcePosition position;
|
||||
private final Returnable<Boolean> overwrite;
|
||||
private final Returnable<Boolean> physics;
|
||||
private final Position position;
|
||||
|
||||
public BlockFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> blockData,
|
||||
Expression<Boolean> overwrite, Platform platform, SourcePosition position) {
|
||||
public BlockFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> blockData,
|
||||
Returnable<Boolean> overwrite, Returnable<Boolean> physics, Platform platform, Position position) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
@@ -46,10 +47,11 @@ public class BlockFunction implements Function<Void> {
|
||||
this.overwrite = overwrite;
|
||||
this.platform = platform;
|
||||
this.position = position;
|
||||
this.physics = physics;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Void apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
|
||||
BlockState rot = getBlockState(implementationArguments, scope);
|
||||
setBlock(implementationArguments, scope, arguments, rot);
|
||||
@@ -57,7 +59,7 @@ public class BlockFunction implements Function<Void> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@@ -68,16 +70,15 @@ public class BlockFunction implements Function<Void> {
|
||||
|
||||
void setBlock(ImplementationArguments implementationArguments, Scope scope,
|
||||
TerraImplementationArguments arguments, BlockState rot) {
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
|
||||
z.evaluate(implementationArguments, scope).doubleValue()),
|
||||
arguments.getRotation());
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(),
|
||||
z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation());
|
||||
try {
|
||||
Vector3.Mutable set = Vector3.of(FastMath.roundToInt(xz.getX()),
|
||||
y.evaluate(implementationArguments, scope).doubleValue(),
|
||||
y.apply(implementationArguments, scope).doubleValue(),
|
||||
FastMath.roundToInt(xz.getZ())).mutable().add(arguments.getOrigin());
|
||||
BlockState current = arguments.getWorld().getBlockState(set);
|
||||
if(overwrite.evaluate(implementationArguments, scope) || current.isAir()) {
|
||||
arguments.getWorld().setBlockState(set, rot);
|
||||
if(overwrite.apply(implementationArguments, scope) || current.isAir()) {
|
||||
arguments.getWorld().setBlockState(set, rot, physics.apply(implementationArguments, scope));
|
||||
}
|
||||
} catch(RuntimeException e) {
|
||||
logger.error("Failed to place block at location {}", arguments.getOrigin(), e);
|
||||
@@ -85,16 +86,16 @@ public class BlockFunction implements Function<Void> {
|
||||
}
|
||||
|
||||
protected BlockState getBlockState(ImplementationArguments arguments, Scope scope) {
|
||||
return data.computeIfAbsent(blockData.evaluate(arguments, scope), platform.getWorldHandle()::createBlockState);
|
||||
return data.computeIfAbsent(blockData.apply(arguments, scope), platform.getWorldHandle()::createBlockState);
|
||||
}
|
||||
|
||||
|
||||
public static class Constant extends BlockFunction {
|
||||
private final BlockState state;
|
||||
|
||||
public Constant(Expression<Number> x, Expression<Number> y, Expression<Number> z, StringConstant blockData,
|
||||
Expression<Boolean> overwrite, Platform platform, SourcePosition position) {
|
||||
super(x, y, z, blockData, overwrite, platform, position);
|
||||
public Constant(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, StringConstant blockData,
|
||||
Returnable<Boolean> overwrite, Returnable<Boolean> physics, Platform platform, Position position) {
|
||||
super(x, y, z, blockData, overwrite, physics, platform, position);
|
||||
this.state = platform.getWorldHandle().createBlockState(blockData.getConstant());
|
||||
}
|
||||
|
||||
|
||||
+10
-10
@@ -9,22 +9,22 @@ package com.dfsek.terra.addons.terrascript.script.functions;
|
||||
|
||||
import net.jafama.FastMath;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.util.RotationUtil;
|
||||
import com.dfsek.terra.api.util.vector.Vector2;
|
||||
import com.dfsek.terra.api.util.vector.Vector3;
|
||||
|
||||
|
||||
public class CheckBlockFunction implements Function<String> {
|
||||
private final Expression<Number> x, y, z;
|
||||
private final SourcePosition position;
|
||||
private final Returnable<Number> x, y, z;
|
||||
private final Position position;
|
||||
|
||||
public CheckBlockFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, SourcePosition position) {
|
||||
public CheckBlockFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Position position) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
@@ -33,11 +33,11 @@ public class CheckBlockFunction implements Function<String> {
|
||||
|
||||
|
||||
@Override
|
||||
public String evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public String apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
|
||||
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
|
||||
z.evaluate(implementationArguments, scope).doubleValue()),
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(),
|
||||
z.apply(implementationArguments, scope).doubleValue()),
|
||||
arguments.getRotation());
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ public class CheckBlockFunction implements Function<String> {
|
||||
.toVector3()
|
||||
.mutable()
|
||||
.add(Vector3.of(FastMath.roundToInt(xz.getX()),
|
||||
y.evaluate(implementationArguments, scope)
|
||||
y.apply(implementationArguments, scope)
|
||||
.doubleValue(), FastMath.roundToInt(xz.getZ()))))
|
||||
.getAsString();
|
||||
if(data.contains("[")) return data.substring(0, data.indexOf('[')); // Strip properties
|
||||
@@ -54,7 +54,7 @@ public class CheckBlockFunction implements Function<String> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
+11
-12
@@ -7,14 +7,14 @@
|
||||
|
||||
package com.dfsek.terra.addons.terrascript.script.functions;
|
||||
|
||||
import com.dfsek.terra.addons.terrascript.lexer.SourcePosition;
|
||||
import com.dfsek.terra.addons.terrascript.parser.exceptions.ParseException;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Expression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.ImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Returnable;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.Scope;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.constants.ConstantExpression;
|
||||
import com.dfsek.terra.addons.terrascript.parser.lang.functions.Function;
|
||||
import com.dfsek.terra.addons.terrascript.script.TerraImplementationArguments;
|
||||
import com.dfsek.terra.addons.terrascript.tokenizer.Position;
|
||||
import com.dfsek.terra.api.Platform;
|
||||
import com.dfsek.terra.api.entity.Entity;
|
||||
import com.dfsek.terra.api.entity.EntityType;
|
||||
@@ -26,12 +26,12 @@ import com.dfsek.terra.api.util.vector.Vector3;
|
||||
|
||||
public class EntityFunction implements Function<Void> {
|
||||
private final EntityType data;
|
||||
private final Expression<Number> x, y, z;
|
||||
private final SourcePosition position;
|
||||
private final Returnable<Number> x, y, z;
|
||||
private final Position position;
|
||||
private final Platform platform;
|
||||
|
||||
public EntityFunction(Expression<Number> x, Expression<Number> y, Expression<Number> z, Expression<String> data, Platform platform,
|
||||
SourcePosition position) {
|
||||
public EntityFunction(Returnable<Number> x, Returnable<Number> y, Returnable<Number> z, Returnable<String> data, Platform platform,
|
||||
Position position) {
|
||||
this.position = position;
|
||||
this.platform = platform;
|
||||
if(!(data instanceof ConstantExpression)) throw new ParseException("Entity data must be constant", data.getPosition());
|
||||
@@ -43,13 +43,12 @@ public class EntityFunction implements Function<Void> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void evaluate(ImplementationArguments implementationArguments, Scope scope) {
|
||||
public Void apply(ImplementationArguments implementationArguments, Scope scope) {
|
||||
TerraImplementationArguments arguments = (TerraImplementationArguments) implementationArguments;
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.evaluate(implementationArguments, scope).doubleValue(),
|
||||
z.evaluate(implementationArguments, scope).doubleValue()),
|
||||
arguments.getRotation());
|
||||
Vector2 xz = RotationUtil.rotateVector(Vector2.of(x.apply(implementationArguments, scope).doubleValue(),
|
||||
z.apply(implementationArguments, scope).doubleValue()), arguments.getRotation());
|
||||
|
||||
Entity entity = arguments.getWorld().spawnEntity(Vector3.of(xz.getX(), y.evaluate(implementationArguments, scope).doubleValue(),
|
||||
Entity entity = arguments.getWorld().spawnEntity(Vector3.of(xz.getX(), y.apply(implementationArguments, scope).doubleValue(),
|
||||
xz.getZ())
|
||||
.mutable()
|
||||
.add(arguments.getOrigin())
|
||||
@@ -60,7 +59,7 @@ public class EntityFunction implements Function<Void> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SourcePosition getPosition() {
|
||||
public Position getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user