mirror of
https://github.com/DanilaFe/abacus
synced 2026-01-25 16:15:19 +00:00
Compare commits
19 Commits
promotion-
...
website-up
| Author | SHA1 | Date | |
|---|---|---|---|
| 91978686e6 | |||
| 9a8d0afc19 | |||
| 5aba5c350b | |||
| 21b7bd5e2b | |||
| dc4eee6342 | |||
| 6909f210d6 | |||
| fd246f935c | |||
| 6604af5b0f | |||
| d49a763e8f | |||
| 48a4d8adc2 | |||
| 5417b45106 | |||
| 585cabc478 | |||
| 28802cfed3 | |||
| 428df8bfd3 | |||
| 146f3994ef | |||
| daffdb6b42 | |||
| 178f59ef7b | |||
| 61616a428a | |||
| 9c77fa8aeb |
@@ -1,4 +1,3 @@
|
|||||||
dependencies {
|
dependencies {
|
||||||
compile 'com.moandjiezana.toml:toml4j:0.7.1'
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,150 +0,0 @@
|
|||||||
package org.nwapw.abacus;
|
|
||||||
|
|
||||||
import org.nwapw.abacus.config.Configuration;
|
|
||||||
import org.nwapw.abacus.number.NumberInterface;
|
|
||||||
import org.nwapw.abacus.number.PromotionManager;
|
|
||||||
import org.nwapw.abacus.parsing.LexerTokenizer;
|
|
||||||
import org.nwapw.abacus.parsing.ShuntingYardParser;
|
|
||||||
import org.nwapw.abacus.parsing.TreeBuilder;
|
|
||||||
import org.nwapw.abacus.plugin.NumberImplementation;
|
|
||||||
import org.nwapw.abacus.plugin.PluginManager;
|
|
||||||
import org.nwapw.abacus.plugin.StandardPlugin;
|
|
||||||
import org.nwapw.abacus.tree.NumberReducer;
|
|
||||||
import org.nwapw.abacus.tree.TreeNode;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The main calculator class. This is responsible
|
|
||||||
* for piecing together all of the components, allowing
|
|
||||||
* their interaction with each other.
|
|
||||||
*/
|
|
||||||
public class Abacus {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The default number implementation to be used if no other one is available / selected.
|
|
||||||
*/
|
|
||||||
public static final NumberImplementation DEFAULT_IMPLEMENTATION = StandardPlugin.IMPLEMENTATION_NAIVE;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The plugin manager responsible for
|
|
||||||
* loading and unloading plugins,
|
|
||||||
* and getting functions from them.
|
|
||||||
*/
|
|
||||||
private PluginManager pluginManager;
|
|
||||||
/**
|
|
||||||
* The reducer used to evaluate the tree.
|
|
||||||
*/
|
|
||||||
private NumberReducer numberReducer;
|
|
||||||
/**
|
|
||||||
* The configuration loaded from a file.
|
|
||||||
*/
|
|
||||||
private Configuration configuration;
|
|
||||||
/**
|
|
||||||
* The tree builder used to construct a tree
|
|
||||||
* from a string.
|
|
||||||
*/
|
|
||||||
private TreeBuilder treeBuilder;
|
|
||||||
/**
|
|
||||||
* Promotion manager responsible for the promotion system.
|
|
||||||
*/
|
|
||||||
private PromotionManager promotionManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new instance of the Abacus calculator.
|
|
||||||
*
|
|
||||||
* @param configuration the configuration object for this Abacus instance.
|
|
||||||
*/
|
|
||||||
public Abacus(Configuration configuration) {
|
|
||||||
pluginManager = new PluginManager(this);
|
|
||||||
numberReducer = new NumberReducer(this);
|
|
||||||
this.configuration = new Configuration(configuration);
|
|
||||||
LexerTokenizer lexerTokenizer = new LexerTokenizer();
|
|
||||||
ShuntingYardParser shuntingYardParser = new ShuntingYardParser();
|
|
||||||
treeBuilder = new TreeBuilder<>(lexerTokenizer, shuntingYardParser);
|
|
||||||
promotionManager = new PromotionManager(this);
|
|
||||||
|
|
||||||
pluginManager.addListener(shuntingYardParser);
|
|
||||||
pluginManager.addListener(lexerTokenizer);
|
|
||||||
pluginManager.addListener(promotionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the promotion manager.
|
|
||||||
*
|
|
||||||
* @return the promotion manager.
|
|
||||||
*/
|
|
||||||
public PromotionManager getPromotionManager() {
|
|
||||||
return promotionManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current tree builder.
|
|
||||||
*
|
|
||||||
* @return the main tree builder in this abacus instance.
|
|
||||||
*/
|
|
||||||
public TreeBuilder getTreeBuilder() {
|
|
||||||
return treeBuilder;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the current plugin manager,
|
|
||||||
*
|
|
||||||
* @return the plugin manager in this abacus instance.
|
|
||||||
*/
|
|
||||||
public PluginManager getPluginManager() {
|
|
||||||
return pluginManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the reducer that is responsible for transforming
|
|
||||||
* an expression into a number.
|
|
||||||
*
|
|
||||||
* @return the number reducer in this abacus instance.
|
|
||||||
*/
|
|
||||||
public NumberReducer getNumberReducer() {
|
|
||||||
return numberReducer;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the configuration object associated with this instance.
|
|
||||||
*
|
|
||||||
* @return the configuration object.
|
|
||||||
*/
|
|
||||||
public Configuration getConfiguration() {
|
|
||||||
return configuration;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a string into a tree structure using the main
|
|
||||||
* tree builder.
|
|
||||||
*
|
|
||||||
* @param input the input string to parse
|
|
||||||
* @return the resulting tree, null if the tree builder or the produced tree are null.
|
|
||||||
*/
|
|
||||||
public TreeNode parseString(String input) {
|
|
||||||
return treeBuilder.fromString(input);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Evaluates the given tree using the main
|
|
||||||
* number reducer.
|
|
||||||
*
|
|
||||||
* @param tree the tree to reduce, must not be null.
|
|
||||||
* @return the resulting number, or null of the reduction failed.
|
|
||||||
*/
|
|
||||||
public NumberInterface evaluateTree(TreeNode tree) {
|
|
||||||
return tree.reduce(numberReducer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number implementation.
|
|
||||||
*
|
|
||||||
* @return the number implementation to use for creating numbers.
|
|
||||||
*/
|
|
||||||
public NumberImplementation getNumberImplementation() {
|
|
||||||
NumberImplementation selectedImplementation =
|
|
||||||
pluginManager.numberImplementationFor(configuration.getNumberImplementation());
|
|
||||||
if (selectedImplementation != null) return selectedImplementation;
|
|
||||||
return DEFAULT_IMPLEMENTATION;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
package org.nwapw.abacus.config;
|
|
||||||
|
|
||||||
import com.moandjiezana.toml.Toml;
|
|
||||||
import com.moandjiezana.toml.TomlWriter;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The configuration object that stores
|
|
||||||
* options that the user can change.
|
|
||||||
*/
|
|
||||||
public class Configuration {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The defaults TOML string.
|
|
||||||
*/
|
|
||||||
private static final String DEFAULT_CONFIG =
|
|
||||||
"numberImplementation = \"naive\"\n" +
|
|
||||||
"disabledPlugins = []";
|
|
||||||
/**
|
|
||||||
* The defaults TOML object, parsed from the string.
|
|
||||||
*/
|
|
||||||
private static final Toml DEFAULT_TOML = new Toml().read(DEFAULT_CONFIG);
|
|
||||||
/**
|
|
||||||
* The TOML writer used to write this configuration to a file.
|
|
||||||
*/
|
|
||||||
private static final TomlWriter TOML_WRITER = new TomlWriter();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The computation delay for which the thread can run without interruption.
|
|
||||||
*/
|
|
||||||
private double computationDelay = 0;
|
|
||||||
/**
|
|
||||||
* The implementation of the number that should be used.
|
|
||||||
*/
|
|
||||||
private String numberImplementation = "<default>";
|
|
||||||
/**
|
|
||||||
* The list of disabled plugins in this Configuration.
|
|
||||||
*/
|
|
||||||
private Set<String> disabledPlugins = new HashSet<>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new configuration form the given configuration.
|
|
||||||
*
|
|
||||||
* @param copyFrom the configuration to copy.
|
|
||||||
*/
|
|
||||||
public Configuration(Configuration copyFrom) {
|
|
||||||
copyFrom(copyFrom);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new configuration with the given values.
|
|
||||||
*
|
|
||||||
* @param computationDelay the delay before the computation gets killed.
|
|
||||||
* @param numberImplementation the number implementation, like "naive" or "precise"
|
|
||||||
* @param disabledPlugins the list of disabled plugins.
|
|
||||||
*/
|
|
||||||
public Configuration(double computationDelay, String numberImplementation, String[] disabledPlugins) {
|
|
||||||
this.computationDelay = computationDelay;
|
|
||||||
this.numberImplementation = numberImplementation;
|
|
||||||
this.disabledPlugins.addAll(Arrays.asList(disabledPlugins));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a configuration from a given file, keeping non-specified fields default.
|
|
||||||
*
|
|
||||||
* @param fromFile the file to load from.
|
|
||||||
*/
|
|
||||||
public Configuration(File fromFile) {
|
|
||||||
if (!fromFile.exists()) return;
|
|
||||||
copyFrom(new Toml(DEFAULT_TOML).read(fromFile).to(Configuration.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies the values from the given configuration into this one.
|
|
||||||
*
|
|
||||||
* @param otherConfiguration the configuration to copy from.
|
|
||||||
*/
|
|
||||||
public void copyFrom(Configuration otherConfiguration) {
|
|
||||||
this.computationDelay = otherConfiguration.computationDelay;
|
|
||||||
this.numberImplementation = otherConfiguration.numberImplementation;
|
|
||||||
this.disabledPlugins.addAll(otherConfiguration.disabledPlugins);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves this configuration to the given file, creating
|
|
||||||
* any directories that do not exist.
|
|
||||||
*
|
|
||||||
* @param file the file to save to.
|
|
||||||
*/
|
|
||||||
public void saveTo(File file) {
|
|
||||||
if (file.getParentFile() != null) file.getParentFile().mkdirs();
|
|
||||||
try {
|
|
||||||
TOML_WRITER.write(this, file);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the value of this configuration as a string.
|
|
||||||
*
|
|
||||||
* @return the string that represents this configuration.
|
|
||||||
*/
|
|
||||||
public String asTomlString() {
|
|
||||||
return TOML_WRITER.write(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the number implementation from this configuration.
|
|
||||||
*
|
|
||||||
* @return the number implementation.
|
|
||||||
*/
|
|
||||||
public String getNumberImplementation() {
|
|
||||||
return numberImplementation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the number implementation for the configuration
|
|
||||||
*
|
|
||||||
* @param numberImplementation the number implementation.
|
|
||||||
*/
|
|
||||||
public void setNumberImplementation(String numberImplementation) {
|
|
||||||
this.numberImplementation = numberImplementation;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the list of disabled plugins.
|
|
||||||
*
|
|
||||||
* @return the list of disabled plugins.
|
|
||||||
*/
|
|
||||||
public Set<String> getDisabledPlugins() {
|
|
||||||
return disabledPlugins;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the computation delay specified in the configuration.
|
|
||||||
*
|
|
||||||
* @return the computaton delay.
|
|
||||||
*/
|
|
||||||
public double getComputationDelay() {
|
|
||||||
return computationDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the computation delay.
|
|
||||||
*
|
|
||||||
* @param computationDelay the new computation delay.
|
|
||||||
*/
|
|
||||||
public void setComputationDelay(double computationDelay) {
|
|
||||||
this.computationDelay = computationDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package org.nwapw.abacus.function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exception thrown if the function parameters do not match
|
||||||
|
* requirements.
|
||||||
|
*/
|
||||||
|
public class DomainException extends RuntimeException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DomainException.
|
||||||
|
* @param reason the reason for which the exception is thrown.
|
||||||
|
*/
|
||||||
|
public DomainException(String reason) {
|
||||||
|
super(reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new DomainException with a default message.
|
||||||
|
*/
|
||||||
|
public DomainException(){
|
||||||
|
this("Domain Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ package org.nwapw.abacus.plugin;
|
|||||||
|
|
||||||
import org.nwapw.abacus.function.*;
|
import org.nwapw.abacus.function.*;
|
||||||
import org.nwapw.abacus.number.NumberInterface;
|
import org.nwapw.abacus.number.NumberInterface;
|
||||||
|
import org.nwapw.abacus.variables.VariableDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A plugin class that can be externally implemented and loaded via the
|
* A plugin class that can be externally implemented and loaded via the
|
||||||
@@ -219,4 +220,12 @@ public abstract class Plugin {
|
|||||||
*/
|
*/
|
||||||
public abstract void onDisable();
|
public abstract void onDisable();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the variable database.
|
||||||
|
* @return the variable database.
|
||||||
|
*/
|
||||||
|
public final VariableDatabase getVariableDatabase(){
|
||||||
|
return manager.getVariableDatabase();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package org.nwapw.abacus.plugin;
|
|||||||
import org.nwapw.abacus.Abacus;
|
import org.nwapw.abacus.Abacus;
|
||||||
import org.nwapw.abacus.function.*;
|
import org.nwapw.abacus.function.*;
|
||||||
import org.nwapw.abacus.number.NumberInterface;
|
import org.nwapw.abacus.number.NumberInterface;
|
||||||
|
import org.nwapw.abacus.variables.VariableDatabase;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -421,4 +422,12 @@ public class PluginManager {
|
|||||||
public Set<Class<?>> getLoadedPluginClasses() {
|
public Set<Class<?>> getLoadedPluginClasses() {
|
||||||
return loadedPluginClasses;
|
return loadedPluginClasses;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the variable database.
|
||||||
|
* @return the database.
|
||||||
|
*/
|
||||||
|
public VariableDatabase getVariableDatabase(){
|
||||||
|
return abacus.getVariableDatabase();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
package org.nwapw.abacus.plugin;
|
package org.nwapw.abacus.plugin;
|
||||||
|
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.nwapw.abacus.function.*;
|
import org.nwapw.abacus.function.*;
|
||||||
import org.nwapw.abacus.number.NaiveNumber;
|
import org.nwapw.abacus.number.NaiveNumber;
|
||||||
import org.nwapw.abacus.number.NumberInterface;
|
import org.nwapw.abacus.number.NumberInterface;
|
||||||
import org.nwapw.abacus.number.PreciseNumber;
|
import org.nwapw.abacus.number.PreciseNumber;
|
||||||
|
import org.nwapw.abacus.tree.Reducer;
|
||||||
|
import org.nwapw.abacus.tree.TreeNode;
|
||||||
|
import org.nwapw.abacus.tree.VariableNode;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
@@ -14,6 +19,40 @@ import java.util.HashMap;
|
|||||||
*/
|
*/
|
||||||
public class StandardPlugin extends Plugin {
|
public class StandardPlugin extends Plugin {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set operator.
|
||||||
|
*/
|
||||||
|
public final TreeValueOperator opSet = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
|
||||||
|
@Override
|
||||||
|
public boolean matchesParams(NumberImplementation implementation, TreeNode[] params) {
|
||||||
|
return params.length == 2 && params[0] instanceof VariableNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NumberInterface applyWithReducerInternal(NumberImplementation implementation, Reducer<? extends NumberInterface> reducer, TreeNode[] params) {
|
||||||
|
String assignTo = ((VariableNode) params[0]).getVariable();
|
||||||
|
NumberInterface value = params[1].reduce(reducer);
|
||||||
|
getVariableDatabase().getVariables().put(assignTo, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
* The define operator.
|
||||||
|
*/
|
||||||
|
public final TreeValueOperator opDefine = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
|
||||||
|
@Override
|
||||||
|
public boolean matchesParams(NumberImplementation implementation, TreeNode[] params) {
|
||||||
|
return params.length == 2 && params[0] instanceof VariableNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public NumberInterface applyWithReducerInternal(NumberImplementation implementation, Reducer<? extends NumberInterface> reducer, TreeNode[] params) {
|
||||||
|
String assignTo = ((VariableNode) params[0]).getVariable();
|
||||||
|
getVariableDatabase().getDefinitions().put(assignTo, params[1]);
|
||||||
|
return params[1].reduce(reducer);
|
||||||
|
}
|
||||||
|
};
|
||||||
/**
|
/**
|
||||||
* The addition operator, +
|
* The addition operator, +
|
||||||
*/
|
*/
|
||||||
@@ -712,6 +751,9 @@ public class StandardPlugin extends Plugin {
|
|||||||
registerOperator("^", OP_CARET);
|
registerOperator("^", OP_CARET);
|
||||||
registerOperator("!", OP_FACTORIAL);
|
registerOperator("!", OP_FACTORIAL);
|
||||||
|
|
||||||
|
registerTreeValueOperator("=", opSet);
|
||||||
|
registerTreeValueOperator(":=", opDefine);
|
||||||
|
|
||||||
registerOperator("nPr", OP_NPR);
|
registerOperator("nPr", OP_NPR);
|
||||||
registerOperator("nCr", OP_NCR);
|
registerOperator("nCr", OP_NCR);
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import org.nwapw.abacus.function.TreeValueOperator;
|
|||||||
import org.nwapw.abacus.number.NumberInterface;
|
import org.nwapw.abacus.number.NumberInterface;
|
||||||
import org.nwapw.abacus.number.PromotionManager;
|
import org.nwapw.abacus.number.PromotionManager;
|
||||||
import org.nwapw.abacus.number.PromotionResult;
|
import org.nwapw.abacus.number.PromotionResult;
|
||||||
|
import org.nwapw.abacus.variables.VariableDatabase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A reducer implementation that turns a tree into a single number.
|
* A reducer implementation that turns a tree into a single number.
|
||||||
@@ -35,6 +36,12 @@ public class NumberReducer implements Reducer<NumberInterface> {
|
|||||||
if (node instanceof NumberNode) {
|
if (node instanceof NumberNode) {
|
||||||
return abacus.getNumberImplementation().instanceForString(((NumberNode) node).getNumber());
|
return abacus.getNumberImplementation().instanceForString(((NumberNode) node).getNumber());
|
||||||
} else if (node instanceof VariableNode) {
|
} else if (node instanceof VariableNode) {
|
||||||
|
VariableDatabase database = abacus.getVariableDatabase();
|
||||||
|
String name = ((VariableNode) node).getVariable();
|
||||||
|
NumberInterface variable = database.getVariables().get(name);
|
||||||
|
if(variable != null) return variable;
|
||||||
|
TreeNode definition = database.getDefinitions().get(name);
|
||||||
|
if(definition != null) return definition.reduce(this);
|
||||||
return abacus.getNumberImplementation().instanceForString("0");
|
return abacus.getNumberImplementation().instanceForString("0");
|
||||||
} else if (node instanceof NumberBinaryNode) {
|
} else if (node instanceof NumberBinaryNode) {
|
||||||
NumberInterface left = (NumberInterface) children[0];
|
NumberInterface left = (NumberInterface) children[0];
|
||||||
|
|||||||
90
core/src/main/kotlin/org/nwapw/abacus/Abacus.kt
Normal file
90
core/src/main/kotlin/org/nwapw/abacus/Abacus.kt
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package org.nwapw.abacus
|
||||||
|
|
||||||
|
import org.nwapw.abacus.config.Configuration
|
||||||
|
import org.nwapw.abacus.number.NumberInterface
|
||||||
|
import org.nwapw.abacus.number.PromotionManager
|
||||||
|
import org.nwapw.abacus.parsing.LexerTokenizer
|
||||||
|
import org.nwapw.abacus.parsing.ShuntingYardParser
|
||||||
|
import org.nwapw.abacus.parsing.TreeBuilder
|
||||||
|
import org.nwapw.abacus.plugin.NumberImplementation
|
||||||
|
import org.nwapw.abacus.plugin.PluginManager
|
||||||
|
import org.nwapw.abacus.plugin.StandardPlugin
|
||||||
|
import org.nwapw.abacus.tree.NumberReducer
|
||||||
|
import org.nwapw.abacus.tree.TreeNode
|
||||||
|
import org.nwapw.abacus.variables.VariableDatabase
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Core class to handle all mathematics.
|
||||||
|
*
|
||||||
|
* The main calculator class. This is responsible
|
||||||
|
* for piecing together all of the components, allowing
|
||||||
|
* their interaction with each other.
|
||||||
|
*
|
||||||
|
* @property configuration the configuration to use.
|
||||||
|
*/
|
||||||
|
class Abacus(val configuration: Configuration) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tokenizer used to convert strings into tokens.
|
||||||
|
*/
|
||||||
|
private val tokenizer = LexerTokenizer()
|
||||||
|
/**
|
||||||
|
* Parser the parser used to convert tokens into trees.
|
||||||
|
*/
|
||||||
|
private val parser = ShuntingYardParser()
|
||||||
|
/**
|
||||||
|
* The plugin manager used to handle loading and unloading plugins.
|
||||||
|
*/
|
||||||
|
val pluginManager = PluginManager(this)
|
||||||
|
/**
|
||||||
|
* The reducer used to turn trees into a single number.
|
||||||
|
*/
|
||||||
|
val numberReducer = NumberReducer(this)
|
||||||
|
/**
|
||||||
|
* The tree builder that handles the conversion of strings into trees.
|
||||||
|
*/
|
||||||
|
val treeBuilder = TreeBuilder(tokenizer, parser)
|
||||||
|
/**
|
||||||
|
* The promotion manager used to convert between number implementations.
|
||||||
|
*/
|
||||||
|
val promotionManager = PromotionManager(this)
|
||||||
|
/**
|
||||||
|
* The database of variable definitions.
|
||||||
|
*/
|
||||||
|
val variableDatabase = VariableDatabase(this)
|
||||||
|
/**
|
||||||
|
* The number implementation used by default.
|
||||||
|
*/
|
||||||
|
val numberImplementation: NumberImplementation
|
||||||
|
get() {
|
||||||
|
val selectedImplementation =
|
||||||
|
pluginManager.numberImplementationFor(configuration.numberImplementation)
|
||||||
|
if (selectedImplementation != null) return selectedImplementation
|
||||||
|
return StandardPlugin.IMPLEMENTATION_NAIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
pluginManager.addListener(tokenizer)
|
||||||
|
pluginManager.addListener(parser)
|
||||||
|
pluginManager.addListener(promotionManager)
|
||||||
|
pluginManager.addListener(variableDatabase)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a string into a tree structure using the main
|
||||||
|
* tree builder.
|
||||||
|
*
|
||||||
|
* @param input the input string to parse
|
||||||
|
* @return the resulting tree, null if the tree builder or the produced tree are null.
|
||||||
|
*/
|
||||||
|
fun parseString(input: String): TreeNode? = treeBuilder.fromString(input)
|
||||||
|
/**
|
||||||
|
* Evaluates the given tree using the main
|
||||||
|
* number reducer.
|
||||||
|
*
|
||||||
|
* @param tree the tree to reduce, must not be null.
|
||||||
|
* @return the resulting number, or null of the reduction failed.
|
||||||
|
*/
|
||||||
|
fun evaluateTree(tree: TreeNode): NumberInterface? = tree.reduce(numberReducer)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package org.nwapw.abacus.config
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class that holds information that tells Abacus how to behave.
|
||||||
|
*
|
||||||
|
* Configuration stores information about how Abacus should behave, for
|
||||||
|
* instance, what number implementation it should use and what
|
||||||
|
* plugins should be ignored during loading.
|
||||||
|
*
|
||||||
|
* @property numberImplementation the number implementation Abacus should use for loading.
|
||||||
|
* @param disabledPlugins the plugins that should be disabled and not loaded by the plugin manager.
|
||||||
|
*/
|
||||||
|
open class Configuration(var numberImplementation: String = "<default>", disabledPlugins: Array<String> = emptyArray()) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The set of disabled plugins that should be ignored by the plugin manager.
|
||||||
|
*/
|
||||||
|
val disabledPlugins = disabledPlugins.toMutableSet()
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.nwapw.abacus.function.applicable
|
package org.nwapw.abacus.function.applicable
|
||||||
|
|
||||||
|
import org.nwapw.abacus.function.DomainException
|
||||||
import org.nwapw.abacus.plugin.NumberImplementation
|
import org.nwapw.abacus.plugin.NumberImplementation
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -25,7 +26,7 @@ interface Applicable<in T : Any, out O : Any> {
|
|||||||
* @param params the parameters to apply to.
|
* @param params the parameters to apply to.
|
||||||
* @return the result of the application.
|
* @return the result of the application.
|
||||||
*/
|
*/
|
||||||
fun applyInternal(implementation: NumberImplementation, params: Array<out T>): O?
|
fun applyInternal(implementation: NumberImplementation, params: Array<out T>): O
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the parameters can be used with this applicable, returns
|
* If the parameters can be used with this applicable, returns
|
||||||
@@ -34,8 +35,8 @@ interface Applicable<in T : Any, out O : Any> {
|
|||||||
* @param params the parameters to apply to.
|
* @param params the parameters to apply to.
|
||||||
* @return the result of the operation, or null if parameters do not match.
|
* @return the result of the operation, or null if parameters do not match.
|
||||||
*/
|
*/
|
||||||
fun apply(implementation: NumberImplementation, vararg params: T): O? {
|
fun apply(implementation: NumberImplementation, vararg params: T): O {
|
||||||
if (!matchesParams(implementation, params)) return null
|
if (!matchesParams(implementation, params)) throw DomainException()
|
||||||
return applyInternal(implementation, params)
|
return applyInternal(implementation, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package org.nwapw.abacus.function.applicable
|
package org.nwapw.abacus.function.applicable
|
||||||
|
|
||||||
|
import org.nwapw.abacus.function.DomainException
|
||||||
import org.nwapw.abacus.plugin.NumberImplementation
|
import org.nwapw.abacus.plugin.NumberImplementation
|
||||||
import org.nwapw.abacus.tree.Reducer
|
import org.nwapw.abacus.tree.Reducer
|
||||||
|
|
||||||
@@ -27,7 +28,7 @@ interface ReducerApplicable<in T : Any, out O : Any, in R : Any> {
|
|||||||
* @param params the arguments to apply to.
|
* @param params the arguments to apply to.
|
||||||
* @return the result of the application.
|
* @return the result of the application.
|
||||||
*/
|
*/
|
||||||
fun applyWithReducerInternal(implementation: NumberImplementation, reducer: Reducer<R>, params: Array<out T>): O?
|
fun applyWithReducerInternal(implementation: NumberImplementation, reducer: Reducer<R>, params: Array<out T>): O
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies this applicable to the given arguments, and reducer,
|
* Applies this applicable to the given arguments, and reducer,
|
||||||
@@ -36,8 +37,8 @@ interface ReducerApplicable<in T : Any, out O : Any, in R : Any> {
|
|||||||
* @param params the arguments to apply to.
|
* @param params the arguments to apply to.
|
||||||
* @return the result of the application, or null if the arguments are incompatible.
|
* @return the result of the application, or null if the arguments are incompatible.
|
||||||
*/
|
*/
|
||||||
fun applyWithReducer(implementation: NumberImplementation, reducer: Reducer<R>, vararg params: T): O? {
|
fun applyWithReducer(implementation: NumberImplementation, reducer: Reducer<R>, vararg params: T): O {
|
||||||
if (!matchesParams(implementation, params)) return null
|
if (!matchesParams(implementation, params)) throw DomainException()
|
||||||
return applyWithReducerInternal(implementation, reducer, params)
|
return applyWithReducerInternal(implementation, reducer, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package org.nwapw.abacus.variables
|
||||||
|
|
||||||
|
import org.nwapw.abacus.Abacus
|
||||||
|
import org.nwapw.abacus.number.NumberInterface
|
||||||
|
import org.nwapw.abacus.plugin.PluginListener
|
||||||
|
import org.nwapw.abacus.plugin.PluginManager
|
||||||
|
import org.nwapw.abacus.tree.TreeNode
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A database for variables and definition.
|
||||||
|
*
|
||||||
|
* The variable database is used to keep track of
|
||||||
|
* variables and definitions throughout the calculator.
|
||||||
|
*
|
||||||
|
* @property abacus the Abacus instance.
|
||||||
|
*/
|
||||||
|
class VariableDatabase(val abacus: Abacus): PluginListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The variables that are stored in the database.
|
||||||
|
*/
|
||||||
|
val variables = mutableMapOf<String, NumberInterface>()
|
||||||
|
/**
|
||||||
|
* The definitions that are stored in the database.
|
||||||
|
*/
|
||||||
|
val definitions = mutableMapOf<String, TreeNode>()
|
||||||
|
|
||||||
|
override fun onLoad(manager: PluginManager?) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnload(manager: PluginManager?) {
|
||||||
|
variables.clear()
|
||||||
|
definitions.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -5,13 +5,14 @@ import org.junit.BeforeClass;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.nwapw.abacus.Abacus;
|
import org.nwapw.abacus.Abacus;
|
||||||
import org.nwapw.abacus.config.Configuration;
|
import org.nwapw.abacus.config.Configuration;
|
||||||
|
import org.nwapw.abacus.function.DomainException;
|
||||||
import org.nwapw.abacus.number.NumberInterface;
|
import org.nwapw.abacus.number.NumberInterface;
|
||||||
import org.nwapw.abacus.plugin.StandardPlugin;
|
import org.nwapw.abacus.plugin.StandardPlugin;
|
||||||
import org.nwapw.abacus.tree.TreeNode;
|
import org.nwapw.abacus.tree.TreeNode;
|
||||||
|
|
||||||
public class CalculationTests {
|
public class CalculationTests {
|
||||||
|
|
||||||
private static Abacus abacus = new Abacus(new Configuration(0, "precise", new String[]{}));
|
private static Abacus abacus = new Abacus(new Configuration( "precise", new String[]{}));
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
public static void prepareTests() {
|
public static void prepareTests() {
|
||||||
@@ -28,11 +29,14 @@ public class CalculationTests {
|
|||||||
Assert.assertTrue(result.toString().startsWith(output));
|
Assert.assertTrue(result.toString().startsWith(output));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void testEvalError(String input, String parseOutput) {
|
private void testDomainException(String input, String parseOutput) {
|
||||||
TreeNode parsedTree = abacus.parseString(input);
|
TreeNode parsedTree = abacus.parseString(input);
|
||||||
Assert.assertNotNull(parsedTree);
|
Assert.assertNotNull(parsedTree);
|
||||||
Assert.assertEquals(parsedTree.toString(), parseOutput);
|
Assert.assertEquals(parsedTree.toString(), parseOutput);
|
||||||
Assert.assertNull(abacus.evaluateTree(parsedTree));
|
try {
|
||||||
|
abacus.evaluateTree(parsedTree);
|
||||||
|
Assert.fail("Function did not throw DomainException.");
|
||||||
|
} catch (DomainException e){ }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -73,7 +77,7 @@ public class CalculationTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testLn() {
|
public void testLn() {
|
||||||
testEvalError("ln(-1)", "ln((1)`)");
|
testDomainException("ln(-1)", "ln((1)`)");
|
||||||
testOutput("ln2", "ln(2)", "0.6931471805599453094172321214581765680755");
|
testOutput("ln2", "ln(2)", "0.6931471805599453094172321214581765680755");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,8 +104,8 @@ public class CalculationTests {
|
|||||||
testOutput("2^-1", "(2^(1)`)", "0.5");
|
testOutput("2^-1", "(2^(1)`)", "0.5");
|
||||||
testOutput("2^50", "(2^50)", "112589990684262");
|
testOutput("2^50", "(2^50)", "112589990684262");
|
||||||
testOutput("7^(-sqrt2*17)", "(7^((sqrt(2)*17))`)", "4.81354609155297814551845300063563");
|
testOutput("7^(-sqrt2*17)", "(7^((sqrt(2)*17))`)", "4.81354609155297814551845300063563");
|
||||||
testEvalError("0^0", "(0^0)");
|
testDomainException("0^0", "(0^0)");
|
||||||
testEvalError("(-13)^.9999", "((13)`^.9999)");
|
testDomainException("(-13)^.9999", "((13)`^.9999)");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public class TokenizerTests {
|
public class TokenizerTests {
|
||||||
|
|
||||||
private static Abacus abacus = new Abacus(new Configuration(0, "precise", new String[]{}));
|
private static Abacus abacus = new Abacus(new Configuration("precise", new String[]{}));
|
||||||
private static LexerTokenizer lexerTokenizer = new LexerTokenizer();
|
private static LexerTokenizer lexerTokenizer = new LexerTokenizer();
|
||||||
private static NumberFunction subtractFunction = new NumberFunction() {
|
private static NumberFunction subtractFunction = new NumberFunction() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
{% include head.html %}
|
{% include head.html %}
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
|
margin: 0px;
|
||||||
margin-top: 50px;
|
margin-top: 50px;
|
||||||
color: white;
|
color: white;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
@@ -37,6 +38,58 @@
|
|||||||
background-color: #06e8a4;
|
background-color: #06e8a4;
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.fullwidth {
|
||||||
|
width: 100%;
|
||||||
|
height: auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.fullwidth img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 450px;
|
||||||
|
margin: auto;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
display: block;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.white {
|
||||||
|
background-color: white;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.green {
|
||||||
|
background-color: #06e8a4;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.fullwidth div.double {
|
||||||
|
height: 100%;
|
||||||
|
text-align: left;
|
||||||
|
width: 50%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 40px;
|
||||||
|
float: left;
|
||||||
|
background-color: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 750px) {
|
||||||
|
div.fullwidth div.double {
|
||||||
|
width: 100%;
|
||||||
|
padding: 15px;
|
||||||
|
}
|
||||||
|
div.fullwidth img {
|
||||||
|
margin-top: 0px;
|
||||||
|
margin-bottom: 0px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
div.fullwidth div.double h1, h2, h3, h4, h5, h6 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
</style>
|
</style>
|
||||||
<body>
|
<body>
|
||||||
<img src="https://raw.githubusercontent.com/DanilaFe/abacus/master/image/logo.png" id="logo">
|
<img src="https://raw.githubusercontent.com/DanilaFe/abacus/master/image/logo.png" id="logo">
|
||||||
@@ -49,5 +102,58 @@
|
|||||||
<a class="button inverted" href="https://github.com/DanilaFe/abacus/wiki">Wiki</a>
|
<a class="button inverted" href="https://github.com/DanilaFe/abacus/wiki">Wiki</a>
|
||||||
</div>
|
</div>
|
||||||
<img src="http://i.imgur.com/Min70QY.png" title="source: imgur.com" id="image_preview"/>
|
<img src="http://i.imgur.com/Min70QY.png" title="source: imgur.com" id="image_preview"/>
|
||||||
|
<h2>Features</h2>
|
||||||
|
<div class="fullwidth white">
|
||||||
|
<div class="double">
|
||||||
|
<img src="https://i.imgur.com/gmGJBBK.png">
|
||||||
|
</div>
|
||||||
|
<div class="double">
|
||||||
|
<h2>Precision</h2>
|
||||||
|
Abacus uses a mathematical tool called Taylor Series to determine values
|
||||||
|
as accurate as the user desires. Of course, this comes with some
|
||||||
|
performance issues with larger numbers. However, Abacus has been
|
||||||
|
tested to generate the value of e correctly to a thousand digits.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="fullwidth green">
|
||||||
|
<div class="double">
|
||||||
|
<h2>Configurable and Customizable</h2>
|
||||||
|
The very first idea for Abacus was inspired by how difficult it was
|
||||||
|
to program a TI-84 calculator. Only two languages were available, TI-BASIC
|
||||||
|
and Assembly, the latter having virtually no documentation. Determined
|
||||||
|
to be better than a TI-84, Abacus implemented a plugin system that allows
|
||||||
|
users to easily create and add plugins written in the same programming
|
||||||
|
language as Abacus itself - Java. These plugins can access the full
|
||||||
|
power of the language, and implement their own ways of handling numbers,
|
||||||
|
as well as their own functions and even operators.<br><br>
|
||||||
|
Besides the ability to add plugins, Abacus also adds some general
|
||||||
|
options that can be used to make the user's experience more pleasant.
|
||||||
|
For instance, it allows for a computation limit to be set in order
|
||||||
|
to prevent excessively long evaluation: 8!!! is, for example, an expression
|
||||||
|
that even Wolfram Alpha doesn't compute accurately, and will never finish
|
||||||
|
on Abacus (it's simply too large). The computation limit will allow Abacus
|
||||||
|
to kill a computation if it takes too long. Support for user-definable
|
||||||
|
precision is also planned.
|
||||||
|
</div>
|
||||||
|
<div class="double">
|
||||||
|
<img src="https://i.imgur.com/JzenWPV.png">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="fullwidth white">
|
||||||
|
<div class="double">
|
||||||
|
<img src="https://i.imgur.com/jY17I3A.png">
|
||||||
|
</div>
|
||||||
|
<div class="double">
|
||||||
|
<h2>Built-in Documentation</h2>
|
||||||
|
Abacus plugins are given a mechanism to register documentation for
|
||||||
|
the functions that they provide. The Abacus GUI displays these
|
||||||
|
functions in a searchable list, allowing the user to read the parameters
|
||||||
|
that have to be supplied to each function, as well as learn about
|
||||||
|
its return value.<br><br>
|
||||||
|
The search finds functions not only by their names, but also by relevant
|
||||||
|
terms mentioned in the function's description, thus allowing related
|
||||||
|
functions to be displayed together.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ $code-color: #efefef;
|
|||||||
$accent-color: #00AFE8;
|
$accent-color: #00AFE8;
|
||||||
$clear-color: white;
|
$clear-color: white;
|
||||||
$title-font: "Open Sans";
|
$title-font: "Open Sans";
|
||||||
$text-font: Helvetica;
|
$text-font: "Raleway";
|
||||||
$code-font: "Source Code Pro";
|
$code-font: "Source Code Pro";
|
||||||
$max-width: 850px;
|
$max-width: 850px;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
|
compile 'com.moandjiezana.toml:toml4j:0.7.1'
|
||||||
compile project(':core')
|
compile project(':core')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.nwapw.abacus.Abacus;
|
|||||||
import org.nwapw.abacus.config.Configuration;
|
import org.nwapw.abacus.config.Configuration;
|
||||||
import org.nwapw.abacus.function.Documentation;
|
import org.nwapw.abacus.function.Documentation;
|
||||||
import org.nwapw.abacus.function.DocumentationType;
|
import org.nwapw.abacus.function.DocumentationType;
|
||||||
|
import org.nwapw.abacus.function.DomainException;
|
||||||
import org.nwapw.abacus.number.*;
|
import org.nwapw.abacus.number.*;
|
||||||
import org.nwapw.abacus.plugin.ClassFinder;
|
import org.nwapw.abacus.plugin.ClassFinder;
|
||||||
import org.nwapw.abacus.plugin.PluginListener;
|
import org.nwapw.abacus.plugin.PluginListener;
|
||||||
@@ -152,6 +153,8 @@ public class AbacusController implements PluginListener {
|
|||||||
return resultingString;
|
return resultingString;
|
||||||
} catch (ComputationInterruptedException exception) {
|
} catch (ComputationInterruptedException exception) {
|
||||||
return ERR_STOP;
|
return ERR_STOP;
|
||||||
|
} catch (DomainException exception) {
|
||||||
|
return exception.getMessage();
|
||||||
} catch (RuntimeException exception) {
|
} catch (RuntimeException exception) {
|
||||||
exception.printStackTrace();
|
exception.printStackTrace();
|
||||||
return ERR_EXCEPTION;
|
return ERR_EXCEPTION;
|
||||||
@@ -194,7 +197,7 @@ public class AbacusController implements PluginListener {
|
|||||||
*/
|
*/
|
||||||
private final Runnable TIMER_RUNNABLE = () -> {
|
private final Runnable TIMER_RUNNABLE = () -> {
|
||||||
try {
|
try {
|
||||||
Configuration abacusConfig = abacus.getConfiguration();
|
ExtendedConfiguration abacusConfig = (ExtendedConfiguration) abacus.getConfiguration();
|
||||||
if (abacusConfig.getComputationDelay() == 0) return;
|
if (abacusConfig.getComputationDelay() == 0) return;
|
||||||
Thread.sleep((long) (abacusConfig.getComputationDelay() * 1000));
|
Thread.sleep((long) (abacusConfig.getComputationDelay() * 1000));
|
||||||
performStop();
|
performStop();
|
||||||
@@ -254,12 +257,12 @@ public class AbacusController implements PluginListener {
|
|||||||
if (oldValue.equals(settingsTab)) alertIfApplyNeeded(true);
|
if (oldValue.equals(settingsTab)) alertIfApplyNeeded(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
abacus = new Abacus(new Configuration(CONFIG_FILE));
|
abacus = new Abacus(new ExtendedConfiguration(CONFIG_FILE));
|
||||||
PluginManager abacusPluginManager = abacus.getPluginManager();
|
PluginManager abacusPluginManager = abacus.getPluginManager();
|
||||||
abacusPluginManager.addListener(this);
|
abacusPluginManager.addListener(this);
|
||||||
performScan();
|
performScan();
|
||||||
|
|
||||||
computationLimitField.setText(Double.toString(abacus.getConfiguration().getComputationDelay()));
|
computationLimitField.setText(Double.toString(((ExtendedConfiguration) abacus.getConfiguration()).getComputationDelay()));
|
||||||
computationLimitField.textProperty().addListener((observable, oldValue, newValue) -> {
|
computationLimitField.textProperty().addListener((observable, oldValue, newValue) -> {
|
||||||
if (!newValue.matches("(\\d+(\\.\\d*)?)?")) {
|
if (!newValue.matches("(\\d+(\\.\\d*)?)?")) {
|
||||||
computationLimitField.setText(oldValue);
|
computationLimitField.setText(oldValue);
|
||||||
@@ -336,8 +339,8 @@ public class AbacusController implements PluginListener {
|
|||||||
if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName());
|
if (!pluginEntry.isEnabled()) disabledPlugins.add(pluginEntry.getClassName());
|
||||||
}
|
}
|
||||||
if (computationLimitField.getText().matches("\\d*(\\.\\d+)?") && computationLimitField.getText().length() != 0)
|
if (computationLimitField.getText().matches("\\d*(\\.\\d+)?") && computationLimitField.getText().length() != 0)
|
||||||
configuration.setComputationDelay(Double.parseDouble(computationLimitField.getText()));
|
((ExtendedConfiguration) configuration).setComputationDelay(Double.parseDouble(computationLimitField.getText()));
|
||||||
configuration.saveTo(CONFIG_FILE);
|
((ExtendedConfiguration) configuration).saveTo(CONFIG_FILE);
|
||||||
changesMade = false;
|
changesMade = false;
|
||||||
reloadAlertShown = false;
|
reloadAlertShown = false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package org.nwapw.abacus.fx
|
||||||
|
|
||||||
|
import com.moandjiezana.toml.Toml
|
||||||
|
import com.moandjiezana.toml.TomlWriter
|
||||||
|
import org.nwapw.abacus.config.Configuration
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Additional settings for user interface.
|
||||||
|
*
|
||||||
|
* ExtendedConfiguration is used to add other settings
|
||||||
|
* that aren't built into Abacus core, but are necessary
|
||||||
|
* for the fx module.
|
||||||
|
*
|
||||||
|
* @property computationDelay the delay before which the computation stops.
|
||||||
|
* @param implementation the number implementation, same as [Configuration.numberImplementation]
|
||||||
|
* @param disabledPlugins the list of plugins that should be disabled, same as [Configuration.disabledPlugins]
|
||||||
|
*/
|
||||||
|
class ExtendedConfiguration(var computationDelay: Double = 0.0,
|
||||||
|
implementation: String = "<default>",
|
||||||
|
disabledPlugins: Array<String> = emptyArray())
|
||||||
|
: Configuration(implementation, disabledPlugins) {
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
/**
|
||||||
|
* The default TOML.
|
||||||
|
*/
|
||||||
|
val DEFAULT_TOML_STRING = """
|
||||||
|
computationDelay=0.0
|
||||||
|
implementation="naive"
|
||||||
|
disabledPlugins=[]
|
||||||
|
"""
|
||||||
|
/**
|
||||||
|
* A reader with the default TOML data.
|
||||||
|
*/
|
||||||
|
val DEFAULT_TOML_READER = Toml().read(DEFAULT_TOML_STRING)
|
||||||
|
/**
|
||||||
|
* A writer used to writing the configuration to disk.
|
||||||
|
*/
|
||||||
|
val DEFAULT_TOML_WRITER = TomlWriter()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new configuration from a file on disk.
|
||||||
|
* @param tomlFile the file from disk to load.
|
||||||
|
*/
|
||||||
|
constructor(tomlFile: File) : this() {
|
||||||
|
copyFrom(Toml(DEFAULT_TOML_READER).read(tomlFile).to(ExtendedConfiguration::class.java))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copies data from another configuration into this one.
|
||||||
|
* @param config the configuration to copy from.
|
||||||
|
*/
|
||||||
|
fun copyFrom(config: ExtendedConfiguration) {
|
||||||
|
computationDelay = config.computationDelay
|
||||||
|
numberImplementation = config.numberImplementation
|
||||||
|
disabledPlugins.clear()
|
||||||
|
disabledPlugins.addAll(config.disabledPlugins)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Saves this configuration to a file.
|
||||||
|
* @param file the file to save to.
|
||||||
|
*/
|
||||||
|
fun saveTo(file: File) {
|
||||||
|
DEFAULT_TOML_WRITER.write(this, file)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user