mirror of
https://github.com/DanilaFe/abacus
synced 2024-12-22 23:40:08 -08:00
Rewrite number reducer in Kotlin.
This commit is contained in:
parent
f0e38fed87
commit
863be5bcfc
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,6 +1,8 @@
|
||||||
package org.nwapw.abacus
|
package org.nwapw.abacus
|
||||||
|
|
||||||
import org.nwapw.abacus.config.Configuration
|
import org.nwapw.abacus.config.Configuration
|
||||||
|
import org.nwapw.abacus.context.MutableReductionContext
|
||||||
|
import org.nwapw.abacus.context.ReductionContext
|
||||||
import org.nwapw.abacus.number.NumberInterface
|
import org.nwapw.abacus.number.NumberInterface
|
||||||
import org.nwapw.abacus.number.PromotionManager
|
import org.nwapw.abacus.number.PromotionManager
|
||||||
import org.nwapw.abacus.parsing.LexerTokenizer
|
import org.nwapw.abacus.parsing.LexerTokenizer
|
||||||
|
@ -36,10 +38,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.
|
||||||
*/
|
*/
|
||||||
|
@ -52,16 +50,16 @@ class Abacus(val configuration: Configuration) {
|
||||||
* The database of variable definitions.
|
* The database of variable definitions.
|
||||||
*/
|
*/
|
||||||
val variableDatabase = VariableDatabase(this)
|
val variableDatabase = VariableDatabase(this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number implementation used by default.
|
* The hidden, mutable implementation of the context.
|
||||||
*/
|
*/
|
||||||
val numberImplementation: NumberImplementation
|
private val mutableContext = MutableReductionContext(numberImplementation = StandardPlugin.IMPLEMENTATION_NAIVE)
|
||||||
get() {
|
/**
|
||||||
val selectedImplementation =
|
* The base context from which calculations are started.
|
||||||
pluginManager.numberImplementationFor(configuration.numberImplementation)
|
*/
|
||||||
if (selectedImplementation != null) return selectedImplementation
|
val context: ReductionContext
|
||||||
return StandardPlugin.IMPLEMENTATION_NAIVE
|
get() = mutableContext
|
||||||
}
|
|
||||||
|
|
||||||
init {
|
init {
|
||||||
pluginManager.addListener(tokenizer)
|
pluginManager.addListener(tokenizer)
|
||||||
|
@ -85,6 +83,7 @@ class Abacus(val configuration: Configuration) {
|
||||||
* @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 resulting number, or null of the reduction failed.
|
||||||
*/
|
*/
|
||||||
fun evaluateTree(tree: TreeNode): NumberInterface? = tree.reduce(numberReducer)
|
fun evaluateTree(tree: TreeNode): NumberInterface? =
|
||||||
|
tree.reduce(NumberReducer(this, context.mutableSubInstance()))
|
||||||
|
|
||||||
}
|
}
|
57
core/src/main/kotlin/org/nwapw/abacus/tree/NumberReducer.kt
Normal file
57
core/src/main/kotlin/org/nwapw/abacus/tree/NumberReducer.kt
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
package org.nwapw.abacus.tree
|
||||||
|
|
||||||
|
import org.nwapw.abacus.Abacus
|
||||||
|
import org.nwapw.abacus.context.MutableReductionContext
|
||||||
|
import org.nwapw.abacus.function.NumberFunction
|
||||||
|
import org.nwapw.abacus.number.NumberInterface
|
||||||
|
|
||||||
|
class NumberReducer(val abacus: Abacus, val context: MutableReductionContext) : Reducer<NumberInterface> {
|
||||||
|
|
||||||
|
override fun reduceNode(treeNode: TreeNode, vararg children: Any): NumberInterface? {
|
||||||
|
val promotionManager = abacus.promotionManager
|
||||||
|
return when(treeNode){
|
||||||
|
is NumberNode -> {
|
||||||
|
context.inheritedNumberImplementation?.instanceForString(treeNode.number)
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
is NumberUnaryNode -> {
|
||||||
|
val child = children[0] as NumberInterface
|
||||||
|
abacus.pluginManager.operatorFor(treeNode.operation)
|
||||||
|
.apply(abacus.pluginManager.interfaceImplementationFor(child.javaClass), child)
|
||||||
|
}
|
||||||
|
is NumberBinaryNode -> {
|
||||||
|
val left = children[0] as NumberInterface
|
||||||
|
val right = children[1] as NumberInterface
|
||||||
|
val promotionResult = promotionManager.promote(left, right) ?: return null
|
||||||
|
abacus.pluginManager.operatorFor(treeNode.operation).apply(promotionResult.promotedTo, *promotionResult.items)
|
||||||
|
}
|
||||||
|
is FunctionNode -> {
|
||||||
|
val promotionResult = promotionManager
|
||||||
|
.promote(*children.map { it as NumberInterface }.toTypedArray()) ?: return null
|
||||||
|
abacus.pluginManager.functionFor(treeNode.callTo).apply(promotionResult.promotedTo, *promotionResult.items)
|
||||||
|
}
|
||||||
|
is TreeValueUnaryNode -> {
|
||||||
|
abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
|
||||||
|
.applyWithReducer(context.inheritedNumberImplementation!!, this, children[0] as TreeNode)
|
||||||
|
}
|
||||||
|
is TreeValueBinaryNode -> {
|
||||||
|
abacus.pluginManager.treeValueOperatorFor(treeNode.operation)
|
||||||
|
.applyWithReducer(context.inheritedNumberImplementation!!, this,
|
||||||
|
children[0] as TreeNode, children[1] as TreeNode)
|
||||||
|
}
|
||||||
|
is TreeValueFunctionNode -> {
|
||||||
|
abacus.pluginManager.treeValueFunctionFor(treeNode.callTo)
|
||||||
|
.applyWithReducer(context.inheritedNumberImplementation!!, this,
|
||||||
|
*children.map { it as TreeNode }.toTypedArray())
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user