Skip to content

Repository files navigation

Calx VM

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.

Usages

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_entryrun_traced_entry,允许 validated program 按准确名称执行入口。当前 checkout 正在准备发布,消费者应确认 crates.io 可用后再使用精确版本。范围见0.5.1 说明

0.4:严格 F64Buffer

0.4 增加不可变的 F64Buffer concrete value。函数参数、单返回值、local、 block/loop 与 typed host import 可以传递共享的连续 f64 storage;global 和 constant literal 会被明确拒绝。f64-buffer.lenf64.to-i64-indexf64-buffer.get 提供最小读取路径, 非法数值转换和越界访问都会 trap,不返回 Nil,也不接受 DynamicList 替代。 Rust embedding 可按所有权意图选择 f64_buffer_sharef64_buffer_adoptf64_buffer_copy_from_slice。源码路径可用 calx check demos/f64-buffer.cirru 验证;运行时 buffer 由 typed entry argument 或 host import 提供。

0.4: strict F64Buffer

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.cirru

The 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 ProgramBuilder API / Rust 构造 API

编译器和 Rust embedding 可以用 ProgramBuilderFunctionBuilder 与 opaque declaration handles 直接构造严格程序,不需要生成 Cirru 文本。builder 只返回未验证的 CalxProgram;执行前 仍须经过 ValidatedProgram::try_from_programCalxVM::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.

Named strict entries / 严格具名入口

一个 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.

Syntax Sugar

Code of:

fn main ()
  i.add
    const 1
    i.mul
      const 2
      const 3

  echo
    dup

  assert "|expected 7"
    i.eq
      const 7

is desugared to:

fn main ()
  const 2
  const 3
  i.mul
  const 1
  i.add

  dup
  echo

  const 7
  i.eq
  assert "|expected 7"

Instructions

Find docs on https://docs.rs/calx_vm/ .

Highly inspired by:

Preprocess

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, and br-if are 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.

Development roadmap / 强化路线图

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.

License

MIT

About

[Toy] Stack-based VM, with dynamic data

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages