diff --git a/api/src/main/kotlin/io/smnp/callable/function/FunctionDefinitionTool.kt b/api/src/main/kotlin/io/smnp/callable/function/FunctionDefinitionTool.kt index 66f9236..aa783cc 100644 --- a/api/src/main/kotlin/io/smnp/callable/function/FunctionDefinitionTool.kt +++ b/api/src/main/kotlin/io/smnp/callable/function/FunctionDefinitionTool.kt @@ -12,7 +12,7 @@ class FunctionDefinitionTool { } inner class FunctionDefinitionToolStage2(private val signature: Signature) { - infix fun define(body: (Environment, List) -> Value) { + infix fun body(body: (Environment, List) -> Value) { definitions.add(FunctionDefinition(signature, body)) } } diff --git a/app/src/main/kotlin/io/smnp/callable/function/CustomFunction.kt b/app/src/main/kotlin/io/smnp/callable/function/CustomFunction.kt index 98fb85a..473c3bc 100644 --- a/app/src/main/kotlin/io/smnp/callable/function/CustomFunction.kt +++ b/app/src/main/kotlin/io/smnp/callable/function/CustomFunction.kt @@ -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() } } diff --git a/app/src/main/kotlin/io/smnp/dsl/ast/model/node/ReturnNode.kt b/app/src/main/kotlin/io/smnp/dsl/ast/model/node/ReturnNode.kt index 5b5949d..bd853a4 100644 --- a/app/src/main/kotlin/io/smnp/dsl/ast/model/node/ReturnNode.kt +++ b/app/src/main/kotlin/io/smnp/dsl/ast/model/node/ReturnNode.kt @@ -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] diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/BlockEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/BlockEvaluator.kt index 95b4721..2a1f7bf 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/BlockEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/BlockEvaluator.kt @@ -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() diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt index 4d7f426..2dc133b 100644 --- a/app/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/DefaultEvaluator.kt @@ -12,6 +12,7 @@ class DefaultEvaluator : Evaluator() { ConditionEvaluator(), BlockEvaluator(), ThrowEvaluator(), + ReturnEvaluator(), ExpressionEvaluator() ).evaluate(node, environment) } diff --git a/app/src/main/kotlin/io/smnp/evaluation/evaluator/ReturnEvaluator.kt b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ReturnEvaluator.kt new file mode 100644 index 0000000..a20ee61 --- /dev/null +++ b/app/src/main/kotlin/io/smnp/evaluation/evaluator/ReturnEvaluator.kt @@ -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) + } +} \ No newline at end of file diff --git a/app/src/main/kotlin/io/smnp/evaluation/model/exception/Return.kt b/app/src/main/kotlin/io/smnp/evaluation/model/exception/Return.kt new file mode 100644 index 0000000..24cd715 --- /dev/null +++ b/app/src/main/kotlin/io/smnp/evaluation/model/exception/Return.kt @@ -0,0 +1,5 @@ +package io.smnp.evaluation.model.exception + +import io.smnp.type.model.Value + +class Return(val value: Value) : Exception() \ No newline at end of file diff --git a/modules/io/src/main/kotlin/io/smnp/ext/io/function/PrintlnFunction.kt b/modules/io/src/main/kotlin/io/smnp/ext/io/function/PrintlnFunction.kt index 41a5edd..62a0d9f 100644 --- a/modules/io/src/main/kotlin/io/smnp/ext/io/function/PrintlnFunction.kt +++ b/modules/io/src/main/kotlin/io/smnp/ext/io/function/PrintlnFunction.kt @@ -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).joinToString("") { it.value!!.toString() }) Value.void() diff --git a/modules/lang/src/main/kotlin/io/smnp/ext/lang/function/DebugFunction.kt b/modules/lang/src/main/kotlin/io/smnp/ext/lang/function/DebugFunction.kt index ac4cbd2..a91dd59 100644 --- a/modules/lang/src/main/kotlin/io/smnp/ext/lang/function/DebugFunction.kt +++ b/modules/lang/src/main/kotlin/io/smnp/ext/lang/function/DebugFunction.kt @@ -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() }