1
0
mirror of https://github.com/DanilaFe/abacus synced 2026-01-25 16:15:19 +00:00

Compare commits

...

19 Commits

Author SHA1 Message Date
e430e738cf Merge branch 'master' into fixes 2017-09-16 03:03:52 -07:00
f6e326e0f1 Revert "Remove unnecessary nullability from parseString."
88e3bb7109
2017-09-16 03:02:35 -07:00
07581557c7 Merge pull request #27 from DanilaFe/fixes
Fix a number of small issues not worthy of their own branches.
2017-09-16 01:26:40 -07:00
14ac9c67f4 Implement the comparable interface. 2017-09-16 00:18:43 -07:00
0ff071e212 Add a more complete .gitignore 2017-09-16 00:17:03 -07:00
88e3bb7109 Remove unnecessary nullability from parseString. 2017-09-16 00:16:48 -07:00
540e5d6099 Load default implementation if one is not found. 2017-09-16 00:16:32 -07:00
c9e93d87a2 Merge pull request #23 from DanilaFe/thread-safety
Make some parts of the code more thread safe.
2017-09-15 22:59:42 -07:00
337edd68fa Merge branch 'master' into thread-safety 2017-09-15 22:58:33 -07:00
08967fbb8f Merge pull request #22 from DanilaFe/less-null
Remove some null-heavy parts of the code.
2017-09-15 22:56:54 -07:00
46f78bb2ed Merge pull request #21 from DanilaFe/context
Implement a Context system which allows concurrent creation of variables.
2017-09-15 22:51:56 -07:00
5b4773dee1 Do not use null in exceptions and add messages to exceptions. 2017-09-11 19:32:57 -07:00
be94394a5c Catch one exception. 2017-09-11 19:32:57 -07:00
45de25cd50 Move exceptions to their own package and subclass one class. 2017-09-11 19:32:57 -07:00
52ab357fe1 Remove nullability from reduction. 2017-09-11 19:32:57 -07:00
1575d3e574 Remove nullability from tree nodes. 2017-09-11 19:32:57 -07:00
87529da15f Precompute all the transitions ahead of time. 2017-09-11 19:32:51 -07:00
7cd117dac1 Add synchronization to the Standard plugin. 2017-09-11 19:32:51 -07:00
8975bfdb99 Precompute Pi, and do not store documentation on access. 2017-09-11 19:32:51 -07:00
29 changed files with 107 additions and 115 deletions

4
.gitignore vendored
View File

@@ -24,7 +24,9 @@ hs_err_pid*
# Custom Stuff # Custom Stuff
# Gradle # Gradle
.gradle/* .gradle/*
build/* **/build/*
**/out/**
**/.DS_Store
# IntelliJ # IntelliJ
.idea/* .idea/*

View File

@@ -0,0 +1,9 @@
package org.nwapw.abacus.exception;
public class AbacusException extends RuntimeException {
public AbacusException(String baseMessage, String description){
super(baseMessage + ((description.equals("")) ? "." : (": " + description)));
}
}

View File

@@ -1,16 +1,16 @@
package org.nwapw.abacus.number; package org.nwapw.abacus.exception;
/** /**
* Exception thrown when the computation is interrupted by * Exception thrown when the computation is interrupted by
* the user. * the user.
*/ */
public class ComputationInterruptedException extends RuntimeException { public class ComputationInterruptedException extends AbacusException {
/** /**
* Creates a new exception of this type. * Creates a new exception of this type.
*/ */
public ComputationInterruptedException() { public ComputationInterruptedException() {
super("Computation interrupted by user."); super("Computation interrupted", "");
} }
} }

View File

@@ -1,24 +1,24 @@
package org.nwapw.abacus.function; package org.nwapw.abacus.exception;
/** /**
* Exception thrown if the function parameters do not match * Exception thrown if the function parameters do not match
* requirements. * requirements.
*/ */
public class DomainException extends RuntimeException { public class DomainException extends AbacusException {
/** /**
* Creates a new DomainException. * Creates a new DomainException.
* @param reason the reason for which the exception is thrown. * @param reason the reason for which the exception is thrown.
*/ */
public DomainException(String reason) { public DomainException(String reason) {
super(reason); super("Domain error", reason);
} }
/** /**
* Creates a new DomainException with a default message. * Creates a new DomainException with a default message.
*/ */
public DomainException(){ public DomainException(){
this("Domain Error"); this("");
} }
} }

View File

@@ -1,17 +1,17 @@
package org.nwapw.abacus.function; package org.nwapw.abacus.exception;
/** /**
* An exception thrown primarily from Tree Value operators and functions, * An exception thrown primarily from Tree Value operators and functions,
* which have to deal with the result of a Reducer as well as the results * which have to deal with the result of a Reducer as well as the results
* of Applicable. * of Applicable.
*/ */
public class EvaluationException extends RuntimeException { public class EvaluationException extends AbacusException {
/** /**
* Creates a new EvaluationException with the default string. * Creates a new EvaluationException with the default string.
*/ */
public EvaluationException() { public EvaluationException() {
super("Error evaluating expression."); this("");
} }
/** /**
@@ -19,7 +19,7 @@ public class EvaluationException extends RuntimeException {
* @param message the message string. * @param message the message string.
*/ */
public EvaluationException(String message) { public EvaluationException(String message) {
super(message); super("Evaluation error", message);
} }
} }

View File

@@ -1,9 +1,11 @@
package org.nwapw.abacus.number; package org.nwapw.abacus.number;
import org.nwapw.abacus.exception.ComputationInterruptedException;
/** /**
* An interface used to represent a number. * An interface used to represent a number.
*/ */
public abstract class NumberInterface { public abstract class NumberInterface implements Comparable<NumberInterface> {
/** /**
* Check if the thread was interrupted and * Check if the thread was interrupted and
@@ -156,14 +158,6 @@ public abstract class NumberInterface {
return intPowInternal(exponent); return intPowInternal(exponent);
} }
/**
* Compares this number to another.
*
* @param number the number to compare to.
* @return same as Integer.compare();
*/
public abstract int compareTo(NumberInterface number);
/** /**
* Same as Math.signum(). * Same as Math.signum().
* *

View File

@@ -154,19 +154,20 @@ public class ShuntingYardParser implements Parser<Match<TokenType>>, PluginListe
return new VariableNode(match.getContent()); return new VariableNode(match.getContent());
} else if (matchType == TokenType.FUNCTION || matchType == TokenType.TREE_VALUE_FUNCTION) { } else if (matchType == TokenType.FUNCTION || matchType == TokenType.TREE_VALUE_FUNCTION) {
String functionName = match.getContent(); String functionName = match.getContent();
CallNode node; List<TreeNode> children = new ArrayList<>();
if (matchType == TokenType.FUNCTION) {
node = new FunctionNode(functionName);
} else {
node = new TreeValueFunctionNode(functionName);
}
while (!matches.isEmpty() && matches.get(0).getType() != TokenType.INTERNAL_FUNCTION_END) { while (!matches.isEmpty() && matches.get(0).getType() != TokenType.INTERNAL_FUNCTION_END) {
TreeNode argument = constructRecursive(matches); TreeNode argument = constructRecursive(matches);
if (argument == null) return null; if (argument == null) return null;
node.getChildren().add(0, argument); children.add(0, argument);
} }
if (matches.isEmpty()) return null; if (matches.isEmpty()) return null;
matches.remove(0); matches.remove(0);
CallNode node;
if (matchType == TokenType.FUNCTION) {
node = new FunctionNode(functionName, children);
} else {
node = new TreeValueFunctionNode(functionName, children);
}
return node; return node;
} }
return null; return null;

View File

@@ -141,6 +141,7 @@ public class PluginManager {
registeredNumberImplementations.put(name, implementation); registeredNumberImplementations.put(name, implementation);
interfaceImplementationNames.put(implementation.getImplementation(), name); interfaceImplementationNames.put(implementation.getImplementation(), name);
interfaceImplementations.put(implementation.getImplementation(), implementation); interfaceImplementations.put(implementation.getImplementation(), implementation);
cachedPi.put(implementation.getImplementation(), implementation.instanceForPi());
} }
/** /**
@@ -218,10 +219,6 @@ public class PluginManager {
break; break;
} }
} }
if (toReturn == null) {
toReturn = new Documentation(name, "", "", "", type);
registerDocumentation(toReturn);
}
return toReturn; return toReturn;
} }
@@ -252,14 +249,7 @@ public class PluginManager {
* @return pi * @return pi
*/ */
public NumberInterface piFor(Class<? extends NumberInterface> forClass) { public NumberInterface piFor(Class<? extends NumberInterface> forClass) {
if (cachedPi.containsKey(forClass)) return cachedPi.get(forClass); return cachedPi.get(forClass);
NumberImplementation implementation = interfaceImplementationFor(forClass);
NumberInterface generatedPi = null;
if (implementation != null) {
generatedPi = implementation.instanceForPi();
}
cachedPi.put(forClass, generatedPi);
return generatedPi;
} }
/** /**

View File

@@ -29,8 +29,7 @@ public class StandardPlugin extends Plugin {
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) {
String assignTo = ((VariableNode) params[0]).getVariable(); String assignTo = ((VariableNode) params[0]).getVariable();
NumberInterface value = params[1].reduce(context.getReducer()); NumberInterface value = params[1].reduce(context.getInheritedReducer());
if(value == null) throw new EvaluationException();
context.setVariable(assignTo, value); context.setVariable(assignTo, value);
return value; return value;
} }
@@ -48,9 +47,7 @@ public class StandardPlugin extends Plugin {
public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) {
String assignTo = ((VariableNode) params[0]).getVariable(); String assignTo = ((VariableNode) params[0]).getVariable();
context.setDefinition(assignTo, params[1]); context.setDefinition(assignTo, params[1]);
NumberInterface value = params[1].reduce(context.getReducer()); return params[1].reduce(context.getInheritedReducer());
if(value == null) throw new EvaluationException();
return value;
} }
}; };
/** /**
@@ -696,8 +693,7 @@ public class StandardPlugin extends Plugin {
* @param n non-negative integer. * @param n non-negative integer.
* @return a number of numClass with value n factorial. * @return a number of numClass with value n factorial.
*/ */
public static NumberInterface factorial(NumberImplementation implementation, int n) { synchronized public static NumberInterface factorial(NumberImplementation implementation, int n) {
if (!FACTORIAL_LISTS.containsKey(implementation)) { if (!FACTORIAL_LISTS.containsKey(implementation)) {
FACTORIAL_LISTS.put(implementation, new ArrayList<>()); FACTORIAL_LISTS.put(implementation, new ArrayList<>());
FACTORIAL_LISTS.get(implementation).add(implementation.instanceForString("1")); FACTORIAL_LISTS.get(implementation).add(implementation.instanceForString("1"));

View File

@@ -68,6 +68,7 @@ class Abacus(val configuration: Configuration) {
pluginManager.reload() pluginManager.reload()
with(mutableContext) { with(mutableContext) {
numberImplementation = pluginManager.numberImplementationFor(configuration.numberImplementation) numberImplementation = pluginManager.numberImplementationFor(configuration.numberImplementation)
?: StandardPlugin.IMPLEMENTATION_NAIVE
clearVariables() clearVariables()
clearDefinitions() clearDefinitions()
} }

View File

@@ -1,7 +1,7 @@
package org.nwapw.abacus.function.applicable package org.nwapw.abacus.function.applicable
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.function.DomainException import org.nwapw.abacus.exception.DomainException
/** /**
* A class that can be applied to arguments. * A class that can be applied to arguments.
@@ -36,7 +36,8 @@ interface Applicable<in T : Any, out O : Any> {
* @return the result of the operation, or null if parameters do not match. * @return the result of the operation, or null if parameters do not match.
*/ */
fun apply(context: MutableEvaluationContext, vararg params: T): O { fun apply(context: MutableEvaluationContext, vararg params: T): O {
if (!matchesParams(context, params)) throw DomainException() if (!matchesParams(context, params))
throw DomainException("parameters do not match function requirements.")
return applyInternal(context, params) return applyInternal(context, params)
} }

View File

@@ -37,21 +37,6 @@ class PromotionManager(val abacus: Abacus) : PluginListener {
return null return null
} }
/**
* If a path between the given implementations has already been computed, uses
* the already calculated path. Otherwise, calls [computePathBetween] to compute a new
* path.
*
* @param from the implementation to start from.
* @param to the implementation to get to.
* @return the resulting promotion path, or null if it is not found
*/
fun getPathBetween(from: NumberImplementation, to: NumberImplementation): PromotionPath? {
return computePaths.computeIfAbsent(from to to, {
computePathBetween(it.first, it.second)
})
}
/** /**
* Promote all the numbers in the list to the same number implementation, to ensure * Promote all the numbers in the list to the same number implementation, to ensure
* they can be used with each other. Finds the highest priority implementation * they can be used with each other. Finds the highest priority implementation
@@ -66,16 +51,26 @@ class PromotionManager(val abacus: Abacus) : PluginListener {
val highestPriority = implementations.sortedBy { it.priority }.last() val highestPriority = implementations.sortedBy { it.priority }.last()
return PromotionResult(items = numbers.map { return PromotionResult(items = numbers.map {
if(it.javaClass == highestPriority.implementation) it if(it.javaClass == highestPriority.implementation) it
else getPathBetween(pluginManager.interfaceImplementationFor(it.javaClass), highestPriority) else computePaths[pluginManager.interfaceImplementationFor(it.javaClass) to highestPriority]
?.promote(it) ?: return null ?.promote(it) ?: return null
}.toTypedArray(), promotedTo = highestPriority) }.toTypedArray(), promotedTo = highestPriority)
} }
override fun onLoad(manager: PluginManager?) { override fun onLoad(manager: PluginManager) {
val implementations = manager.allNumberImplementations.map { manager.numberImplementationFor(it) }
for((index, value) in implementations.withIndex()){
for(i in index until implementations.size){
val other = implementations[i]
val promoteFrom = if(other.priority > value.priority) value else other
val promoteTo = if(other.priority > value.priority) other else value
val path = computePathBetween(promoteFrom, promoteTo)
computePaths.put(promoteFrom to promoteTo, path)
}
}
} }
override fun onUnload(manager: PluginManager?) { override fun onUnload(manager: PluginManager) {
computePaths.clear() computePaths.clear()
} }

View File

@@ -11,10 +11,10 @@ package org.nwapw.abacus.tree
* @param left the left node. * @param left the left node.
* @param right the right node. * @param right the right node.
*/ */
abstract class BinaryNode(val operation: String, val left: TreeNode? = null, val right: TreeNode?) : TreeNode() { abstract class BinaryNode(val operation: String, val left: TreeNode, val right: TreeNode) : TreeNode() {
override fun toString(): String { override fun toString(): String {
return "(" + (left?.toString() ?: "null") + operation + (right?.toString() ?: "null") + ")" return "(" + left.toString() + operation + right.toString() + ")"
} }
} }

View File

@@ -7,13 +7,9 @@ package org.nwapw.abacus.tree
* to extend this functionality. * to extend this functionality.
* *
* @param callTo the name of the things being called. * @param callTo the name of the things being called.
* @param children the children of this node.
*/ */
abstract class CallNode(val callTo: String) : TreeNode() { abstract class CallNode(val callTo: String, val children: List<TreeNode>) : TreeNode() {
/**
* The list of children this node has.
*/
val children: MutableList<TreeNode> = mutableListOf()
override fun toString(): String { override fun toString(): String {
val buffer = StringBuffer() val buffer = StringBuffer()

View File

@@ -3,4 +3,4 @@ package org.nwapw.abacus.tree
import org.nwapw.abacus.context.MutableEvaluationContext import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
data class EvaluationResult(val value: NumberInterface?, val resultingContext: MutableEvaluationContext) data class EvaluationResult(val value: NumberInterface, val resultingContext: MutableEvaluationContext)

View File

@@ -8,10 +8,10 @@ package org.nwapw.abacus.tree
* *
* @param function the function string. * @param function the function string.
*/ */
class FunctionNode(function: String) : CallNode(function) { class FunctionNode(function: String, children: List<TreeNode>) : CallNode(function, children) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
val children = Array<Any>(children.size, { children[it].reduce(reducer) ?: return null; }) val children = Array<Any>(children.size, { children[it].reduce(reducer) })
return reducer.reduceNode(this, *children) return reducer.reduceNode(this, *children)
} }

View File

@@ -10,12 +10,12 @@ package org.nwapw.abacus.tree
* @param left the left child of this node. * @param left the left child of this node.
* @param right the right child of this node. * @param right the right child of this node.
*/ */
class NumberBinaryNode(operation: String, left: TreeNode?, right: TreeNode?) class NumberBinaryNode(operation: String, left: TreeNode, right: TreeNode)
: BinaryNode(operation, left, right) { : BinaryNode(operation, left, right) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
val left = left?.reduce(reducer) ?: return null val left = left.reduce(reducer)
val right = right?.reduce(reducer) ?: return null val right = right.reduce(reducer)
return reducer.reduceNode(this, left, right) return reducer.reduceNode(this, left, right)
} }

View File

@@ -10,7 +10,7 @@ package org.nwapw.abacus.tree
*/ */
class NumberNode(val number: String) : TreeNode() { class NumberNode(val number: String) : TreeNode() {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this) return reducer.reduceNode(this)
} }

View File

@@ -2,6 +2,7 @@ package org.nwapw.abacus.tree
import org.nwapw.abacus.Abacus import org.nwapw.abacus.Abacus
import org.nwapw.abacus.context.EvaluationContext import org.nwapw.abacus.context.EvaluationContext
import org.nwapw.abacus.exception.EvaluationException
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
class NumberReducer(val abacus: Abacus, context: EvaluationContext) : Reducer<NumberInterface> { class NumberReducer(val abacus: Abacus, context: EvaluationContext) : Reducer<NumberInterface> {
@@ -12,18 +13,19 @@ class NumberReducer(val abacus: Abacus, context: EvaluationContext) : Reducer<Nu
this.context.reducer = this this.context.reducer = this
} }
override fun reduceNode(treeNode: TreeNode, vararg children: Any): NumberInterface? { override fun reduceNode(treeNode: TreeNode, vararg children: Any): NumberInterface {
val promotionManager = abacus.promotionManager val promotionManager = abacus.promotionManager
return when(treeNode){ return when(treeNode){
is NumberNode -> { is NumberNode -> {
context.inheritedNumberImplementation?.instanceForString(treeNode.number) context.inheritedNumberImplementation?.instanceForString(treeNode.number)
?: throw EvaluationException("no number implementation selected.")
} }
is VariableNode -> { is VariableNode -> {
val variable = context.getVariable(treeNode.variable) val variable = context.getVariable(treeNode.variable)
if(variable != null) return variable if(variable != null) return variable
val definition = context.getDefinition(treeNode.variable) val definition = context.getDefinition(treeNode.variable)
if(definition != null) return definition.reduce(this) if(definition != null) return definition.reduce(this)
null throw EvaluationException("variable is not defined.")
} }
is NumberUnaryNode -> { is NumberUnaryNode -> {
val child = children[0] as NumberInterface val child = children[0] as NumberInterface
@@ -34,29 +36,31 @@ class NumberReducer(val abacus: Abacus, context: EvaluationContext) : Reducer<Nu
is NumberBinaryNode -> { is NumberBinaryNode -> {
val left = children[0] as NumberInterface val left = children[0] as NumberInterface
val right = children[1] as NumberInterface val right = children[1] as NumberInterface
val promotionResult = promotionManager.promote(left, right) ?: return null val promotionResult = promotionManager.promote(left, right) ?:
throw EvaluationException("promotion failed.")
context.numberImplementation = promotionResult.promotedTo context.numberImplementation = promotionResult.promotedTo
abacus.pluginManager.operatorFor(treeNode.operation).apply(context, *promotionResult.items) abacus.pluginManager.operatorFor(treeNode.operation).apply(context, *promotionResult.items)
} }
is FunctionNode -> { is FunctionNode -> {
val promotionResult = promotionManager val promotionResult = promotionManager
.promote(*children.map { it as NumberInterface }.toTypedArray()) ?: return null .promote(*children.map { it as NumberInterface }.toTypedArray()) ?:
throw EvaluationException("promotion failed.")
context.numberImplementation = promotionResult.promotedTo context.numberImplementation = promotionResult.promotedTo
abacus.pluginManager.functionFor(treeNode.callTo).apply(context, *promotionResult.items) abacus.pluginManager.functionFor(treeNode.callTo).apply(context, *promotionResult.items)
} }
is TreeValueUnaryNode -> { is TreeValueUnaryNode -> {
abacus.pluginManager.treeValueOperatorFor(treeNode.operation) abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
.apply(context, treeNode.applyTo ?: return null) .apply(context, treeNode.applyTo)
} }
is TreeValueBinaryNode -> { is TreeValueBinaryNode -> {
abacus.pluginManager.treeValueOperatorFor(treeNode.operation) abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
.apply(context, treeNode.left ?: return null, treeNode.right ?: return null) .apply(context, treeNode.left, treeNode.right)
} }
is TreeValueFunctionNode -> { is TreeValueFunctionNode -> {
abacus.pluginManager.treeValueFunctionFor(treeNode.callTo) abacus.pluginManager.treeValueFunctionFor(treeNode.callTo)
.apply(context, *treeNode.children.toTypedArray()) .apply(context, *treeNode.children.toTypedArray())
} }
else -> null else -> throw EvaluationException("unrecognized tree node.")
} }
} }

View File

@@ -8,11 +8,11 @@ package org.nwapw.abacus.tree
* @param operation the operation this node performs. * @param operation the operation this node performs.
* @param child the child this node should be applied to. * @param child the child this node should be applied to.
*/ */
class NumberUnaryNode(operation: String, child: TreeNode?) class NumberUnaryNode(operation: String, child: TreeNode)
: UnaryNode(operation, child) { : UnaryNode(operation, child) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
val child = applyTo?.reduce(reducer) ?: return null val child = applyTo.reduce(reducer)
return reducer.reduceNode(this, child) return reducer.reduceNode(this, child)
} }

View File

@@ -14,6 +14,6 @@ interface Reducer<out T> {
* @param treeNode the tree node to reduce. * @param treeNode the tree node to reduce.
* @param children the list of children, of type T. * @param children the list of children, of type T.
*/ */
fun reduceNode(treeNode: TreeNode, vararg children: Any): T? fun reduceNode(treeNode: TreeNode, vararg children: Any): T
} }

View File

@@ -5,6 +5,6 @@ package org.nwapw.abacus.tree
*/ */
abstract class TreeNode { abstract class TreeNode {
abstract fun <T : Any> reduce(reducer: Reducer<T>): T? abstract fun <T : Any> reduce(reducer: Reducer<T>): T
} }

View File

@@ -11,10 +11,10 @@ package org.nwapw.abacus.tree
* @param left the left child of this node. * @param left the left child of this node.
* @param right the right child of this node. * @param right the right child of this node.
*/ */
class TreeValueBinaryNode(operation: String, left: TreeNode?, right: TreeNode?) class TreeValueBinaryNode(operation: String, left: TreeNode, right: TreeNode)
: BinaryNode(operation, left, right) { : BinaryNode(operation, left, right) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this) return reducer.reduceNode(this)
} }

View File

@@ -7,9 +7,9 @@ package org.nwapw.abacus.tree
* is mostly to help the reducer. Besides that, this class also does not * is mostly to help the reducer. Besides that, this class also does not
* even attempt to reduce its children. * even attempt to reduce its children.
*/ */
class TreeValueFunctionNode(name: String) : CallNode(name) { class TreeValueFunctionNode(name: String, children: List<TreeNode>) : CallNode(name, children) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this) return reducer.reduceNode(this)
} }

View File

@@ -9,11 +9,11 @@ package org.nwapw.abacus.tree
* @param operation the operation this node performs. * @param operation the operation this node performs.
* @param child the node the operation should be applied to. * @param child the node the operation should be applied to.
*/ */
class TreeValueUnaryNode(operation: String, child: TreeNode?) class TreeValueUnaryNode(operation: String, child: TreeNode)
: UnaryNode(operation, child) { : UnaryNode(operation, child) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this); return reducer.reduceNode(this)
} }
} }

View File

@@ -9,10 +9,10 @@ package org.nwapw.abacus.tree
* @param operation the operation applied to the given node. * @param operation the operation applied to the given node.
* @param applyTo the node to which the operation will be applied. * @param applyTo the node to which the operation will be applied.
*/ */
abstract class UnaryNode(val operation: String, val applyTo: TreeNode? = null) : TreeNode() { abstract class UnaryNode(val operation: String, val applyTo: TreeNode) : TreeNode() {
override fun toString(): String { override fun toString(): String {
return "(" + (applyTo?.toString() ?: "null") + ")" + operation return "(" + applyTo.toString() + ")" + operation
} }
} }

View File

@@ -10,7 +10,7 @@ package org.nwapw.abacus.tree
*/ */
class VariableNode(val variable: String) : TreeNode() { class VariableNode(val variable: String) : TreeNode() {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this) return reducer.reduceNode(this)
} }

View File

@@ -5,7 +5,7 @@ import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration; import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.function.DomainException; import org.nwapw.abacus.exception.DomainException;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.plugin.StandardPlugin; import org.nwapw.abacus.plugin.StandardPlugin;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.TreeNode;

View File

@@ -12,9 +12,12 @@ import javafx.util.Callback;
import javafx.util.StringConverter; import javafx.util.StringConverter;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.config.Configuration; import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.exception.AbacusException;
import org.nwapw.abacus.exception.ComputationInterruptedException;
import org.nwapw.abacus.function.Documentation; import org.nwapw.abacus.function.Documentation;
import org.nwapw.abacus.function.DocumentationType; import org.nwapw.abacus.function.DocumentationType;
import org.nwapw.abacus.function.DomainException; import org.nwapw.abacus.exception.DomainException;
import org.nwapw.abacus.exception.EvaluationException;
import org.nwapw.abacus.number.*; import org.nwapw.abacus.number.*;
import org.nwapw.abacus.plugin.ClassFinder; import org.nwapw.abacus.plugin.ClassFinder;
import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginListener;
@@ -147,16 +150,11 @@ public class AbacusController implements PluginListener {
} }
EvaluationResult result = abacus.evaluateTree(constructedTree); EvaluationResult result = abacus.evaluateTree(constructedTree);
NumberInterface evaluatedNumber = result.getValue(); NumberInterface evaluatedNumber = result.getValue();
if (evaluatedNumber == null) {
return ERR_EVAL;
}
String resultingString = evaluatedNumber.toString(); String resultingString = evaluatedNumber.toString();
historyData.add(new HistoryModel(inputField.getText(), constructedTree.toString(), resultingString)); historyData.add(new HistoryModel(inputField.getText(), constructedTree.toString(), resultingString));
abacus.applyToContext(result.getResultingContext()); abacus.applyToContext(result.getResultingContext());
return resultingString; return resultingString;
} catch (ComputationInterruptedException exception) { } catch (AbacusException exception) {
return ERR_STOP;
} catch (DomainException exception) {
return exception.getMessage(); return exception.getMessage();
} catch (RuntimeException exception) { } catch (RuntimeException exception) {
exception.printStackTrace(); exception.printStackTrace();
@@ -363,7 +361,12 @@ public class AbacusController implements PluginListener {
enabledPlugins.add(plugin); enabledPlugins.add(plugin);
} }
PluginManager pluginManager = abacus.getPluginManager(); PluginManager pluginManager = abacus.getPluginManager();
functionList.addAll(manager.getAllFunctions().stream().map(name -> pluginManager.documentationFor(name, DocumentationType.FUNCTION)) functionList.addAll(manager.getAllFunctions().stream().map(name -> {
Documentation documentationInstance = pluginManager.documentationFor(name, DocumentationType.FUNCTION);
if(documentationInstance == null)
documentationInstance = new Documentation(name, "", "", "", DocumentationType.FUNCTION);
return documentationInstance;
})
.collect(Collectors.toCollection(ArrayList::new))); .collect(Collectors.toCollection(ArrayList::new)));
functionList.addAll(manager.getAllTreeValueFunctions().stream().map(name -> pluginManager.documentationFor(name, DocumentationType.TREE_VALUE_FUNCTION)) functionList.addAll(manager.getAllTreeValueFunctions().stream().map(name -> pluginManager.documentationFor(name, DocumentationType.TREE_VALUE_FUNCTION))
.collect(Collectors.toCollection(ArrayList::new))); .collect(Collectors.toCollection(ArrayList::new)));