From 01f80bbb531bca743c0308c8ad469105ca627f4b Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 00:43:36 -0700 Subject: [PATCH 01/29] Abstract some of the Function functionality further. --- .../org/nwapw/abacus/function/Applicable.java | 38 +++++++++++++++++++ .../org/nwapw/abacus/function/Function.java | 30 +-------------- 2 files changed, 39 insertions(+), 29 deletions(-) create mode 100644 core/src/main/java/org/nwapw/abacus/function/Applicable.java diff --git a/core/src/main/java/org/nwapw/abacus/function/Applicable.java b/core/src/main/java/org/nwapw/abacus/function/Applicable.java new file mode 100644 index 0000000..ced0608 --- /dev/null +++ b/core/src/main/java/org/nwapw/abacus/function/Applicable.java @@ -0,0 +1,38 @@ +package org.nwapw.abacus.function; + +/** + * A class that represents something that can be applied to one or more + * arguments of the same type, and returns a single value from that application. + * @param the type of the parameters passed to this applicable. + * @param the return type of the applicable. + */ +public abstract class Applicable { + + /** + * Checks if the given applicable can be used with the given parameters. + * @param params the parameter array to verify for compatibility. + * @return whether the array can be used with applyInternal. + */ + protected abstract boolean matchesParams(T[] params); + + /** + * Applies the applicable object to the given parameters, + * without checking for compatibility. + * @param params the parameters to apply to. + * @return the result of the application. + */ + protected abstract O applyInternal(T[] params); + + /** + * If the parameters can be used with this applicable, returns + * the result of the application of the applicable to the parameters. + * Otherwise, returns null. + * @param params the parameters to apply to. + * @return the result of the operation, or null if parameters do not match. + */ + public O apply(T... params){ + if(!matchesParams(params)) return null; + return applyInternal(params); + } + +} diff --git a/core/src/main/java/org/nwapw/abacus/function/Function.java b/core/src/main/java/org/nwapw/abacus/function/Function.java index bd5af72..9ee9509 100755 --- a/core/src/main/java/org/nwapw/abacus/function/Function.java +++ b/core/src/main/java/org/nwapw/abacus/function/Function.java @@ -6,34 +6,6 @@ import org.nwapw.abacus.number.NumberInterface; * A function that operates on one or more * inputs and returns a single number. */ -public abstract class Function { - - /** - * Checks whether the given params will work for the given function. - * - * @param params the given params - * @return true if the params can be used with this function. - */ - protected abstract boolean matchesParams(NumberInterface[] params); - - /** - * Internal apply implementation, which already receives appropriately promoted - * parameters that have bee run through matchesParams - * - * @param params the promoted parameters. - * @return the return value of the function. - */ - protected abstract NumberInterface applyInternal(NumberInterface[] params); - - /** - * Function to check, promote arguments and run the function. - * - * @param params the raw input parameters. - * @return the return value of the function, or null if an error occurred. - */ - public NumberInterface apply(NumberInterface... params) { - if (!matchesParams(params)) return null; - return applyInternal(params); - } +public abstract class Function extends Applicable { } From 00462281fe43e8a6c76be3ac4aae4ff6face270d Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 00:49:16 -0700 Subject: [PATCH 02/29] Add a function that operates on trees. --- .../org/nwapw/abacus/function/TreeValueFunction.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java diff --git a/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java b/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java new file mode 100644 index 0000000..cd802c4 --- /dev/null +++ b/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java @@ -0,0 +1,12 @@ +package org.nwapw.abacus.function; + +import org.nwapw.abacus.number.NumberInterface; +import org.nwapw.abacus.tree.TreeNode; + +/** + * A function that operates on parse tree nodes instead of on already simplified numbers. + * Despite this, it returns a number, not a tree. + */ +public abstract class TreeValueFunction extends Applicable { + +} From 40c80db914b98712cb85ffee228821933bfc5c91 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 00:59:39 -0700 Subject: [PATCH 03/29] Add tree value functions to plugins. --- .../java/org/nwapw/abacus/plugin/Plugin.java | 28 +++++++++++-- .../nwapw/abacus/plugin/PluginManager.java | 39 +++++++++++++++++-- 2 files changed, 59 insertions(+), 8 deletions(-) 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 4907131..4b71d56 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -1,9 +1,6 @@ package org.nwapw.abacus.plugin; -import org.nwapw.abacus.function.Documentation; -import org.nwapw.abacus.function.DocumentationType; -import org.nwapw.abacus.function.Function; -import org.nwapw.abacus.function.Operator; +import org.nwapw.abacus.function.*; import org.nwapw.abacus.number.NumberInterface; /** @@ -69,6 +66,17 @@ public abstract class Plugin { manager.registerFunction(name, toRegister); } + /** + * To be used in load(). Registers a tree value function abstract class + * with the plugin internally, which makes it accessible to the plugin manager. + * + * @param name the name to register by. + * @param toRegister the tree value function implementation. + */ + protected final void registerTreeValueFunction(String name, TreeValueFunction toRegister) { + manager.registerTreeValueFunction(name, toRegister); + } + /** * To be used in load(). Registers an operator abstract class * with the plugin internally, which makes it accessible to @@ -114,6 +122,18 @@ public abstract class Plugin { return manager.functionFor(name); } + /** + * Searches the PluginManager for the given function name. + * This can be used by the plugins internally in order to call functions + * they do not provide. + * + * @param name the name for which to search. + * @return the resulting tree value function, or null if none was found for that name. + */ + protected final TreeValueFunction treeValueFunctionFor(String name){ + return manager.treeValueFunctionFor(name); + } + /** * Searches the PluginManager for the given operator name. * This can be used by the plugins internally in order to call 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 b808411..b69e0db 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -1,10 +1,7 @@ package org.nwapw.abacus.plugin; import org.nwapw.abacus.Abacus; -import org.nwapw.abacus.function.Documentation; -import org.nwapw.abacus.function.DocumentationType; -import org.nwapw.abacus.function.Function; -import org.nwapw.abacus.function.Operator; +import org.nwapw.abacus.function.*; import org.nwapw.abacus.number.NumberInterface; import java.lang.reflect.InvocationTargetException; @@ -31,6 +28,10 @@ public class PluginManager { * The map of functions registered by the plugins. */ private Map registeredFunctions; + /** + * The map of tree value functions regstered by the plugins. + */ + private Map registeredTreeValueFunctions; /** * The map of operators registered by the plugins */ @@ -72,6 +73,7 @@ public class PluginManager { loadedPluginClasses = new HashSet<>(); plugins = new HashSet<>(); registeredFunctions = new HashMap<>(); + registeredTreeValueFunctions = new HashMap<>(); registeredOperators = new HashMap<>(); registeredNumberImplementations = new HashMap<>(); registeredDocumentation = new HashSet<>(); @@ -90,6 +92,16 @@ public class PluginManager { registeredFunctions.put(name, function); } + /** + * Registers a tree value function under the given name. + * + * @param name the name of the function. + * @param function the function to register. + */ + public void registerTreeValueFunction(String name, TreeValueFunction function) { + registeredTreeValueFunctions.put(name, function); + } + /** * Registers an operator under the given name. * @@ -130,6 +142,16 @@ public class PluginManager { return registeredFunctions.get(name); } + /** + * Gets the tree value function registered under the given name. + * + * @param name the name of the function. + * @return the function, or null if it was not found. + */ + public TreeValueFunction treeValueFunctionFor(String name){ + return registeredTreeValueFunctions.get(name); + } + /** * Gets the operator registered under the given name. * @@ -302,6 +324,15 @@ public class PluginManager { return registeredFunctions.keySet(); } + /** + * Gets all the tree vlaue functions loaded by the PluginManager. + * + * @return the set of all the tree value functions that were loaded. + */ + public Set getAllTreeValueFunctions() { + return registeredTreeValueFunctions.keySet(); + } + /** * Gets all the operators loaded by the Plugin Manager. * From ac19c7b23091ad064d0347d338e5600a379432d5 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 01:03:12 -0700 Subject: [PATCH 04/29] Change lexer tokenizer to recognize tree value functions. --- .../main/java/org/nwapw/abacus/parsing/LexerTokenizer.java | 6 ++++++ core/src/main/java/org/nwapw/abacus/tree/TokenType.java | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java b/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java index b7bdd1f..14ecf95 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java @@ -53,6 +53,9 @@ public class LexerTokenizer implements Tokenizer>, PluginListen for (String function : manager.getAllFunctions()) { lexer.register(Pattern.sanitize(function), TokenType.FUNCTION); } + for (String function : manager.getAllTreeValueFunctions()){ + lexer.register(Pattern.sanitize(function), TokenType.TREE_VALUE_FUNCTION); + } } @Override @@ -63,6 +66,9 @@ public class LexerTokenizer implements Tokenizer>, PluginListen for (String function : manager.getAllFunctions()) { lexer.unregister(Pattern.sanitize(function), TokenType.FUNCTION); } + for (String function : manager.getAllTreeValueFunctions()){ + lexer.unregister(Pattern.sanitize(function), TokenType.TREE_VALUE_FUNCTION); + } } } diff --git a/core/src/main/java/org/nwapw/abacus/tree/TokenType.java b/core/src/main/java/org/nwapw/abacus/tree/TokenType.java index aa1957a..857e9b4 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/TokenType.java +++ b/core/src/main/java/org/nwapw/abacus/tree/TokenType.java @@ -7,7 +7,7 @@ package org.nwapw.abacus.tree; public enum TokenType { INTERNAL_FUNCTION_END(-1), - ANY(0), WHITESPACE(1), COMMA(2), OP(3), NUM(4), VARIABLE(5), FUNCTION(6), OPEN_PARENTH(7), CLOSE_PARENTH(8); + ANY(0), WHITESPACE(1), COMMA(2), OP(3), NUM(4), VARIABLE(5), FUNCTION(6), TREE_VALUE_FUNCTION(6), OPEN_PARENTH(7), CLOSE_PARENTH(8); /** * The priority by which this token gets sorted. From c5cd0f81adda127fcf06995ebcac98c104254f6e Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 01:07:59 -0700 Subject: [PATCH 05/29] Remove data modifier from tree classes. --- core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt | 2 +- core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt | 2 +- core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt | 2 +- core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt | 2 +- core/src/main/kotlin/org/nwapw/abacus/tree/VariableNode.kt | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt index 7505f82..01efa8d 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt @@ -11,7 +11,7 @@ package org.nwapw.abacus.tree * @param left the left node. * @param right the right node. */ -data class BinaryNode(val operation: String, val left: TreeNode? = null, val right: TreeNode?) : TreeNode() { +class BinaryNode(val operation: String, val left: TreeNode? = null, val right: TreeNode?) : TreeNode() { override fun reduce(reducer: Reducer): T? { val leftReduce = left?.reduce(reducer) ?: return null diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt index 64c1298..dcc8b09 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt @@ -8,7 +8,7 @@ package org.nwapw.abacus.tree * * @param function the function string. */ -data class FunctionNode(val function: String) : TreeNode() { +class FunctionNode(val function: String) : TreeNode() { /** * List of function parameters added to this node. diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt index de6597a..624a50a 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt @@ -10,7 +10,7 @@ import org.nwapw.abacus.number.NumberInterface * * @number the number value of this node. */ -data class NumberNode(val number: String) : TreeNode() { +class NumberNode(val number: String) : TreeNode() { override fun reduce(reducer: Reducer): T? { return reducer.reduceNode(this) diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt index 65853ba..c2375b2 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt @@ -9,7 +9,7 @@ package org.nwapw.abacus.tree * @param operation the operation applied to the given node. * @param applyTo the node to which the operation will be applied. */ -data class UnaryNode(val operation: String, val applyTo: TreeNode? = null) : TreeNode() { +class UnaryNode(val operation: String, val applyTo: TreeNode? = null) : TreeNode() { override fun reduce(reducer: Reducer): T? { val reducedChild = applyTo?.reduce(reducer) ?: return null diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/VariableNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/VariableNode.kt index 0bf05c6..93d91dc 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/VariableNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/VariableNode.kt @@ -8,7 +8,7 @@ package org.nwapw.abacus.tree * * @param variable the actual variable name that this node represents. */ -data class VariableNode(val variable: String) : TreeNode() { +class VariableNode(val variable: String) : TreeNode() { override fun reduce(reducer: Reducer): T? { return reducer.reduceNode(this) From bc26ad0b8826330968908d5f789ea3e52af1854b Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 01:17:52 -0700 Subject: [PATCH 06/29] Abstract the call functionality, and add TreeValueFunctionNode. --- .../abacus/parsing/ShuntingYardParser.java | 2 +- .../org/nwapw/abacus/tree/NumberReducer.java | 2 +- .../kotlin/org/nwapw/abacus/tree/CallNode.kt | 29 +++++++++++++++ .../org/nwapw/abacus/tree/FunctionNode.kt | 36 +------------------ .../abacus/tree/TreeValueFunctionNode.kt | 16 +++++++++ 5 files changed, 48 insertions(+), 37 deletions(-) create mode 100644 core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt create mode 100644 core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueFunctionNode.kt diff --git a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java index c792463..c1a35a5 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java @@ -144,7 +144,7 @@ public class ShuntingYardParser implements Parser>, PluginListe while (!matches.isEmpty() && matches.get(0).getType() != TokenType.INTERNAL_FUNCTION_END) { TreeNode argument = constructRecursive(matches); if (argument == null) return null; - node.prependChild(argument); + node.getChildren().add(0, argument); } if (matches.isEmpty()) return null; matches.remove(0); 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 4dae775..a252896 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -46,7 +46,7 @@ public class NumberReducer implements Reducer { for (int i = 0; i < convertedChildren.length; i++) { convertedChildren[i] = (NumberInterface) children[i]; } - Function function = abacus.getPluginManager().functionFor(((FunctionNode) node).getFunction()); + Function function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo()); if (function == null) return null; return function.apply(convertedChildren); } diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt new file mode 100644 index 0000000..5c059ae --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt @@ -0,0 +1,29 @@ +package org.nwapw.abacus.tree + +/** + * Represents a more generic function call. + * + * This class does not specify how it should be reduced, allowing other classes + * to extend this functionality. + * + * @param callTo the name of the things being called. + */ +abstract class CallNode(val callTo: String) : TreeNode() { + + /** + * The list of children this node has. + */ + val children: MutableList = mutableListOf() + + override fun toString(): String { + val buffer = StringBuffer() + buffer.append(callTo) + buffer.append("(") + for(i in 0 until children.size){ + buffer.append(children[i].toString()) + buffer.append(if(i != children.size - 1) ", " else ")") + } + return buffer.toString() + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt index dcc8b09..813ad52 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/FunctionNode.kt @@ -8,45 +8,11 @@ package org.nwapw.abacus.tree * * @param function the function string. */ -class FunctionNode(val function: String) : TreeNode() { - - /** - * List of function parameters added to this node. - */ - val children: MutableList = mutableListOf() +class FunctionNode(function: String) : CallNode(function) { override fun reduce(reducer: Reducer): T? { val children = Array(children.size, { children[it].reduce(reducer) ?: return null; }) return reducer.reduceNode(this, *children) } - override fun toString(): String { - val buffer = StringBuffer() - buffer.append(function) - buffer.append('(') - for (i in 0 until children.size) { - buffer.append(children[i].toString()) - buffer.append(if (i == children.size - 1) ")" else ",") - } - return buffer.toString() - } - - /** - * Appends a child to this node's list of children. - * - * @node the node to append. - */ - fun appendChild(node: TreeNode) { - children.add(node) - } - - /** - * Prepends a child to this node's list of children. - * - * @node the node to prepend. - */ - fun prependChild(node: TreeNode) { - children.add(0, node) - } - } \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueFunctionNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueFunctionNode.kt new file mode 100644 index 0000000..68c358e --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueFunctionNode.kt @@ -0,0 +1,16 @@ +package org.nwapw.abacus.tree + +/** + * A tree node that represents a tree value function call. + * + * This is in many ways similar to a simple FunctionNode, and the distinction + * is mostly to help the reducer. Besides that, this class also does not + * even attempt to reduce its children. + */ +class TreeValueFunctionNode(name: String) : CallNode(name) { + + override fun reduce(reducer: Reducer): T? { + return reducer.reduceNode(this) + } + +} From 6b9252f9020bf5075938e1fde52c96a29a814a09 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 01:21:28 -0700 Subject: [PATCH 07/29] Add parsing of TreeValueFunctions. --- .../abacus/parsing/ShuntingYardParser.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java index c1a35a5..95bc4b2 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java @@ -55,7 +55,7 @@ public class ShuntingYardParser implements Parser>, PluginListe matchType = match.getType(); if (matchType == TokenType.NUM || matchType == TokenType.VARIABLE) { output.add(match); - } else if (matchType == TokenType.FUNCTION) { + } else if (matchType == TokenType.FUNCTION || matchType == TokenType.TREE_VALUE_FUNCTION) { output.add(new Match<>("", TokenType.INTERNAL_FUNCTION_END)); tokenStack.push(match); } else if (matchType == TokenType.OP) { @@ -78,7 +78,8 @@ public class ShuntingYardParser implements Parser>, PluginListe while (!tokenStack.empty() && type == OperatorType.BINARY_INFIX) { Match otherMatch = tokenStack.peek(); TokenType otherMatchType = otherMatch.getType(); - if (!(otherMatchType == TokenType.OP || otherMatchType == TokenType.FUNCTION)) break; + if (!(otherMatchType == TokenType.OP || otherMatchType == TokenType.FUNCTION || + otherMatchType == TokenType.TREE_VALUE_FUNCTION)) break; if (otherMatchType == TokenType.OP) { int otherPrecedence = precedenceMap.get(otherMatch.getContent()); @@ -105,7 +106,8 @@ public class ShuntingYardParser implements Parser>, PluginListe while (!tokenStack.empty()) { Match match = tokenStack.peek(); TokenType newMatchType = match.getType(); - if (!(newMatchType == TokenType.OP || newMatchType == TokenType.FUNCTION)) return null; + if (!(newMatchType == TokenType.OP || newMatchType == TokenType.FUNCTION || + newMatchType == TokenType.TREE_VALUE_FUNCTION)) return null; output.add(tokenStack.pop()); } return output; @@ -138,9 +140,14 @@ public class ShuntingYardParser implements Parser>, PluginListe return new NumberNode(match.getContent()); } else if (matchType == TokenType.VARIABLE) { return new VariableNode(match.getContent()); - } else if (matchType == TokenType.FUNCTION) { + } else if (matchType == TokenType.FUNCTION || matchType == TokenType.TREE_VALUE_FUNCTION) { String functionName = match.getContent(); - FunctionNode node = new FunctionNode(functionName); + CallNode node; + if(matchType == TokenType.FUNCTION){ + node = new FunctionNode(functionName); + } else { + node = new TreeValueFunctionNode(functionName); + } while (!matches.isEmpty() && matches.get(0).getType() != TokenType.INTERNAL_FUNCTION_END) { TreeNode argument = constructRecursive(matches); if (argument == null) return null; From 26305c3baef925467c1ebe7af996fc551a7c24b8 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 01:41:32 -0700 Subject: [PATCH 08/29] Add the withReducer variants of the Applier functions. --- .../abacus/function/TreeValueFunction.java | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java b/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java index cd802c4..a34cecc 100644 --- a/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java +++ b/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java @@ -1,6 +1,7 @@ package org.nwapw.abacus.function; import org.nwapw.abacus.number.NumberInterface; +import org.nwapw.abacus.tree.Reducer; import org.nwapw.abacus.tree.TreeNode; /** @@ -9,4 +10,34 @@ import org.nwapw.abacus.tree.TreeNode; */ public abstract class TreeValueFunction extends Applicable { + @Override + protected NumberInterface applyInternal(TreeNode[] params) { + return null; + } + + @Override + public NumberInterface apply(TreeNode... params) { + return null; + } + + /** + * Applies the tree value functions to the given tree nodes, + * using the given reducer. + * @param reducer the reducer to use. + * @param params the parameters to apply to. + * @return the result of the application. + */ + public abstract NumberInterface applyWithReducerInternal(Reducer reducer, TreeNode[] params); + + /** + * Checks if the given parameters and reducer can be used + * with this function, and if so, calls the function on them. + * @param reducer the reducer to use. + * @param params the parameters to apply to. + * @return the result of the application, or null if the parameters are incompatible. + */ + public NumberInterface applyWithReducer(Reducer reducer, TreeNode... params) { + if(!matchesParams(params) || reducer == null) return null; + return applyWithReducerInternal(reducer, params); + } } From 1a47e07e97221b6e3faf0e756da8f839221ab273 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 01:41:51 -0700 Subject: [PATCH 09/29] Add Tree Value Functions to NumberReducer. --- .../java/org/nwapw/abacus/tree/NumberReducer.java | 11 +++++++++++ 1 file changed, 11 insertions(+) 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 a252896..0a3c4ab 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -2,6 +2,7 @@ package org.nwapw.abacus.tree; import org.nwapw.abacus.Abacus; import org.nwapw.abacus.function.Function; +import org.nwapw.abacus.function.TreeValueFunction; import org.nwapw.abacus.number.NumberInterface; /** @@ -49,6 +50,16 @@ public class NumberReducer implements Reducer { Function function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo()); if (function == null) return null; return function.apply(convertedChildren); + } else if (node instanceof TreeValueFunctionNode){ + CallNode callNode = (CallNode) node; + TreeNode[] realChildren = new TreeNode[callNode.getChildren().size()]; + for(int i = 0; i < realChildren.length; i++){ + realChildren[i] = callNode.getChildren().get(i); + } + TreeValueFunction function = + abacus.getPluginManager().treeValueFunctionFor(callNode.getCallTo()); + if(function == null) return null; + return function.applyWithReducer(this, realChildren); } return null; } From 1f0addccea290b58e20abd7897361bc957e61c8e Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 01:51:14 -0700 Subject: [PATCH 10/29] Add documentation loading for functions. --- .../main/java/org/nwapw/abacus/function/DocumentationType.java | 2 +- fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/nwapw/abacus/function/DocumentationType.java b/core/src/main/java/org/nwapw/abacus/function/DocumentationType.java index e3ab7fd..5edc9a0 100644 --- a/core/src/main/java/org/nwapw/abacus/function/DocumentationType.java +++ b/core/src/main/java/org/nwapw/abacus/function/DocumentationType.java @@ -6,6 +6,6 @@ package org.nwapw.abacus.function; */ public enum DocumentationType { - FUNCTION + FUNCTION, TREE_VALUE_FUNCTION } diff --git a/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java b/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java index 0194953..e8096fd 100644 --- a/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java +++ b/fx/src/main/java/org/nwapw/abacus/fx/AbacusController.java @@ -360,6 +360,8 @@ public class AbacusController implements PluginListener { PluginManager pluginManager = abacus.getPluginManager(); functionList.addAll(manager.getAllFunctions().stream().map(name -> pluginManager.documentationFor(name, DocumentationType.FUNCTION)) .collect(Collectors.toCollection(ArrayList::new))); + functionList.addAll(manager.getAllTreeValueFunctions().stream().map(name -> pluginManager.documentationFor(name, DocumentationType.TREE_VALUE_FUNCTION)) + .collect(Collectors.toCollection(ArrayList::new))); functionList.sort(Comparator.comparing(Documentation::getCodeName)); } From d04adf4da57e94022489275757f61376bb36f9d4 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 14:55:05 -0700 Subject: [PATCH 11/29] Add Applicable to Operator, therby removing the need for Functions in it --- .../java/org/nwapw/abacus/plugin/Plugin.java | 5 ++- .../nwapw/abacus/plugin/PluginManager.java | 6 +-- .../nwapw/abacus/plugin/StandardPlugin.java | 43 ++++++++++--------- .../org/nwapw/abacus/tree/NumberReducer.java | 12 +++--- .../nwapw/abacus/function/NumberOperator.kt | 15 +++++++ .../org/nwapw/abacus/function/Operator.kt | 7 ++- .../nwapw/abacus/tests/TokenizerTests.java | 35 +++++++++++---- 7 files changed, 80 insertions(+), 43 deletions(-) create mode 100644 core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt 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 4b71d56..1e6763f 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -1,6 +1,7 @@ package org.nwapw.abacus.plugin; import org.nwapw.abacus.function.*; +import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; /** @@ -85,7 +86,7 @@ public abstract class Plugin { * @param name the name of the operator. * @param operator the operator to register. */ - protected final void registerOperator(String name, Operator operator) { + protected final void registerOperator(String name, NumberOperator operator) { manager.registerOperator(name, operator); } @@ -142,7 +143,7 @@ public abstract class Plugin { * @param name the name for which to search * @return the resulting operator, or null if none was found for that name. */ - protected final Operator operatorFor(String name) { + protected final NumberOperator operatorFor(String name) { return manager.operatorFor(name); } 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 b69e0db..9d2952a 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -35,7 +35,7 @@ public class PluginManager { /** * The map of operators registered by the plugins */ - private Map registeredOperators; + private Map registeredOperators; /** * The map of number implementations registered by the plugins. */ @@ -108,7 +108,7 @@ public class PluginManager { * @param name the name of the operator. * @param operator the operator to register. */ - public void registerOperator(String name, Operator operator) { + public void registerOperator(String name, NumberOperator operator) { registeredOperators.put(name, operator); } @@ -158,7 +158,7 @@ public class PluginManager { * @param name the name of the operator. * @return the operator, or null if it was not found. */ - public Operator operatorFor(String name) { + public NumberOperator operatorFor(String name) { return registeredOperators.get(name); } 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 cc2db4b..1568b15 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -4,6 +4,9 @@ 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.BinaryNode; +import org.nwapw.abacus.tree.Reducer; +import org.nwapw.abacus.tree.TreeNode; import java.util.ArrayList; import java.util.HashMap; @@ -18,7 +21,7 @@ public class StandardPlugin extends Plugin { /** * The addition operator, + */ - public static final Operator OP_ADD = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0, new Function() { + public static final NumberOperator OP_ADD = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length >= 1; @@ -32,11 +35,11 @@ public class StandardPlugin extends Plugin { } return sum; } - }); + }; /** * The subtraction operator, - */ - public static final Operator OP_SUBTRACT = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0, new Function() { + public static final NumberOperator OP_SUBTRACT = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 2; @@ -47,11 +50,11 @@ public class StandardPlugin extends Plugin { return params[0].subtract(params[1]); } - }); + }; /** * The negation operator, - */ - public static final Operator OP_NEGATE = new Operator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0, new Function() { + public static final NumberOperator OP_NEGATE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -61,11 +64,11 @@ public class StandardPlugin extends Plugin { protected NumberInterface applyInternal(NumberInterface[] params) { return params[0].negate(); } - }); + }; /** * The multiplication operator, * */ - public static final Operator OP_MULTIPLY = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1, new Function() { + public static final NumberOperator OP_MULTIPLY = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length >= 1; @@ -79,11 +82,11 @@ public class StandardPlugin extends Plugin { } return product; } - }); + }; /** * The combination operator. */ - public static final Operator OP_NCR = new Operator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0, new Function() { + public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 2 && params[0].fractionalPart().signum() == 0 @@ -92,9 +95,9 @@ public class StandardPlugin extends Plugin { @Override protected NumberInterface applyInternal(NumberInterface[] params) { - return OP_NPR.getFunction().apply(params).divide(OP_FACTORIAL.getFunction().apply(params[1])); + return OP_NPR.apply(params).divide(OP_FACTORIAL.apply(params[1])); } - }); + }; /** * The implementation for double-based naive numbers. */ @@ -152,7 +155,7 @@ public class StandardPlugin extends Plugin { /** * The division operator, / */ - public static final Operator OP_DIVIDE = new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1, new Function() { + public static final NumberOperator OP_DIVIDE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 2 && params[1].compareTo(fromInt(params[0].getClass(), 0)) != 0; @@ -162,11 +165,11 @@ public class StandardPlugin extends Plugin { protected NumberInterface applyInternal(NumberInterface[] params) { return params[0].divide(params[1]); } - }); + }; /** * The factorial operator, ! */ - public static final Operator OP_FACTORIAL = new Operator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0, new Function() { + public static final NumberOperator OP_FACTORIAL = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0) { //private HashMap, ArrayList> storedList = new HashMap, ArrayList>(); @Override protected boolean matchesParams(NumberInterface[] params) { @@ -194,11 +197,11 @@ public class StandardPlugin extends Plugin { storedList.get(params[0].getClass()).add(NaiveNumber.ONE.promoteTo(params[0].getClass())); }*/ } - }); + }; /** * The permutation operator. */ - public static final Operator OP_NPR = new Operator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0, new Function() { + public static final NumberOperator OP_NPR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 2 && params[0].fractionalPart().signum() == 0 @@ -224,7 +227,7 @@ public class StandardPlugin extends Plugin { } return total; } - }); + }; /** * The absolute value function, abs(-3) = 3 */ @@ -336,7 +339,7 @@ public class StandardPlugin extends Plugin { /** * The caret / pow operator, ^ */ - public static final Operator OP_CARET = new Operator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2, new Function() { + public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { @Override protected boolean matchesParams(NumberInterface[] params) { NumberInterface zero = fromInt(params[0].getClass(), 0); @@ -362,7 +365,7 @@ public class StandardPlugin extends Plugin { } return FUNCTION_EXP.apply(FUNCTION_LN.apply(FUNCTION_ABS.apply(params[0])).multiply(params[1])); } - }); + }; /** * The square root function. */ @@ -374,7 +377,7 @@ public class StandardPlugin extends Plugin { @Override protected NumberInterface applyInternal(NumberInterface[] params) { - return OP_CARET.getFunction().apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass()))); + return OP_CARET.apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass()))); } }; private static final HashMap, ArrayList> FACTORIAL_LISTS = new HashMap<>(); 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 0a3c4ab..a62f395 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -2,8 +2,10 @@ package org.nwapw.abacus.tree; import org.nwapw.abacus.Abacus; import org.nwapw.abacus.function.Function; +import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.function.TreeValueFunction; import org.nwapw.abacus.number.NumberInterface; +import org.nwapw.abacus.plugin.NumberImplementation; /** * A reducer implementation that turns a tree into a single number. @@ -34,14 +36,12 @@ public class NumberReducer implements Reducer { } else if (node instanceof BinaryNode) { NumberInterface left = (NumberInterface) children[0]; NumberInterface right = (NumberInterface) children[1]; - Function function = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation()).getFunction(); - if (function == null) return null; - return function.apply(left, right); + Operator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation()); + return operator.apply(left, right); } else if (node instanceof UnaryNode) { NumberInterface child = (NumberInterface) children[0]; - Function functionn = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation()).getFunction(); - if (functionn == null) return null; - return functionn.apply(child); + Operator operator = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation()); + return operator.apply(child); } else if (node instanceof FunctionNode) { NumberInterface[] convertedChildren = new NumberInterface[children.length]; for (int i = 0; i < convertedChildren.length; i++) { diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt new file mode 100644 index 0000000..cf7979d --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt @@ -0,0 +1,15 @@ +package org.nwapw.abacus.function + +import org.nwapw.abacus.number.NumberInterface + +/** + * An operator that operates on NumberImplementations. + * + * This is simply an alias for Operator. + * @param associativity the associativity of the operator. + * @param type the type of the operator (binary, unary, etc) + * @param precedence the precedence of the operator. + */ +abstract class NumberOperator(associativity: OperatorAssociativity, type: OperatorType, + precedence: Int) : + Operator(associativity, type, precedence) \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt index e0cb60f..0a70b68 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt @@ -3,12 +3,11 @@ package org.nwapw.abacus.function /** * A single operator that can be used by Abacus. * - * This is a data class that holds the information about a single operator, such as a plus or minus. + * This is a class that holds the information about a single operator, such as a plus or minus. * * @param associativity the associativity of this operator, used for order of operations;. * @param type the type of this operator, used for parsing (infix / prefix / postfix and binary / unary) * @param precedence the precedence of this operator, used for order of operations. - * @param function the function this operator applies to its arguments. */ -data class Operator(val associativity: OperatorAssociativity, val type: OperatorType, - val precedence: Int, val function: Function) \ No newline at end of file +abstract class Operator(val associativity: OperatorAssociativity, val type: OperatorType, + val precedence: Int) : Applicable() \ No newline at end of file diff --git a/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java b/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java index 56515e3..014bbbb 100644 --- a/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java +++ b/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java @@ -5,10 +5,7 @@ import org.junit.BeforeClass; import org.junit.Test; import org.nwapw.abacus.Abacus; import org.nwapw.abacus.config.Configuration; -import org.nwapw.abacus.function.Function; -import org.nwapw.abacus.function.Operator; -import org.nwapw.abacus.function.OperatorAssociativity; -import org.nwapw.abacus.function.OperatorType; +import org.nwapw.abacus.function.*; import org.nwapw.abacus.lexing.pattern.Match; import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.parsing.LexerTokenizer; @@ -35,10 +32,32 @@ public class TokenizerTests { private static Plugin testPlugin = new Plugin(abacus.getPluginManager()) { @Override public void onEnable() { - registerOperator("+", new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, - 0, subtractFunction)); - registerOperator("-", new Operator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, - 0, subtractFunction)); + registerOperator("+", new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, + 0) { + + @Override + protected boolean matchesParams(NumberInterface[] params) { + return true; + } + + @Override + protected NumberInterface applyInternal(NumberInterface[] params) { + return subtractFunction.apply(params); + } + }); + registerOperator("-", new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, + 0) { + + @Override + protected boolean matchesParams(NumberInterface[] params) { + return true; + } + + @Override + protected NumberInterface applyInternal(NumberInterface[] params) { + return subtractFunction.apply(params); + } + }); registerFunction("subtract", subtractFunction); } From f83f2a7aaae48cf97e999bce5e25a139e488d34a Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 14:56:36 -0700 Subject: [PATCH 12/29] Rename Function to NumberFunction. --- .../{Function.java => NumberFunction.java} | 2 +- .../java/org/nwapw/abacus/plugin/Plugin.java | 5 +-- .../nwapw/abacus/plugin/PluginManager.java | 6 +-- .../nwapw/abacus/plugin/StandardPlugin.java | 37 +++++++++---------- .../org/nwapw/abacus/tree/NumberReducer.java | 5 +-- .../nwapw/abacus/tests/TokenizerTests.java | 2 +- 6 files changed, 26 insertions(+), 31 deletions(-) rename core/src/main/java/org/nwapw/abacus/function/{Function.java => NumberFunction.java} (65%) diff --git a/core/src/main/java/org/nwapw/abacus/function/Function.java b/core/src/main/java/org/nwapw/abacus/function/NumberFunction.java similarity index 65% rename from core/src/main/java/org/nwapw/abacus/function/Function.java rename to core/src/main/java/org/nwapw/abacus/function/NumberFunction.java index 9ee9509..24461c2 100755 --- a/core/src/main/java/org/nwapw/abacus/function/Function.java +++ b/core/src/main/java/org/nwapw/abacus/function/NumberFunction.java @@ -6,6 +6,6 @@ import org.nwapw.abacus.number.NumberInterface; * A function that operates on one or more * inputs and returns a single number. */ -public abstract class Function extends Applicable { +public abstract class NumberFunction extends Applicable { } 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 1e6763f..229df85 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -1,7 +1,6 @@ package org.nwapw.abacus.plugin; import org.nwapw.abacus.function.*; -import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NumberInterface; /** @@ -63,7 +62,7 @@ public abstract class Plugin { * @param name the name to register by. * @param toRegister the function implementation. */ - protected final void registerFunction(String name, Function toRegister) { + protected final void registerFunction(String name, NumberFunction toRegister) { manager.registerFunction(name, toRegister); } @@ -119,7 +118,7 @@ public abstract class Plugin { * @param name the name for which to search * @return the resulting function, or null if none was found for that name. */ - protected final Function functionFor(String name) { + protected final NumberFunction functionFor(String name) { return manager.functionFor(name); } 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 9d2952a..a6a2a1f 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -27,7 +27,7 @@ public class PluginManager { /** * The map of functions registered by the plugins. */ - private Map registeredFunctions; + private Map registeredFunctions; /** * The map of tree value functions regstered by the plugins. */ @@ -88,7 +88,7 @@ public class PluginManager { * @param name the name of the function. * @param function the function to register. */ - public void registerFunction(String name, Function function) { + public void registerFunction(String name, NumberFunction function) { registeredFunctions.put(name, function); } @@ -138,7 +138,7 @@ public class PluginManager { * @param name the name of the function. * @return the function, or null if it was not found. */ - public Function functionFor(String name) { + public NumberFunction functionFor(String name) { return registeredFunctions.get(name); } 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 1568b15..c8cee64 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -4,9 +4,6 @@ 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.BinaryNode; -import org.nwapw.abacus.tree.Reducer; -import org.nwapw.abacus.tree.TreeNode; import java.util.ArrayList; import java.util.HashMap; @@ -231,7 +228,7 @@ public class StandardPlugin extends Plugin { /** * The absolute value function, abs(-3) = 3 */ - public static final Function FUNCTION_ABS = new Function() { + public static final NumberFunction FUNCTION_ABS = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -245,7 +242,7 @@ public class StandardPlugin extends Plugin { /** * The natural log function. */ - public static final Function FUNCTION_LN = new Function() { + public static final NumberFunction FUNCTION_LN = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1 && params[0].compareTo(fromInt(params[0].getClass(), 0)) > 0; @@ -325,7 +322,7 @@ public class StandardPlugin extends Plugin { /** * Gets a random number smaller or equal to the given number's integer value. */ - public static final Function FUNCTION_RAND_INT = new Function() { + public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -369,7 +366,7 @@ public class StandardPlugin extends Plugin { /** * The square root function. */ - public static final Function FUNCTION_SQRT = new Function() { + public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -384,7 +381,7 @@ public class StandardPlugin extends Plugin { /** * The exponential function, exp(1) = e^1 = 2.71... */ - public static final Function FUNCTION_EXP = new Function() { + public static final NumberFunction FUNCTION_EXP = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -421,7 +418,7 @@ public class StandardPlugin extends Plugin { /** * The sine function (the argument is interpreted in radians). */ - public final Function functionSin = new Function() { + public final NumberFunction functionSin = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -445,7 +442,7 @@ public class StandardPlugin extends Plugin { /** * The cosine function (the argument is in radians). */ - public final Function functionCos = new Function() { + public final NumberFunction functionCos = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -460,7 +457,7 @@ public class StandardPlugin extends Plugin { /** * The tangent function (the argument is in radians). */ - public final Function functionTan = new Function() { + public final NumberFunction functionTan = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -474,7 +471,7 @@ public class StandardPlugin extends Plugin { /** * The secant function (the argument is in radians). */ - public final Function functionSec = new Function() { + public final NumberFunction functionSec = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -488,7 +485,7 @@ public class StandardPlugin extends Plugin { /** * The cosecant function (the argument is in radians). */ - public final Function functionCsc = new Function() { + public final NumberFunction functionCsc = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -502,7 +499,7 @@ public class StandardPlugin extends Plugin { /** * The cotangent function (the argument is in radians). */ - public final Function functionCot = new Function() { + public final NumberFunction functionCot = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -517,7 +514,7 @@ public class StandardPlugin extends Plugin { /** * The arcsine function (return type in radians). */ - public final Function functionArcsin = new Function() { + public final NumberFunction functionArcsin = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1 @@ -550,7 +547,7 @@ public class StandardPlugin extends Plugin { /** * The arccosine function. */ - public final Function functionArccos = new Function() { + public final NumberFunction functionArccos = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0; @@ -566,7 +563,7 @@ public class StandardPlugin extends Plugin { /** * The arccosecant function. */ - public final Function functionArccsc = new Function() { + public final NumberFunction functionArccsc = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0; @@ -582,7 +579,7 @@ public class StandardPlugin extends Plugin { /** * The arcsecant function. */ - public final Function functionArcsec = new Function() { + public final NumberFunction functionArcsec = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0; @@ -598,7 +595,7 @@ public class StandardPlugin extends Plugin { /** * The arctangent function. */ - public final Function functionArctan = new Function() { + public final NumberFunction functionArctan = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; @@ -639,7 +636,7 @@ public class StandardPlugin extends Plugin { /** * The arccotangent function. Range: (0, pi). */ - public final Function functionArccot = new Function() { + public final NumberFunction functionArccot = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 1; 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 a62f395..ec3b6f3 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -1,11 +1,10 @@ package org.nwapw.abacus.tree; import org.nwapw.abacus.Abacus; -import org.nwapw.abacus.function.Function; +import org.nwapw.abacus.function.NumberFunction; import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.function.TreeValueFunction; import org.nwapw.abacus.number.NumberInterface; -import org.nwapw.abacus.plugin.NumberImplementation; /** * A reducer implementation that turns a tree into a single number. @@ -47,7 +46,7 @@ public class NumberReducer implements Reducer { for (int i = 0; i < convertedChildren.length; i++) { convertedChildren[i] = (NumberInterface) children[i]; } - Function function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo()); + NumberFunction function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo()); if (function == null) return null; return function.apply(convertedChildren); } else if (node instanceof TreeValueFunctionNode){ diff --git a/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java b/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java index 014bbbb..5eaea16 100644 --- a/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java +++ b/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java @@ -18,7 +18,7 @@ public class TokenizerTests { private static Abacus abacus = new Abacus(new Configuration(0, "precise", new String[]{})); private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); - private static Function subtractFunction = new Function() { + private static NumberFunction subtractFunction = new NumberFunction() { @Override protected boolean matchesParams(NumberInterface[] params) { return params.length == 2; From 225a926f86a6981c8961c6e752c32b6bc857d7cb Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 14:59:41 -0700 Subject: [PATCH 13/29] Move NumberFunction into Kotlin. --- .../org/nwapw/abacus/function/NumberFunction.java | 11 ----------- .../org/nwapw/abacus/function/NumberFunction.kt | 11 +++++++++++ 2 files changed, 11 insertions(+), 11 deletions(-) delete mode 100755 core/src/main/java/org/nwapw/abacus/function/NumberFunction.java create mode 100644 core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt diff --git a/core/src/main/java/org/nwapw/abacus/function/NumberFunction.java b/core/src/main/java/org/nwapw/abacus/function/NumberFunction.java deleted file mode 100755 index 24461c2..0000000 --- a/core/src/main/java/org/nwapw/abacus/function/NumberFunction.java +++ /dev/null @@ -1,11 +0,0 @@ -package org.nwapw.abacus.function; - -import org.nwapw.abacus.number.NumberInterface; - -/** - * A function that operates on one or more - * inputs and returns a single number. - */ -public abstract class NumberFunction extends Applicable { - -} diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt b/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt new file mode 100644 index 0000000..a706274 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt @@ -0,0 +1,11 @@ +package org.nwapw.abacus.function + +import org.nwapw.abacus.number.NumberInterface + +/** + * A function that operates on numbers. + * + * This function takes some number of input NumberInterfaces and returns + * another NumberInterface as a result. + */ +abstract class NumberFunction : Applicable() \ No newline at end of file From da1c78945e9771f69b016b7933173a5e2e77fb10 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 15:25:46 -0700 Subject: [PATCH 14/29] Move the code for applicables that require a Reducer. --- .../abacus/function/ReducerApplicable.java | 44 +++++++++++++++++++ .../abacus/function/TreeValueFunction.java | 43 ------------------ .../abacus/function/TreeValueFunction.kt | 12 +++++ 3 files changed, 56 insertions(+), 43 deletions(-) create mode 100644 core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java delete mode 100644 core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java create mode 100644 core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt diff --git a/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java b/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java new file mode 100644 index 0000000..7713404 --- /dev/null +++ b/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java @@ -0,0 +1,44 @@ +package org.nwapw.abacus.function; + +import org.nwapw.abacus.tree.Reducer; + +/** + * A slightly more specific Applicable that requires a reducer + * to be passed to it along with the parameters. + * @param the type of the input arguments. + * @param the return type of the application. + * @param the required type of the reducer. + */ +public abstract class ReducerApplicable extends Applicable { + + @Override + protected final O applyInternal(T[] params) { + return null; + } + + @Override + public final O apply(T... params) { + return null; + } + + /** + * Applies this applicable to the given arguments, and reducer. + * @param reducer the reducer to use in the application. + * @param args the arguments to apply to. + * @return the result of the application. + */ + public abstract O applyWithReducerInternal(Reducer reducer, T[] args); + + /** + * Applies this applicable to the given arguments, and reducer, + * if the arguments and reducer are compatible with this applicable. + * @param reducer the reducer to use in the application. + * @param args the arguments to apply to. + * @return the result of the application, or null if the arguments are incompatible. + */ + public O applyWithReducer(Reducer reducer, T...args) { + if(!matchesParams(args) || reducer == null) return null; + return applyWithReducerInternal(reducer, args); + } + +} diff --git a/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java b/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java deleted file mode 100644 index a34cecc..0000000 --- a/core/src/main/java/org/nwapw/abacus/function/TreeValueFunction.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.nwapw.abacus.function; - -import org.nwapw.abacus.number.NumberInterface; -import org.nwapw.abacus.tree.Reducer; -import org.nwapw.abacus.tree.TreeNode; - -/** - * A function that operates on parse tree nodes instead of on already simplified numbers. - * Despite this, it returns a number, not a tree. - */ -public abstract class TreeValueFunction extends Applicable { - - @Override - protected NumberInterface applyInternal(TreeNode[] params) { - return null; - } - - @Override - public NumberInterface apply(TreeNode... params) { - return null; - } - - /** - * Applies the tree value functions to the given tree nodes, - * using the given reducer. - * @param reducer the reducer to use. - * @param params the parameters to apply to. - * @return the result of the application. - */ - public abstract NumberInterface applyWithReducerInternal(Reducer reducer, TreeNode[] params); - - /** - * Checks if the given parameters and reducer can be used - * with this function, and if so, calls the function on them. - * @param reducer the reducer to use. - * @param params the parameters to apply to. - * @return the result of the application, or null if the parameters are incompatible. - */ - public NumberInterface applyWithReducer(Reducer reducer, TreeNode... params) { - if(!matchesParams(params) || reducer == null) return null; - return applyWithReducerInternal(reducer, params); - } -} diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt new file mode 100644 index 0000000..2038e6b --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt @@ -0,0 +1,12 @@ +package org.nwapw.abacus.function + +import org.nwapw.abacus.number.NumberInterface +import org.nwapw.abacus.tree.TreeNode + +/** + * A function that operates on trees. + * + * A function that operates on parse tree nodes instead of on already simplified numbers. + * Despite this, it returns a number, not a tree. + */ +abstract class TreeValueFunction : ReducerApplicable() From 8a3c61460247a25c86c55515a745713ca287ab44 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 15:42:10 -0700 Subject: [PATCH 15/29] Make applicable into an interface. --- .../org/nwapw/abacus/function/Applicable.java | 8 +- .../abacus/function/ReducerApplicable.java | 10 +- .../nwapw/abacus/plugin/StandardPlugin.java | 104 +++++++++--------- .../org/nwapw/abacus/tree/NumberReducer.java | 5 +- .../nwapw/abacus/function/NumberFunction.kt | 2 +- .../nwapw/abacus/function/NumberOperator.kt | 3 +- .../org/nwapw/abacus/function/Operator.kt | 4 +- .../abacus/function/TreeValueFunction.kt | 2 +- 8 files changed, 70 insertions(+), 68 deletions(-) diff --git a/core/src/main/java/org/nwapw/abacus/function/Applicable.java b/core/src/main/java/org/nwapw/abacus/function/Applicable.java index ced0608..2133848 100644 --- a/core/src/main/java/org/nwapw/abacus/function/Applicable.java +++ b/core/src/main/java/org/nwapw/abacus/function/Applicable.java @@ -6,14 +6,14 @@ package org.nwapw.abacus.function; * @param the type of the parameters passed to this applicable. * @param the return type of the applicable. */ -public abstract class Applicable { +public interface Applicable { /** * Checks if the given applicable can be used with the given parameters. * @param params the parameter array to verify for compatibility. * @return whether the array can be used with applyInternal. */ - protected abstract boolean matchesParams(T[] params); + boolean matchesParams(T[] params); /** * Applies the applicable object to the given parameters, @@ -21,7 +21,7 @@ public abstract class Applicable { * @param params the parameters to apply to. * @return the result of the application. */ - protected abstract O applyInternal(T[] params); + O applyInternal(T[] params); /** * If the parameters can be used with this applicable, returns @@ -30,7 +30,7 @@ public abstract class Applicable { * @param params the parameters to apply to. * @return the result of the operation, or null if parameters do not match. */ - public O apply(T... params){ + default O apply(T... params){ if(!matchesParams(params)) return null; return applyInternal(params); } diff --git a/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java b/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java index 7713404..bff7934 100644 --- a/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java +++ b/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java @@ -9,15 +9,15 @@ import org.nwapw.abacus.tree.Reducer; * @param the return type of the application. * @param the required type of the reducer. */ -public abstract class ReducerApplicable extends Applicable { +public interface ReducerApplicable extends Applicable { @Override - protected final O applyInternal(T[] params) { + default O applyInternal(T[] params) { return null; } @Override - public final O apply(T... params) { + default O apply(T... params) { return null; } @@ -27,7 +27,7 @@ public abstract class ReducerApplicable extends Applicable { * @param args the arguments to apply to. * @return the result of the application. */ - public abstract O applyWithReducerInternal(Reducer reducer, T[] args); + O applyWithReducerInternal(Reducer reducer, T[] args); /** * Applies this applicable to the given arguments, and reducer, @@ -36,7 +36,7 @@ public abstract class ReducerApplicable extends Applicable { * @param args the arguments to apply to. * @return the result of the application, or null if the arguments are incompatible. */ - public O applyWithReducer(Reducer reducer, T...args) { + default O applyWithReducer(Reducer reducer, T...args) { if(!matchesParams(args) || reducer == null) return null; return applyWithReducerInternal(reducer, args); } 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 c8cee64..1e0ca6f 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -20,12 +20,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_ADD = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length >= 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface sum = params[0]; for (int i = 1; i < params.length; i++) { sum = sum.add(params[i]); @@ -38,12 +38,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_SUBTRACT = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 2; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return params[0].subtract(params[1]); } @@ -53,12 +53,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_NEGATE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return params[0].negate(); } }; @@ -67,12 +67,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_MULTIPLY = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length >= 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface product = params[0]; for (int i = 1; i < params.length; i++) { product = product.multiply(params[i]); @@ -85,13 +85,13 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 2 && params[0].fractionalPart().signum() == 0 && params[1].fractionalPart().signum() == 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return OP_NPR.apply(params).divide(OP_FACTORIAL.apply(params[1])); } }; @@ -154,12 +154,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_DIVIDE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 2 && params[1].compareTo(fromInt(params[0].getClass(), 0)) != 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return params[0].divide(params[1]); } }; @@ -169,14 +169,14 @@ public class StandardPlugin extends Plugin { public static final NumberOperator OP_FACTORIAL = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0) { //private HashMap, ArrayList> storedList = new HashMap, ArrayList>(); @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1 && params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0 && params[0].signum() >= 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { if (params[0].signum() == 0) { return fromInt(params[0].getClass(), 1); } @@ -200,13 +200,13 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_NPR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 2 && params[0].fractionalPart().signum() == 0 && params[1].fractionalPart().signum() == 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { if (params[0].compareTo(params[1]) < 0 || params[0].signum() < 0 || (params[0].signum() == 0 && params[1].signum() != 0)) return fromInt(params[0].getClass(), 0); @@ -230,12 +230,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberFunction FUNCTION_ABS = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return params[0].multiply(fromInt(params[0].getClass(), params[0].signum())); } }; @@ -244,12 +244,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberFunction FUNCTION_LN = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1 && params[0].compareTo(fromInt(params[0].getClass(), 0)) > 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface param = params[0]; NumberInterface one = fromInt(param.getClass(), 1); int powersOf2 = 0; @@ -324,12 +324,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return fromInt(params[0].getClass(), (int) Math.round(Math.random() * params[0].floor().intValue())); } }; @@ -338,7 +338,7 @@ public class StandardPlugin extends Plugin { */ public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { NumberInterface zero = fromInt(params[0].getClass(), 0); return params.length == 2 && !(params[0].compareTo(zero) == 0 @@ -347,7 +347,7 @@ public class StandardPlugin extends Plugin { } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface zero = fromInt(params[0].getClass(), 0); if (params[0].compareTo(zero) == 0) return zero; @@ -368,12 +368,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return OP_CARET.apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass()))); } }; @@ -383,12 +383,12 @@ public class StandardPlugin extends Plugin { */ public static final NumberFunction FUNCTION_EXP = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface maxError = params[0].getMaxError(); int n = 0; if (params[0].signum() < 0) { @@ -420,12 +420,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionSin = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface pi = piFor(params[0].getClass()); NumberInterface twoPi = pi.multiply(fromInt(pi.getClass(), 2)); NumberInterface theta = getSmallAngle(params[0], pi); @@ -444,12 +444,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionCos = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return functionSin.apply(piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) .subtract(params[0])); } @@ -459,12 +459,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionTan = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return functionSin.apply(params[0]).divide(functionCos.apply(params[0])); } }; @@ -473,12 +473,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionSec = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return fromInt(params[0].getClass(), 1).divide(functionCos.apply(params[0])); } }; @@ -487,12 +487,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionCsc = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return fromInt(params[0].getClass(), 1).divide(functionSin.apply(params[0])); } }; @@ -501,12 +501,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionCot = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return functionCos.apply(params[0]).divide(functionSin.apply(params[0])); } }; @@ -516,13 +516,13 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionArcsin = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { if (FUNCTION_ABS.apply(params[0]).compareTo(new NaiveNumber(0.8).promoteTo(params[0].getClass())) >= 0) { NumberInterface[] newParams = {FUNCTION_SQRT.apply(fromInt(params[0].getClass(), 1).subtract(params[0].multiply(params[0])))}; return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) @@ -549,12 +549,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionArccos = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) <= 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) .subtract(functionArcsin.apply(params)); } @@ -565,12 +565,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionArccsc = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])}; return functionArcsin.apply(reciprocalParamArr); } @@ -581,12 +581,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionArcsec = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1 && FUNCTION_ABS.apply(params[0]).compareTo(fromInt(params[0].getClass(), 1)) >= 0; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { NumberInterface[] reciprocalParamArr = {fromInt(params[0].getClass(), 1).divide(params[0])}; return functionArccos.apply(reciprocalParamArr); } @@ -597,12 +597,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionArctan = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { if (params[0].signum() == -1) { NumberInterface[] negatedParams = {params[0].negate()}; return applyInternal(negatedParams).negate(); @@ -638,12 +638,12 @@ public class StandardPlugin extends Plugin { */ public final NumberFunction functionArccot = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 1; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return piFor(params[0].getClass()).divide(fromInt(params[0].getClass(), 2)) .subtract(functionArctan.apply(params)); } 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 ec3b6f3..5160a3b 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -2,6 +2,7 @@ package org.nwapw.abacus.tree; import org.nwapw.abacus.Abacus; import org.nwapw.abacus.function.NumberFunction; +import org.nwapw.abacus.function.NumberOperator; import org.nwapw.abacus.function.Operator; import org.nwapw.abacus.function.TreeValueFunction; import org.nwapw.abacus.number.NumberInterface; @@ -35,11 +36,11 @@ public class NumberReducer implements Reducer { } else if (node instanceof BinaryNode) { NumberInterface left = (NumberInterface) children[0]; NumberInterface right = (NumberInterface) children[1]; - Operator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation()); + NumberOperator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation()); return operator.apply(left, right); } else if (node instanceof UnaryNode) { NumberInterface child = (NumberInterface) children[0]; - Operator operator = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation()); + NumberOperator operator = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation()); return operator.apply(child); } else if (node instanceof FunctionNode) { NumberInterface[] convertedChildren = new NumberInterface[children.length]; diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt b/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt index a706274..d0946e6 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt @@ -8,4 +8,4 @@ import org.nwapw.abacus.number.NumberInterface * This function takes some number of input NumberInterfaces and returns * another NumberInterface as a result. */ -abstract class NumberFunction : Applicable() \ No newline at end of file +abstract class NumberFunction : Applicable \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt index cf7979d..9b1f2f1 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt @@ -12,4 +12,5 @@ import org.nwapw.abacus.number.NumberInterface */ abstract class NumberOperator(associativity: OperatorAssociativity, type: OperatorType, precedence: Int) : - Operator(associativity, type, precedence) \ No newline at end of file + Operator(associativity, type, precedence), + Applicable \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt index 0a70b68..31f1028 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt @@ -9,5 +9,5 @@ package org.nwapw.abacus.function * @param type the type of this operator, used for parsing (infix / prefix / postfix and binary / unary) * @param precedence the precedence of this operator, used for order of operations. */ -abstract class Operator(val associativity: OperatorAssociativity, val type: OperatorType, - val precedence: Int) : Applicable() \ No newline at end of file +open class Operator(val associativity: OperatorAssociativity, val type: OperatorType, + val precedence: Int) \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt index 2038e6b..42568ea 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt @@ -9,4 +9,4 @@ import org.nwapw.abacus.tree.TreeNode * A function that operates on parse tree nodes instead of on already simplified numbers. * Despite this, it returns a number, not a tree. */ -abstract class TreeValueFunction : ReducerApplicable() +abstract class TreeValueFunction : ReducerApplicable From ca2681cc210eb08728f3020854c3bb686e501194 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 15:49:35 -0700 Subject: [PATCH 16/29] Add a TreeValueOperator. --- .../nwapw/abacus/function/TreeValueOperator.kt | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt new file mode 100644 index 0000000..beed6b2 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt @@ -0,0 +1,15 @@ +package org.nwapw.abacus.function + +import org.nwapw.abacus.number.NumberInterface +import javax.swing.tree.TreeNode + +/** + * An operator that operates on trees. + * + * This operator operates on parse trees, returning, however a number. + * @param associativity the associativity of the operator. + * @param type the type of the operator (infix, postfix, etc) + * @param precedence the precedence of the operator. + */ +abstract class TreeValueOperator(associativity: OperatorAssociativity, type: OperatorType, + precedence: Int) : ReducerApplicable \ No newline at end of file From 5b1a48c02e2401d06af9696a5fbef2d8d39ec561 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 16:07:23 -0700 Subject: [PATCH 17/29] Convert Applicable interfaces into Kotlin. --- .../nwapw/abacus/function/NumberFunction.kt | 1 + .../nwapw/abacus/function/NumberOperator.kt | 1 + .../abacus/function/TreeValueFunction.kt | 1 + .../abacus/function/TreeValueOperator.kt | 1 + .../abacus/function/applicable/Applicable.kt} | 21 +++++++------ .../function/applicable/ReducerApplicable.kt} | 31 +++++++++---------- 6 files changed, 30 insertions(+), 26 deletions(-) rename core/src/main/{java/org/nwapw/abacus/function/Applicable.java => kotlin/org/nwapw/abacus/function/applicable/Applicable.kt} (68%) rename core/src/main/{java/org/nwapw/abacus/function/ReducerApplicable.java => kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt} (54%) diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt b/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt index d0946e6..f76f147 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/NumberFunction.kt @@ -1,5 +1,6 @@ package org.nwapw.abacus.function +import org.nwapw.abacus.function.applicable.Applicable import org.nwapw.abacus.number.NumberInterface /** diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt index 9b1f2f1..81349c3 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/NumberOperator.kt @@ -1,5 +1,6 @@ package org.nwapw.abacus.function +import org.nwapw.abacus.function.applicable.Applicable import org.nwapw.abacus.number.NumberInterface /** diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt index 42568ea..7b31d92 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueFunction.kt @@ -1,5 +1,6 @@ package org.nwapw.abacus.function +import org.nwapw.abacus.function.applicable.ReducerApplicable import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.tree.TreeNode diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt index beed6b2..990ef1c 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt @@ -1,5 +1,6 @@ package org.nwapw.abacus.function +import org.nwapw.abacus.function.applicable.ReducerApplicable import org.nwapw.abacus.number.NumberInterface import javax.swing.tree.TreeNode diff --git a/core/src/main/java/org/nwapw/abacus/function/Applicable.java b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/Applicable.kt similarity index 68% rename from core/src/main/java/org/nwapw/abacus/function/Applicable.java rename to core/src/main/kotlin/org/nwapw/abacus/function/applicable/Applicable.kt index 2133848..4988c2a 100644 --- a/core/src/main/java/org/nwapw/abacus/function/Applicable.java +++ b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/Applicable.kt @@ -1,27 +1,28 @@ -package org.nwapw.abacus.function; +package org.nwapw.abacus.function.applicable /** - * A class that represents something that can be applied to one or more + * A class that can be applied to arguments. + * + * Applicable is a class that represents something that can be applied to one or more * arguments of the same type, and returns a single value from that application. * @param the type of the parameters passed to this applicable. * @param the return type of the applicable. */ -public interface Applicable { +interface Applicable { /** * Checks if the given applicable can be used with the given parameters. * @param params the parameter array to verify for compatibility. * @return whether the array can be used with applyInternal. */ - boolean matchesParams(T[] params); - + fun matchesParams(params: Array): Boolean /** * Applies the applicable object to the given parameters, * without checking for compatibility. * @param params the parameters to apply to. * @return the result of the application. */ - O applyInternal(T[] params); + fun applyInternal(params: Array): O? /** * If the parameters can be used with this applicable, returns @@ -30,9 +31,9 @@ public interface Applicable { * @param params the parameters to apply to. * @return the result of the operation, or null if parameters do not match. */ - default O apply(T... params){ - if(!matchesParams(params)) return null; - return applyInternal(params); + fun apply(vararg params: T): O? { + if(!matchesParams(params)) return null + return applyInternal(params) } -} +} \ No newline at end of file diff --git a/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt similarity index 54% rename from core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java rename to core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt index bff7934..6de6a27 100644 --- a/core/src/main/java/org/nwapw/abacus/function/ReducerApplicable.java +++ b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt @@ -1,24 +1,24 @@ -package org.nwapw.abacus.function; +package org.nwapw.abacus.function.applicable -import org.nwapw.abacus.tree.Reducer; +import org.nwapw.abacus.tree.Reducer /** - * A slightly more specific Applicable that requires a reducer + * Applicable that requires a reducer. + * + * ReducerApplicable slightly more specific Applicable that requires a reducer * to be passed to it along with the parameters. * @param the type of the input arguments. * @param the return type of the application. * @param the required type of the reducer. */ -public interface ReducerApplicable extends Applicable { +interface ReducerApplicable : Applicable { - @Override - default O applyInternal(T[] params) { - return null; + override fun applyInternal(params: Array): O? { + return null } - @Override - default O apply(T... params) { - return null; + override fun apply(vararg params: T): O? { + return null } /** @@ -27,8 +27,7 @@ public interface ReducerApplicable extends Applicable { * @param args the arguments to apply to. * @return the result of the application. */ - O applyWithReducerInternal(Reducer reducer, T[] args); - + fun applyWithReducerInternal(reducer: Reducer, params: Array): O? /** * Applies this applicable to the given arguments, and reducer, * if the arguments and reducer are compatible with this applicable. @@ -36,9 +35,9 @@ public interface ReducerApplicable extends Applicable { * @param args the arguments to apply to. * @return the result of the application, or null if the arguments are incompatible. */ - default O applyWithReducer(Reducer reducer, T...args) { - if(!matchesParams(args) || reducer == null) return null; - return applyWithReducerInternal(reducer, args); + fun applyWithReducer(reducer: Reducer, vararg params: T): O? { + if(!matchesParams(params)) return null + return applyWithReducerInternal(reducer, params) } -} +} \ No newline at end of file From 73075c57b9cc922c156661fb63b0205c65ccf91d Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 17:31:47 -0700 Subject: [PATCH 18/29] Add registering TreeValueOperators. --- .../java/org/nwapw/abacus/plugin/Plugin.java | 24 +++++++++++++ .../nwapw/abacus/plugin/PluginManager.java | 36 +++++++++++++++++++ 2 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 229df85..8f0441c 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -89,6 +89,18 @@ public abstract class Plugin { manager.registerOperator(name, operator); } + /** + * To be used in load(). Registers an operator + * with the plugin internally, which makes it accessible + * to the plugin manager. + * + * @param name the name of the tree value operator. + * @param operator the tree value operator to register. + */ + protected final void registerTreeValueOperator(String name, TreeValueOperator operator){ + manager.registerTreeValueOperator(name, operator); + } + /** * To be used in load(). Registers a new number implementation with the plugin. * This makes it accessible to the plugin manager. @@ -146,6 +158,18 @@ public abstract class Plugin { return manager.operatorFor(name); } + /** + * Searches the PluginManager for the given tree value operator name. + * This can be used by the plugins internally in order to call + * operations they do not provide. + * + * @param name the name for which to search. + * @return the resulting tree value operator, or null if none was found for that name. + */ + protected final TreeValueOperator treeValueOperatorFor(String name) { + return manager.treeValueOperatorFor(name); + } + /** * Searches the PluginManager for the given number implementation * name. This can be used by the plugins internally in order to find 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 a6a2a1f..90439fa 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -36,6 +36,10 @@ public class PluginManager { * The map of operators registered by the plugins */ private Map registeredOperators; + /** + * The map of tree value operators registered by the plugins. + */ + private Map registeredTreeValueOperators; /** * The map of number implementations registered by the plugins. */ @@ -75,6 +79,7 @@ public class PluginManager { registeredFunctions = new HashMap<>(); registeredTreeValueFunctions = new HashMap<>(); registeredOperators = new HashMap<>(); + registeredTreeValueOperators = new HashMap<>(); registeredNumberImplementations = new HashMap<>(); registeredDocumentation = new HashSet<>(); cachedInterfaceImplementations = new HashMap<>(); @@ -112,6 +117,16 @@ public class PluginManager { registeredOperators.put(name, operator); } + /** + * Registers a tree value operator under the given name. + * + * @param name the name of the tree value operator. + * @param operator the tree value operator to register. + */ + public void registerTreeValueOperator(String name, TreeValueOperator operator){ + registeredTreeValueOperators.put(name, operator); + } + /** * Registers a number implementation under the given name. * @@ -162,6 +177,16 @@ public class PluginManager { return registeredOperators.get(name); } + /** + * Gets the tree value operator registered under the given name. + * + * @param name the name of the tree value operator. + * @return the operator, or null if it was not found. + */ + public TreeValueOperator treeValueOperatorFor(String name) { + return registeredTreeValueOperators.get(name); + } + /** * Gets the number implementation registered under the given name. * @@ -299,7 +324,9 @@ public class PluginManager { plugin.disable(); } registeredFunctions.clear(); + registeredTreeValueFunctions.clear(); registeredOperators.clear(); + registeredTreeValueOperators.clear(); registeredNumberImplementations.clear(); registeredDocumentation.clear(); cachedInterfaceImplementations.clear(); @@ -342,6 +369,15 @@ public class PluginManager { return registeredOperators.keySet(); } + /** + * Gets all the tree value operators loaded by the PluginManager. + * + * @return the set of all tree value operators that were loaded. + */ + public Set getAllTreeValueOperators(){ + return registeredTreeValueOperators.keySet(); + } + /** * Gets all the number implementations loaded by the Plugin Manager. * From 07d7343339bd221a11dd340b21174d90b5119e3d Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 17:46:25 -0700 Subject: [PATCH 19/29] Abstract some Binary and Unary node logic. --- .../abacus/parsing/ShuntingYardParser.java | 4 ++-- .../org/nwapw/abacus/tree/NumberReducer.java | 4 ++-- .../org/nwapw/abacus/tree/BinaryNode.kt | 8 +------ .../org/nwapw/abacus/tree/NumberBinaryNode.kt | 22 +++++++++++++++++++ .../org/nwapw/abacus/tree/NumberUnaryNode.kt | 19 ++++++++++++++++ .../kotlin/org/nwapw/abacus/tree/UnaryNode.kt | 7 +----- 6 files changed, 47 insertions(+), 17 deletions(-) create mode 100644 core/src/main/kotlin/org/nwapw/abacus/tree/NumberBinaryNode.kt create mode 100644 core/src/main/kotlin/org/nwapw/abacus/tree/NumberUnaryNode.kt diff --git a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java index 95bc4b2..b7bac6d 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java @@ -130,11 +130,11 @@ public class ShuntingYardParser implements Parser>, PluginListe TreeNode right = constructRecursive(matches); TreeNode left = constructRecursive(matches); if (left == null || right == null) return null; - else return new BinaryNode(operator, left, right); + else return new NumberBinaryNode(operator, left, right); } else { TreeNode applyTo = constructRecursive(matches); if (applyTo == null) return null; - else return new UnaryNode(operator, applyTo); + else return new NumberUnaryNode(operator, applyTo); } } else if (matchType == TokenType.NUM) { return new NumberNode(match.getContent()); 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 5160a3b..c744195 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -33,12 +33,12 @@ public class NumberReducer implements Reducer { return abacus.numberFromString(((NumberNode) node).getNumber()); } else if(node instanceof VariableNode) { return abacus.numberFromString("0"); - } else if (node instanceof BinaryNode) { + } else if (node instanceof NumberBinaryNode) { NumberInterface left = (NumberInterface) children[0]; NumberInterface right = (NumberInterface) children[1]; NumberOperator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation()); return operator.apply(left, right); - } else if (node instanceof UnaryNode) { + } else if (node instanceof NumberUnaryNode) { NumberInterface child = (NumberInterface) children[0]; NumberOperator operator = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation()); return operator.apply(child); diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt index 01efa8d..4d0d9dd 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/BinaryNode.kt @@ -11,13 +11,7 @@ package org.nwapw.abacus.tree * @param left the left node. * @param right the right node. */ -class BinaryNode(val operation: String, val left: TreeNode? = null, val right: TreeNode?) : TreeNode() { - - override fun reduce(reducer: Reducer): T? { - val leftReduce = left?.reduce(reducer) ?: return null - val rightReduce = right?.reduce(reducer) ?: return null - return reducer.reduceNode(this, leftReduce, rightReduce) - } +abstract class BinaryNode(val operation: String, val left: TreeNode? = null, val right: TreeNode?) : TreeNode() { override fun toString(): String { return "(" + (left?.toString() ?: "null") + operation + (right?.toString() ?: "null") + ")" diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/NumberBinaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberBinaryNode.kt new file mode 100644 index 0000000..74c2206 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberBinaryNode.kt @@ -0,0 +1,22 @@ +package org.nwapw.abacus.tree + +/** + * A binary operator node that reduces its children. + * + * NumberBinaryNode operates by simply reducing its children and + * then using the result of that reduction to reduce itself. + * + * @param operation the operation this node performs. + * @param left the left child of this node. + * @param right the right child of this node. + */ +class NumberBinaryNode(operation: String, left: TreeNode?, right: TreeNode?) + : BinaryNode(operation, left, right) { + + override fun reduce(reducer: Reducer): T? { + val left = left?.reduce(reducer) ?: return null + val right = right?.reduce(reducer) ?: return null + return reducer.reduceNode(this, left, right) + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/NumberUnaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberUnaryNode.kt new file mode 100644 index 0000000..e4fee3f --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberUnaryNode.kt @@ -0,0 +1,19 @@ +package org.nwapw.abacus.tree + +/** + * A unary operator node that reduces its children. + * + * NumberUnaryNode operates by simply reducing its child, + * and using the result of that reduction to reduce itself. + * @param operation the operation this node performs. + * @param child the child this node should be applied to. + */ +class NumberUnaryNode(operation: String, child: TreeNode?) + : UnaryNode(operation, child) { + + override fun reduce(reducer: Reducer): T? { + val child = applyTo?.reduce(reducer) ?: return null + return reducer.reduceNode(this, child) + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt index c2375b2..285231b 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/UnaryNode.kt @@ -9,12 +9,7 @@ package org.nwapw.abacus.tree * @param operation the operation applied to the given node. * @param applyTo the node to which the operation will be applied. */ -class UnaryNode(val operation: String, val applyTo: TreeNode? = null) : TreeNode() { - - override fun reduce(reducer: Reducer): T? { - val reducedChild = applyTo?.reduce(reducer) ?: return null - return reducer.reduceNode(this, reducedChild) - } +abstract class UnaryNode(val operation: String, val applyTo: TreeNode? = null) : TreeNode() { override fun toString(): String { return "(" + (applyTo?.toString() ?: "null") + ")" + operation From 9d52d55e68ffacb97636c7451367fde85db2b36f Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 18:42:41 -0700 Subject: [PATCH 20/29] Add TreeValue operator nodes, and parsing for them. --- .../nwapw/abacus/parsing/LexerTokenizer.java | 6 ++++ .../abacus/parsing/ShuntingYardParser.java | 30 +++++++++++++------ .../java/org/nwapw/abacus/tree/TokenType.java | 3 +- .../nwapw/abacus/tree/TreeValueBinaryNode.kt | 21 +++++++++++++ .../nwapw/abacus/tree/TreeValueUnaryNode.kt | 19 ++++++++++++ 5 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueBinaryNode.kt create mode 100644 core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueUnaryNode.kt diff --git a/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java b/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java index 14ecf95..2d7b16b 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/LexerTokenizer.java @@ -50,6 +50,9 @@ public class LexerTokenizer implements Tokenizer>, PluginListen for (String operator : manager.getAllOperators()) { lexer.register(Pattern.sanitize(operator), TokenType.OP); } + for (String operator : manager.getAllTreeValueOperators()){ + lexer.register(Pattern.sanitize(operator), TokenType.TREE_VALUE_OP); + } for (String function : manager.getAllFunctions()) { lexer.register(Pattern.sanitize(function), TokenType.FUNCTION); } @@ -63,6 +66,9 @@ public class LexerTokenizer implements Tokenizer>, PluginListen for (String operator : manager.getAllOperators()) { lexer.unregister(Pattern.sanitize(operator), TokenType.OP); } + for (String operator : manager.getAllTreeValueOperators()){ + lexer.unregister(Pattern.sanitize(operator), TokenType.TREE_VALUE_OP); + } for (String function : manager.getAllFunctions()) { lexer.unregister(Pattern.sanitize(function), TokenType.FUNCTION); } diff --git a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java index b7bac6d..fd74bc0 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java @@ -58,7 +58,7 @@ public class ShuntingYardParser implements Parser>, PluginListe } else if (matchType == TokenType.FUNCTION || matchType == TokenType.TREE_VALUE_FUNCTION) { output.add(new Match<>("", TokenType.INTERNAL_FUNCTION_END)); tokenStack.push(match); - } else if (matchType == TokenType.OP) { + } else if (matchType == TokenType.OP || matchType == TokenType.TREE_VALUE_OP) { String tokenString = match.getContent(); OperatorType type = typeMap.get(tokenString); int precedence = precedenceMap.get(tokenString); @@ -70,7 +70,7 @@ public class ShuntingYardParser implements Parser>, PluginListe } if (tokenString.equals("-") && (previousType == null || previousType == TokenType.OP || - previousType == TokenType.OPEN_PARENTH)) { + previousType == TokenType.TREE_VALUE_OP || previousType == TokenType.OPEN_PARENTH)) { from.add(0, new Match<>("`", TokenType.OP)); continue; } @@ -78,10 +78,12 @@ public class ShuntingYardParser implements Parser>, PluginListe while (!tokenStack.empty() && type == OperatorType.BINARY_INFIX) { Match otherMatch = tokenStack.peek(); TokenType otherMatchType = otherMatch.getType(); - if (!(otherMatchType == TokenType.OP || otherMatchType == TokenType.FUNCTION || - otherMatchType == TokenType.TREE_VALUE_FUNCTION)) break; + if (!(otherMatchType == TokenType.OP || + otherMatchType == TokenType.TREE_VALUE_OP || + otherMatchType == TokenType.FUNCTION || + otherMatchType == TokenType.TREE_VALUE_FUNCTION)) break; - if (otherMatchType == TokenType.OP) { + if (otherMatchType == TokenType.OP || otherMatchType == TokenType.TREE_VALUE_OP) { int otherPrecedence = precedenceMap.get(otherMatch.getContent()); if (otherPrecedence < precedence || (associativity == OperatorAssociativity.RIGHT && otherPrecedence == precedence)) { @@ -106,7 +108,9 @@ public class ShuntingYardParser implements Parser>, PluginListe while (!tokenStack.empty()) { Match match = tokenStack.peek(); TokenType newMatchType = match.getType(); - if (!(newMatchType == TokenType.OP || newMatchType == TokenType.FUNCTION || + if (!(newMatchType == TokenType.OP || + newMatchType == TokenType.TREE_VALUE_OP || + newMatchType == TokenType.FUNCTION || newMatchType == TokenType.TREE_VALUE_FUNCTION)) return null; output.add(tokenStack.pop()); } @@ -123,18 +127,26 @@ public class ShuntingYardParser implements Parser>, PluginListe if (matches.size() == 0) return null; Match match = matches.remove(0); TokenType matchType = match.getType(); - if (matchType == TokenType.OP) { + if (matchType == TokenType.OP || matchType == TokenType.TREE_VALUE_OP) { String operator = match.getContent(); OperatorType type = typeMap.get(operator); if (type == OperatorType.BINARY_INFIX) { TreeNode right = constructRecursive(matches); TreeNode left = constructRecursive(matches); if (left == null || right == null) return null; - else return new NumberBinaryNode(operator, left, right); + if(matchType == TokenType.OP) { + return new NumberBinaryNode(operator, left, right); + } else { + return new TreeValueBinaryNode(operator, left, right); + } } else { TreeNode applyTo = constructRecursive(matches); if (applyTo == null) return null; - else return new NumberUnaryNode(operator, applyTo); + if(matchType == TokenType.OP){ + return new NumberUnaryNode(operator, applyTo); + } else { + return new TreeValueUnaryNode(operator, applyTo); + } } } else if (matchType == TokenType.NUM) { return new NumberNode(match.getContent()); diff --git a/core/src/main/java/org/nwapw/abacus/tree/TokenType.java b/core/src/main/java/org/nwapw/abacus/tree/TokenType.java index 857e9b4..ff1ca5e 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/TokenType.java +++ b/core/src/main/java/org/nwapw/abacus/tree/TokenType.java @@ -7,7 +7,8 @@ package org.nwapw.abacus.tree; public enum TokenType { INTERNAL_FUNCTION_END(-1), - ANY(0), WHITESPACE(1), COMMA(2), OP(3), NUM(4), VARIABLE(5), FUNCTION(6), TREE_VALUE_FUNCTION(6), OPEN_PARENTH(7), CLOSE_PARENTH(8); + ANY(0), WHITESPACE(1), COMMA(2), OP(3), TREE_VALUE_OP(3), + NUM(4), VARIABLE(5), FUNCTION(6), TREE_VALUE_FUNCTION(6), OPEN_PARENTH(7), CLOSE_PARENTH(8); /** * The priority by which this token gets sorted. diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueBinaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueBinaryNode.kt new file mode 100644 index 0000000..4edfef3 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueBinaryNode.kt @@ -0,0 +1,21 @@ +package org.nwapw.abacus.tree + +/** + * A tree node that represents a binary tree value operator. + * + * + * The tree value operators operate on trees, and so this + * node does not reduce its children. It is up to the implementation to handle + * reduction. + * @param operation the operation this node performs. + * @param left the left child of this node. + * @param right the right child of this node. + */ +class TreeValueBinaryNode(operation: String, left: TreeNode?, right: TreeNode?) + : BinaryNode(operation, left, right) { + + override fun reduce(reducer: Reducer): T? { + return reducer.reduceNode(this) + } + +} \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueUnaryNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueUnaryNode.kt new file mode 100644 index 0000000..fdc0db5 --- /dev/null +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/TreeValueUnaryNode.kt @@ -0,0 +1,19 @@ +package org.nwapw.abacus.tree + +/** + * A tree node that represents a unary tree value operator. + * + * The tree value operators operate on trees, and so this + * node does not reduce its children. It is up to the implementation to handle + * reduction. + * @param operation the operation this node performs. + * @param child the node the operation should be applied to. + */ +class TreeValueUnaryNode(operation: String, child: TreeNode?) + : UnaryNode(operation, child) { + + override fun reduce(reducer: Reducer): T? { + return reducer.reduceNode(this); + } + +} \ No newline at end of file From bfc1ed581961bcf61d47c314e5a87bf34126c93a Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 18:47:49 -0700 Subject: [PATCH 21/29] Fix incorrect template argument. --- .../main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt index 990ef1c..1087532 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt @@ -2,7 +2,7 @@ package org.nwapw.abacus.function import org.nwapw.abacus.function.applicable.ReducerApplicable import org.nwapw.abacus.number.NumberInterface -import javax.swing.tree.TreeNode +import org.nwapw.abacus.tree.TreeNode /** * An operator that operates on trees. From 20b2e77ee138d143249821031ebc2ef036901bc9 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 18:48:05 -0700 Subject: [PATCH 22/29] Add reduction of TreeValue operators. --- .../org/nwapw/abacus/tree/NumberReducer.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 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 c744195..fa73958 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java +++ b/core/src/main/java/org/nwapw/abacus/tree/NumberReducer.java @@ -1,10 +1,7 @@ package org.nwapw.abacus.tree; import org.nwapw.abacus.Abacus; -import org.nwapw.abacus.function.NumberFunction; -import org.nwapw.abacus.function.NumberOperator; -import org.nwapw.abacus.function.Operator; -import org.nwapw.abacus.function.TreeValueFunction; +import org.nwapw.abacus.function.*; import org.nwapw.abacus.number.NumberInterface; /** @@ -60,6 +57,18 @@ public class NumberReducer implements Reducer { abacus.getPluginManager().treeValueFunctionFor(callNode.getCallTo()); if(function == null) return null; return function.applyWithReducer(this, realChildren); + } else if (node instanceof TreeValueBinaryNode) { + BinaryNode binaryNode = (BinaryNode) node; + TreeValueOperator operator = abacus.getPluginManager() + .treeValueOperatorFor(binaryNode.getOperation()); + if(operator == null) return null; + return operator.applyWithReducer(this, binaryNode.getLeft(), binaryNode.getRight()); + } else if(node instanceof TreeValueUnaryNode) { + UnaryNode unaryNode = (UnaryNode) node; + TreeValueOperator operator = abacus.getPluginManager() + .treeValueOperatorFor(unaryNode.getOperation()); + if(operator == null) return null; + return operator.applyWithReducer(this, unaryNode.getApplyTo()); } return null; } From f8eb0515838dee6ff44dede8dc9099ce3e72c175 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 19:48:56 -0700 Subject: [PATCH 23/29] Fix token precedence for variable names / operators. --- core/src/main/java/org/nwapw/abacus/tree/TokenType.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/nwapw/abacus/tree/TokenType.java b/core/src/main/java/org/nwapw/abacus/tree/TokenType.java index ff1ca5e..7df9a94 100644 --- a/core/src/main/java/org/nwapw/abacus/tree/TokenType.java +++ b/core/src/main/java/org/nwapw/abacus/tree/TokenType.java @@ -7,8 +7,8 @@ package org.nwapw.abacus.tree; public enum TokenType { INTERNAL_FUNCTION_END(-1), - ANY(0), WHITESPACE(1), COMMA(2), OP(3), TREE_VALUE_OP(3), - NUM(4), VARIABLE(5), FUNCTION(6), TREE_VALUE_FUNCTION(6), OPEN_PARENTH(7), CLOSE_PARENTH(8); + ANY(0), WHITESPACE(1), COMMA(2), VARIABLE(3), OP(4), TREE_VALUE_OP(4), + NUM(5), FUNCTION(6), TREE_VALUE_FUNCTION(6), OPEN_PARENTH(7), CLOSE_PARENTH(7); /** * The priority by which this token gets sorted. From b98b08b872cf9f70c3e0131979f61fab31b324c9 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 19:49:15 -0700 Subject: [PATCH 24/29] Make sure TreeValueOperator extends Operator. --- .../kotlin/org/nwapw/abacus/function/TreeValueOperator.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt index 1087532..7c4eea7 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/TreeValueOperator.kt @@ -13,4 +13,6 @@ import org.nwapw.abacus.tree.TreeNode * @param precedence the precedence of the operator. */ abstract class TreeValueOperator(associativity: OperatorAssociativity, type: OperatorType, - precedence: Int) : ReducerApplicable \ No newline at end of file + precedence: Int) : + Operator(associativity, type, precedence), + ReducerApplicable \ No newline at end of file From c2feedee3210b0f2b6c0739b8dfae953fc33f778 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 25 Aug 2017 19:49:37 -0700 Subject: [PATCH 25/29] Register precedences of TreeValue operators. --- .../java/org/nwapw/abacus/parsing/ShuntingYardParser.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java index fd74bc0..7490d96 100644 --- a/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java +++ b/core/src/main/java/org/nwapw/abacus/parsing/ShuntingYardParser.java @@ -189,6 +189,12 @@ public class ShuntingYardParser implements Parser>, PluginListe associativityMap.put(operator, operatorInstance.getAssociativity()); typeMap.put(operator, operatorInstance.getType()); } + for (String operator : manager.getAllTreeValueOperators()) { + Operator operatorInstance = manager.treeValueOperatorFor(operator); + precedenceMap.put(operator, operatorInstance.getPrecedence()); + associativityMap.put(operator, operatorInstance.getAssociativity()); + typeMap.put(operator, operatorInstance.getType()); + } } @Override From 385a64eace766526b3565d125a625391a4ff4fb5 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 26 Aug 2017 11:52:02 -0700 Subject: [PATCH 26/29] Make ReducerApplicable an independent interface. --- .../function/applicable/ReducerApplicable.kt | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt index 6de6a27..f1a3036 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt @@ -11,20 +11,18 @@ import org.nwapw.abacus.tree.Reducer * @param the return type of the application. * @param the required type of the reducer. */ -interface ReducerApplicable : Applicable { - - override fun applyInternal(params: Array): O? { - return null - } - - override fun apply(vararg params: T): O? { - return null - } +interface ReducerApplicable { + /** + * Checks if this applicable can be applied to the + * given parameters. + * @param params the parameters to check. + */ + fun matchesParams(params: Array): Boolean /** * Applies this applicable to the given arguments, and reducer. * @param reducer the reducer to use in the application. - * @param args the arguments to apply to. + * @param params the arguments to apply to. * @return the result of the application. */ fun applyWithReducerInternal(reducer: Reducer, params: Array): O? @@ -32,7 +30,7 @@ interface ReducerApplicable : Applicable * Applies this applicable to the given arguments, and reducer, * if the arguments and reducer are compatible with this applicable. * @param reducer the reducer to use in the application. - * @param args 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. */ fun applyWithReducer(reducer: Reducer, vararg params: T): O? { From fbc12ec41ca35e9ac187f9f9d5d75dca5dbec137 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 26 Aug 2017 12:19:34 -0700 Subject: [PATCH 27/29] Format newly written code. --- .../java/org/nwapw/abacus/plugin/Plugin.java | 8 +- .../nwapw/abacus/plugin/PluginManager.java | 10 +- .../nwapw/abacus/plugin/StandardPlugin.java | 118 +++++++++--------- .../org/nwapw/abacus/function/Operator.kt | 2 +- .../abacus/function/applicable/Applicable.kt | 5 +- .../function/applicable/ReducerApplicable.kt | 6 +- .../kotlin/org/nwapw/abacus/tree/CallNode.kt | 4 +- .../org/nwapw/abacus/tree/NumberNode.kt | 2 - 8 files changed, 78 insertions(+), 77 deletions(-) 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 8f0441c..223d7aa 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/Plugin.java @@ -70,7 +70,7 @@ public abstract class Plugin { * To be used in load(). Registers a tree value function abstract class * with the plugin internally, which makes it accessible to the plugin manager. * - * @param name the name to register by. + * @param name the name to register by. * @param toRegister the tree value function implementation. */ protected final void registerTreeValueFunction(String name, TreeValueFunction toRegister) { @@ -94,10 +94,10 @@ public abstract class Plugin { * with the plugin internally, which makes it accessible * to the plugin manager. * - * @param name the name of the tree value operator. + * @param name the name of the tree value operator. * @param operator the tree value operator to register. */ - protected final void registerTreeValueOperator(String name, TreeValueOperator operator){ + protected final void registerTreeValueOperator(String name, TreeValueOperator operator) { manager.registerTreeValueOperator(name, operator); } @@ -142,7 +142,7 @@ public abstract class Plugin { * @param name the name for which to search. * @return the resulting tree value function, or null if none was found for that name. */ - protected final TreeValueFunction treeValueFunctionFor(String name){ + protected final TreeValueFunction treeValueFunctionFor(String name) { return manager.treeValueFunctionFor(name); } 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 90439fa..64b3eb3 100644 --- a/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/PluginManager.java @@ -100,7 +100,7 @@ public class PluginManager { /** * Registers a tree value function under the given name. * - * @param name the name of the function. + * @param name the name of the function. * @param function the function to register. */ public void registerTreeValueFunction(String name, TreeValueFunction function) { @@ -120,10 +120,10 @@ public class PluginManager { /** * Registers a tree value operator under the given name. * - * @param name the name of the tree value operator. + * @param name the name of the tree value operator. * @param operator the tree value operator to register. */ - public void registerTreeValueOperator(String name, TreeValueOperator operator){ + public void registerTreeValueOperator(String name, TreeValueOperator operator) { registeredTreeValueOperators.put(name, operator); } @@ -163,7 +163,7 @@ public class PluginManager { * @param name the name of the function. * @return the function, or null if it was not found. */ - public TreeValueFunction treeValueFunctionFor(String name){ + public TreeValueFunction treeValueFunctionFor(String name) { return registeredTreeValueFunctions.get(name); } @@ -374,7 +374,7 @@ public class PluginManager { * * @return the set of all tree value operators that were loaded. */ - public Set getAllTreeValueOperators(){ + public Set getAllTreeValueOperators() { return registeredTreeValueOperators.keySet(); } 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 1e0ca6f..3ba9d76 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -80,21 +80,6 @@ public class StandardPlugin extends Plugin { return product; } }; - /** - * The combination operator. - */ - public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { - @Override - public boolean matchesParams(NumberInterface[] params) { - return params.length == 2 && params[0].fractionalPart().signum() == 0 - && params[1].fractionalPart().signum() == 0; - } - - @Override - public NumberInterface applyInternal(NumberInterface[] params) { - return OP_NPR.apply(params).divide(OP_FACTORIAL.apply(params[1])); - } - }; /** * The implementation for double-based naive numbers. */ @@ -109,6 +94,20 @@ public class StandardPlugin extends Plugin { return new NaiveNumber(Math.PI); } }; + /** + * The square root function. + */ + public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { + @Override + public boolean matchesParams(NumberInterface[] params) { + return params.length == 1; + } + + @Override + public NumberInterface applyInternal(NumberInterface[] params) { + return OP_CARET.apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass()))); + } + }; /** * The implementation for the infinite-precision BigDecimal. */ @@ -225,6 +224,21 @@ public class StandardPlugin extends Plugin { return total; } }; + /** + * The combination operator. + */ + public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { + @Override + public boolean matchesParams(NumberInterface[] params) { + return params.length == 2 && params[0].fractionalPart().signum() == 0 + && params[1].fractionalPart().signum() == 0; + } + + @Override + public NumberInterface applyInternal(NumberInterface[] params) { + return OP_NPR.apply(params).divide(OP_FACTORIAL.apply(params[1])); + } + }; /** * The absolute value function, abs(-3) = 3 */ @@ -333,50 +347,6 @@ public class StandardPlugin extends Plugin { return fromInt(params[0].getClass(), (int) Math.round(Math.random() * params[0].floor().intValue())); } }; - /** - * The caret / pow operator, ^ - */ - public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { - @Override - public boolean matchesParams(NumberInterface[] params) { - NumberInterface zero = fromInt(params[0].getClass(), 0); - return params.length == 2 - && !(params[0].compareTo(zero) == 0 - && params[1].compareTo(zero) == 0) - && !(params[0].signum() == -1 && params[1].fractionalPart().compareTo(zero) != 0); - } - - @Override - public NumberInterface applyInternal(NumberInterface[] params) { - NumberInterface zero = fromInt(params[0].getClass(), 0); - if (params[0].compareTo(zero) == 0) - return zero; - else if (params[1].compareTo(zero) == 0) - return fromInt(params[0].getClass(), 1); - //Detect integer bases: - if (params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0 - && FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[0].getClass(), Integer.MAX_VALUE)) < 0 - && FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[1].getClass(), 1)) >= 0) { - NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; - return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(newParams)); - } - return FUNCTION_EXP.apply(FUNCTION_LN.apply(FUNCTION_ABS.apply(params[0])).multiply(params[1])); - } - }; - /** - * The square root function. - */ - public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { - @Override - public boolean matchesParams(NumberInterface[] params) { - return params.length == 1; - } - - @Override - public NumberInterface applyInternal(NumberInterface[] params) { - return OP_CARET.apply(params[0], ((new NaiveNumber(0.5)).promoteTo(params[0].getClass()))); - } - }; private static final HashMap, ArrayList> FACTORIAL_LISTS = new HashMap<>(); /** * The exponential function, exp(1) = e^1 = 2.71... @@ -415,6 +385,36 @@ public class StandardPlugin extends Plugin { } } }; + /** + * The caret / pow operator, ^ + */ + public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { + @Override + public boolean matchesParams(NumberInterface[] params) { + NumberInterface zero = fromInt(params[0].getClass(), 0); + return params.length == 2 + && !(params[0].compareTo(zero) == 0 + && params[1].compareTo(zero) == 0) + && !(params[0].signum() == -1 && params[1].fractionalPart().compareTo(zero) != 0); + } + + @Override + public NumberInterface applyInternal(NumberInterface[] params) { + NumberInterface zero = fromInt(params[0].getClass(), 0); + if (params[0].compareTo(zero) == 0) + return zero; + else if (params[1].compareTo(zero) == 0) + return fromInt(params[0].getClass(), 1); + //Detect integer bases: + if (params[0].fractionalPart().compareTo(fromInt(params[0].getClass(), 0)) == 0 + && FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[0].getClass(), Integer.MAX_VALUE)) < 0 + && FUNCTION_ABS.apply(params[1]).compareTo(fromInt(params[1].getClass(), 1)) >= 0) { + NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; + return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(newParams)); + } + return FUNCTION_EXP.apply(FUNCTION_LN.apply(FUNCTION_ABS.apply(params[0])).multiply(params[1])); + } + }; /** * The sine function (the argument is interpreted in radians). */ diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt b/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt index 31f1028..754589b 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/Operator.kt @@ -10,4 +10,4 @@ package org.nwapw.abacus.function * @param precedence the precedence of this operator, used for order of operations. */ open class Operator(val associativity: OperatorAssociativity, val type: OperatorType, - val precedence: Int) \ No newline at end of file + val precedence: Int) \ No newline at end of file diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/applicable/Applicable.kt b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/Applicable.kt index 4988c2a..5e219c1 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/applicable/Applicable.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/Applicable.kt @@ -8,7 +8,7 @@ package org.nwapw.abacus.function.applicable * @param the type of the parameters passed to this applicable. * @param the return type of the applicable. */ -interface Applicable { +interface Applicable { /** * Checks if the given applicable can be used with the given parameters. @@ -16,6 +16,7 @@ interface Applicable { * @return whether the array can be used with applyInternal. */ fun matchesParams(params: Array): Boolean + /** * Applies the applicable object to the given parameters, * without checking for compatibility. @@ -32,7 +33,7 @@ interface Applicable { * @return the result of the operation, or null if parameters do not match. */ fun apply(vararg params: T): O? { - if(!matchesParams(params)) return null + if (!matchesParams(params)) return null return applyInternal(params) } diff --git a/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt index f1a3036..6cef5e1 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/function/applicable/ReducerApplicable.kt @@ -11,7 +11,7 @@ import org.nwapw.abacus.tree.Reducer * @param the return type of the application. * @param the required type of the reducer. */ -interface ReducerApplicable { +interface ReducerApplicable { /** * Checks if this applicable can be applied to the @@ -19,6 +19,7 @@ interface ReducerApplicable { * @param params the parameters to check. */ fun matchesParams(params: Array): Boolean + /** * Applies this applicable to the given arguments, and reducer. * @param reducer the reducer to use in the application. @@ -26,6 +27,7 @@ interface ReducerApplicable { * @return the result of the application. */ fun applyWithReducerInternal(reducer: Reducer, params: Array): O? + /** * Applies this applicable to the given arguments, and reducer, * if the arguments and reducer are compatible with this applicable. @@ -34,7 +36,7 @@ interface ReducerApplicable { * @return the result of the application, or null if the arguments are incompatible. */ fun applyWithReducer(reducer: Reducer, vararg params: T): O? { - if(!matchesParams(params)) return null + if (!matchesParams(params)) return null return applyWithReducerInternal(reducer, params) } diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt index 5c059ae..5f99494 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/CallNode.kt @@ -19,9 +19,9 @@ abstract class CallNode(val callTo: String) : TreeNode() { val buffer = StringBuffer() buffer.append(callTo) buffer.append("(") - for(i in 0 until children.size){ + for (i in 0 until children.size) { buffer.append(children[i].toString()) - buffer.append(if(i != children.size - 1) ", " else ")") + buffer.append(if (i != children.size - 1) ", " else ")") } return buffer.toString() } diff --git a/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt index 624a50a..3507568 100644 --- a/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt +++ b/core/src/main/kotlin/org/nwapw/abacus/tree/NumberNode.kt @@ -1,7 +1,5 @@ package org.nwapw.abacus.tree -import org.nwapw.abacus.number.NumberInterface - /** * A tree node that holds a single number value. * From e3c37cf10a41c391d44c91186edc400d1280dab6 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Mon, 28 Aug 2017 12:59:16 -0700 Subject: [PATCH 28/29] Bring tests up to date. --- .../java/org/nwapw/abacus/tests/TokenizerTests.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java b/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java index 5eaea16..79a7cd2 100644 --- a/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java +++ b/core/src/test/java/org/nwapw/abacus/tests/TokenizerTests.java @@ -20,12 +20,12 @@ public class TokenizerTests { private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); private static NumberFunction subtractFunction = new NumberFunction() { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return params.length == 2; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return params[0].subtract(params[1]); } }; @@ -36,12 +36,12 @@ public class TokenizerTests { 0) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return true; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return subtractFunction.apply(params); } }); @@ -49,12 +49,12 @@ public class TokenizerTests { 0) { @Override - protected boolean matchesParams(NumberInterface[] params) { + public boolean matchesParams(NumberInterface[] params) { return true; } @Override - protected NumberInterface applyInternal(NumberInterface[] params) { + public NumberInterface applyInternal(NumberInterface[] params) { return subtractFunction.apply(params); } }); From ae0ec0c375177f05300956beda201a7bb252592a Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Tue, 29 Aug 2017 18:31:47 -0700 Subject: [PATCH 29/29] Switch add and multiply to two parameters. --- .../org/nwapw/abacus/plugin/StandardPlugin.java | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) 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 3ba9d76..16bbba1 100755 --- a/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java +++ b/core/src/main/java/org/nwapw/abacus/plugin/StandardPlugin.java @@ -21,16 +21,12 @@ public class StandardPlugin extends Plugin { public static final NumberOperator OP_ADD = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { @Override public boolean matchesParams(NumberInterface[] params) { - return params.length >= 1; + return params.length == 2; } @Override public NumberInterface applyInternal(NumberInterface[] params) { - NumberInterface sum = params[0]; - for (int i = 1; i < params.length; i++) { - sum = sum.add(params[i]); - } - return sum; + return params[0].add(params[1]); } }; /** @@ -68,16 +64,12 @@ public class StandardPlugin extends Plugin { public static final NumberOperator OP_MULTIPLY = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { @Override public boolean matchesParams(NumberInterface[] params) { - return params.length >= 1; + return params.length == 2; } @Override public NumberInterface applyInternal(NumberInterface[] params) { - NumberInterface product = params[0]; - for (int i = 1; i < params.length; i++) { - product = product.multiply(params[i]); - } - return product; + return params[0].multiply(params[1]); } }; /**