1
0
Mirror von https://github.com/DanilaFe/abacus synchronisiert 2026-01-25 16:15:19 +00:00

Commits vergleichen

..

32 Commits

Autor SHA1 Nachricht Datum
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
00f8475044 Merge branch 'master' into context 2017-09-11 19:32:42 -07:00
f0efae21be Merge pull request #19 from DanilaFe/fix-loading
Fix exception during startup if configuration is missing.
2017-09-11 19:32:17 -07:00
1667edc72b Merge branch 'master' into context 2017-09-11 19:14:07 -07:00
f2ac7b109a Remove old imports. 2017-09-10 18:19:30 -07:00
67d240b8f6 Remove the unused variable database class. 2017-09-10 17:57:43 -07:00
059226a4d4 Rename the context class. 2017-09-06 22:54:21 -07:00
ef1890f24d Switch Abacus to returning an EvaluationResult with the context. 2017-09-06 22:22:15 -07:00
782669a32b Change button to "Save". 2017-09-06 22:04:28 -07:00
924849bd8b Make reloads go through the Abacus core. 2017-09-06 22:03:54 -07:00
91986112a1 Switch all applicables to use the Context. 2017-09-06 21:43:07 -07:00
58fea9c52b Move the files into the correct source directory. 2017-09-06 20:48:43 -07:00
863be5bcfc Rewrite number reducer in Kotlin. 2017-09-06 20:39:38 -07:00
f0e38fed87 Add the contexts and delegates for them. 2017-09-06 20:36:25 -07:00
41 geänderte Dateien mit 595 neuen und 457 gelöschten Zeilen

4
.gitignore vendored
Datei anzeigen

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

Datei anzeigen

@@ -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)));
}
}

Datei anzeigen

@@ -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", "");
} }
} }

Datei anzeigen

@@ -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("");
} }
} }

Datei anzeigen

@@ -0,0 +1,25 @@
package org.nwapw.abacus.exception;
/**
* 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
* of Applicable.
*/
public class EvaluationException extends AbacusException {
/**
* Creates a new EvaluationException with the default string.
*/
public EvaluationException() {
this("");
}
/**
* Creates a new EvaluationError with the given message string.
* @param message the message string.
*/
public EvaluationException(String message) {
super("Evaluation error", message);
}
}

Datei anzeigen

@@ -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().
* *

Datei anzeigen

@@ -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;

Datei anzeigen

@@ -2,7 +2,6 @@ package org.nwapw.abacus.plugin;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.function.*;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.variables.VariableDatabase;
/** /**
* A plugin class that can be externally implemented and loaded via the * A plugin class that can be externally implemented and loaded via the
@@ -220,12 +219,4 @@ public abstract class Plugin {
*/ */
public abstract void onDisable(); public abstract void onDisable();
/**
* Get the variable database.
* @return the variable database.
*/
public final VariableDatabase getVariableDatabase(){
return manager.getVariableDatabase();
}
} }

Datei anzeigen

@@ -3,7 +3,6 @@ package org.nwapw.abacus.plugin;
import org.nwapw.abacus.Abacus; import org.nwapw.abacus.Abacus;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.function.*;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.variables.VariableDatabase;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.util.HashMap; import java.util.HashMap;
@@ -142,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());
} }
/** /**
@@ -219,10 +219,6 @@ public class PluginManager {
break; break;
} }
} }
if (toReturn == null) {
toReturn = new Documentation(name, "", "", "", type);
registerDocumentation(toReturn);
}
return toReturn; return toReturn;
} }
@@ -253,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;
} }
/** /**
@@ -423,11 +412,4 @@ public class PluginManager {
return loadedPluginClasses; return loadedPluginClasses;
} }
/**
* Gets the variable database.
* @return the database.
*/
public VariableDatabase getVariableDatabase(){
return abacus.getVariableDatabase();
}
} }

Datei anzeigen

@@ -1,12 +1,10 @@
package org.nwapw.abacus.plugin; package org.nwapw.abacus.plugin;
import org.jetbrains.annotations.NotNull; import org.nwapw.abacus.context.MutableEvaluationContext;
import org.jetbrains.annotations.Nullable;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.function.*;
import org.nwapw.abacus.number.NaiveNumber; import org.nwapw.abacus.number.NaiveNumber;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.number.PreciseNumber; import org.nwapw.abacus.number.PreciseNumber;
import org.nwapw.abacus.tree.Reducer;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.TreeNode;
import org.nwapw.abacus.tree.VariableNode; import org.nwapw.abacus.tree.VariableNode;
@@ -24,15 +22,15 @@ public class StandardPlugin extends Plugin {
*/ */
public final TreeValueOperator opSet = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { public final TreeValueOperator opSet = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, TreeNode[] params) { public boolean matchesParams(MutableEvaluationContext context, TreeNode[] params) {
return params.length == 2 && params[0] instanceof VariableNode; return params.length == 2 && params[0] instanceof VariableNode;
} }
@Override @Override
public NumberInterface applyWithReducerInternal(NumberImplementation implementation, Reducer<? extends NumberInterface> reducer, 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(reducer); NumberInterface value = params[1].reduce(context.getInheritedReducer());
getVariableDatabase().getVariables().put(assignTo, value); context.setVariable(assignTo, value);
return value; return value;
} }
}; };
@@ -41,16 +39,15 @@ public class StandardPlugin extends Plugin {
*/ */
public final TreeValueOperator opDefine = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { public final TreeValueOperator opDefine = new TreeValueOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, TreeNode[] params) { public boolean matchesParams(MutableEvaluationContext context, TreeNode[] params) {
return params.length == 2 && params[0] instanceof VariableNode; return params.length == 2 && params[0] instanceof VariableNode;
} }
@Nullable
@Override @Override
public NumberInterface applyWithReducerInternal(NumberImplementation implementation, Reducer<? extends NumberInterface> reducer, TreeNode[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) {
String assignTo = ((VariableNode) params[0]).getVariable(); String assignTo = ((VariableNode) params[0]).getVariable();
getVariableDatabase().getDefinitions().put(assignTo, params[1]); context.setDefinition(assignTo, params[1]);
return params[1].reduce(reducer); return params[1].reduce(context.getInheritedReducer());
} }
}; };
/** /**
@@ -58,12 +55,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_ADD = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_ADD = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return params[0].add(params[1]); return params[0].add(params[1]);
} }
}; };
@@ -72,12 +69,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_SUBTRACT = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_SUBTRACT = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return params[0].subtract(params[1]); return params[0].subtract(params[1]);
} }
@@ -87,12 +84,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_NEGATE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) { public static final NumberOperator OP_NEGATE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.UNARY_PREFIX, 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return params[0].negate(); return params[0].negate();
} }
}; };
@@ -101,12 +98,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_MULTIPLY = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { public static final NumberOperator OP_MULTIPLY = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return params[0].multiply(params[1]); return params[0].multiply(params[1]);
} }
}; };
@@ -135,7 +132,8 @@ public class StandardPlugin extends Plugin {
@Override @Override
public NumberInterface instanceForPi() { public NumberInterface instanceForPi() {
NumberInterface C = FUNCTION_SQRT.apply(this, new PreciseNumber("10005")).multiply(new PreciseNumber("426880")); MutableEvaluationContext dummyContext = new MutableEvaluationContext(null, this, null);
NumberInterface C = FUNCTION_SQRT.apply(dummyContext, new PreciseNumber("10005")).multiply(new PreciseNumber("426880"));
NumberInterface M = PreciseNumber.ONE; NumberInterface M = PreciseNumber.ONE;
NumberInterface L = new PreciseNumber("13591409"); NumberInterface L = new PreciseNumber("13591409");
NumberInterface X = M; NumberInterface X = M;
@@ -165,12 +163,12 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_DIVIDE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) { public static final NumberOperator OP_DIVIDE = new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, 1) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 2 && params[1].compareTo(implementation.instanceForString(Integer.toString(0))) != 0; return params.length == 2 && params[1].compareTo(context.getInheritedNumberImplementation().instanceForString(Integer.toString(0))) != 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return params[0].divide(params[1]); return params[0].divide(params[1]);
} }
}; };
@@ -180,14 +178,15 @@ public class StandardPlugin extends Plugin {
public static final NumberOperator OP_FACTORIAL = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0) { public static final NumberOperator OP_FACTORIAL = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.UNARY_POSTFIX, 0) {
//private HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> storedList = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>(); //private HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>> storedList = new HashMap<Class<? extends NumberInterface>, ArrayList<NumberInterface>>();
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1 return params.length == 1
&& params[0].fractionalPart().compareTo(implementation.instanceForString("0")) == 0 && params[0].fractionalPart().compareTo(context.getInheritedNumberImplementation().instanceForString("0")) == 0
&& params[0].signum() >= 0; && params[0].signum() >= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
if (params[0].signum() == 0) { if (params[0].signum() == 0) {
return implementation.instanceForString("1"); return implementation.instanceForString("1");
} }
@@ -211,13 +210,14 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_NPR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_NPR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 2 && params[0].fractionalPart().signum() == 0 return params.length == 2 && params[0].fractionalPart().signum() == 0
&& params[1].fractionalPart().signum() == 0; && params[1].fractionalPart().signum() == 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
if (params[0].compareTo(params[1]) < 0 || if (params[0].compareTo(params[1]) < 0 ||
params[0].signum() < 0 || params[0].signum() < 0 ||
(params[0].signum() == 0 && params[1].signum() != 0)) return implementation.instanceForString("0"); (params[0].signum() == 0 && params[1].signum() != 0)) return implementation.instanceForString("0");
@@ -241,14 +241,14 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) { public static final NumberOperator OP_NCR = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 2 && params[0].fractionalPart().signum() == 0 return params.length == 2 && params[0].fractionalPart().signum() == 0
&& params[1].fractionalPart().signum() == 0; && params[1].fractionalPart().signum() == 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return OP_NPR.apply(implementation, params).divide(OP_FACTORIAL.apply(implementation, params[1])); return OP_NPR.apply(context, params).divide(OP_FACTORIAL.apply(context, params[1]));
} }
}; };
/** /**
@@ -256,13 +256,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_ABS = new NumberFunction() { public static final NumberFunction FUNCTION_ABS = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return params[0].multiply(implementation.instanceForString(Integer.toString(params[0].signum()))); return params[0].multiply(context.getInheritedNumberImplementation().instanceForString(Integer.toString(params[0].signum())));
} }
}; };
/** /**
@@ -270,16 +270,17 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_LN = new NumberFunction() { public static final NumberFunction FUNCTION_LN = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && params[0].compareTo(implementation.instanceForString("0")) > 0; return params.length == 1 && params[0].compareTo(context.getInheritedNumberImplementation().instanceForString("0")) > 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface param = params[0]; NumberInterface param = params[0];
NumberInterface one = implementation.instanceForString("1"); NumberInterface one = implementation.instanceForString("1");
int powersOf2 = 0; int powersOf2 = 0;
while (FUNCTION_ABS.apply(implementation, param.subtract(one)).compareTo(implementation.instanceForString(".1")) >= 0) { while (FUNCTION_ABS.apply(context, param.subtract(one)).compareTo(implementation.instanceForString(".1")) >= 0) {
if (param.subtract(one).signum() == 1) { if (param.subtract(one).signum() == 1) {
param = param.divide(implementation.instanceForString("2")); param = param.divide(implementation.instanceForString("2"));
powersOf2++; powersOf2++;
@@ -296,7 +297,7 @@ public class StandardPlugin extends Plugin {
} }
} }
} }
return getLog2(implementation, param).multiply(implementation.instanceForString(Integer.toString(powersOf2))).add(getLogPartialSum(implementation, param)); return getLog2(context.getInheritedNumberImplementation(), param).multiply(implementation.instanceForString(Integer.toString(powersOf2))).add(getLogPartialSum(context, param));
} }
/** /**
@@ -305,13 +306,13 @@ public class StandardPlugin extends Plugin {
* @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.) * @param x value at which the series is evaluated. 0 < x < 2. (x=2 is convergent but impractical.)
* @return the partial sum. * @return the partial sum.
*/ */
private NumberInterface getLogPartialSum(NumberImplementation implementation, NumberInterface x) { private NumberInterface getLogPartialSum(MutableEvaluationContext context, NumberInterface x) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface maxError = x.getMaxError(); NumberInterface maxError = x.getMaxError();
x = x.subtract(implementation.instanceForString("1")); //Terms used are for log(x+1). x = x.subtract(implementation.instanceForString("1")); //Terms used are for log(x+1).
NumberInterface currentNumerator = x, currentTerm = x, sum = x; NumberInterface currentNumerator = x, currentTerm = x, sum = x;
int n = 1; int n = 1;
while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(maxError) > 0) { while (FUNCTION_ABS.apply(context, currentTerm).compareTo(maxError) > 0) {
n++; n++;
currentNumerator = currentNumerator.multiply(x).negate(); currentNumerator = currentNumerator.multiply(x).negate();
currentTerm = currentNumerator.divide(implementation.instanceForString(Integer.toString(n))); currentTerm = currentNumerator.divide(implementation.instanceForString(Integer.toString(n)));
@@ -350,13 +351,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() { public static final NumberFunction FUNCTION_RAND_INT = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return implementation.instanceForString(Long.toString(Math.round(Math.random() * params[0].floor().intValue()))); return context.getInheritedNumberImplementation().instanceForString(Long.toString(Math.round(Math.random() * params[0].floor().intValue())));
} }
}; };
/** /**
@@ -364,8 +365,8 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) { public static final NumberOperator OP_CARET = new NumberOperator(OperatorAssociativity.RIGHT, OperatorType.BINARY_INFIX, 2) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
NumberInterface zero = implementation.instanceForString("0"); NumberInterface zero = context.getInheritedNumberImplementation().instanceForString("0");
return params.length == 2 return params.length == 2
&& !(params[0].compareTo(zero) == 0 && !(params[0].compareTo(zero) == 0
&& params[1].compareTo(zero) == 0) && params[1].compareTo(zero) == 0)
@@ -373,7 +374,8 @@ public class StandardPlugin extends Plugin {
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface zero = implementation.instanceForString("0"); NumberInterface zero = implementation.instanceForString("0");
if (params[0].compareTo(zero) == 0) if (params[0].compareTo(zero) == 0)
return zero; return zero;
@@ -381,12 +383,12 @@ public class StandardPlugin extends Plugin {
return implementation.instanceForString("1"); return implementation.instanceForString("1");
//Detect integer bases: //Detect integer bases:
if (params[0].fractionalPart().compareTo(implementation.instanceForString("0")) == 0 if (params[0].fractionalPart().compareTo(implementation.instanceForString("0")) == 0
&& FUNCTION_ABS.apply(implementation, params[1]).compareTo(implementation.instanceForString(Integer.toString(Integer.MAX_VALUE))) < 0 && FUNCTION_ABS.apply(context, params[1]).compareTo(implementation.instanceForString(Integer.toString(Integer.MAX_VALUE))) < 0
&& FUNCTION_ABS.apply(implementation, params[1]).compareTo(implementation.instanceForString("1")) >= 0) { && FUNCTION_ABS.apply(context, params[1]).compareTo(implementation.instanceForString("1")) >= 0) {
NumberInterface[] newParams = {params[0], params[1].fractionalPart()}; NumberInterface[] newParams = {params[0], params[1].fractionalPart()};
return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(implementation, newParams)); return params[0].intPow(params[1].floor().intValue()).multiply(applyInternal(context, newParams));
} }
return FUNCTION_EXP.apply(implementation, FUNCTION_LN.apply(implementation, FUNCTION_ABS.apply(implementation, params[0])).multiply(params[1])); return FUNCTION_EXP.apply(context, FUNCTION_LN.apply(context, FUNCTION_ABS.apply(context, params[0])).multiply(params[1]));
} }
}; };
/** /**
@@ -394,13 +396,13 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_SQRT = new NumberFunction() { public static final NumberFunction FUNCTION_SQRT = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return OP_CARET.apply(implementation, params[0], implementation.instanceForString(".5")); return OP_CARET.apply(context, params[0], context.getInheritedNumberImplementation().instanceForString(".5"));
} }
}; };
private static final HashMap<NumberImplementation, ArrayList<NumberInterface>> FACTORIAL_LISTS = new HashMap<>(); private static final HashMap<NumberImplementation, ArrayList<NumberInterface>> FACTORIAL_LISTS = new HashMap<>();
@@ -409,17 +411,18 @@ public class StandardPlugin extends Plugin {
*/ */
public static final NumberFunction FUNCTION_EXP = new NumberFunction() { public static final NumberFunction FUNCTION_EXP = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface maxError = params[0].getMaxError(); NumberInterface maxError = params[0].getMaxError();
int n = 0; int n = 0;
if (params[0].signum() < 0) { if (params[0].signum() < 0) {
NumberInterface[] negatedParams = {params[0].negate()}; NumberInterface[] negatedParams = {params[0].negate()};
return implementation.instanceForString("1").divide(applyInternal(implementation, negatedParams)); return implementation.instanceForString("1").divide(applyInternal(context, negatedParams));
} else { } else {
//We need n such that x^(n+1) * 3^ceil(x) <= maxError * (n+1)!. //We need n such that x^(n+1) * 3^ceil(x) <= maxError * (n+1)!.
//right and left refer to lhs and rhs in the above inequality. //right and left refer to lhs and rhs in the above inequality.
@@ -446,15 +449,16 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionSin = new NumberFunction() { public final NumberFunction functionSin = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface pi = piFor(params[0].getClass()); NumberInterface pi = piFor(params[0].getClass());
NumberInterface twoPi = pi.multiply(implementation.instanceForString("2")); NumberInterface twoPi = pi.multiply(implementation.instanceForString("2"));
NumberInterface theta = getSmallAngle(implementation, params[0], pi); NumberInterface theta = getSmallAngle(context, params[0], pi);
//System.out.println(theta); //System.out.println(theta);
if (theta.compareTo(pi.multiply(implementation.instanceForString("1.5"))) >= 0) { if (theta.compareTo(pi.multiply(implementation.instanceForString("1.5"))) >= 0) {
theta = theta.subtract(twoPi); theta = theta.subtract(twoPi);
@@ -462,7 +466,7 @@ public class StandardPlugin extends Plugin {
theta = pi.subtract(theta); theta = pi.subtract(theta);
} }
//System.out.println(theta); //System.out.println(theta);
return sinTaylor(implementation, theta); return sinTaylor(context, theta);
} }
}; };
/** /**
@@ -470,13 +474,13 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCos = new NumberFunction() { public final NumberFunction functionCos = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return functionSin.apply(implementation, piFor(params[0].getClass()).divide(implementation.instanceForString("2")) return functionSin.apply(context, piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2"))
.subtract(params[0])); .subtract(params[0]));
} }
}; };
@@ -485,13 +489,13 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionTan = new NumberFunction() { public final NumberFunction functionTan = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return functionSin.apply(implementation, params[0]).divide(functionCos.apply(implementation, params[0])); return functionSin.apply(context, params[0]).divide(functionCos.apply(context, params[0]));
} }
}; };
/** /**
@@ -499,13 +503,13 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionSec = new NumberFunction() { public final NumberFunction functionSec = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return implementation.instanceForString("1").divide(functionCos.apply(implementation, params[0])); return context.getInheritedNumberImplementation().instanceForString("1").divide(functionCos.apply(context, params[0]));
} }
}; };
/** /**
@@ -513,13 +517,13 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCsc = new NumberFunction() { public final NumberFunction functionCsc = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return implementation.instanceForString("1").divide(functionSin.apply(implementation, params[0])); return context.getInheritedNumberImplementation().instanceForString("1").divide(functionSin.apply(context, params[0]));
} }
}; };
/** /**
@@ -527,13 +531,13 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionCot = new NumberFunction() { public final NumberFunction functionCot = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return functionCos.apply(implementation, params[0]).divide(functionSin.apply(implementation, params[0])); return functionCos.apply(context, params[0]).divide(functionSin.apply(context, params[0]));
} }
}; };
@@ -542,23 +546,24 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArcsin = new NumberFunction() { public final NumberFunction functionArcsin = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1 return params.length == 1
&& FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) <= 0; && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) <= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
if (FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString(".8")) >= 0) { NumberImplementation implementation = context.getInheritedNumberImplementation();
NumberInterface[] newParams = {FUNCTION_SQRT.apply(implementation, implementation.instanceForString("1").subtract(params[0].multiply(params[0])))}; if (FUNCTION_ABS.apply(context, params[0]).compareTo(implementation.instanceForString(".8")) >= 0) {
NumberInterface[] newParams = {FUNCTION_SQRT.apply(context, implementation.instanceForString("1").subtract(params[0].multiply(params[0])))};
return piFor(params[0].getClass()).divide(implementation.instanceForString("2")) return piFor(params[0].getClass()).divide(implementation.instanceForString("2"))
.subtract(applyInternal(implementation, newParams)).multiply(implementation.instanceForString(Integer.toString(params[0].signum()))); .subtract(applyInternal(context, newParams)).multiply(implementation.instanceForString(Integer.toString(params[0].signum())));
} }
NumberInterface currentTerm = params[0], sum = currentTerm, NumberInterface currentTerm = params[0], sum = currentTerm,
multiplier = currentTerm.multiply(currentTerm), summandBound = sum.getMaxError().multiply(implementation.instanceForString("1").subtract(multiplier)), multiplier = currentTerm.multiply(currentTerm), summandBound = sum.getMaxError().multiply(implementation.instanceForString("1").subtract(multiplier)),
power = currentTerm, coefficient = implementation.instanceForString("1"); power = currentTerm, coefficient = implementation.instanceForString("1");
int exponent = 1; int exponent = 1;
while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(summandBound) > 0) { while (FUNCTION_ABS.apply(context, currentTerm).compareTo(summandBound) > 0) {
exponent += 2; exponent += 2;
power = power.multiply(multiplier); power = power.multiply(multiplier);
coefficient = coefficient.multiply(implementation.instanceForString(Integer.toString(exponent - 2))) coefficient = coefficient.multiply(implementation.instanceForString(Integer.toString(exponent - 2)))
@@ -575,14 +580,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccos = new NumberFunction() { public final NumberFunction functionArccos = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) <= 0; return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) <= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return piFor(params[0].getClass()).divide(implementation.instanceForString("2")) return piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2"))
.subtract(functionArcsin.apply(implementation, params)); .subtract(functionArcsin.apply(context, params));
} }
}; };
@@ -591,14 +596,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccsc = new NumberFunction() { public final NumberFunction functionArccsc = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) >= 0; return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) >= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberInterface[] reciprocalParamArr = {implementation.instanceForString("1").divide(params[0])}; NumberInterface[] reciprocalParamArr = {context.getInheritedNumberImplementation().instanceForString("1").divide(params[0])};
return functionArcsin.apply(implementation, reciprocalParamArr); return functionArcsin.apply(context, reciprocalParamArr);
} }
}; };
@@ -607,14 +612,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArcsec = new NumberFunction() { public final NumberFunction functionArcsec = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1 && FUNCTION_ABS.apply(implementation, params[0]).compareTo(implementation.instanceForString("1")) >= 0; return params.length == 1 && FUNCTION_ABS.apply(context, params[0]).compareTo(context.getInheritedNumberImplementation().instanceForString("1")) >= 0;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberInterface[] reciprocalParamArr = {implementation.instanceForString("1").divide(params[0])}; NumberInterface[] reciprocalParamArr = {context.getInheritedNumberImplementation().instanceForString("1").divide(params[0])};
return functionArccos.apply(implementation, reciprocalParamArr); return functionArccos.apply(context, reciprocalParamArr);
} }
}; };
@@ -623,20 +628,21 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArctan = new NumberFunction() { public final NumberFunction functionArctan = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
NumberImplementation implementation = context.getInheritedNumberImplementation();
if (params[0].signum() == -1) { if (params[0].signum() == -1) {
NumberInterface[] negatedParams = {params[0].negate()}; NumberInterface[] negatedParams = {params[0].negate()};
return applyInternal(implementation, negatedParams).negate(); return applyInternal(context, negatedParams).negate();
} }
if (params[0].compareTo(implementation.instanceForString("1")) > 0) { if (params[0].compareTo(implementation.instanceForString("1")) > 0) {
NumberInterface[] reciprocalParams = {implementation.instanceForString("1").divide(params[0])}; NumberInterface[] reciprocalParams = {implementation.instanceForString("1").divide(params[0])};
return piFor(params[0].getClass()).divide(implementation.instanceForString("2")) return piFor(params[0].getClass()).divide(implementation.instanceForString("2"))
.subtract(applyInternal(implementation, reciprocalParams)); .subtract(applyInternal(context, reciprocalParams));
} }
if (params[0].compareTo(implementation.instanceForString("1")) == 0) { if (params[0].compareTo(implementation.instanceForString("1")) == 0) {
return piFor(params[0].getClass()).divide(implementation.instanceForString("4")); return piFor(params[0].getClass()).divide(implementation.instanceForString("4"));
@@ -644,12 +650,12 @@ public class StandardPlugin extends Plugin {
if (params[0].compareTo(implementation.instanceForString(".9")) >= 0) { if (params[0].compareTo(implementation.instanceForString(".9")) >= 0) {
NumberInterface[] newParams = {params[0].multiply(implementation.instanceForString("2")) NumberInterface[] newParams = {params[0].multiply(implementation.instanceForString("2"))
.divide(implementation.instanceForString("1").subtract(params[0].multiply(params[0])))}; .divide(implementation.instanceForString("1").subtract(params[0].multiply(params[0])))};
return applyInternal(implementation, newParams).divide(implementation.instanceForString("2")); return applyInternal(context, newParams).divide(implementation.instanceForString("2"));
} }
NumberInterface currentPower = params[0], currentTerm = currentPower, sum = currentTerm, NumberInterface currentPower = params[0], currentTerm = currentPower, sum = currentTerm,
maxError = params[0].getMaxError(), multiplier = currentPower.multiply(currentPower).negate(); maxError = params[0].getMaxError(), multiplier = currentPower.multiply(currentPower).negate();
int n = 1; int n = 1;
while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(maxError) > 0) { while (FUNCTION_ABS.apply(context, currentTerm).compareTo(maxError) > 0) {
n += 2; n += 2;
currentPower = currentPower.multiply(multiplier); currentPower = currentPower.multiply(multiplier);
currentTerm = currentPower.divide(implementation.instanceForString(Integer.toString(n))); currentTerm = currentPower.divide(implementation.instanceForString(Integer.toString(n)));
@@ -664,14 +670,14 @@ public class StandardPlugin extends Plugin {
*/ */
public final NumberFunction functionArccot = new NumberFunction() { public final NumberFunction functionArccot = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 1; return params.length == 1;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return piFor(params[0].getClass()).divide(implementation.instanceForString("2")) return piFor(params[0].getClass()).divide(context.getInheritedNumberImplementation().instanceForString("2"))
.subtract(functionArctan.apply(implementation, params)); .subtract(functionArctan.apply(context, params));
} }
}; };
@@ -687,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"));
@@ -709,16 +714,16 @@ public class StandardPlugin extends Plugin {
* @param x where the series is evaluated. * @param x where the series is evaluated.
* @return the value of the series * @return the value of the series
*/ */
private static NumberInterface sinTaylor(NumberImplementation implementation, NumberInterface x) { private static NumberInterface sinTaylor(MutableEvaluationContext context, NumberInterface x) {
NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm = x, sum = x; NumberInterface power = x, multiplier = x.multiply(x).negate(), currentTerm = x, sum = x;
NumberInterface maxError = x.getMaxError(); NumberInterface maxError = x.getMaxError();
int n = 1; int n = 1;
do { do {
n += 2; n += 2;
power = power.multiply(multiplier); power = power.multiply(multiplier);
currentTerm = power.divide(factorial(implementation, n)); currentTerm = power.divide(factorial(context.getInheritedNumberImplementation(), n));
sum = sum.add(currentTerm); sum = sum.add(currentTerm);
} while (FUNCTION_ABS.apply(implementation, currentTerm).compareTo(maxError) > 0); } while (FUNCTION_ABS.apply(context, currentTerm).compareTo(maxError) > 0);
return sum; return sum;
} }
@@ -728,10 +733,10 @@ public class StandardPlugin extends Plugin {
* @param phi an angle (in radians). * @param phi an angle (in radians).
* @return theta in [0, 2pi) that differs from phi by a multiple of 2pi. * @return theta in [0, 2pi) that differs from phi by a multiple of 2pi.
*/ */
private static NumberInterface getSmallAngle(NumberImplementation implementation, NumberInterface phi, NumberInterface pi) { private static NumberInterface getSmallAngle(MutableEvaluationContext context, NumberInterface phi, NumberInterface pi) {
NumberInterface twoPi = pi.multiply(implementation.instanceForString("2")); NumberInterface twoPi = pi.multiply(context.getInheritedNumberImplementation().instanceForString("2"));
NumberInterface theta = FUNCTION_ABS.apply(implementation, phi).subtract(twoPi NumberInterface theta = FUNCTION_ABS.apply(context, phi).subtract(twoPi
.multiply(FUNCTION_ABS.apply(implementation, phi).divide(twoPi).floor())); //Now theta is in [0, 2pi). .multiply(FUNCTION_ABS.apply(context, phi).divide(twoPi).floor())); //Now theta is in [0, 2pi).
if (phi.signum() < 0) { if (phi.signum() < 0) {
theta = twoPi.subtract(theta); theta = twoPi.subtract(theta);
} }

Datei anzeigen

@@ -1,93 +0,0 @@
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.TreeValueFunction;
import org.nwapw.abacus.function.TreeValueOperator;
import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.number.PromotionManager;
import org.nwapw.abacus.number.PromotionResult;
import org.nwapw.abacus.variables.VariableDatabase;
/**
* A reducer implementation that turns a tree into a single number.
* This is not always guaranteed to work.
*/
public class NumberReducer implements Reducer<NumberInterface> {
/**
* The plugin manager from which to draw the functions.
*/
private Abacus abacus;
/**
* Creates a new number reducer.
*
* @param abacus the calculator instance.
*/
public NumberReducer(Abacus abacus) {
this.abacus = abacus;
}
@Override
public NumberInterface reduceNode(TreeNode node, Object... children) {
PromotionManager manager = abacus.getPromotionManager();
if (node instanceof NumberNode) {
return abacus.getNumberImplementation().instanceForString(((NumberNode) node).getNumber());
} else if (node instanceof VariableNode) {
VariableDatabase database = abacus.getVariableDatabase();
String name = ((VariableNode) node).getVariable();
NumberInterface variable = database.getVariables().get(name);
if(variable != null) return variable;
TreeNode definition = database.getDefinitions().get(name);
if(definition != null) return definition.reduce(this);
return abacus.getNumberImplementation().instanceForString("0");
} else if (node instanceof NumberBinaryNode) {
NumberInterface left = (NumberInterface) children[0];
NumberInterface right = (NumberInterface) children[1];
NumberOperator operator = abacus.getPluginManager().operatorFor(((BinaryNode) node).getOperation());
PromotionResult result = manager.promote(left, right);
if (result == null) return null;
return operator.apply(result.getPromotedTo(), result.getItems());
} else if (node instanceof NumberUnaryNode) {
NumberInterface child = (NumberInterface) children[0];
NumberOperator operator = abacus.getPluginManager().operatorFor(((UnaryNode) node).getOperation());
return operator.apply(abacus.getPluginManager().interfaceImplementationFor(child.getClass()), child);
} else if (node instanceof FunctionNode) {
NumberInterface[] convertedChildren = new NumberInterface[children.length];
for (int i = 0; i < convertedChildren.length; i++) {
convertedChildren[i] = (NumberInterface) children[i];
}
NumberFunction function = abacus.getPluginManager().functionFor(((FunctionNode) node).getCallTo());
if (function == null) return null;
PromotionResult result = manager.promote(convertedChildren);
if (result == null) return null;
return function.apply(result.getPromotedTo(), result.getItems());
} 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(abacus.getNumberImplementation(), 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(abacus.getNumberImplementation(), 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(abacus.getNumberImplementation(), this, unaryNode.getApplyTo());
}
return null;
}
}

Datei anzeigen

@@ -1,17 +1,17 @@
package org.nwapw.abacus package org.nwapw.abacus
import org.nwapw.abacus.config.Configuration import org.nwapw.abacus.config.Configuration
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.context.EvaluationContext
import org.nwapw.abacus.number.PromotionManager import org.nwapw.abacus.number.PromotionManager
import org.nwapw.abacus.parsing.LexerTokenizer import org.nwapw.abacus.parsing.LexerTokenizer
import org.nwapw.abacus.parsing.ShuntingYardParser import org.nwapw.abacus.parsing.ShuntingYardParser
import org.nwapw.abacus.parsing.TreeBuilder import org.nwapw.abacus.parsing.TreeBuilder
import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.plugin.PluginManager import org.nwapw.abacus.plugin.PluginManager
import org.nwapw.abacus.plugin.StandardPlugin import org.nwapw.abacus.plugin.StandardPlugin
import org.nwapw.abacus.tree.EvaluationResult
import org.nwapw.abacus.tree.NumberReducer import org.nwapw.abacus.tree.NumberReducer
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.TreeNode
import org.nwapw.abacus.variables.VariableDatabase
/** /**
* Core class to handle all mathematics. * Core class to handle all mathematics.
@@ -36,10 +36,6 @@ class Abacus(val configuration: Configuration) {
* The plugin manager used to handle loading and unloading plugins. * The plugin manager used to handle loading and unloading plugins.
*/ */
val pluginManager = PluginManager(this) val pluginManager = PluginManager(this)
/**
* The reducer used to turn trees into a single number.
*/
val numberReducer = NumberReducer(this)
/** /**
* The tree builder that handles the conversion of strings into trees. * The tree builder that handles the conversion of strings into trees.
*/ */
@@ -48,28 +44,43 @@ class Abacus(val configuration: Configuration) {
* The promotion manager used to convert between number implementations. * The promotion manager used to convert between number implementations.
*/ */
val promotionManager = PromotionManager(this) val promotionManager = PromotionManager(this)
/** /**
* The database of variable definitions. * The hidden, mutable implementation of the context.
*/ */
val variableDatabase = VariableDatabase(this) private val mutableContext = MutableEvaluationContext(numberImplementation = StandardPlugin.IMPLEMENTATION_NAIVE)
/** /**
* The number implementation used by default. * The base context from which calculations are started.
*/ */
val numberImplementation: NumberImplementation val context: EvaluationContext
get() { get() = mutableContext
val selectedImplementation =
pluginManager.numberImplementationFor(configuration.numberImplementation)
if (selectedImplementation != null) return selectedImplementation
return StandardPlugin.IMPLEMENTATION_NAIVE
}
init { init {
pluginManager.addListener(tokenizer) pluginManager.addListener(tokenizer)
pluginManager.addListener(parser) pluginManager.addListener(parser)
pluginManager.addListener(promotionManager) pluginManager.addListener(promotionManager)
pluginManager.addListener(variableDatabase)
} }
/**
* Reloads the Abacus core.
*/
fun reload(){
pluginManager.reload()
with(mutableContext) {
numberImplementation = pluginManager.numberImplementationFor(configuration.numberImplementation)
?: StandardPlugin.IMPLEMENTATION_NAIVE
clearVariables()
clearDefinitions()
}
}
/**
* Merges the current context with the provided one, updating
* variables and the like.
* @param context the context to apply.
*/
fun applyToContext(context: EvaluationContext){
mutableContext.apply(context)
}
/** /**
* Parses a string into a tree structure using the main * Parses a string into a tree structure using the main
* tree builder. * tree builder.
@@ -79,12 +90,26 @@ class Abacus(val configuration: Configuration) {
*/ */
fun parseString(input: String): TreeNode? = treeBuilder.fromString(input) fun parseString(input: String): TreeNode? = treeBuilder.fromString(input)
/** /**
* Evaluates the given tree using the main * Evaluates the given tree.
* number reducer.
* *
* @param tree the tree to reduce, must not be null. * @param tree the tree to reduce, must not be null.
* @return the resulting number, or null of the reduction failed. * @return the evaluation result.
*/ */
fun evaluateTree(tree: TreeNode): NumberInterface? = tree.reduce(numberReducer) fun evaluateTree(tree: TreeNode): EvaluationResult {
return evaluateTreeWithContext(tree, context.mutableSubInstance())
}
/**
* Evaluates the given tree using a different context than
* the default one.
*
* @param tree the tree to reduce, must not be null.
* @param context the context to use for the evaluation.
* @return the evaluation result.
*/
fun evaluateTreeWithContext(tree: TreeNode, context: MutableEvaluationContext): EvaluationResult {
val newReducer = NumberReducer(this, context)
val evaluationValue = tree.reduce(newReducer)
return EvaluationResult(evaluationValue, newReducer.context)
}
} }

Datei anzeigen

@@ -0,0 +1,26 @@
package org.nwapw.abacus.context
import kotlin.reflect.KProperty
/**
* A delegate to accumulate a collection of elements in a [EvaluationContext] hierarchy.
*
* ChainAccumulateDelegate is similar to the [ChainSearchDelegate], however, it operates only on collections.
* Instead of returning the most recent collection, it merges them into a [Set].
*
* @param T the type of element in the collection.
* @property valueGetter the getter used to access the collection from the context.
*/
class ChainAccumulateDelegate<out T>(private val valueGetter: EvaluationContext.() -> Collection<T>) {
operator fun getValue(selfRef: Any, property: KProperty<*>): Set<T> {
val set = mutableSetOf<T>()
var currentRef: EvaluationContext = selfRef as? EvaluationContext ?: return set
while(true) {
set.addAll(currentRef.valueGetter())
currentRef = currentRef.parent ?: break
}
return set
}
}

Datei anzeigen

@@ -0,0 +1,29 @@
package org.nwapw.abacus.context
import kotlin.reflect.KProperty
/**
* A delegate to search a hierarchy made up of [EvaluationContext].
*
* ChainSearchDelegate is a variable delegate written specifically for use in [EvaluationContext], because
* of its hierarchical structure. Variables not found in the current context are searched
* for in its parent, which continues recursively until the context being examined has no parent.
* This class assists that logic, which is commonly re-used with different variable types, by calling
* [valueGetter] on the current context, then its parent, etc.
*
* @param V the type of the property to search recursively.
* @property valueGetter the getter lambda to access the value from the context.
*/
class ChainSearchDelegate<out V>(private val valueGetter: EvaluationContext.() -> V?) {
operator fun getValue(selfRef: Any, property: KProperty<*>): V? {
var currentRef = selfRef as? EvaluationContext ?: return null
var returnedValue = currentRef.valueGetter()
while (returnedValue == null) {
currentRef = currentRef.parent ?: break
returnedValue = currentRef.valueGetter()
}
return returnedValue
}
}

Datei anzeigen

@@ -0,0 +1,84 @@
package org.nwapw.abacus.context
import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.tree.Reducer
import org.nwapw.abacus.tree.TreeNode
/**
* A context for the reduction of a [org.nwapw.abacus.tree.TreeNode] into a number.
*
* The reduction context is used to carry important state information captured at the beginning
* of the reduction of an expression, such as the variables and the implementation in use.
*
* @property parent the parent of this context.
* @property numberImplementation the implementation for numbers of this context.
* @property reducer the reducer used by this context.
*/
open class EvaluationContext(val parent: EvaluationContext? = null,
open val numberImplementation: NumberImplementation? = null,
open val reducer: Reducer<NumberInterface>? = null) {
/**
* The map of variables in this context.
*/
protected val variableMap = mutableMapOf<String, NumberInterface>()
/**
* The map of definitions in this context.
*/
protected val definitionMap = mutableMapOf<String, TreeNode>()
/**
* The set of all variable names defined in this context.
*/
val variables: Set<String>
get() = variableMap.keys
/**
* The set of all definition names defined in this context.
*/
val definitions: Set<String>
get() = definitionMap.keys
/**
* The implementation inherited from this context's parent.
*/
val inheritedNumberImplementation: NumberImplementation?
by ChainSearchDelegate { numberImplementation}
/**
* The reducer inherited from this context's parent.
*/
val inheritedReducer: Reducer<NumberInterface>?
by ChainSearchDelegate { reducer }
/**
* The set of all variables in this context and its parents.
*/
val inheritedVariables: Set<String> by ChainAccumulateDelegate { variables }
/**
* The set of all definition in this context and its parents.
*/
val inheritedDefinitions: Set<String> by ChainAccumulateDelegate { definitions }
/**
* Create a new child instance of this context that is mutable.
* @return the new child instance.
*/
fun mutableSubInstance(): MutableEvaluationContext = MutableEvaluationContext(this)
/**
* Gets a variable stored in this context.
*/
fun getVariable(name: String): NumberInterface? {
return variableMap[name] ?: parent?.getVariable(name)
}
/**
* Gets the definition stored in this context.
*/
fun getDefinition(name: String): TreeNode? {
return definitionMap[name] ?: parent?.getDefinition(name)
}
}

Datei anzeigen

@@ -0,0 +1,69 @@
package org.nwapw.abacus.context
import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.tree.Reducer
import org.nwapw.abacus.tree.TreeNode
/**
* A reduction context that is mutable.
* @param parent the parent of this context.
* @param numberImplementation the number implementation used in this context.
* @param reducer the reducer used in this context
*/
class MutableEvaluationContext(parent: EvaluationContext? = null,
numberImplementation: NumberImplementation? = null,
reducer: Reducer<NumberInterface>? = null) :
EvaluationContext(parent, numberImplementation, reducer) {
override var numberImplementation: NumberImplementation? = super.numberImplementation
override var reducer: Reducer<NumberInterface>? = super.reducer
/**
* Writes data stored in the [other] context over data stored in this one.
* @param other the context from which to copy data.
*/
fun apply(other: EvaluationContext) {
if(other.numberImplementation != null) numberImplementation = other.numberImplementation
if(other.reducer != null) reducer = other.reducer
for(name in other.variables) {
setVariable(name, other.getVariable(name) ?: continue)
}
for(name in other.definitions) {
setDefinition(name, other.getDefinition(name) ?: continue)
}
}
/**
* Sets a variable to a certain [value].
* @param name the name of the variable.
* @param value the value of the variable.
*/
fun setVariable(name: String, value: NumberInterface) {
variableMap[name] = value
}
/**
* Set a definition to a certain [value].
* @param name the name of the definition.
* @param value the value of the definition.
*/
fun setDefinition(name: String, value: TreeNode) {
definitionMap[name] = value
}
/**
* Clears the variables defined in this context.
*/
fun clearVariables(){
variableMap.clear()
}
/**
* Clears the definitions defined in this context.
*/
fun clearDefinitions(){
definitionMap.clear()
}
}

Datei anzeigen

@@ -1,6 +1,6 @@
package org.nwapw.abacus.function package org.nwapw.abacus.function
import org.nwapw.abacus.function.applicable.ReducerApplicable import org.nwapw.abacus.function.applicable.Applicable
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.TreeNode
@@ -10,4 +10,4 @@ import org.nwapw.abacus.tree.TreeNode
* A function that operates on parse tree nodes instead of on already simplified numbers. * A function that operates on parse tree nodes instead of on already simplified numbers.
* Despite this, it returns a number, not a tree. * Despite this, it returns a number, not a tree.
*/ */
abstract class TreeValueFunction : ReducerApplicable<TreeNode, NumberInterface, NumberInterface> abstract class TreeValueFunction : Applicable<TreeNode, NumberInterface>

Datei anzeigen

@@ -1,6 +1,6 @@
package org.nwapw.abacus.function package org.nwapw.abacus.function
import org.nwapw.abacus.function.applicable.ReducerApplicable import org.nwapw.abacus.function.applicable.Applicable
import org.nwapw.abacus.number.NumberInterface import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.tree.TreeNode import org.nwapw.abacus.tree.TreeNode
@@ -15,4 +15,4 @@ import org.nwapw.abacus.tree.TreeNode
abstract class TreeValueOperator(associativity: OperatorAssociativity, type: OperatorType, abstract class TreeValueOperator(associativity: OperatorAssociativity, type: OperatorType,
precedence: Int) : precedence: Int) :
Operator(associativity, type, precedence), Operator(associativity, type, precedence),
ReducerApplicable<TreeNode, NumberInterface, NumberInterface> Applicable<TreeNode, NumberInterface>

Datei anzeigen

@@ -1,7 +1,7 @@
package org.nwapw.abacus.function.applicable package org.nwapw.abacus.function.applicable
import org.nwapw.abacus.function.DomainException import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.plugin.NumberImplementation import org.nwapw.abacus.exception.DomainException
/** /**
* A class that can be applied to arguments. * A class that can be applied to arguments.
@@ -18,7 +18,7 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameter array to verify for compatibility. * @param params the parameter array to verify for compatibility.
* @return whether the array can be used with applyInternal. * @return whether the array can be used with applyInternal.
*/ */
fun matchesParams(implementation: NumberImplementation, params: Array<out T>): Boolean fun matchesParams(context: MutableEvaluationContext, params: Array<out T>): Boolean
/** /**
* Applies the applicable object to the given parameters, * Applies the applicable object to the given parameters,
@@ -26,7 +26,7 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameters to apply to. * @param params the parameters to apply to.
* @return the result of the application. * @return the result of the application.
*/ */
fun applyInternal(implementation: NumberImplementation, params: Array<out T>): O fun applyInternal(context: MutableEvaluationContext, params: Array<out T>): O
/** /**
* If the parameters can be used with this applicable, returns * If the parameters can be used with this applicable, returns
@@ -35,9 +35,10 @@ interface Applicable<in T : Any, out O : Any> {
* @param params the parameters to apply to. * @param params the parameters to apply to.
* @return the result of the operation, or null if parameters do not match. * @return the result of the operation, or null if parameters do not match.
*/ */
fun apply(implementation: NumberImplementation, vararg params: T): O { fun apply(context: MutableEvaluationContext, vararg params: T): O {
if (!matchesParams(implementation, params)) throw DomainException() if (!matchesParams(context, params))
return applyInternal(implementation, params) throw DomainException("parameters do not match function requirements.")
return applyInternal(context, params)
} }
} }

Datei anzeigen

@@ -1,45 +0,0 @@
package org.nwapw.abacus.function.applicable
import org.nwapw.abacus.function.DomainException
import org.nwapw.abacus.plugin.NumberImplementation
import org.nwapw.abacus.tree.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 <T> the type of the input arguments.
* @param <O> the return type of the application.
* @param <R> the required type of the reducer.
*/
interface ReducerApplicable<in T : Any, out O : Any, in R : Any> {
/**
* Checks if this applicable can be applied to the
* given parameters.
* @param params the parameters to check.
*/
fun matchesParams(implementation: NumberImplementation, params: Array<out T>): Boolean
/**
* Applies this applicable to the given arguments, and reducer.
* @param reducer the reducer to use in the application.
* @param params the arguments to apply to.
* @return the result of the application.
*/
fun applyWithReducerInternal(implementation: NumberImplementation, reducer: Reducer<R>, params: Array<out T>): O
/**
* 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 params the arguments to apply to.
* @return the result of the application, or null if the arguments are incompatible.
*/
fun applyWithReducer(implementation: NumberImplementation, reducer: Reducer<R>, vararg params: T): O {
if (!matchesParams(implementation, params)) throw DomainException()
return applyWithReducerInternal(implementation, reducer, params)
}
}

Datei anzeigen

@@ -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()
} }

Datei anzeigen

@@ -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() + ")"
} }
} }

Datei anzeigen

@@ -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()

Datei anzeigen

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

Datei anzeigen

@@ -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)
} }

Datei anzeigen

@@ -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)
} }

Datei anzeigen

@@ -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)
} }

Datei anzeigen

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

Datei anzeigen

@@ -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)
} }

Datei anzeigen

@@ -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
} }

Datei anzeigen

@@ -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
} }

Datei anzeigen

@@ -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)
} }

Datei anzeigen

@@ -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)
} }

Datei anzeigen

@@ -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)
} }
} }

Datei anzeigen

@@ -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
} }
} }

Datei anzeigen

@@ -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)
} }

Datei anzeigen

@@ -1,37 +0,0 @@
package org.nwapw.abacus.variables
import org.nwapw.abacus.Abacus
import org.nwapw.abacus.number.NumberInterface
import org.nwapw.abacus.plugin.PluginListener
import org.nwapw.abacus.plugin.PluginManager
import org.nwapw.abacus.tree.TreeNode
/**
* A database for variables and definition.
*
* The variable database is used to keep track of
* variables and definitions throughout the calculator.
*
* @property abacus the Abacus instance.
*/
class VariableDatabase(val abacus: Abacus): PluginListener {
/**
* The variables that are stored in the database.
*/
val variables = mutableMapOf<String, NumberInterface>()
/**
* The definitions that are stored in the database.
*/
val definitions = mutableMapOf<String, TreeNode>()
override fun onLoad(manager: PluginManager?) {
}
override fun onUnload(manager: PluginManager?) {
variables.clear()
definitions.clear()
}
}

Datei anzeigen

@@ -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;
@@ -17,14 +17,14 @@ public class CalculationTests {
@BeforeClass @BeforeClass
public static void prepareTests() { public static void prepareTests() {
abacus.getPluginManager().addInstantiated(new StandardPlugin(abacus.getPluginManager())); abacus.getPluginManager().addInstantiated(new StandardPlugin(abacus.getPluginManager()));
abacus.getPluginManager().load(); abacus.reload();
} }
private void testOutput(String input, String parseOutput, String output) { private void testOutput(String input, String parseOutput, String output) {
TreeNode parsedTree = abacus.parseString(input); TreeNode parsedTree = abacus.parseString(input);
Assert.assertNotNull(parsedTree); Assert.assertNotNull(parsedTree);
Assert.assertEquals(parsedTree.toString(), parseOutput); Assert.assertEquals(parsedTree.toString(), parseOutput);
NumberInterface result = abacus.evaluateTree(parsedTree); NumberInterface result = abacus.evaluateTree(parsedTree).getValue();
Assert.assertNotNull(result); Assert.assertNotNull(result);
Assert.assertTrue(result.toString().startsWith(output)); Assert.assertTrue(result.toString().startsWith(output));
} }

Datei anzeigen

@@ -5,11 +5,11 @@ 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.context.MutableEvaluationContext;
import org.nwapw.abacus.function.*; import org.nwapw.abacus.function.*;
import org.nwapw.abacus.lexing.pattern.Match; import org.nwapw.abacus.lexing.pattern.Match;
import org.nwapw.abacus.number.NumberInterface; import org.nwapw.abacus.number.NumberInterface;
import org.nwapw.abacus.parsing.LexerTokenizer; import org.nwapw.abacus.parsing.LexerTokenizer;
import org.nwapw.abacus.plugin.NumberImplementation;
import org.nwapw.abacus.plugin.Plugin; import org.nwapw.abacus.plugin.Plugin;
import org.nwapw.abacus.tree.TokenType; import org.nwapw.abacus.tree.TokenType;
@@ -21,12 +21,12 @@ public class TokenizerTests {
private static LexerTokenizer lexerTokenizer = new LexerTokenizer(); private static LexerTokenizer lexerTokenizer = new LexerTokenizer();
private static NumberFunction subtractFunction = new NumberFunction() { private static NumberFunction subtractFunction = new NumberFunction() {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return params.length == 2; return params.length == 2;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return params[0].subtract(params[1]); return params[0].subtract(params[1]);
} }
}; };
@@ -37,26 +37,26 @@ public class TokenizerTests {
0) { 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return true; return true;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return subtractFunction.apply(implementation, params); return subtractFunction.apply(context, params);
} }
}); });
registerOperator("-", new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX, registerOperator("-", new NumberOperator(OperatorAssociativity.LEFT, OperatorType.BINARY_INFIX,
0) { 0) {
@Override @Override
public boolean matchesParams(NumberImplementation implementation, NumberInterface[] params) { public boolean matchesParams(MutableEvaluationContext context, NumberInterface[] params) {
return true; return true;
} }
@Override @Override
public NumberInterface applyInternal(NumberImplementation implementation, NumberInterface[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, NumberInterface[] params) {
return subtractFunction.apply(implementation, params); return subtractFunction.apply(context, params);
} }
}); });
registerFunction("subtract", subtractFunction); registerFunction("subtract", subtractFunction);
@@ -80,7 +80,7 @@ public class TokenizerTests {
public static void prepareTests() { public static void prepareTests() {
abacus.getPluginManager().addListener(lexerTokenizer); abacus.getPluginManager().addListener(lexerTokenizer);
abacus.getPluginManager().addInstantiated(testPlugin); abacus.getPluginManager().addInstantiated(testPlugin);
abacus.getPluginManager().load(); abacus.reload();
} }
@Test @Test

Datei anzeigen

@@ -12,14 +12,18 @@ 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;
import org.nwapw.abacus.plugin.PluginManager; import org.nwapw.abacus.plugin.PluginManager;
import org.nwapw.abacus.plugin.StandardPlugin; import org.nwapw.abacus.plugin.StandardPlugin;
import org.nwapw.abacus.tree.EvaluationResult;
import org.nwapw.abacus.tree.TreeNode; import org.nwapw.abacus.tree.TreeNode;
import java.io.File; import java.io.File;
@@ -144,16 +148,13 @@ public class AbacusController implements PluginListener {
if (constructedTree == null) { if (constructedTree == null) {
return ERR_SYNTAX; return ERR_SYNTAX;
} }
NumberInterface evaluatedNumber = abacus.evaluateTree(constructedTree); EvaluationResult result = abacus.evaluateTree(constructedTree);
if (evaluatedNumber == null) { NumberInterface evaluatedNumber = result.getValue();
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());
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();
@@ -320,13 +321,13 @@ public class AbacusController implements PluginListener {
} catch (IOException | ClassNotFoundException e) { } catch (IOException | ClassNotFoundException e) {
e.printStackTrace(); e.printStackTrace();
} }
abacusPluginManager.reload(); abacus.reload();
} }
@FXML @FXML
public void performReload() { public void performReload() {
alertIfApplyNeeded(true); alertIfApplyNeeded(true);
abacus.getPluginManager().reload(); abacus.reload();
} }
@FXML @FXML
@@ -360,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)));

Datei anzeigen

@@ -54,7 +54,7 @@
<TextField fx:id="computationLimitField" GridPane.columnIndex="1" GridPane.rowIndex="2"/> <TextField fx:id="computationLimitField" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<FlowPane GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="3" hgap="10" <FlowPane GridPane.columnIndex="0" GridPane.columnSpan="2" GridPane.rowIndex="3" hgap="10"
vgap="10"> vgap="10">
<Button text="Apply" onAction="#performSave"/> <Button text="Save" onAction="#performSave"/>
<Button text="Reload Plugins" onAction="#performReload"/> <Button text="Reload Plugins" onAction="#performReload"/>
<Button text="Apply and Reload" onAction="#performSaveAndReload"/> <Button text="Apply and Reload" onAction="#performSaveAndReload"/>
<Button text="Scan Plugins" onAction="#performScan"/> <Button text="Scan Plugins" onAction="#performScan"/>