# Quarkdown ValueFactory Expression Parsing Architecture: A Deep Dive

> Explore Quarkdown's ValueFactory architecture for expression parsing. Understand its multi-stage pipeline transforming input into typed Value objects via tokenization and evaluation.

- Repository: [Giorgio Garofalo/quarkdown](https://github.com/iamgio/quarkdown)
- Tags: architecture
- Published: 2026-04-29

---

**The `ValueFactory` object in Quarkdown serves as the central conversion hub that transforms raw user input into typed `Value` objects through a multi-stage pipeline involving tokenization, `ComposedExpression` construction, and visitor-based evaluation.**

Quarkdown is a modern markdown-based typesetting system that supports dynamic function calls within document content. At the heart of this capability lies the **Quarkdown ValueFactory expression parsing architecture**, which converts strings, numbers, and complex expressions into executable `Value` instances. Located in [`quarkdown-core/src/main/kotlin/com/quarkdown/core/function/value/factory/ValueFactory.kt`](https://github.com/iamgio/quarkdown/blob/main/quarkdown-core/src/main/kotlin/com/quarkdown/core/function/value/factory/ValueFactory.kt), this factory handles everything from simple scalar conversion to nested function evaluation without exposing parsing internals to callers.

## Core Components of the ValueFactory Architecture

### The ValueFactory Object

The `ValueFactory` object acts as a static utility exposing conversion methods for every supported type. Key entry points include `eval()` for general expression handling, `safeExpression()` for fault-tolerant parsing, and specialized converters like `number()`, `range()`, and `lambda()`. Each method returns a concrete `Value` subtype—such as `NumberValue`, `ObjectValue<Range>`, or `LambdaValue`—that integrates seamlessly with the compiler's pipeline.

### Expression Hierarchy

Expressions in Quarkdown follow a hierarchical structure centered around the `Expression` interface. A `ComposedExpression` represents a sequence of sub-expressions containing both static text and unresolved function calls, while `SafeExpression` wraps any expression with fallback behavior to handle runtime failures gracefully.

### Visitor Pattern Implementation

Evaluation delegates to dedicated visitors rather than inline logic. The `EvalExpressionVisitor` traverses expression trees to resolve function calls via the current `Context` and produce `OutputValue` results. For concatenation operations, the `AppendExpressionVisitor` merges multiple expressions into a single coherent unit.

## The Expression Parsing Pipeline

### Entry Point and Safe Wrapping

Processing begins with `ValueFactory.eval(raw, context, fallback)`, which internally invokes `safeExpression()`. This method attempts to parse the input via `expression()` and, upon failure, returns a `SafeExpression` that catches `InvalidExpressionEvalException` and resorts to the fallback—typically treating the raw content as markdown.

### Tokenization and Node Processing

When `expression()` receives a string, it first strips comments using `COMMENT_REGEX`, then checks for the forced-lambda prefix `@lambda`. For general expressions, it tokenizes input via `newExpressionLexer()` and transforms each token into sub-expressions through `nodeToExpression()`. Plain text becomes a `DynamicValue`, while function calls generate `UncheckedFunctionCall` nodes that remain unresolved until evaluation time.

### Evaluation Strategy

The `ComposedExpression.eval()` method triggers `EvalExpressionVisitor` to process each sub-expression sequentially. The visitor resolves function calls against the provided `Context`, ensuring that only `OutputValue` instances reach the final result. If any sub-expression returns a non-output type, the system raises a `PipelineException`.

## Type Conversion Capabilities

Beyond expression parsing, `ValueFactory` provides extensive type coercion utilities:

- **Scalar values**: `string()`, `number()`, and `boolean()` wrap raw inputs in `StringValue`, `NumberValue`, or `BooleanValue`
- **Dimensional units**: `size()` parses CSS-like measurements (e.g., "12px") into `ObjectValue<Size>`, while `sizes()` handles multi-value declarations
- **Collections**: `iterable()` converts Kotlin collections, `Range` objects, or markdown lists into `OrderedCollectionValue`, and `dictionary()` builds key-value mappings
- **Lambdas**: `lambda()` delegates to `LambdaParser` to parse parameter definitions and body content into executable `LambdaValue` objects
- **Markdown**: `blockMarkdown()`, `inlineMarkdown()`, and `markdown()` transform raw markdown into AST sub-trees, enabling nested function expansion

## Error Handling and Safety Mechanisms

The architecture implements multiple safety layers to prevent compilation failures. **Scalar converters** throw `IllegalRawValueException` when inputs fail format validation. During expression evaluation, `InvalidExpressionEvalException` signals runtime errors like undefined function calls. The `SafeExpression` wrapper intercepts these exceptions and substitutes the configured fallback, ensuring that documents with invalid expressions degrade gracefully to plain text rather than crashing the pipeline.

## Summary

- **Quarkdown ValueFactory expression parsing architecture** centralizes all value conversion logic in a single static factory object located in [`ValueFactory.kt`](https://github.com/iamgio/quarkdown/blob/main/ValueFactory.kt)
- The pipeline progresses through `eval()` → `safeExpression()` → `expression()` → `ComposedExpression` → `EvalExpressionVisitor` evaluation
- **SafeExpression** provides fault tolerance by catching `InvalidExpressionEvalException` and falling back to markdown representation
- **EvalExpressionVisitor** resolves function calls within expressions using the current compilation context
- Specialized converters handle scalars, ranges, sizes, colors, enumerations, lambdas, and markdown lists through dedicated utility methods

## Frequently Asked Questions

### What is the difference between `ValueFactory.eval()` and `ValueFactory.safeExpression()`?

`ValueFactory.eval()` immediately evaluates an expression and returns a concrete `OutputValue`, throwing exceptions on failure. `ValueFactory.safeExpression()` returns a `SafeExpression` wrapper that catches `InvalidExpressionEvalException` during evaluation and substitutes a fallback value, making it suitable for user-generated content where partial failure is acceptable.

### How does Quarkdown handle mixed text and function calls in expressions?

The lexer tokenizes mixed content into `PlainTextNode` and `FunctionCallNode` instances. `ValueFactory` transforms these into a `ComposedExpression` containing sub-expressions. During evaluation, `EvalExpressionVisitor` processes each node sequentially, concatenating static text with resolved function call results into a single `OutputValue`.

### What happens when a lambda expression is detected in the input?

When input starts with the `@lambda` prefix or is explicitly passed to `ValueFactory.lambda()`, the factory delegates to `LambdaParser` located in [`quarkdown-core/src/main/kotlin/com/quarkdown/core/parser/walker/lambda/LambdaParser.kt`](https://github.com/iamgio/quarkdown/blob/main/quarkdown-core/src/main/kotlin/com/quarkdown/core/parser/walker/lambda/LambdaParser.kt). This parser extracts parameter definitions and body content, creating a `LambdaValue` that executes its body within a forked context when invoked.

### How are markdown lists converted to iterable values?

`ValueFactory.iterable()` detects markdown list syntax and utilizes `MarkdownListToCollectionValue` utilities to parse the structure. Each list item becomes an element in an `OrderedCollectionValue`, enabling functions to iterate over document-defined collections without external data sources.