Skip to content

Commit

Permalink
Replace FunctionArgumentsLinker with new ArgumentBindings
Browse files Browse the repository at this point in the history
  • Loading branch information
iamgio committed Jul 30, 2024
1 parent 5c05ed2 commit 12dc7e9
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 64 deletions.
9 changes: 5 additions & 4 deletions core/src/main/kotlin/eu/iamgio/quarkdown/function/Function.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package eu.iamgio.quarkdown.function

import eu.iamgio.quarkdown.function.call.FunctionArgumentsLinker
import eu.iamgio.quarkdown.function.call.FunctionCall
import eu.iamgio.quarkdown.function.call.binding.ArgumentBindings
import eu.iamgio.quarkdown.function.value.OutputValue

/**
Expand All @@ -21,9 +22,9 @@ interface Function<T : OutputValue<*>> {
/**
* Function that maps the input arguments into an output value.
* Arguments and [parameters] compliance in terms of matching types and count is not checked here.
* The [FunctionArgumentsLinker] allows looking up argument values by their parameter name.
* The [ArgumentBindings] allow looking up argument values by their parameter.
*/
val invoke: FunctionArgumentsLinker.() -> T
val invoke: (ArgumentBindings) -> T
}

/**
Expand All @@ -33,7 +34,7 @@ interface Function<T : OutputValue<*>> {
data class SimpleFunction<T : OutputValue<*>>(
override val name: String,
override val parameters: List<FunctionParameter<*>>,
override val invoke: FunctionArgumentsLinker.() -> T,
override val invoke: (ArgumentBindings) -> T,
) : Function<T>

fun Function<*>.asString() =
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package eu.iamgio.quarkdown.function.call

import eu.iamgio.quarkdown.context.Context
import eu.iamgio.quarkdown.function.Function
import eu.iamgio.quarkdown.function.call.binding.AllArgumentsBinder
import eu.iamgio.quarkdown.function.expression.Expression
import eu.iamgio.quarkdown.function.expression.visitor.ExpressionVisitor
import eu.iamgio.quarkdown.function.value.OutputValue
Expand All @@ -25,11 +26,9 @@ data class FunctionCall<T : OutputValue<*>>(
* @return the function output
*/
fun execute(): T {
// Allows linking arguments to their parameter.
val linker = FunctionArgumentsLinker(this)
linker.link()

return function.invoke(linker)
// Allows binding each argument to its parameter.
val bindings = AllArgumentsBinder(this).createBindings(function.parameters)
return function.invoke(bindings)
}

override fun <T> accept(visitor: ExpressionVisitor<T>): T = visitor.visit(this)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ typealias ArgumentBindings = Map<FunctionParameter<*>, FunctionCallArgument>

/**
* Builder of parameter-argument pairs of a function call.
* Allows binding each argument to its corresponding parameter,
* and may throw an exception if some cannot be paired.
* @see InjectedArgumentsBinder
* @see InjectedArgumentsBinder
* @see AllArgumentsBinder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package eu.iamgio.quarkdown.function.reflect

import eu.iamgio.quarkdown.function.Function
import eu.iamgio.quarkdown.function.FunctionParameter
import eu.iamgio.quarkdown.function.call.FunctionArgumentsLinker
import eu.iamgio.quarkdown.function.call.binding.ArgumentBindings
import eu.iamgio.quarkdown.function.error.FunctionRuntimeException
import eu.iamgio.quarkdown.function.value.InputValue
import eu.iamgio.quarkdown.function.value.OutputValue
Expand Down Expand Up @@ -39,10 +39,10 @@ class KFunctionAdapter<T : OutputValue<*>>(private val function: KFunction<T>) :
)
}

override val invoke: FunctionArgumentsLinker.() -> T
get() = {
override val invoke: (ArgumentBindings) -> T
get() = { bindings ->
val args =
this.links.asSequence().associate { (parameter, argument) ->
bindings.asSequence().associate { (parameter, argument) ->
// Corresponding KParameter.
val param = function.parameters[parameter.index]

Expand Down
32 changes: 23 additions & 9 deletions core/src/test/kotlin/eu/iamgio/quarkdown/StandaloneFunctionTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import eu.iamgio.quarkdown.function.FunctionParameter
import eu.iamgio.quarkdown.function.SimpleFunction
import eu.iamgio.quarkdown.function.call.FunctionCall
import eu.iamgio.quarkdown.function.call.FunctionCallArgument
import eu.iamgio.quarkdown.function.call.binding.ArgumentBindings
import eu.iamgio.quarkdown.function.error.InvalidArgumentCountException
import eu.iamgio.quarkdown.function.error.MismatchingArgumentTypeException
import eu.iamgio.quarkdown.function.error.NoSuchElementFunctionException
Expand All @@ -34,6 +35,19 @@ import kotlin.test.assertNull
* For tests of function calls from Quarkdown sources see [FunctionNodeExpansionTest].
*/
class StandaloneFunctionTest {
/**
* @param name name of the parameter to get the corresponding argument value for
* @param T type of the value
* @return the value of the argument by the given name
* @throws NoSuchElementException if [name] does not match any parameter name
*/
private inline fun <reified T> ArgumentBindings.arg(name: String): T =
this.entries
.first { it.key.name == name }
.value // Map.Entry method: returns FunctionCallArgument
.value // FunctionCallArgument method: returns InputValue<T>
.unwrappedValue as T // InputValue<T> method: returns T

@Test
fun `no arguments`() {
val function =
Expand All @@ -59,9 +73,9 @@ class StandaloneFunctionTest {
FunctionParameter("to", StringValue::class, index = 0),
FunctionParameter("from", StringValue::class, index = 1),
),
) {
val to = arg<String>("to")
val from = arg<String>("from")
) { bindings ->
val to = bindings.arg<String>("to")
val from = bindings.arg<String>("from")
ValueFactory.string("Hello $to from $from")
}

Expand Down Expand Up @@ -96,9 +110,9 @@ class StandaloneFunctionTest {
FunctionParameter("to", StringValue::class, index = 0),
FunctionParameter("from", StringValue::class, index = 1),
),
) {
val to = arg<String>("to")
val from = arg<String>("from")
) { bindings ->
val to = bindings.arg<String>("to")
val from = bindings.arg<String>("from")
ValueFactory.string("Hello $to from $from")
}

Expand Down Expand Up @@ -139,9 +153,9 @@ class StandaloneFunctionTest {
FunctionParameter("to", StringValue::class, index = 0),
FunctionParameter("from", StringValue::class, index = 1),
),
) {
val to = arg<String>("to")
val from = arg<String>("from")
) { bindings ->
val to = bindings.arg<String>("to")
val from = bindings.arg<String>("from")
ValueFactory.string("Hello $to from $from")
}

Expand Down
4 changes: 2 additions & 2 deletions stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Flow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ fun function(

// The custom function itself.
val function =
SimpleFunction(name, parameters) {
val args = this.links.values.map { it.value }.toTypedArray()
SimpleFunction(name, parameters) { bindings ->
val args = bindings.values.map { it.value }.toTypedArray()

// The final result is evaluated and returned as a dynamic, hence it can be used as any type.
body.invokeDynamic(*args)
Expand Down

0 comments on commit 12dc7e9

Please sign in to comment.