Abacus/core/src/main/kotlin/org/nwapw/abacus/Abacus.kt

115 lines
3.7 KiB
Kotlin

package org.nwapw.abacus
import org.nwapw.abacus.config.Configuration
import org.nwapw.abacus.context.MutableEvaluationContext
import org.nwapw.abacus.context.EvaluationContext
import org.nwapw.abacus.number.PromotionManager
import org.nwapw.abacus.parsing.LexerTokenizer
import org.nwapw.abacus.parsing.ShuntingYardParser
import org.nwapw.abacus.parsing.TreeBuilder
import org.nwapw.abacus.plugin.PluginManager
import org.nwapw.abacus.plugin.StandardPlugin
import org.nwapw.abacus.tree.EvaluationResult
import org.nwapw.abacus.tree.NumberReducer
import org.nwapw.abacus.tree.TreeNode
/**
* Core class to handle all mathematics.
*
* The main calculator class. This is responsible
* for piecing together all of the components, allowing
* their interaction with each other.
*
* @property configuration the configuration to use.
*/
class Abacus(val configuration: Configuration) {
/**
* The tokenizer used to convert strings into tokens.
*/
private val tokenizer = LexerTokenizer()
/**
* Parser the parser used to convert tokens into trees.
*/
private val parser = ShuntingYardParser()
/**
* The plugin manager used to handle loading and unloading plugins.
*/
val pluginManager = PluginManager(this)
/**
* The tree builder that handles the conversion of strings into trees.
*/
val treeBuilder = TreeBuilder(tokenizer, parser)
/**
* The promotion manager used to convert between number implementations.
*/
val promotionManager = PromotionManager(this)
/**
* The hidden, mutable implementation of the context.
*/
private val mutableContext = MutableEvaluationContext(numberImplementation = StandardPlugin.IMPLEMENTATION_NAIVE)
/**
* The base context from which calculations are started.
*/
val context: EvaluationContext
get() = mutableContext
init {
pluginManager.addListener(tokenizer)
pluginManager.addListener(parser)
pluginManager.addListener(promotionManager)
}
/**
* 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
* tree builder.
*
* @param input the input string to parse
* @return the resulting tree, null if the tree builder or the produced tree are null.
*/
fun parseString(input: String): TreeNode = treeBuilder.fromString(input)
/**
* Evaluates the given tree.
*
* @param tree the tree to reduce, must not be null.
* @return the evaluation result.
*/
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)
}
}