Key Differences Between KCL's AST Evaluator and Fast Evaluator

The AST evaluator executes a complete compilation pipeline including type checking and schema validation, while the fast evaluator interprets the AST directly to prioritize speed over language feature completeness.

The KCL programming language (kcl-lang/kcl) provides two distinct execution engines for running configuration code. Understanding the key differences between KCL's AST evaluator and its fast evaluator is essential for choosing the right approach for production deployments versus rapid prototyping scenarios.

Architectural Overview

KCL implements two fundamentally different execution strategies within its Rust codebase. The AST evaluator (kcl_evaluator::Evaluator) located in crates/evaluator/src/lib.rs processes code through a comprehensive compilation pipeline. In contrast, the fast evaluator (FastRunner) defined in crates/runner/src/runner.rs provides a lightweight interpretation path controlled by the fast_eval boolean flag in ExecProgramArgs.

The AST Evaluator: Full Compilation Pipeline

The AST evaluator represents KCL's production-grade execution engine. Defined at lines 55-68 of crates/evaluator/src/lib.rs, the Evaluator struct performs comprehensive semantic analysis before producing results.

The core structure initializes with a reference to the parsed program:

pub struct Evaluator<'ctx> {
    pub program: &'ctx ast::Program,
    // runtime, scopes, lazy evaluation, schema & rule stacks, etc.
}

The execution flow follows a strict pipeline via the run method (lines 62-68):

let modules = self.program.get_modules_for_pkg(kcl_ast::MAIN_PKG);
self.init_scope(kcl_ast::MAIN_PKG);
self.compile_ast_modules(&modules);
Ok(self.plan_globals_to_string())

This path executes parsing → type-checking → schema resolution → rule execution → runtime evaluation. According to the source code, the evaluator resolves imports, validates schemas, applies constraints, and generates both JSON and YAML results while handling hidden attributes, schema-type paths, and configuration overrides.

The Fast Evaluator: Direct AST Interpretation

The fast evaluator bypasses the compilation stage entirely. Located in crates/runner/src/runner.rs at lines 258-262, the FastRunner struct interprets the AST directly without semantic analysis.

The mode is controlled by the fast_eval boolean field (lines 68-71):

/// fast_eval denotes directly executing at the AST level to obtain
/// the result without any form of compilation.
#[serde(skip)]
pub fast_eval: bool,

When fast_eval is set to true, the Runner::run method instantiates FastRunner instead of the full Evaluator. The FastRunner walks the AST and evaluates expressions immediately, skipping type inference, schema merging, default value filling, and constraint validation.

Feature Support and Performance Comparison

The key differences between KCL's AST evaluator and its fast evaluator manifest in three critical areas:

Performance Characteristics

  • AST Evaluator: Slower execution due to comprehensive analysis, but guarantees correctness and complete error diagnostics with source-level information
  • Fast Evaluator: Much faster for simple scripts due to zero compilation overhead, limited to runtime panic reporting only

Language Feature Support

  • AST Evaluator: Full support for schemas, rules, constraints, imports, and complex configuration merging
  • Fast Evaluator: Limited to basic expressions and statements; ignores schemas, constraints, and import resolution

Execution Model

  • AST Evaluator: Creates a full evaluation context with scopes, lazy evaluation, and schema stacks
  • Fast Evaluator: Direct interpretation without compilation-stage work or validation

Practical Usage Examples

Full Evaluation with the AST Evaluator

Use Evaluator::new() for production scenarios requiring complete language semantics:

use kcl_evaluator::Evaluator;
use kcl_ast::ast::Program;

// Assume `program` is a parsed KCL AST.
let evaluator = Evaluator::new(&program);
let (json, yaml) = evaluator.run().expect("evaluation failed");
println!("JSON:\n{}", json);
println!("YAML:\n{}", yaml);

This approach validates all constraints and provides precise error locations referencing exact source positions when validation fails.

Fast Evaluation via API

Enable fast evaluation by setting fast_eval: true in ExecProgramArgs:

use kcl_runner::ExecProgramArgs;

let mut args = ExecProgramArgs::default();
args.k_filename_list = vec!["example.k".into()];
args.fast_eval = true;   // Enable fast path

let result = kcl_runner::run_program(args).map_err_to_result().unwrap();
println!("JSON (fast): {}", result.json_result);

Direct FastRunner Usage

For embedded scenarios, instantiate FastRunner directly:

use kcl_runner::{FastRunner, RunnerOptions};

let options = RunnerOptions {
    fast_eval: true,
    ..Default::default()
};
let fast_runner = FastRunner::new(Some(options));
let result = fast_runner.run().expect("fast run failed");
println!("Result: {}", result.json_result);

When using the fast evaluator, scripts containing schema definitions or import statements may produce different output compared to the full evaluator, as these features are not processed.

Summary

  • The AST evaluator in crates/evaluator/src/lib.rs provides production-grade execution with full semantic analysis, type checking, and schema validation through the Evaluator struct and its run method.
  • The fast evaluator in crates/runner/src/runner.rs offers lightweight AST interpretation via FastRunner when the fast_eval flag is enabled, prioritizing execution speed over feature completeness.
  • Use the AST evaluator for production deployments requiring constraint validation, import resolution, and precise error diagnostics pointing to specific source locations.
  • Use the fast evaluator for rapid prototyping, REPL-like interactions, or simple scripts where execution speed outweighs the need for schema validation and type checking.
  • The execution mode is controlled through the fast_eval field in ExecProgramArgs (lines 68-71) or by directly instantiating the respective runner struct.

Frequently Asked Questions

When should I use the AST evaluator versus the fast evaluator?

Use the AST evaluator when running production configuration pipelines that require schema validation, constraint checking, import resolution, and detailed error reporting with source-level diagnostics. Use the fast evaluator for development workflows, quick syntax verification, or simple scripts where you prioritize execution speed over strict validation of KCL's advanced features like schemas and rules.

What features are unavailable in the fast evaluator?

According to the implementation in crates/runner/src/runner.rs, the fast evaluator does not perform type checking, schema default value filling, constraint validation, or import resolution. It evaluates basic expressions and statements only, meaning schemas, rules, and complex configuration merging defined in crates/evaluator/src/lib.rs are ignored during execution.

How do I enable fast evaluation in KCL?

You can enable fast evaluation by setting fast_eval: true in the ExecProgramArgs struct when calling kcl_runner::run_program(), or by using the --fast_eval (-K) CLI flag which propagates through crates/cmd/src/lib.rs to the runner configuration. Developers can also instantiate FastRunner directly from crates/runner/src/runner.rs for embedded use cases requiring minimal overhead.

Does the fast evaluator produce the same output as the AST evaluator?

No. While both return JSON results through ExecProgramResult, the fast evaluator produces different output for scripts using schemas, constraints, or imports because it skips the validation and merging stages that occur in the full compilation pipeline. For simple scripts without schema definitions, the output may be identical, but production configurations should always use the AST evaluator to ensure complete semantic correctness.

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 →