diff --git a/src/main/java/net/pixaurora/janerator/config/ConfigFileManager.java b/src/main/java/net/pixaurora/janerator/config/ConfigFileManager.java index e90c2ae..1a7c262 100644 --- a/src/main/java/net/pixaurora/janerator/config/ConfigFileManager.java +++ b/src/main/java/net/pixaurora/janerator/config/ConfigFileManager.java @@ -17,6 +17,7 @@ import net.minecraft.world.level.Level; import net.pixaurora.janerator.Janerator; import net.pixaurora.janerator.RegistryCache; +import net.pixaurora.janerator.graphing.ConfiguredGrapherSettings; public class ConfigFileManager { private final Path savePath; @@ -88,7 +89,7 @@ private JaneratorConfig createDefault() { List.of( new GraphProperties( Level.OVERWORLD, - new GrapherFactory( + new ConfiguredGrapherSettings( List.of( "phi = (1 + sqrt(5)) / 2", "log_phi = ln(phi)", diff --git a/src/main/java/net/pixaurora/janerator/config/GraphProperties.java b/src/main/java/net/pixaurora/janerator/config/GraphProperties.java index e3a5754..ffd1481 100644 --- a/src/main/java/net/pixaurora/janerator/config/GraphProperties.java +++ b/src/main/java/net/pixaurora/janerator/config/GraphProperties.java @@ -7,45 +7,46 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.world.level.Level; import net.minecraft.world.level.levelgen.FlatLevelSource; -import net.pixaurora.janerator.graphing.ConfiguredGraphLogic; +import net.pixaurora.janerator.graphing.Grapher; +import net.pixaurora.janerator.graphing.ConfiguredGrapherSettings; public class GraphProperties { private ResourceKey dimension; - private GrapherFactory grapherFactory; + private ConfiguredGrapherSettings grapherSettings; private FlatLevelSource shadedGenerator; private FlatLevelSource outlineGenerator; - private ThreadLocal grapher; + private ThreadLocal grapher; public static Codec CODEC = RecordCodecBuilder.create( instance -> instance.group( ResourceKey.codec(Registries.DIMENSION).fieldOf("dimension").forGetter(GraphProperties::getDimension), - GrapherFactory.CODEC.fieldOf("function_to_graph").forGetter(GraphProperties::getGrapherFactory), + ConfiguredGrapherSettings.CODEC.fieldOf("function_to_graph").forGetter(GraphProperties::getGrapherSettings), FlatLevelSource.CODEC.fieldOf("shaded_in_generator").forGetter(GraphProperties::getShadedGenerator), FlatLevelSource.CODEC.fieldOf("outlines_generator").forGetter(GraphProperties::getOutlineGenerator) ).apply(instance, GraphProperties::new) ); - public GraphProperties(ResourceKey dimension, GrapherFactory grapherFactory, FlatLevelSource shadedGenerator, FlatLevelSource outlineGenerator) { + public GraphProperties(ResourceKey dimension, ConfiguredGrapherSettings grapherSettings, FlatLevelSource shadedGenerator, FlatLevelSource outlineGenerator) { this.dimension = dimension; - this.grapherFactory = grapherFactory; + this.grapherSettings = grapherSettings; this.shadedGenerator = shadedGenerator; this.outlineGenerator = outlineGenerator; - this.grapher = ThreadLocal.withInitial(() -> this.grapherFactory.createGraphLogic()); + this.grapher = ThreadLocal.withInitial(() -> Grapher.fromConfig(this.grapherSettings)); } public ResourceKey getDimension() { return this.dimension; } - public GrapherFactory getGrapherFactory() { - return this.grapherFactory; + public ConfiguredGrapherSettings getGrapherSettings() { + return this.grapherSettings; } - public ConfiguredGraphLogic getLocalGrapher() { + public Grapher getLocalGrapher() { return this.grapher.get(); } diff --git a/src/main/java/net/pixaurora/janerator/config/GrapherFactory.java b/src/main/java/net/pixaurora/janerator/config/GrapherFactory.java deleted file mode 100644 index 6bfd2b8..0000000 --- a/src/main/java/net/pixaurora/janerator/config/GrapherFactory.java +++ /dev/null @@ -1,42 +0,0 @@ -package net.pixaurora.janerator.config; - -import java.util.List; - -import com.mojang.serialization.Codec; -import com.mojang.serialization.codecs.RecordCodecBuilder; - -import net.pixaurora.janerator.graphing.ConfiguredGraphLogic; - -public class GrapherFactory { - public static final Codec CODEC = RecordCodecBuilder.create( - instance -> instance.group( - Codec.STRING.listOf().fieldOf("variable_definitions").forGetter(GrapherFactory::getVariableDefinitions), - Codec.STRING.fieldOf("return_statement").forGetter(GrapherFactory::getReturnStatement) - ) - .apply(instance, GrapherFactory::new) - ); - - private List variableDefinitions; - private String returnStatement; - - private ConfiguredGraphLogic baseInstance; - - public GrapherFactory(List variableDefinitions, String returnStatement) { - this.variableDefinitions = variableDefinitions; - this.returnStatement = returnStatement; - - this.baseInstance = new ConfiguredGraphLogic(variableDefinitions, returnStatement); - } - - public ConfiguredGraphLogic createGraphLogic() { - return new ConfiguredGraphLogic(this.baseInstance); - } - - public List getVariableDefinitions() { - return variableDefinitions; - } - - public String getReturnStatement() { - return returnStatement; - } -} diff --git a/src/main/java/net/pixaurora/janerator/graphing/ConfiguredGraphLogic.java b/src/main/java/net/pixaurora/janerator/graphing/ConfiguredGraphLogic.java deleted file mode 100644 index 3d73957..0000000 --- a/src/main/java/net/pixaurora/janerator/graphing/ConfiguredGraphLogic.java +++ /dev/null @@ -1,87 +0,0 @@ -package net.pixaurora.janerator.graphing; - -import java.util.ArrayList; -import java.util.List; - -import org.mariuszgromada.math.mxparser.License; -import org.mariuszgromada.math.mxparser.mXparser; - -public class ConfiguredGraphLogic { - private List independentVariables; - private int variableCount; - - private List variableDefinitions; - private WrappedFunction overrideFunction; - - static { - License.iConfirmNonCommercialUse("Rina Shaw "); - - mXparser.disableImpliedMultiplicationMode(); // Implied multiplication breaks searching for missing user-defined arguments - mXparser.disableAlmostIntRounding(); - mXparser.disableCanonicalRounding(); - mXparser.disableUlpRounding(); - } - - public ConfiguredGraphLogic(List variableDefinitions, String returnStatement) { - this.independentVariables = new ArrayList<>(); - this.variableDefinitions = new ArrayList<>(); - - List variables = variableDefinitions - .stream() - .map(Variable::new) - .toList(); - - List allKnownVariableNames = new ArrayList<>(List.of("x", "z")); - List independentVariableNames = new ArrayList<>(); - for (Variable variable : variables) { - variable.validateNeedsOnly(allKnownVariableNames); - allKnownVariableNames.add(variable.name); - - if (variable.isCompletelyIndependent()) { - this.independentVariables.add(variable.evaluate()); - continue; - } - - List missingDependentVariables = variable.getMissingVariablesToEvaluate(independentVariableNames); - if (missingDependentVariables.size() == 0) { - WrappedFunction variableDefinition = new WrappedFunction(variable, independentVariableNames); - - this.independentVariables.add(variableDefinition.evaluate(this.independentVariables)); - independentVariableNames.add(variable.name); - } else { - this.variableDefinitions.add(new WrappedFunction(variable, allKnownVariableNames)); - } - } - - Variable returnValue = new Variable("shouldOverride = " + returnStatement); - returnValue.validateNeedsOnly(allKnownVariableNames); - - this.overrideFunction = new WrappedFunction(returnValue, allKnownVariableNames); - - this.variableCount = allKnownVariableNames.size(); - } - - public ConfiguredGraphLogic(ConfiguredGraphLogic other) { - this.independentVariables = other.independentVariables; - this.variableCount = other.variableCount; - - this.variableDefinitions = other.variableDefinitions - .stream() - .map(variable -> new WrappedFunction(variable)) - .toList(); - this.overrideFunction = new WrappedFunction(other.overrideFunction); - } - - public boolean isShaded(double x, double z) { - List variables = new ArrayList<>(this.variableCount); - variables.add(x); - variables.add(z); - variables.addAll(this.independentVariables); - - for (WrappedFunction variable : this.variableDefinitions) { - variables.add(variable.evaluate(variables)); - } - - return this.overrideFunction.evaluate(variables) == 1.0; - } -} diff --git a/src/main/java/net/pixaurora/janerator/graphing/ConfiguredGrapherSettings.java b/src/main/java/net/pixaurora/janerator/graphing/ConfiguredGrapherSettings.java new file mode 100644 index 0000000..3afd725 --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/ConfiguredGrapherSettings.java @@ -0,0 +1,75 @@ +package net.pixaurora.janerator.graphing; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import org.mariuszgromada.math.mxparser.License; +import org.mariuszgromada.math.mxparser.mXparser; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import net.pixaurora.janerator.graphing.variable.InputVariable; +import net.pixaurora.janerator.graphing.variable.Variable; + +public class ConfiguredGrapherSettings { + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + Codec.STRING.listOf().fieldOf("variable_definitions").forGetter(ConfiguredGrapherSettings::getVariableDefinitions), + Codec.STRING.fieldOf("return_statement").forGetter(ConfiguredGrapherSettings::getReturnStatement) + ) + .apply(instance, ConfiguredGrapherSettings::new) + ); + + static { + License.iConfirmNonCommercialUse("Rina Shaw "); + + mXparser.disableImpliedMultiplicationMode(); // Implied multiplication breaks searching for missing user-defined arguments + mXparser.disableAlmostIntRounding(); + mXparser.disableCanonicalRounding(); + mXparser.disableUlpRounding(); + } + + private List variableDefinitions; + private String returnStatement; + + private List variables; + + public ConfiguredGrapherSettings(List variableDefinitions, String returnStatement) { + this.variableDefinitions = variableDefinitions; + this.returnStatement = returnStatement; + + this.variables = new ArrayList<>(this.variableDefinitions.size() + 1); + this.variables.add(new InputVariable("x")); + this.variables.add(new InputVariable("z")); + + Map variableTable = new HashMap<>( + this.variables.stream() + .collect(Collectors.toMap(Variable::getName, variable -> variable)) + ); + + for (String definition : variableDefinitions) { + Variable nextVariable = Variable.fromStringDefinition(variableTable, definition); + + this.variables.add(nextVariable); + variableTable.put(nextVariable.getName(), nextVariable); + } + + this.variables.add(Variable.fromStringDefinition(variableTable, "returnValue = " + returnStatement)); + } + + public List getVariableDefinitions() { + return this.variableDefinitions; + } + + public String getReturnStatement() { + return this.returnStatement; + } + + public List getVariables() { + return this.variables; + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/Grapher.java b/src/main/java/net/pixaurora/janerator/graphing/Grapher.java new file mode 100644 index 0000000..0bb648e --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/Grapher.java @@ -0,0 +1,88 @@ +package net.pixaurora.janerator.graphing; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; + +import net.pixaurora.janerator.graphing.instruction.Instruction; +import net.pixaurora.janerator.graphing.variable.IndependentVariable; +import net.pixaurora.janerator.graphing.variable.InputVariable; +import net.pixaurora.janerator.graphing.variable.Variable; + +public class Grapher { + private List startingVariables; + private List intermediaryInstructions; + private int returnIndex; + + public Grapher(List startingVariables, List instructionsToApply, int returnIndex) { + this.startingVariables = startingVariables; + this.intermediaryInstructions = instructionsToApply; + this.returnIndex = returnIndex; + } + + public static Grapher fromConfig(ConfiguredGrapherSettings config) { + AtomicInteger count = new AtomicInteger(-1); + Map nameToIndex = new HashMap<>( + Map.of( + "x", count.getAndIncrement(), + "z", count.getAndIncrement() + ) + ); + + List allVariables = config.getVariables(); + List variableDefinitions = config.getVariables().stream() + .filter(variable -> ! (variable instanceof InputVariable)) + .toList(); + + + for (Variable variable : variableDefinitions) { + nameToIndex.computeIfAbsent(variable.getName(), name -> count.getAndIncrement()); + } + + List instructions = new ArrayList<>(); + List startingVariables = IntStream.range(0, count.get()) + .mapToDouble(value -> 0.0) + .boxed() + .toList(); + + for (Variable variable : variableDefinitions) { + int setIndex = nameToIndex.get(variable.getName()); + int[] accessIndexes = variable.getRequiredVariables().stream() + .map(Variable::getName) + .map(nameToIndex::get) + .mapToInt(Integer::valueOf) + .toArray(); + + Instruction instruction = variable.createInstruction(accessIndexes, setIndex); + + boolean definedOnce = allVariables.stream() + .filter(other -> variable.getName() == other.getName()) + .count() < 1; + + if ( + variable instanceof IndependentVariable && definedOnce + ) { + instruction.execute(startingVariables); + } else { + instructions.add(instruction); + } + } + + return new Grapher(startingVariables, instructions, nameToIndex.get("returnValue")); + } + + public boolean isShaded(double x, double z) { + List variables = new ArrayList<>(this.startingVariables); + variables.set(0, x); + variables.set(0, z); + + for (Instruction instruction : this.intermediaryInstructions) { + instruction.execute(variables); + } + + return variables.get(this.returnIndex) == 0.0; + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/Variable.java b/src/main/java/net/pixaurora/janerator/graphing/Variable.java deleted file mode 100644 index aace6f6..0000000 --- a/src/main/java/net/pixaurora/janerator/graphing/Variable.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.pixaurora.janerator.graphing; - -import java.util.Arrays; -import java.util.List; - -import org.mariuszgromada.math.mxparser.Expression; - -import net.pixaurora.janerator.config.GraphingConfigException; - -public class Variable { - public String name; - public String definition; - public List requiredVariables; - - private Expression expression; - - public Variable(String userDefinition) { - List parts = Arrays.asList(userDefinition.split("=")); - if (parts.size() != 2) { - throw new GraphingConfigException(String.format("Function definition `%s` must have 1 = sign.", userDefinition)); - } - - this.name = parts.get(0).strip(); - this.definition = parts.get(1); - - this.expression = new Expression(definition); - this.requiredVariables = Arrays.asList(this.expression.getMissingUserDefinedArguments()); - } - - public List getMissingVariablesToEvaluate(List knownVariables) { - return this.requiredVariables - .stream() - .filter(variable -> ! knownVariables.contains(variable)) - .toList(); - } - - public void validateNeedsOnly(List variableNames) { - List missingVariables = this.getMissingVariablesToEvaluate(variableNames); - if (missingVariables.size() > 0) { - throw new GraphingConfigException( - String.format( - "Variable definition for %s is using unknown variables %s", - this.name, - String.join(", ", missingVariables) - ) - ); - } - } - - public boolean isCompletelyIndependent() { - return this.requiredVariables.size() == 0; - } - - public double evaluate() { - return this.expression.calculate(); - } -} diff --git a/src/main/java/net/pixaurora/janerator/graphing/WrappedFunction.java b/src/main/java/net/pixaurora/janerator/graphing/WrappedFunction.java deleted file mode 100644 index 8706bd4..0000000 --- a/src/main/java/net/pixaurora/janerator/graphing/WrappedFunction.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.pixaurora.janerator.graphing; - -import java.util.List; - -import org.mariuszgromada.math.mxparser.Function; - -public class WrappedFunction { - private String name; - private Function function; - private List variableIndices; - - WrappedFunction(Variable variable, List variableOrder) { - this.name = variable.name; - this.variableIndices = variable.requiredVariables - .stream() - .map(variableOrder::indexOf) - .toList(); - - this.function = new Function(this.name, variable.definition, variable.requiredVariables.toArray(new String[]{})); - } - - WrappedFunction(WrappedFunction other) { - this.name = other.name; - this.variableIndices = other.variableIndices; - this.function = other.function.cloneForThreadSafe(); - } - - public String getName() { - return this.name; - } - - public double evaluate(List variables) { - return this.function.calculate( - this.variableIndices - .stream() - .map(variables::get) - .mapToDouble(Double::valueOf) - .toArray() - ); - } -} diff --git a/src/main/java/net/pixaurora/janerator/graphing/instruction/DynamicInstruction.java b/src/main/java/net/pixaurora/janerator/graphing/instruction/DynamicInstruction.java new file mode 100644 index 0000000..7b6c00c --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/instruction/DynamicInstruction.java @@ -0,0 +1,29 @@ +package net.pixaurora.janerator.graphing.instruction; + +import java.util.List; + +import org.mariuszgromada.math.mxparser.Function; + +public class DynamicInstruction implements Instruction { + private final int[] accessIndexes; + private final int setIndex; + + private final Function executedFunction; + + public DynamicInstruction(int[] accessIndexes, int setIndex, Function executedFunction) { + this.accessIndexes = accessIndexes; + this.setIndex = setIndex; + + this.executedFunction = executedFunction; + } + + public void execute(List variables) { + double[] args = new double[this.accessIndexes.length]; + + for (int i = 0; i < this.accessIndexes.length; i++) { + args[i] = variables.get(i); + } + + variables.set(this.setIndex, this.executedFunction.calculate(args)); + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/instruction/Instruction.java b/src/main/java/net/pixaurora/janerator/graphing/instruction/Instruction.java new file mode 100644 index 0000000..426c98a --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/instruction/Instruction.java @@ -0,0 +1,7 @@ +package net.pixaurora.janerator.graphing.instruction; + +import java.util.List; + +public interface Instruction { + public void execute(List variables); +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/instruction/StaticInstruction.java b/src/main/java/net/pixaurora/janerator/graphing/instruction/StaticInstruction.java new file mode 100644 index 0000000..7b318bf --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/instruction/StaticInstruction.java @@ -0,0 +1,18 @@ +package net.pixaurora.janerator.graphing.instruction; + +import java.util.List; + +public class StaticInstruction implements Instruction { + private int setIndex; + private double value; + + public StaticInstruction(int setIndex, double value) { + this.setIndex = setIndex; + this.value = value; + } + + @Override + public void execute(List variables) { + variables.set(this.setIndex, this.value); + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/variable/Definition.java b/src/main/java/net/pixaurora/janerator/graphing/variable/Definition.java new file mode 100644 index 0000000..e235982 --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/variable/Definition.java @@ -0,0 +1,46 @@ +package net.pixaurora.janerator.graphing.variable; + +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import org.mariuszgromada.math.mxparser.Expression; + +import net.pixaurora.janerator.config.GraphingConfigException; + +public class Definition { + private String name; + private List requiredNames; + + private Expression expression; + + public Definition(String definitionText) { + List parts = Arrays.asList(definitionText.split("=")); + if (parts.size() != 2) { + throw new GraphingConfigException(String.format("Function definition `%s` must have exactly one equal sign (=)", definitionText)); + } + + this.name = parts.get(0); + this.expression = new Expression(parts.get(1)); + + this.requiredNames = List.of(this.expression.getMissingUserDefinedArguments()); + } + + public String getName() { + return this.name; + } + + public List getRequiredNames() { + return this.requiredNames; + } + + public String getExpressionText() { + return this.expression.getExpressionString(); + } + + public List getRequiredVariables(Map variableTable) { + return this.requiredNames.stream() + .map(name -> variableTable.getOrDefault(name, new MissingVariable(name))) + .toList(); + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/variable/DependentVariable.java b/src/main/java/net/pixaurora/janerator/graphing/variable/DependentVariable.java new file mode 100644 index 0000000..cbc4405 --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/variable/DependentVariable.java @@ -0,0 +1,41 @@ +package net.pixaurora.janerator.graphing.variable; + +import java.util.List; + +import org.mariuszgromada.math.mxparser.Function; + +import net.pixaurora.janerator.graphing.instruction.DynamicInstruction; +import net.pixaurora.janerator.graphing.instruction.Instruction; + +public class DependentVariable implements Variable { + private String name; + + private List requiredVariables; + private String definitionStatement; + + public DependentVariable(String name, List usedVariables, String definitionStatement) { + this.name = name; + + this.requiredVariables = usedVariables; + this.definitionStatement = definitionStatement; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public List getRequiredVariables() { + return this.requiredVariables; + } + + public Function asFunction() { + return new Function(this.name, this.definitionStatement, this.getRequiredNames()); + } + + @Override + public Instruction createInstruction(int[] accessIndexes, int setIndex) { + return new DynamicInstruction(accessIndexes, setIndex, this.asFunction()); + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/variable/IndependentVariable.java b/src/main/java/net/pixaurora/janerator/graphing/variable/IndependentVariable.java new file mode 100644 index 0000000..7d3375e --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/variable/IndependentVariable.java @@ -0,0 +1,58 @@ +package net.pixaurora.janerator.graphing.variable; + +import java.util.List; + +import org.mariuszgromada.math.mxparser.Function; + +import net.pixaurora.janerator.graphing.instruction.Instruction; +import net.pixaurora.janerator.graphing.instruction.StaticInstruction; + +public class IndependentVariable implements Variable { + private String name; + private List requiredVariables; + + private double value; + + public IndependentVariable(String name, List requiredIndependentVariables, String definitionStatement) { + this.name = name; + this.requiredVariables = requiredIndependentVariables.stream() + .map(variable -> (Variable) variable) + .toList(); + + Function function = new Function( + name, + definitionStatement, + this.getRequiredNames() + ); + + if (requiredIndependentVariables.size() == 0) { + this.value = function.calculate(); + } else { + this.value = function.calculate( + requiredIndependentVariables.stream() + .map(IndependentVariable::getValue) + .mapToDouble(Double::valueOf) + .toArray() + ); + } + } + + @Override + public String getName() { + return this.name; + } + + @Override + public List getRequiredVariables() { + return this.requiredVariables; + } + + public double getValue() { + return this.value; + } + + @Override + public Instruction createInstruction(int[] accessIndexes, int setIndex) { + return new StaticInstruction(setIndex, this.value); + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/variable/InputVariable.java b/src/main/java/net/pixaurora/janerator/graphing/variable/InputVariable.java new file mode 100644 index 0000000..b864b95 --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/variable/InputVariable.java @@ -0,0 +1,28 @@ +package net.pixaurora.janerator.graphing.variable; + +import java.util.List; + +import net.pixaurora.janerator.graphing.instruction.Instruction; + +public class InputVariable implements Variable { + private String name; + + public InputVariable(String name) { + this.name = name; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public List getRequiredVariables() { + return List.of(); + } + + @Override + public Instruction createInstruction(int[] accessIndexes, int setIndex) { + throw new UnsupportedOperationException("Input variables cannot have instructions associated with them!"); + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/variable/MissingVariable.java b/src/main/java/net/pixaurora/janerator/graphing/variable/MissingVariable.java new file mode 100644 index 0000000..4dcd6a8 --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/variable/MissingVariable.java @@ -0,0 +1,28 @@ +package net.pixaurora.janerator.graphing.variable; + +import java.util.List; + +import net.pixaurora.janerator.graphing.instruction.Instruction; + +public class MissingVariable implements Variable { + private String name; + + public MissingVariable(String name) { + this.name = name; + } + + @Override + public String getName() { + return this.name; + } + + @Override + public List getRequiredVariables() { + return List.of(); + } + + @Override + public Instruction createInstruction(int[] accessIndexes, int setIndex) { + throw new UnsupportedOperationException("Missing variables cannot create instructions!"); + } +} diff --git a/src/main/java/net/pixaurora/janerator/graphing/variable/Variable.java b/src/main/java/net/pixaurora/janerator/graphing/variable/Variable.java new file mode 100644 index 0000000..4a9a64d --- /dev/null +++ b/src/main/java/net/pixaurora/janerator/graphing/variable/Variable.java @@ -0,0 +1,60 @@ +package net.pixaurora.janerator.graphing.variable; + +import java.util.List; +import java.util.Map; + +import net.pixaurora.janerator.Janerator; +import net.pixaurora.janerator.config.GraphingConfigException; +import net.pixaurora.janerator.graphing.instruction.Instruction; + +public interface Variable { + public static Variable fromStringDefinition(Map variableTable, String definitionText) { + Definition definition = new Definition(definitionText); + + String name = definition.getName().strip(); + List requiredVariables = definition.getRequiredVariables(variableTable); + String expressionText = definition.getExpressionText(); + + List missingNames = requiredVariables.stream() + .filter(variable -> variable instanceof MissingVariable) + .map(Variable::getName) + .toList(); + if (missingNames.size() > 0) { + Janerator.LOGGER.info("A" + variableTable.toString()); + throw new GraphingConfigException( + String.format( + "Variable definition for `%s` is using unknown variables `%s`", + definition.getName(), + String.join(", ", missingNames) + ) + ); + } + + if ( + requiredVariables.stream() + .allMatch(variable -> variable instanceof IndependentVariable) + ) { + List requiredIndependentVariables = requiredVariables.stream() + .map(variable -> (IndependentVariable) variable) + .toList(); + + return new IndependentVariable(name, requiredIndependentVariables, expressionText); + } else { + return new DependentVariable(name, requiredVariables, expressionText); + } + } + + public String getName(); + + public List getRequiredVariables(); + + public default String[] getRequiredNames() { + return this.getRequiredVariables() + .stream() + .map(Variable::getName) + .toList() + .toArray(new String[]{}); + } + + public Instruction createInstruction(int[] accessIndexes, int setIndex); +}