Quarkdown ValueFactory Expression Parsing Architecture: A Deep Dive

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, 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
  • The pipeline progresses through eval()safeExpression()expression()ComposedExpressionEvalExpressionVisitor 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. 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →