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) {
|
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))
|
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.FunctionDefinitionArgumentsNode
|
||||||
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
|
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
|
||||||
import io.smnp.dsl.ast.model.node.IdentifierNode
|
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
|
import io.smnp.type.model.Value
|
||||||
|
|
||||||
object CustomFunction {
|
object CustomFunction {
|
||||||
@@ -13,10 +15,17 @@ object CustomFunction {
|
|||||||
override fun define(new: FunctionDefinitionTool) {
|
override fun define(new: FunctionDefinitionTool) {
|
||||||
val (_, argumentsNode, bodyNode) = node
|
val (_, argumentsNode, bodyNode) = node
|
||||||
val signature = FunctionSignatureParser.parseSignature(argumentsNode as FunctionDefinitionArgumentsNode)
|
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)
|
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()
|
Value.void()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package io.smnp.dsl.ast.model.node
|
package io.smnp.dsl.ast.model.node
|
||||||
|
|
||||||
class ReturnNode(value: Node) : Node(1, value.position) {
|
class ReturnNode(value: Node) : Node(1, value.position) {
|
||||||
|
operator fun component1() = children[0]
|
||||||
|
|
||||||
val value: Node
|
val value: Node
|
||||||
get() = children[0]
|
get() = children[0]
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class BlockEvaluator : Evaluator() {
|
|||||||
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
||||||
val evaluator = DefaultEvaluator()
|
val evaluator = DefaultEvaluator()
|
||||||
val ok = (node as BlockNode).statements.all {
|
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()
|
return if(ok) EvaluatorOutput.ok() else EvaluatorOutput.fail()
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ class DefaultEvaluator : Evaluator() {
|
|||||||
ConditionEvaluator(),
|
ConditionEvaluator(),
|
||||||
BlockEvaluator(),
|
BlockEvaluator(),
|
||||||
ThrowEvaluator(),
|
ThrowEvaluator(),
|
||||||
|
ReturnEvaluator(),
|
||||||
ExpressionEvaluator()
|
ExpressionEvaluator()
|
||||||
).evaluate(node, environment)
|
).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") {
|
class PrintlnFunction : Function("println") {
|
||||||
override fun define(new: FunctionDefinitionTool) {
|
override fun define(new: FunctionDefinitionTool) {
|
||||||
new function vararg(allTypes()) define { _module, (vararg) ->
|
new function vararg(allTypes()) body { _, (vararg) ->
|
||||||
// TODO: Implement equivalent of "toString()" method
|
// TODO: Implement equivalent of "toString()" method
|
||||||
println((vararg.value!! as List<Value>).joinToString("") { it.value!!.toString() })
|
println((vararg.value!! as List<Value>).joinToString("") { it.value!!.toString() })
|
||||||
Value.void()
|
Value.void()
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import io.smnp.type.model.Value
|
|||||||
|
|
||||||
class DebugFunction : Function("debug") {
|
class DebugFunction : Function("debug") {
|
||||||
override fun define(new: FunctionDefinitionTool) {
|
override fun define(new: FunctionDefinitionTool) {
|
||||||
new function simple() define { env, _ ->
|
new function simple() body { env, _ ->
|
||||||
env.printCallStack()
|
env.printCallStack()
|
||||||
Value.void()
|
Value.void()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user