This library is in flux. APIs may change without notice. Generated from source with koruc 0.1.7 on 8/19/2026.
Interpreter
~import std/interpreterKoru Interpreter Standard Library
interpreter.kz · 6 tors · ~[runtime]
Koru Interpreter Standard Library · 25 more lines
Koru Interpreter Standard Library
Enables runtime evaluation of Koru source code
DESIGN:
- Parses Koru source at runtime using the same parser as the compiler
- Walks the AST and executes events via registered dispatchers
- Tracks bindings in an environment as flow progresses
- Uses the shape_checker for optional validation before execution
Usage:
import std/interpreter
import std/runtime
// Register events you want callable at runtime
std/runtime:register(scope: "api") {
greet
process_order
}
// Interpret Koru source
std/interpreter:run(source: user_input, scope: "api")
| result r |> handle_result(value: r.value)
| parse-error e |> respond(status: 400, body: e.message)
| validation-error e |> respond(status: 400, body: e.message)
| dispatch-error e |> respond(status: 500, body: e.event)
// VALUE SERIALIZATION - Convert interpreter Value to JSON
~[retain] pub tor value.stringify { value: Value } -> string// MAIN INTERPRETER EVENTS
//
// The REPL define: install a subflow declaration into the session's
// defined-flows table, making it a verb callable on subsequent runs.
// A definition is `tor name { args }` followed by the impl flow
// `name = <body>`. The body is stored as SOURCE (durable) and re-parsed per
// dispatch; every call it makes runs through the same possession machinery,
// so a defined flow can never reach beyond what the session holds.
//
// The definition-time analyses (declared obligations must match the body's
// real behavior; every call must be within the session's scopes) are the
// richer guarantee and are rungs of the stance, not this slice; call-time
// possession enforcement is the floor and is already structural.
~[retain] pub tor define { source: string, defined: *DefinedFlows }
| defined string
| parse-error { message: string, line: u32, column: u32 }// Parse and execute in one step - the main interpreter entry point
// Use get-scope to get the dispatcher first, then pass it here
~[retain] pub tor run {
source: string,
dispatcher: DispatchFn,
cost_fn: ?CostFn,
creates_obligations_fn: ?ObligationsArrayFn,
discharges_obligations_fn: ?ObligationsArrayFn,
discharge_event_fn: ?DischargeEventFn,
creates_spec_fn: ?CreatesSpecFn,
discharges_spec_fn: ?DischargesSpecFn,
budget: ?u64,
handle_pool: ?*HandlePool,
fail_fast: bool,
scope_name: string,
auto_discharge: bool,
defined: ?*DefinedFlows
}
| result { value: Value, used: u64, handles: u32 }
| exhausted { used: u64, last_event: string, handles: u32 }
| parse-error { message: string, line: u32, column: u32 }
| validation-error string
| dispatch-error { event_name: string, message: string }// Cached parse + execute (reuses parsed flow for identical source input)
~[retain] pub tor run-cached {
source: string,
dispatcher: DispatchFn,
cost_fn: ?CostFn,
creates_obligations_fn: ?ObligationsArrayFn,
discharges_obligations_fn: ?ObligationsArrayFn,
discharge_event_fn: ?DischargeEventFn,
creates_spec_fn: ?CreatesSpecFn,
discharges_spec_fn: ?DischargesSpecFn,
budget: ?u64,
handle_pool: ?*HandlePool,
fail_fast: bool,
scope_name: string,
auto_discharge: bool,
defined: ?*DefinedFlows
}
| result { value: Value, used: u64, handles: u32 }
| exhausted { used: u64, last_event: string, handles: u32 }
| parse-error { message: string, line: u32, column: u32 }
| validation-error string
| dispatch-error { event_name: string, message: string }// Execute pre-parsed AST - for benchmarks and advanced use
// This is the fast path: no parsing overhead, just execution!
~[retain] pub tor eval {
flow: *const ast.Flow,
dispatcher: DispatchFn,
cost_fn: ?CostFn,
creates_obligations_fn: ?ObligationsArrayFn,
discharges_obligations_fn: ?ObligationsArrayFn,
discharge_event_fn: ?DischargeEventFn,
creates_spec_fn: ?CreatesSpecFn,
discharges_spec_fn: ?DischargesSpecFn,
budget: ?u64,
handle_pool: ?*HandlePool,
scope_name: string,
auto_discharge: bool,
defined: ?*DefinedFlows
}
| result { value: Value, used: u64, handles: u32 }
| exhausted { used: u64, last_event: string, handles: u32 }
| validation-error string
| dispatch-error { event_name: string, message: string }// Parse WITHOUT executing — the other half of `eval`.
//
// Interpreter source is pure Koru: it has no file, so it has no host half and
// no ``. That is why this takes no file name. The full compiler parser
// derives its host/pure mode from the filename extension
// (`src/parser.zig:707`), so handing it a synthetic name silently answers a
// question interpreted source does not have; `flow_parser` has no such notion
// and is the only correct parser here.
//
// The returned Flow and every slice it points at are allocated from
// `allocator` — the caller owns the AST and may `eval` it as many times as it
// likes.
~[retain] pub tor parse { source: string, allocator: std.mem.Allocator }
| flow *const ast.Flow
| parse-error { message: string, line: u32, column: u32 }