Enable passing arguments to custom functions
This commit is contained in:
25
api/src/main/kotlin/io/smnp/collection/Stack.kt
Normal file
25
api/src/main/kotlin/io/smnp/collection/Stack.kt
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
package io.smnp.collection
|
||||||
|
|
||||||
|
class Stack<T> private constructor(private val list: MutableList<T>) : List<T> by list {
|
||||||
|
fun push(item: T) {
|
||||||
|
list.add(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun pop(): T? {
|
||||||
|
if(list.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val last = list.last()
|
||||||
|
list.removeAt(list.size-1)
|
||||||
|
return last
|
||||||
|
}
|
||||||
|
|
||||||
|
fun top() = list.last()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun <T> of(vararg items: T): Stack<T> {
|
||||||
|
return Stack(mutableListOf(*items))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,4 +12,9 @@ interface Environment {
|
|||||||
fun printCallStack()
|
fun printCallStack()
|
||||||
fun defineFunction(function: Function)
|
fun defineFunction(function: Function)
|
||||||
fun defineMethod(method: Method)
|
fun defineMethod(method: Method)
|
||||||
|
fun pushScope(scope: MutableMap<String, Value> = mutableMapOf())
|
||||||
|
fun popScope(): Map<String, Value>?
|
||||||
|
fun printScopes()
|
||||||
|
fun setVariable(name: String, value: Value)
|
||||||
|
fun getVariable(name: String): Value
|
||||||
}
|
}
|
||||||
@@ -1,28 +1,22 @@
|
|||||||
package io.smnp.runtime.model
|
package io.smnp.runtime.model
|
||||||
|
|
||||||
|
import io.smnp.collection.Stack
|
||||||
import io.smnp.type.model.Value
|
import io.smnp.type.model.Value
|
||||||
import io.smnp.type.module.Module
|
import io.smnp.type.module.Module
|
||||||
|
|
||||||
|
|
||||||
class CallStack {
|
class CallStack {
|
||||||
private val items = mutableListOf<CallStackItem>()
|
private val items = Stack.of<CallStackFrame>()
|
||||||
|
|
||||||
fun push(module: Module, name: String, arguments: List<Value>) {
|
fun push(module: Module, name: String, arguments: List<Value>) {
|
||||||
items.add(CallStackItem(module, name, arguments))
|
items.push(CallStackFrame(module, name, arguments))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun push(item: CallStackItem) {
|
fun push(frame: CallStackFrame) = items.push(frame)
|
||||||
items.add(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pop(): CallStackItem? {
|
fun pop() = items.pop()
|
||||||
if(items.isEmpty()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
val last = items.last()
|
fun top() = items.top()
|
||||||
items.removeAt(items.size-1)
|
|
||||||
return last
|
|
||||||
}
|
|
||||||
|
|
||||||
fun pretty() {
|
fun pretty() {
|
||||||
items.asReversed().forEachIndexed { index, item -> println("[${items.size - index - 1}] $item") }
|
items.asReversed().forEachIndexed { index, item -> println("[${items.size - index - 1}] $item") }
|
||||||
|
|||||||
35
api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt
Normal file
35
api/src/main/kotlin/io/smnp/runtime/model/CallStackFrame.kt
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
package io.smnp.runtime.model
|
||||||
|
|
||||||
|
import io.smnp.callable.signature.ActualSignatureFormatter
|
||||||
|
import io.smnp.collection.Stack
|
||||||
|
import io.smnp.type.model.Value
|
||||||
|
import io.smnp.type.module.Module
|
||||||
|
|
||||||
|
data class CallStackFrame(
|
||||||
|
val module: Module,
|
||||||
|
val name: String,
|
||||||
|
val arguments: List<Value>
|
||||||
|
) {
|
||||||
|
private val scopes = Stack.of<MutableMap<String, Value>>(mutableMapOf())
|
||||||
|
|
||||||
|
fun pushScope(scope: MutableMap<String, Value> = mutableMapOf()) {
|
||||||
|
scopes.push(scope)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun popScope() = scopes.pop()
|
||||||
|
|
||||||
|
fun setVariable(name: String, value: Value) {
|
||||||
|
val scope = scopes.lastOrNull { it.containsKey(name) } ?: scopes.top()
|
||||||
|
scope[name] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getVariable(name: String): Value {
|
||||||
|
return scopes.lastOrNull { it.containsKey(name) }?.get(name) ?: throw RuntimeException("Variable `$name` not found")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun prettyScope() {
|
||||||
|
scopes.asReversed().forEachIndexed { index, item -> println("[${scopes.size - index - 1}] $item") }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString() = "${module.canonicalName}::$name${ActualSignatureFormatter.format(arguments.toTypedArray())}"
|
||||||
|
}
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
package io.smnp.runtime.model
|
|
||||||
|
|
||||||
import io.smnp.callable.signature.ActualSignatureFormatter
|
|
||||||
import io.smnp.type.model.Value
|
|
||||||
import io.smnp.type.module.Module
|
|
||||||
|
|
||||||
data class CallStackItem(
|
|
||||||
val module: Module,
|
|
||||||
val name: String,
|
|
||||||
val arguments: List<Value>
|
|
||||||
) {
|
|
||||||
override fun toString() = "${module.canonicalName}::$name${ActualSignatureFormatter.format(arguments.toTypedArray())}"
|
|
||||||
}
|
|
||||||
@@ -15,15 +15,18 @@ 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()
|
val evaluator = BlockEvaluator(dedicatedScope = false)
|
||||||
|
|
||||||
new function signature body { env, args ->
|
new function signature body { env, args ->
|
||||||
val boundArguments = FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env)
|
val boundArguments = FunctionEnvironmentProvider.provideEnvironment(argumentsNode, args, env)
|
||||||
// TODO push boundArguments to variables scope
|
|
||||||
try {
|
try {
|
||||||
|
env.pushScope(boundArguments.toMutableMap())
|
||||||
evaluator.evaluate(bodyNode, env)
|
evaluator.evaluate(bodyNode, env)
|
||||||
} catch(value: Return) {
|
} catch(value: Return) {
|
||||||
return@body value.value
|
return@body value.value
|
||||||
|
} finally {
|
||||||
|
env.popScope()
|
||||||
}
|
}
|
||||||
|
|
||||||
Value.void()
|
Value.void()
|
||||||
|
|||||||
@@ -79,4 +79,14 @@ class DefaultEnvironment : Environment {
|
|||||||
override fun defineMethod(method: Method) {
|
override fun defineMethod(method: Method) {
|
||||||
rootModule.addMethod(method)
|
rootModule.addMethod(method)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun pushScope(scope: MutableMap<String, Value>) = callStack.top().pushScope(scope)
|
||||||
|
|
||||||
|
override fun popScope() = callStack.top().popScope()
|
||||||
|
|
||||||
|
override fun printScopes() = callStack.top().prettyScope()
|
||||||
|
|
||||||
|
override fun setVariable(name: String, value: Value) = callStack.top().setVariable(name, value)
|
||||||
|
|
||||||
|
override fun getVariable(name: String) = callStack.top().getVariable(name)
|
||||||
}
|
}
|
||||||
@@ -6,15 +6,18 @@ import io.smnp.environment.Environment
|
|||||||
import io.smnp.evaluation.model.entity.EvaluatorOutput
|
import io.smnp.evaluation.model.entity.EvaluatorOutput
|
||||||
import io.smnp.evaluation.model.enumeration.EvaluationResult
|
import io.smnp.evaluation.model.enumeration.EvaluationResult
|
||||||
|
|
||||||
class BlockEvaluator : Evaluator() {
|
class BlockEvaluator(private val dedicatedScope: Boolean) : Evaluator() {
|
||||||
override fun supportedNodes() = listOf(BlockNode::class)
|
override fun supportedNodes() = listOf(BlockNode::class)
|
||||||
|
|
||||||
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
||||||
val evaluator = DefaultEvaluator()
|
val evaluator = DefaultEvaluator()
|
||||||
|
|
||||||
|
if (dedicatedScope) environment.pushScope()
|
||||||
val ok = (node as BlockNode).statements.all {
|
val ok = (node as BlockNode).statements.all {
|
||||||
evaluator.evaluate(it, environment).result != EvaluationResult.FAILED
|
evaluator.evaluate(it, environment).result != EvaluationResult.FAILED
|
||||||
}
|
}
|
||||||
|
if (dedicatedScope) environment.popScope()
|
||||||
|
|
||||||
return if(ok) EvaluatorOutput.ok() else EvaluatorOutput.fail()
|
return if (ok) EvaluatorOutput.ok() else EvaluatorOutput.fail()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,7 +10,7 @@ class DefaultEvaluator : Evaluator() {
|
|||||||
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
||||||
return oneOf(
|
return oneOf(
|
||||||
ConditionEvaluator(),
|
ConditionEvaluator(),
|
||||||
BlockEvaluator(),
|
BlockEvaluator(true),
|
||||||
ThrowEvaluator(),
|
ThrowEvaluator(),
|
||||||
ReturnEvaluator(),
|
ReturnEvaluator(),
|
||||||
ExpressionEvaluator()
|
ExpressionEvaluator()
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class ExpressionEvaluator : Evaluator() {
|
|||||||
NoteLiteralEvaluator(),
|
NoteLiteralEvaluator(),
|
||||||
ListEvaluator(),
|
ListEvaluator(),
|
||||||
MapEvaluator(),
|
MapEvaluator(),
|
||||||
|
IdentifierEvaluator(),
|
||||||
|
|
||||||
MinusOperatorEvaluator(),
|
MinusOperatorEvaluator(),
|
||||||
NotOperatorEvaluator(),
|
NotOperatorEvaluator(),
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package io.smnp.evaluation.evaluator
|
||||||
|
|
||||||
|
import io.smnp.dsl.ast.model.node.IdentifierNode
|
||||||
|
import io.smnp.dsl.ast.model.node.Node
|
||||||
|
import io.smnp.environment.Environment
|
||||||
|
import io.smnp.evaluation.model.entity.EvaluatorOutput
|
||||||
|
|
||||||
|
class IdentifierEvaluator : Evaluator() {
|
||||||
|
override fun supportedNodes() = listOf(IdentifierNode::class)
|
||||||
|
|
||||||
|
override fun tryToEvaluate(node: Node, environment: Environment): EvaluatorOutput {
|
||||||
|
val identifier = (node as IdentifierNode).token.rawValue
|
||||||
|
return EvaluatorOutput.value(environment.getVariable(identifier))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user