From daffdb6b42cd353ebb45a431ca60fe396461956c Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 1 Sep 2017 23:52:05 -0700 Subject: [PATCH 1/5] Move Abacus core into Kotlin. --- .../main/java/org/nwapw/abacus/Abacus.java | 150 ------------------ .../main/kotlin/org/nwapw/abacus/Abacus.kt | 85 ++++++++++ 2 files changed, 85 insertions(+), 150 deletions(-) delete mode 100644 core/src/main/java/org/nwapw/abacus/Abacus.java create mode 100644 core/src/main/kotlin/org/nwapw/abacus/Abacus.kt diff --git a/core/src/main/java/org/nwapw/abacus/Abacus.java b/core/src/main/java/org/nwapw/abacus/Abacus.java deleted file mode 100644 index 1b1dc49..0000000 --- a/core/src/main/java/org/nwapw/abacus/Abacus.java +++ /dev/null @@ -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; - } - -} diff --git a/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt b/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt new file mode 100644 index 0000000..99214a7 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt @@ -0,0 +1,85 @@ +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 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) + } + + /** + * 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) + +} \ No newline at end of file From 146f3994ef3c743a4274a6a18cfde5b28e5d9505 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 1 Sep 2017 23:52:11 -0700 Subject: [PATCH 2/5] Add the variable database. --- .../main/kotlin/org/nwapw/abacus/Abacus.kt | 5 ++ .../abacus/variables/VariableDatabase.kt | 79 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt diff --git a/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt b/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt index 99214a7..23e6f8e 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt @@ -48,6 +48,10 @@ class Abacus(val configuration: Configuration) { * 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. */ @@ -63,6 +67,7 @@ class Abacus(val configuration: Configuration) { pluginManager.addListener(tokenizer) pluginManager.addListener(parser) pluginManager.addListener(promotionManager) + pluginManager.addListener(variableDatabase) } /** diff --git a/core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt b/core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt new file mode 100644 index 0000000..ab477e2 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt @@ -0,0 +1,79 @@ +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 javax.swing.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. + */ + private val variables = mutableMapOf() + /** + * The definitions that are stored in the database. + */ + private val definitions = mutableMapOf() + + /** + * Stores a variable in the database. + * + * @param name the name of the variable. + * @param value the new value of the variable. + */ + fun storeVariable(name: String, value: NumberInterface) { + variables[name] = value + } + + /** + * Stores a definition in the database + * + * @param name the name of the definition. + * @param value the new value of the definition. + */ + fun storeDefinition(name: String, value: TreeNode) { + definitions[name] = value + } + + /** + * Gets the value of the variable, or 0 if + * it is not defined. + * + * @param name the name of the variable. + * @return the value of the variable. + */ + fun getVariableValue(name: String): NumberInterface { + return variables[name] ?: + abacus.numberImplementation.instanceForString("0") + } + + /** + * Gets the definition. + * + * @param name the name of the definition. + * @return the value of the definition, or null if one doesn't exist. + */ + fun getDefinition(name: String): TreeNode? { + return definitions[name] + } + + override fun onLoad(manager: PluginManager?) { + + } + + override fun onUnload(manager: PluginManager?) { + variables.clear() + definitions.clear() + } + +} \ No newline at end of file From 428df8bfd3929d4eb0a9997a7634350d47df299b Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 1 Sep 2017 23:55:50 -0700 Subject: [PATCH 3/5] Use the variable database for the number reducer. --- core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java index 5d497ec..5ca1ee2 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -35,7 +35,7 @@ public class NumberReducer implements Reducer { if (node instanceof NumberNode) { return abacus.getNumberImplementation().instanceForString(((NumberNode) node).getNumber()); } else if (node instanceof VariableNode) { - return abacus.getNumberImplementation().instanceForString("0"); + return abacus.getVariableDatabase().getVariableValue(((VariableNode) node).getVariable()); } else if (node instanceof NumberBinaryNode) { NumberInterface left = (NumberInterface) children[0]; NumberInterface right = (NumberInterface) children[1]; From 28802cfed3621b3e6667d5c4fc159013d8e46531 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 2 Sep 2017 00:19:44 -0700 Subject: [PATCH 4/5] Remove the additional methods from the VariableDatabase. --- .../org/nwapw/abacus/tree/NumberReducer.java | 9 +++- .../abacus/variables/VariableDatabase.kt | 48 ++----------------- 2 files changed, 11 insertions(+), 46 deletions(-) diff --git a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java index 5ca1ee2..fcea885 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -8,6 +8,7 @@ import org.nwapw.abacus.function.TreeValueOperator; import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.PromotionManager; import org.nwapw.abacus.number.PromotionResult; +import org.nwapw.abacus.variables.VariableDatabase; /** * A reducer implementation that turns a tree into a single number. @@ -35,7 +36,13 @@ public class NumberReducer implements Reducer { if (node instanceof NumberNode) { return abacus.getNumberImplementation().instanceForString(((NumberNode) node).getNumber()); } else if (node instanceof VariableNode) { - return abacus.getVariableDatabase().getVariableValue(((VariableNode) node).getVariable()); + 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"); } else if (node instanceof NumberBinaryNode) { NumberInterface left = (NumberInterface) children[0]; NumberInterface right = (NumberInterface) children[1]; diff --git a/core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt b/core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt index ab477e2..405f26a 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/variables/VariableDatabase.kt @@ -4,7 +4,7 @@ import org.nwapw.abacus.Abacus import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.plugin.PluginListener import org.nwapw.abacus.plugin.PluginManager -import javax.swing.tree.TreeNode +import org.nwapw.abacus.tree.TreeNode /** * A database for variables and definition. @@ -19,53 +19,11 @@ class VariableDatabase(val abacus: Abacus): PluginListener { /** * The variables that are stored in the database. */ - private val variables = mutableMapOf() + val variables = mutableMapOf() /** * The definitions that are stored in the database. */ - private val definitions = mutableMapOf() - - /** - * Stores a variable in the database. - * - * @param name the name of the variable. - * @param value the new value of the variable. - */ - fun storeVariable(name: String, value: NumberInterface) { - variables[name] = value - } - - /** - * Stores a definition in the database - * - * @param name the name of the definition. - * @param value the new value of the definition. - */ - fun storeDefinition(name: String, value: TreeNode) { - definitions[name] = value - } - - /** - * Gets the value of the variable, or 0 if - * it is not defined. - * - * @param name the name of the variable. - * @return the value of the variable. - */ - fun getVariableValue(name: String): NumberInterface { - return variables[name] ?: - abacus.numberImplementation.instanceForString("0") - } - - /** - * Gets the definition. - * - * @param name the name of the definition. - * @return the value of the definition, or null if one doesn't exist. - */ - fun getDefinition(name: String): TreeNode? { - return definitions[name] - } + val definitions = mutableMapOf() override fun onLoad(manager: PluginManager?) { From 585cabc478288fc0a299a3d3bae33d904ca1d6c5 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 2 Sep 2017 00:20:18 -0700 Subject: [PATCH 5/5] Add the ability for plugins to access variables, and add the operators. --- .../java/org/nwapw/abacus/plugin/Plugin.java | 9 ++++ .../nwapw/abacus/plugin/PluginManager.java | 9 ++++ .../nwapw/abacus/plugin/StandardPlugin.java | 42 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java b/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java index 223d7aa..ecec78a 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -2,6 +2,7 @@ package org.nwapw.abacus.plugin; import org.nwapw.abacus.function.*; import org.nwapw.abacus.number.NumberInterface; +import org.nwapw.abacus.variables.VariableDatabase; /** * A plugin class that can be externally implemented and loaded via the @@ -219,4 +220,12 @@ public abstract class Plugin { */ public abstract void onDisable(); + /** + * Get the variable database. + * @return the variable database. + */ + public final VariableDatabase getVariableDatabase(){ + return manager.getVariableDatabase(); + } + } diff --git a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java index 0c99c58..9f7e0ab 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -3,6 +3,7 @@ package org.nwapw.abacus.plugin; import org.nwapw.abacus.Abacus; import org.nwapw.abacus.function.*; import org.nwapw.abacus.number.NumberInterface; +import org.nwapw.abacus.variables.VariableDatabase; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; @@ -421,4 +422,12 @@ public class PluginManager { public Set> getLoadedPluginClasses() { return loadedPluginClasses; } + + /** + * Gets the variable database. + * @return the database. + */ + public VariableDatabase getVariableDatabase(){ + return abacus.getVariableDatabase(); + } } diff --git a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java index 36ac473..b4f919a 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -1,9 +1,14 @@ package org.nwapw.abacus.plugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.nwapw.abacus.function.*; import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; 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.HashMap; @@ -14,6 +19,40 @@ import java.util.HashMap; */ 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 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 reducer, TreeNode[] params) { + String assignTo = ((VariableNode) params[0]).getVariable(); + getVariableDatabase().getDefinitions().put(assignTo, params[1]); + return params[1].reduce(reducer); + } + }; /** * The addition operator, + */ @@ -712,6 +751,9 @@ public class StandardPlugin extends Plugin { registerOperator("^", OP_CARET); registerOperator("!", OP_FACTORIAL); + registerTreeValueOperator("=", opSet); + registerTreeValueOperator(":=", opDefine); + registerOperator("nPr", OP_NPR); registerOperator("nCr", OP_NCR);