mirror of
https://github.com/DanilaFe/abacus
synced 2026-01-26 00:25:20 +00:00
Compare commits
12 Commits
promotion-
...
no-null
| Author | SHA1 | Date | |
|---|---|---|---|
| 6604af5b0f | |||
| d49a763e8f | |||
| 48a4d8adc2 | |||
| 5417b45106 | |||
| 585cabc478 | |||
| 28802cfed3 | |||
| 428df8bfd3 | |||
| 146f3994ef | |||
| daffdb6b42 | |||
| 178f59ef7b | |||
| 61616a428a | |||
| 9c77fa8aeb |
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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)
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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,6 +5,7 @@ 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;
|
||||||
@@ -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)");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
Reference in New Issue
Block a user