diff --git a/core/src/main/kotlin/eu/iamgio/quarkdown/function/value/ValueFactory.kt b/core/src/main/kotlin/eu/iamgio/quarkdown/function/value/ValueFactory.kt index 94ab5db2..bdfc83d2 100644 --- a/core/src/main/kotlin/eu/iamgio/quarkdown/function/value/ValueFactory.kt +++ b/core/src/main/kotlin/eu/iamgio/quarkdown/function/value/ValueFactory.kt @@ -241,43 +241,6 @@ object ValueFactory { expandFunctionCalls = true, ).asInline() - /** - * Evaluates an expression from a raw string input. - * @param raw string input that may contain both static values and function calls (e.g. `"2 + 2 is .sum {2} {2}"`) - * @param context context to retrieve the pipeline from - * @return the expression (in the previous example: `ComposedExpression(DynamicValue("2 + 2 is "), FunctionCall(sum, 2, 2))`) - */ - fun expression( - raw: String, - context: Context, - ): Expression? { - // The content of the argument is tokenized to distinguish static values (string/number/...) - // from nested function calls, which are also expressions. - val components = - this.markdown( - lexer = context.flavor.lexerFactory.newExpressionLexer(raw, allowBlockFunctionCalls = true), - context, - expandFunctionCalls = false, - ).unwrappedValue.children - - if (components.isEmpty()) return null - - /** - * @param node to convert - * @return an expression that matches the node type - */ - fun nodeToExpression(node: Node): Expression = - when (node) { - is PlainTextNode -> DynamicValue(node.text) // The actual type is determined later. - is FunctionCallNode -> context.resolveUnchecked(node) // Function existance is checked later. - - else -> throw IllegalArgumentException("Unexpected node $node in expression $raw") - } - - // Nodes are mapped to expressions. - return ComposedExpression(expressions = components.map(::nodeToExpression)) - } - /** * @param raw string input to parse the expression from * @param context context to retrieve the pipeline from @@ -344,6 +307,43 @@ object ValueFactory { ) } + /** + * Evaluates an expression from a raw string input. + * @param raw string input that may contain both static values and function calls (e.g. `"2 + 2 is .sum {2} {2}"`) + * @param context context to retrieve the pipeline from + * @return the expression (in the previous example: `ComposedExpression(DynamicValue("2 + 2 is "), FunctionCall(sum, 2, 2))`) + */ + fun expression( + raw: String, + context: Context, + ): Expression? { + // The content of the argument is tokenized to distinguish static values (string/number/...) + // from nested function calls, which are also expressions. + val components = + this.markdown( + lexer = context.flavor.lexerFactory.newExpressionLexer(raw, allowBlockFunctionCalls = true), + context, + expandFunctionCalls = false, + ).unwrappedValue.children + + if (components.isEmpty()) return null + + /** + * @param node to convert + * @return an expression that matches the node type + */ + fun nodeToExpression(node: Node): Expression = + when (node) { + is PlainTextNode -> DynamicValue(node.text) // The actual type is determined later. + is FunctionCallNode -> context.resolveUnchecked(node) // Function existance is checked later. + + else -> throw IllegalArgumentException("Unexpected node $node in expression $raw") + } + + // Nodes are mapped to expressions. + return ComposedExpression(expressions = components.map(::nodeToExpression)) + } + /** * Evaluates an expression from a raw string input. * @param raw string input that may contain both static values and function calls (e.g. `"2 + 2 is .sum {2} {2}"`) diff --git a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Ecosystem.kt b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Ecosystem.kt index ca9b0e8e..84fc4245 100644 --- a/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Ecosystem.kt +++ b/stdlib/src/main/kotlin/eu/iamgio/quarkdown/stdlib/Ecosystem.kt @@ -2,7 +2,6 @@ package eu.iamgio.quarkdown.stdlib import eu.iamgio.quarkdown.context.Context import eu.iamgio.quarkdown.function.error.FunctionRuntimeException -import eu.iamgio.quarkdown.function.expression.eval import eu.iamgio.quarkdown.function.reflect.Injected import eu.iamgio.quarkdown.function.value.OutputValue import eu.iamgio.quarkdown.function.value.ValueFactory @@ -36,14 +35,5 @@ fun include( // Evaluate the Quarkdown source. // This automatically converts the source into a value (e.g. a node, a string, a number, etc.) // and fills the current context with new declarations (e.g. variables, functions, link definitions, etc.) - val result = - ValueFactory.expression(raw, context)?.eval() - ?: throw FunctionRuntimeException("Cannot include sub-file $file: the Quarkdown source could not be evaluated") - - // The value must be an output value in order to comply with the function rules. - return result as? OutputValue<*> - ?: throw FunctionRuntimeException( - "Cannot include sub-file $file: the evaluation of the Quarkdown source is not a suitable output value " + - "(${result::class.simpleName} found)", - ) + return ValueFactory.eval(raw, context) }