Calx is an experimental compilation target for statically typed Calcit computational kernels. It provides a validated stack VM, explicit host boundaries, and source-aware traps. Performance decisions use source-backed end-to-end evidence, including compilation, input conversion, and execution.
Calx 是 Calcit 静态计算子集的实验性编译目标,提供验证后的栈式 VM、显式宿主边界与源码诊断。 性能决策以真实源码的编译、输入转换和执行总成本为依据。它目前面向有限 kernel 的 Rust embedding。
The 0.3 design moves performance-sensitive programs toward a strict typed
profile: no Dynamic local/global/import contracts and no implicit nil for
uninitialized or void state. Dynamic behavior remains an explicit legacy
compatibility path. See RFC 0002.
The 0.5.0 strict contract also rejects body Nil constants, all List values, and Nil/List/Link control signatures, including dead code. This tightens 0.4.0 acceptance; use the strict value contract and migration guide. This checkout prepares 0.5.1; consumers must confirm the version is published before upgrading. It adds explicit named strict-entry execution without changing the 0.5 strict value contract. See 0.5.1 release scope. The next work is tracked by #61 and the roadmap.
Version 0.5.1 retains the end-to-end strict path introduced before this release:
CalxProgram -> ValidatedProgram -> CalxVM::from_program -> run_typed.
Typed modules use declared locals/globals, stable indexed imports, exact host
signatures, explicit void results, and non-nil Uninitialized slot state. The path
includes F64 comparisons and the source-aware ProgramBuilder API required by the
Calcit translator experiment. Validated programs may also execute exact named
entries through run_typed_entry and run_traced_entry, while the existing APIs
remain main compatibility wrappers. Native Calcit bindings should consume exact
published crate versions.
0.4.0 提供端到端 strict path:声明式 typed locals/globals、稳定索引的 imports、
精确 host signatures、显式 void 结果和不借用 nil 的 Uninitialized slot state;同时
加入 F64 comparisons,以及 Calcit translator 实验需要的 source-aware ProgramBuilder
API。0.5.0 收紧 strict 准入并复用尾调 frame 的 locals;0.5.1 在不改变该值域合同的前提下增加
run_typed_entry 与 run_traced_entry,允许 validated program 按准确名称执行入口。当前 checkout
正在准备发布,消费者应确认 crates.io 可用后再使用精确版本。范围见0.5.1 说明。
0.4 增加不可变的 F64Buffer concrete value。函数参数、单返回值、local、
block/loop 与 typed host import 可以传递共享的连续 f64 storage;global 和 constant literal
会被明确拒绝。f64-buffer.len、f64.to-i64-index 与 f64-buffer.get 提供最小读取路径,
非法数值转换和越界访问都会 trap,不返回 Nil,也不接受 Dynamic 或 List 替代。
Rust embedding 可按所有权意图选择 f64_buffer_share、f64_buffer_adopt 或
f64_buffer_copy_from_slice。源码路径可用 calx check demos/f64-buffer.cirru 验证;运行时
buffer 由 typed entry argument 或 host import 提供。
0.4 adds an immutable concrete F64Buffer value. Shared
contiguous f64 storage may cross function parameters, a single result, locals,
blocks/loops, and typed host imports; globals and constant literals are rejected.
f64-buffer.len, f64.to-i64-index, and f64-buffer.get form the minimal read
path. Invalid numeric conversions and bounds access trap instead of returning
Nil, and neither Dynamic nor List is accepted as a substitute. Rust hosts
choose the explicit f64_buffer_share, f64_buffer_adopt, or
f64_buffer_copy_from_slice constructor according to ownership intent. Validate
the source path with calx check demos/f64-buffer.cirru; runtime buffers enter
through typed entry arguments or host imports.
# After 0.5.1 is published:
cargo install calx_vm --version 0.5.1
calx hello.cirru
calx run hello.cirru
calx check hello.cirru
calx explain hello.cirruThe first form remains a compatibility alias for calx run. check parses and
validates without lowering or executing guest code. explain shows folded
Cirru, expanded syntax, typed operand/control-stack transitions, and lowered
instructions; use --function NAME to focus on one function. 中文教程见
docs/tutorials/check-and-explain.md。
完整的六篇 strict 入门教程(含 CI 验证的命令、输出和错误案例)见 核心教程 / Core tutorials。 The six-part strict tutorial sequence includes executable commands, checked output excerpts, and failure cases.
it starts with a main function:
fn main ()
const 1
call demo
const 0
call demo
fn demo (($a i64) ->)
local.get $a
if (->)
do
const 11
echo
do
const 20
echo
const 3
echo-s to show instructions:
$ calx demos/if.cirru -s
[calx] start preprocessing
loaded fn: CalxFunc main (-> )
00 Const(I64(1))
01 Call(1)
02 Const(I64(0))
03 Call(1)
loaded fn: CalxFunc demo (I64 -> )
local_names: 0_$a .
00 LocalGet(0)
01 JmpIf(5)
02 Const(I64(20))
03 Echo
04 Jmp(8)
05 Const(I64(11))
06 Echo
07 Jmp(8)
08 Const(I64(3))
09 Echo
[calx] start running
11
3
20
3
[calx] took 67.250µs: Nil编译器和 Rust embedding 可以用 ProgramBuilder、FunctionBuilder 与 opaque declaration
handles 直接构造严格程序,不需要生成 Cirru 文本。builder 只返回未验证的 CalxProgram;执行前
仍须经过 ValidatedProgram::try_from_program 或 CalxVM::from_program。严格边界拒绝 Nil,API
也没有隐式 Dynamic 入口。中文指南与完整示例见
docs/program-builder.md。
Compilers and Rust embeddings can construct strict programs directly with
ProgramBuilder, FunctionBuilder, and opaque declaration handles instead of
generating Cirru text. The builder returns an unvalidated CalxProgram; pass it
through ValidatedProgram::try_from_program or CalxVM::from_program before
execution. See docs/program-builder.md for the API,
source-origin, atomic-error, and compatibility contracts.
一个 ValidatedProgram 可以包含多个独立入口,不需要为 embedding API 合成 main dispatcher。
CalxVM::run_typed_entry("init", args) 按准确函数名选择入口,并在执行前校验该函数的完整参数签名;
run_traced_entry 使用相同的选择、校验、reset 和 interpreter loop,同时保留 trace event limit。
unknown entry 会直接返回结构化错误,不回退到 main 或其他函数。每次运行都会清空 operand stack、frames、
locals 和上一结果;VM globals 继续遵循同一实例内持久化的既有语义。
现有 run_typed(args) 与 run_traced(args, ...) 保持兼容,分别委托给名为 main 的入口。legacy dynamic
VM 不能调用 named strict API;调用方必须从 CalxProgram -> ValidatedProgram 路径构造 strict VM。
A ValidatedProgram may expose multiple independent entries without a
synthetic main dispatcher. CalxVM::run_typed_entry("init", args) selects an
exact function and validates its complete parameter signature before
execution. run_traced_entry shares the same selection, validation, reset, and
interpreter loop while retaining the trace event limit. An unknown entry
returns a structured error and never falls back to main or another function.
Each run clears the operand stack, frames, locals, and prior result; globals
retain the existing per-VM persistence semantics.
Existing run_typed(args) and run_traced(args, ...) remain compatibility
wrappers for the entry named main. Legacy dynamic VMs cannot call the named
strict APIs; construct a strict VM through the CalxProgram -> ValidatedProgram path.
Code of:
fn main ()
i.add
const 1
i.mul
const 2
const 3
echo
dup
assert "|expected 7"
i.eq
const 7is desugared to:
fn main ()
const 2
const 3
i.mul
const 1
i.add
dup
echo
const 7
i.eq
assert "|expected 7"Find docs on https://docs.rs/calx_vm/ .
Highly inspired by:
- WASM https://github.com/WebAssembly/design/blob/main/Semantics.md
- Lox https://github.com/Darksecond/lox/blob/master/lox-vm/src/bettervm/vm.rs
Before Calx runs instructions, it parses, validates, and lowers the program:
- folded Cirru is expanded into flat
CalxSyntax; - a typed operand/control-stack validator checks functions and structured control flow;
block,loop,if,br, andbr-ifare lowered to executable internal instructions;- branch and return instructions preserve declared results while discarding intermediate stack values.
- local variables are renamed to indexes
The codebase would be updated as I'm learning more about WASM.
The teaching, validation, and Calcit compilation roadmap is maintained in
docs/roadmap.md. 路线图正文以中文维护,issue 与 PR 使用中英双语。
The current experimental instruction contract is documented in
docs/instruction-set.md.
The per-opcode parser/validator/lowering/interpreter/test audit is maintained in
docs/instruction-matrix.md.
The bounded mapping between the exercised Calcit/Calx semantics and their
nearest WebAssembly core concepts is documented in
docs/wasm-mapping.md; it is not a binary or runtime
compatibility claim.
Typed validation and trap boundaries are specified in
RFCs/0001-validation-and-traps.md.
Typed local, global, and host import module contracts are specified in
RFCs/0002-typed-boundaries.md.
The initial Calcit compiler subset, all-or-nothing fallback policy, and
versioned scalar host ABI are specified in
RFCs/0003-calcit-subset-and-host-abi.md.
The strict immutable F64Buffer type, indexing traps, ownership rules, and
typed-buffer ABI edition are specified in
RFCs/0004-f64-buffer-abi.md.
Source-aware parse, validation, runtime, and host diagnostics are documented in
docs/diagnostics.md.
MIT