Remove nullability from reduction.

This commit is contained in:
Danila Fedorin 2017-09-07 12:53:12 -07:00
parent 1575d3e574
commit 52ab357fe1
17 changed files with 31 additions and 36 deletions

View File

@ -18,7 +18,7 @@ public class DomainException extends RuntimeException {
* Creates a new DomainException with a default message. * Creates a new DomainException with a default message.
*/ */
public DomainException(){ public DomainException(){
this("Domain Error"); this("Domain error.");
} }
} }

View File

@ -11,7 +11,7 @@ public class EvaluationException extends RuntimeException {
* Creates a new EvaluationException with the default string. * Creates a new EvaluationException with the default string.
*/ */
public EvaluationException() { public EvaluationException() {
super("Error evaluating expression."); super("Evaluation error.");
} }
/** /**

View File

@ -10,7 +10,7 @@ public class ComputationInterruptedException extends RuntimeException {
* Creates a new exception of this type. * Creates a new exception of this type.
*/ */
public ComputationInterruptedException() { public ComputationInterruptedException() {
super("Computation interrupted by user."); super("Computation interrupted.");
} }
} }

View File

@ -29,8 +29,7 @@ public class StandardPlugin extends Plugin {
@Override @Override
public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) {
String assignTo = ((VariableNode) params[0]).getVariable(); String assignTo = ((VariableNode) params[0]).getVariable();
NumberInterface value = params[1].reduce(context.getReducer()); NumberInterface value = params[1].reduce(context.getInheritedReducer());
if(value == null) throw new EvaluationException();
context.setVariable(assignTo, value); context.setVariable(assignTo, value);
return value; return value;
} }
@ -48,9 +47,7 @@ public class StandardPlugin extends Plugin {
public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) { public NumberInterface applyInternal(MutableEvaluationContext context, TreeNode[] params) {
String assignTo = ((VariableNode) params[0]).getVariable(); String assignTo = ((VariableNode) params[0]).getVariable();
context.setDefinition(assignTo, params[1]); context.setDefinition(assignTo, params[1]);
NumberInterface value = params[1].reduce(context.getReducer()); return params[1].reduce(context.getInheritedReducer());
if(value == null) throw new EvaluationException();
return value;
} }
}; };
/** /**

View File

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

View File

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

View File

@ -13,9 +13,9 @@ package org.nwapw.abacus.tree
class NumberBinaryNode(operation: String, left: TreeNode, right: TreeNode) class NumberBinaryNode(operation: String, left: TreeNode, right: TreeNode)
: BinaryNode(operation, left, right) { : BinaryNode(operation, left, right) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
val left = left.reduce(reducer) ?: return null val left = left.reduce(reducer)
val right = right.reduce(reducer) ?: return null val right = right.reduce(reducer)
return reducer.reduceNode(this, left, right) return reducer.reduceNode(this, left, right)
} }

View File

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

View File

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

View File

@ -11,7 +11,7 @@ package org.nwapw.abacus.tree
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) val child = applyTo.reduce(reducer)
return reducer.reduceNode(this, child) return reducer.reduceNode(this, child)
} }

View File

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

View File

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

View File

@ -14,7 +14,7 @@ package org.nwapw.abacus.tree
class TreeValueBinaryNode(operation: String, left: TreeNode, right: TreeNode) class TreeValueBinaryNode(operation: String, left: TreeNode, right: TreeNode)
: BinaryNode(operation, left, right) { : BinaryNode(operation, left, right) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this) return reducer.reduceNode(this)
} }

View File

@ -9,7 +9,7 @@ package org.nwapw.abacus.tree
*/ */
class TreeValueFunctionNode(name: String, children: List<TreeNode>) : CallNode(name, children) { class TreeValueFunctionNode(name: String, children: List<TreeNode>) : CallNode(name, children) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this) return reducer.reduceNode(this)
} }

View File

@ -12,8 +12,8 @@ package org.nwapw.abacus.tree
class TreeValueUnaryNode(operation: String, child: TreeNode) class TreeValueUnaryNode(operation: String, child: TreeNode)
: UnaryNode(operation, child) { : UnaryNode(operation, child) {
override fun <T : Any> reduce(reducer: Reducer<T>): T? { override fun <T : Any> reduce(reducer: Reducer<T>): T {
return reducer.reduceNode(this); return reducer.reduceNode(this)
} }
} }

View File

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

View File

@ -15,6 +15,7 @@ import org.nwapw.abacus.config.Configuration;
import org.nwapw.abacus.function.Documentation; import org.nwapw.abacus.function.Documentation;
import org.nwapw.abacus.function.DocumentationType; import org.nwapw.abacus.function.DocumentationType;
import org.nwapw.abacus.function.DomainException; import org.nwapw.abacus.function.DomainException;
import org.nwapw.abacus.function.EvaluationException;
import org.nwapw.abacus.number.*; import org.nwapw.abacus.number.*;
import org.nwapw.abacus.plugin.ClassFinder; import org.nwapw.abacus.plugin.ClassFinder;
import org.nwapw.abacus.plugin.PluginListener; import org.nwapw.abacus.plugin.PluginListener;
@ -147,16 +148,11 @@ public class AbacusController implements PluginListener {
} }
EvaluationResult result = abacus.evaluateTree(constructedTree); EvaluationResult result = abacus.evaluateTree(constructedTree);
NumberInterface evaluatedNumber = result.getValue(); NumberInterface evaluatedNumber = result.getValue();
if (evaluatedNumber == null) {
return ERR_EVAL;
}
String resultingString = evaluatedNumber.toString(); String resultingString = evaluatedNumber.toString();
historyData.add(new HistoryModel(inputField.getText(), constructedTree.toString(), resultingString)); historyData.add(new HistoryModel(inputField.getText(), constructedTree.toString(), resultingString));
abacus.applyToContext(result.getResultingContext()); abacus.applyToContext(result.getResultingContext());
return resultingString; return resultingString;
} catch (ComputationInterruptedException exception) { } catch (ComputationInterruptedException | DomainException | EvaluationException exception) {
return ERR_STOP;
} catch (DomainException exception) {
return exception.getMessage(); return exception.getMessage();
} catch (RuntimeException exception) { } catch (RuntimeException exception) {
exception.printStackTrace(); exception.printStackTrace();