Add base support for invoking custom functions (arguments' evaluating is still not supported)

This commit is contained in:
2020-03-11 21:20:06 +01:00
parent 6264be6573
commit 7d61756273
9 changed files with 49 additions and 6 deletions

View File

@@ -12,7 +12,7 @@ class FunctionDefinitionTool {
}
inner class FunctionDefinitionToolStage2(private val signature: Signature) {
infix fun define(body: (Environment, List<Value>) -> Value) {
infix fun body(body: (Environment, List<Value>) -> Value) {
definitions.add(FunctionDefinition(signature, body))
}
}

View File

@@ -3,6 +3,8 @@ package io.smnp.callable.function
import io.smnp.dsl.ast.model.node.FunctionDefinitionArgumentsNode
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.evaluation.evaluator.BlockEvaluator
import io.smnp.evaluation.model.exception.Return
import io.smnp.type.model.Value
object CustomFunction {
@@ -13,10 +15,17 @@ object CustomFunction {
override fun define(new: FunctionDefinitionTool) {
val (_, argumentsNode, bodyNode) = node
val signature = FunctionSignatureParser.parseSignature(argumentsNode as FunctionDefinitionArgumentsNode)
val evaluator = BlockEvaluator()
new function signature define { env, args ->
new function signature body { env, args ->
val boundArguments = FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env)
// TODO(Implement bodyNode evaluation)
// TODO push boundArguments to variables scope
try {
evaluator.evaluate(bodyNode, env)
} catch(value: Return) {
return@body value.value
}
Value.void()
}
}

View File

@@ -1,6 +1,8 @@
package io.smnp.dsl.ast.model.node
class ReturnNode(value: Node) : Node(1, value.position) {
operator fun component1() = children[0]
val value: Node
get() = children[0]

View File

@@ -12,7 +12,7 @@ class BlockEvaluator : Evaluator() {
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val evaluator = DefaultEvaluator()
val ok = (node as BlockNode).statements.all {
evaluator.evaluate(it, environment).result == EvaluationResult.OK
evaluator.evaluate(it, environment).result != EvaluationResult.FAILED
}
return if(ok) EvaluatorOutput.ok() else EvaluatorOutput.fail()

View File

@@ -12,6 +12,7 @@ class DefaultEvaluator : Evaluator() {
ConditionEvaluator(),
BlockEvaluator(),
ThrowEvaluator(),
ReturnEvaluator(),
ExpressionEvaluator()
).evaluate(node, environment)
}

View File

@@ -0,0 +1,26 @@
package io.smnp.evaluation.evaluator
import io.smnp.dsl.ast.model.node.Node
import io.smnp.dsl.ast.model.node.ReturnNode
import io.smnp.environment.Environment
import io.smnp.evaluation.model.entity.EvaluatorOutput
import io.smnp.evaluation.model.exception.Return
import io.smnp.type.model.Value
class ReturnEvaluator : Evaluator() {
override fun supportedNodes() = listOf(ReturnNode::class)
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val evaluator = ExpressionEvaluator()
val (valueNode) = node as ReturnNode
val value = evaluator.evaluate(valueNode, environment).value ?: Value.void()
// Disclaimer
// Exception system usage to control program execution flow is really bad idea.
// However because of lack of 'goto' instruction equivalent in Kotlin
// there is a need to use some mechanism to break function execution on 'return' statement
// and immediately go to Environment's method 'invokeFunction()' or 'invokeMethod()',
// which can handle value that came with exception and return it to code being executed.
throw Return(value)
}
}

View File

@@ -0,0 +1,5 @@
package io.smnp.evaluation.model.exception
import io.smnp.type.model.Value
class Return(val value: Value) : Exception()

View File

@@ -8,7 +8,7 @@ import io.smnp.type.model.Value
class PrintlnFunction : Function("println") {
override fun define(new: FunctionDefinitionTool) {
new function vararg(allTypes()) define { _module, (vararg) ->
new function vararg(allTypes()) body { _, (vararg) ->
// TODO: Implement equivalent of "toString()" method
println((vararg.value!! as List<Value>).joinToString("") { it.value!!.toString() })
Value.void()

View File

@@ -7,7 +7,7 @@ import io.smnp.type.model.Value
class DebugFunction : Function("debug") {
override fun define(new: FunctionDefinitionTool) {
new function simple() define { env, _ ->
new function simple() body { env, _ ->
env.printCallStack()
Value.void()
}