Add base support for invoking custom functions (arguments' evaluating is still not supported)
This commit is contained in:
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -12,6 +12,7 @@ class DefaultEvaluator : Evaluator() {
|
||||
ConditionEvaluator(),
|
||||
BlockEvaluator(),
|
||||
ThrowEvaluator(),
|
||||
ReturnEvaluator(),
|
||||
ExpressionEvaluator()
|
||||
).evaluate(node, environment)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package io.smnp.evaluation.model.exception
|
||||
|
||||
import io.smnp.type.model.Value
|
||||
|
||||
class Return(val value: Value) : Exception()
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user