Create scaffolding for custom functions

This commit is contained in:
2020-03-11 19:59:29 +01:00
parent eb4fb1e980
commit e7bf085f58
10 changed files with 101 additions and 5 deletions

View File

@@ -0,0 +1,25 @@
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.type.model.Value
object CustomFunction {
fun create(node: FunctionDefinitionNode): Function {
val identifier = (node.identifier as IdentifierNode).token.rawValue
return object : Function(identifier) {
override fun define(new: FunctionDefinitionTool) {
val (_, argumentsNode, bodyNode) = node
val signature = FunctionSignatureParser.parseSignature(argumentsNode as FunctionDefinitionArgumentsNode)
new function signature define { env, args ->
val boundArguments = FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env)
// TODO(Implement bodyNode evaluation)
Value.void()
}
}
}
}
}

View File

@@ -0,0 +1,26 @@
package io.smnp.callable.function
import io.smnp.dsl.ast.model.node.FunctionDefinitionArgumentsNode
import io.smnp.dsl.ast.model.node.IdentifierNode
import io.smnp.dsl.ast.model.node.OptionalFunctionDefinitionArgumentNode
import io.smnp.dsl.ast.model.node.RegularFunctionDefinitionArgumentNode
import io.smnp.environment.Environment
import io.smnp.error.ShouldNeverReachThisLineException
import io.smnp.evaluation.evaluator.ExpressionEvaluator
import io.smnp.type.model.Value
object FunctionEnvironmentProvider {
fun provideEnvironment(signature: FunctionDefinitionArgumentsNode, actualArgs: List<Value>, environment: Environment): Map<String, Value> {
val evaluator = ExpressionEvaluator()
return signature.items.mapIndexed { index, node ->
when (node) {
is RegularFunctionDefinitionArgumentNode -> (node.identifier as IdentifierNode).token.rawValue to actualArgs[index]
is OptionalFunctionDefinitionArgumentNode -> (node.identifier as IdentifierNode).token.rawValue to evaluator.evaluate(
node.defaultValue,
environment
).value!!
else -> throw ShouldNeverReachThisLineException()
}
}.toMap()
}
}

View File

@@ -3,6 +3,10 @@ package io.smnp.dsl.ast.model.node
import io.smnp.dsl.token.model.entity.TokenPosition
class FunctionDefinitionNode(identifier: Node, arguments: Node, body: Node, position: TokenPosition) : Node(3, position) {
operator fun component1() = children[0]
operator fun component2() = children[1]
operator fun component3() = children[2]
val identifier: Node
get() = children[0]

View File

@@ -1,5 +1,7 @@
package io.smnp.environment
import io.smnp.callable.function.Function
import io.smnp.callable.method.Method
import io.smnp.callable.signature.ActualSignatureFormatter.format
import io.smnp.ext.DefaultModuleRegistry
import io.smnp.runtime.model.CallStack
@@ -69,4 +71,12 @@ class DefaultEnvironment : Environment {
override fun printCallStack() {
callStack.pretty()
}
override fun defineFunction(function: Function) {
rootModule.addFunction(function)
}
override fun defineMethod(method: Method) {
rootModule.addMethod(method)
}
}

View File

@@ -0,0 +1,17 @@
package io.smnp.evaluation.evaluator
import io.smnp.callable.function.CustomFunction
import io.smnp.dsl.ast.model.node.FunctionDefinitionNode
import io.smnp.dsl.ast.model.node.Node
import io.smnp.environment.Environment
import io.smnp.evaluation.model.entity.EvaluatorOutput
class FunctionDefinitionEvaluator : Evaluator() {
override fun supportedNodes() = listOf(FunctionDefinitionNode::class)
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val function = CustomFunction.create(node as FunctionDefinitionNode)
environment.defineFunction(function)
return EvaluatorOutput.ok()
}
}

View File

@@ -10,7 +10,11 @@ class RootEvaluator : Evaluator() {
override fun supportedNodes() = listOf(RootNode::class)
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
val evaluator = ExpressionEvaluator()
val evaluator = oneOf(
ExpressionEvaluator(),
FunctionDefinitionEvaluator()
)
for(child in node.children) {
val output = evaluator.evaluate(child, environment)
if(output.result == EvaluationResult.FAILED) {