Skip to content

Commit

Permalink
Add support for Paralithic let expressions
Browse files Browse the repository at this point in the history
  • Loading branch information
astrsh committed Oct 30, 2024
1 parent 02fdcee commit 5e43f0a
Show file tree
Hide file tree
Showing 18 changed files with 131 additions and 24 deletions.
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ object Versions {

object Libraries {
const val tectonic = "4.2.1"
const val paralithic = "0.7.1"
const val paralithic = "0.8.1"
const val strata = "1.3.2"

const val cloud = "2.0.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.dfsek.terra.addons.noise;

import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;

import java.util.LinkedHashMap;
Expand Down Expand Up @@ -88,6 +89,8 @@ public void initialize() {
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> {
ParseOptions expressionParseOptions = event.getPack().getExpressionParseOptions();

CheckedRegistry<Supplier<ObjectTemplate<NoiseSampler>>> noiseRegistry = event.getPack().getOrCreateRegistry(
NOISE_SAMPLER_TOKEN);
event.getPack()
Expand All @@ -98,7 +101,7 @@ public void initialize() {
.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, () -> new FunctionTemplate(expressionParseOptions))
.applyLoader(CubicSpline.Point.class, CubicSplinePointTemplate::new)
.applyLoader(DerivativeNoiseSampler.class, DerivativeNoiseSamplerTemplate::new);

Expand Down Expand Up @@ -156,9 +159,9 @@ public void initialize() {

Map<String, DimensionApplicableNoiseSampler> packSamplers = new LinkedHashMap<>();
Map<String, FunctionTemplate> packFunctions = new LinkedHashMap<>();
noiseRegistry.register(addon.key("EXPRESSION"), () -> new ExpressionFunctionTemplate(packSamplers, packFunctions));
noiseRegistry.register(addon.key("EXPRESSION"), () -> new ExpressionFunctionTemplate(packSamplers, packFunctions, expressionParseOptions));
noiseRegistry.register(addon.key("EXPRESSION_NORMALIZER"),
() -> new ExpressionNormalizerTemplate(packSamplers, packFunctions));
() -> new ExpressionNormalizerTemplate(packSamplers, packFunctions, expressionParseOptions));

NoiseConfigPackTemplate template = event.loadTemplate(new NoiseConfigPackTemplate());
packSamplers.putAll(template.getSamplers());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.dfsek.terra.addons.noise.config.templates;

import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;
Expand All @@ -20,6 +21,8 @@

@SuppressWarnings("unused")
public class FunctionTemplate implements ObjectTemplate<FunctionTemplate> {
private final ParseOptions parseOptions;

@Value("arguments")
private List<String> args;

Expand All @@ -30,6 +33,10 @@ public class FunctionTemplate implements ObjectTemplate<FunctionTemplate> {
@Default
private @Meta LinkedHashMap<String, @Meta FunctionTemplate> functions = new LinkedHashMap<>();

public FunctionTemplate(ParseOptions parseOptions) {
this.parseOptions = parseOptions;
}

@Override
public FunctionTemplate get() {
return this;
Expand All @@ -47,6 +54,10 @@ public LinkedHashMap<String, FunctionTemplate> getFunctions() {
return functions;
}

public ParseOptions getParseOptions() {
return parseOptions;
}

@Override
public boolean equals(Object o) {
if(this == o) return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.dfsek.terra.addons.noise.config.templates.noise;

import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
Expand All @@ -29,6 +30,7 @@
public class ExpressionFunctionTemplate extends SamplerTemplate<ExpressionFunction> {
private final Map<String, DimensionApplicableNoiseSampler> globalSamplers;
private final Map<String, FunctionTemplate> globalFunctions;
private final ParseOptions parseOptions;
@Value("variables")
@Default
private @Meta Map<String, @Meta Double> vars = new HashMap<>();
Expand All @@ -42,9 +44,11 @@ public class ExpressionFunctionTemplate extends SamplerTemplate<ExpressionFuncti
private @Meta LinkedHashMap<String, @Meta FunctionTemplate> functions = new LinkedHashMap<>();

public ExpressionFunctionTemplate(Map<String, DimensionApplicableNoiseSampler> globalSamplers,
Map<String, FunctionTemplate> globalFunctions) {
Map<String, FunctionTemplate> globalFunctions,
ParseOptions parseOptions) {
this.globalSamplers = globalSamplers;
this.globalFunctions = globalFunctions;
this.parseOptions = parseOptions;
}

@Override
Expand All @@ -54,7 +58,7 @@ public NoiseSampler get() {
var mergedSamplers = new HashMap<>(globalSamplers);
mergedSamplers.putAll(samplers);
try {
return new ExpressionFunction(convertFunctionsAndSamplers(mergedFunctions, mergedSamplers), expression, vars);
return new ExpressionFunction(convertFunctionsAndSamplers(mergedFunctions, mergedSamplers), expression, vars, parseOptions);
} catch(ParseException e) {
throw new RuntimeException("Failed to parse expression.", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

package com.dfsek.terra.addons.noise.config.templates.normalizer;

import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
Expand All @@ -29,6 +30,7 @@ public class ExpressionNormalizerTemplate extends NormalizerTemplate<ExpressionN

private final Map<String, DimensionApplicableNoiseSampler> globalSamplers;
private final Map<String, FunctionTemplate> globalFunctions;
private final ParseOptions parseOptions;

@Value("expression")
private @Meta String expression;
Expand All @@ -46,9 +48,11 @@ public class ExpressionNormalizerTemplate extends NormalizerTemplate<ExpressionN
private @Meta LinkedHashMap<String, @Meta FunctionTemplate> functions = new LinkedHashMap<>();

public ExpressionNormalizerTemplate(Map<String, DimensionApplicableNoiseSampler> globalSamplers,
Map<String, FunctionTemplate> globalFunctions) {
Map<String, FunctionTemplate> globalFunctions,
ParseOptions parseOptions) {
this.globalSamplers = globalSamplers;
this.globalFunctions = globalFunctions;
this.parseOptions = parseOptions;
}

@Override
Expand All @@ -58,7 +62,7 @@ public NoiseSampler get() {
var mergedSamplers = new HashMap<>(globalSamplers);
mergedSamplers.putAll(samplers);
try {
return new ExpressionNormalizer(function, convertFunctionsAndSamplers(mergedFunctions, mergedSamplers), expression, vars);
return new ExpressionNormalizer(function, convertFunctionsAndSamplers(mergedFunctions, mergedSamplers), expression, vars, parseOptions);
} catch(ParseException e) {
throw new RuntimeException("Failed to parse expression.", e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.paralithic.functions.Function;

import java.util.Arrays;
import java.util.Map;

import com.dfsek.terra.api.noise.NoiseSampler;
Expand All @@ -15,12 +17,24 @@ public class ExpressionNormalizer extends Normalizer {

private final Expression expression;

public ExpressionNormalizer(NoiseSampler sampler, Map<String, Function> functions, String eq, Map<String, Double> vars)
public ExpressionNormalizer(NoiseSampler sampler, Map<String, Function> functions, String eq, Map<String, Double> vars, ParseOptions parseOptions)
throws ParseException {
super(sampler);
Parser p = new Parser();

Parser p = new Parser(parseOptions);
Scope scope = new Scope();
scope.addInvocationVariable("in");

// 'in' was used as the invocation variable but conflicts with
// the new 'in' keyword in Paralithic used to denote the end of a let
// expression. To maintain backwards compatibility but also enable the use
// of let expressions, if they're enabled then use the longer 'input'
// invocation variable instead.
if (parseOptions.useLetExpressions()) {
scope.addInvocationVariable("input");
} else {
scope.addInvocationVariable("in");
}

vars.forEach(scope::create);
functions.forEach(p::registerFunction);
expression = p.parse(eq, scope);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ protected UserDefinedFunction(Expression expression, int args) {
public static UserDefinedFunction newInstance(FunctionTemplate template) throws ParseException {
UserDefinedFunction function = CACHE.get(template);
if(function == null) {
Parser parser = new Parser();
Parser parser = new Parser(template.getParseOptions());
Scope parent = new Scope();

Scope functionScope = new Scope().withParent(parent);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.paralithic.functions.Function;
Expand All @@ -24,8 +25,8 @@
public class ExpressionFunction extends NoiseFunction {
private final Expression expression;

public ExpressionFunction(Map<String, Function> functions, String eq, Map<String, Double> vars) throws ParseException {
Parser p = new Parser();
public ExpressionFunction(Map<String, Function> functions, String eq, Map<String, Double> vars, ParseOptions parseOptions) throws ParseException {
Parser p = new Parser(parseOptions);
Scope scope = new Scope();

scope.addInvocationVariable("x");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.dfsek.paralithic.Expression;
import com.dfsek.paralithic.eval.parser.Parser;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.paralithic.eval.parser.Scope;
import com.dfsek.paralithic.eval.tokenizer.ParseException;
import com.dfsek.tectonic.api.depth.DepthTracker;
Expand All @@ -15,14 +16,21 @@


public class DoublePredicateLoader implements TypeLoader<DoublePredicate> {

private final ParseOptions parseOptions;

public DoublePredicateLoader(ParseOptions parseOptions) {
this.parseOptions = parseOptions;
}

@Override
public DoublePredicate load(@NotNull AnnotatedType annotatedType, @NotNull Object o, @NotNull ConfigLoader configLoader,
DepthTracker depthTracker) throws LoadException {
if(o instanceof String expressionString) {
Scope scope = new Scope();
scope.addInvocationVariable("value");
try {
Expression expression = new Parser().parse(expressionString, scope);
Expression expression = new Parser(parseOptions).parse(expressionString, scope);
return d -> expression.evaluate(d) != 0; // Paralithic expressions treat '!= 0' as true
} catch(ParseException e) {
throw new LoadException("Failed to parse double predicate expression", e, depthTracker);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ public void initialize() {
plugin.getEventManager()
.getHandler(FunctionalEventHandler.class)
.register(addon, ConfigPackPreLoadEvent.class)
.then(event -> event.getPack().applyLoader(DoublePredicate.class, new DoublePredicateLoader()))
.then(event -> event.getPack().applyLoader(DoublePredicate.class, new DoublePredicateLoader(event.getPack().getExpressionParseOptions())))
.priority(50)
.failThrough();
}
Expand Down
1 change: 1 addition & 0 deletions common/api/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ dependencies {

api("com.github.ben-manes.caffeine", "caffeine", Versions.Libraries.caffeine)

api("com.dfsek", "paralithic", Versions.Libraries.paralithic)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import java.util.List;
import java.util.Map;

import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;

import com.dfsek.terra.api.addon.BaseAddon;
import com.dfsek.terra.api.properties.PropertyHolder;
import com.dfsek.terra.api.registry.key.Keyed;
Expand Down Expand Up @@ -49,6 +51,8 @@ public interface ConfigPack extends LoaderRegistrar,

Version getVersion();

ParseOptions getExpressionParseOptions();

<T> ConfigPack registerShortcut(TypeKey<T> clazz, String shortcut, ShortcutLoader<T> loader);

default <T> ConfigPack registerShortcut(Class<T> clazz, String shortcut, ShortcutLoader<T> loader) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import ca.solostudios.strata.version.Version;
import ca.solostudios.strata.version.VersionRange;
import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.TypeRegistry;

import java.util.LinkedHashMap;
Expand All @@ -31,6 +32,7 @@
import com.dfsek.terra.api.util.Range;
import com.dfsek.terra.api.util.collection.MaterialSet;
import com.dfsek.terra.api.util.collection.ProbabilityCollection;
import com.dfsek.terra.config.loaders.ExpressionParserOptionsTemplate;
import com.dfsek.terra.config.loaders.LinkedHashMapLoader;
import com.dfsek.terra.config.loaders.MaterialSetLoader;
import com.dfsek.terra.config.loaders.ProbabilityCollectionLoader;
Expand All @@ -53,7 +55,8 @@ public void register(TypeRegistry registry) {
.registerLoader(Version.class, new VersionLoader())
.registerLoader(MaterialSet.class, new MaterialSetLoader())
.registerLoader(VersionRange.class, new VersionRangeLoader())
.registerLoader(LinkedHashMap.class, new LinkedHashMapLoader());
.registerLoader(LinkedHashMap.class, new LinkedHashMapLoader())
.registerLoader(ParseOptions.class, ExpressionParserOptionsTemplate::new);

if(platform != null) {
registry.registerLoader(BaseAddon.class, platform.getAddons())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.dfsek.terra.config.loaders;

import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;
import com.dfsek.tectonic.api.config.template.object.ObjectTemplate;


public class ExpressionParserOptionsTemplate implements ObjectTemplate<ParseOptions> {

private static final ParseOptions DEFAULT_PARSE_OPTIONS = new ParseOptions();

@Value("use-let-expressions")
@Default
private boolean useLetExpressions = DEFAULT_PARSE_OPTIONS.useLetExpressions();

@Override
public ParseOptions get() {
return new ParseOptions(useLetExpressions);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.dfsek.terra.config.pack;

import com.dfsek.paralithic.eval.parser.Parser.ParseOptions;
import com.dfsek.tectonic.api.config.template.ConfigTemplate;
import com.dfsek.tectonic.api.config.template.annotations.Default;
import com.dfsek.tectonic.api.config.template.annotations.Value;


public class ConfigPackExpressionOptionsTemplate implements ConfigTemplate {
@Value("expressions.options")
@Default
private ParseOptions parseOptions = new ParseOptions();

public ParseOptions getParseOptions() {
return parseOptions;
}
}
Loading

0 comments on commit 5e43f0a

Please sign in to comment.