Expand description
§bcgen_lang
Compiles HIR (the representation every LexerSketch language lowers into)
to LSB, the bytecode bvm-lang executes.
§The lazy path
Build or lower a resolved unit, compile it, and hand the module to a
VM:
use hir_lang::{Builder, Name, OpKind};
use intern_lang::Interner;
// fn add(a, b) { a + b }
let mut names = Interner::new();
let mut b = Builder::new();
let (pa, a) = b.local_param(Name::new(names.intern("a")));
let (pb, bb) = b.local_param(Name::new(names.intern("b")));
let (ua, ub) = (b.use_binder(a), b.use_binder(bb));
let sum = b.op(OpKind::Add, &[ua, ub]);
let body = b.block(&[], Some(sum));
let add = b.func(Name::new(names.intern("add")), &[pa, pb], body);
let root = b.module(None, &[add]);
let hir = b.finish(root)?;
let out = bcgen_lang::compile(&hir, &names)?;
let module = out.module();
assert!(module.function(out.function(add).unwrap()).is_some());
assert!(!bytecode_lang::encode(module).is_empty());Running it (with bvm-lang): Program::load(out.into_module(), &host),
then vm.run(func, &[Value::Int(2), Value::Int(3)]) returns Int(5).
§What it compiles
HIR spec v3 (hir-lang 0.4) to LSB format 2 (bytecode-lang 0.3), in the
dynamic profile: every value is an LSB dyn. Functions with defaults
(per call or once), named, variadic, and by-reference parameters, each
carrying its LSB parameter list so dynamic calls bind in the VM; locals in
registers, shared variables in LSB references; closures with explicit,
implicit, and recursive captures; generators (keyed yield, yield from), await, and spawn; if, the loop primitive with its step,
labeled break/continue, return; match by a sequential decision
procedure, raising NoMatch when no arm matches; direct, dynamic, host,
and method calls; maps and arrays with PHP value semantics, separation
that copies only what is shared, and key coercion (or shared references);
let_place and PHP references into array elements; every OPS v2
operation with its policy (pow, promote, shift = saturate);
union and intersection type tests and casts; throw and
try/catch/finally by LSB’s canonical lowering, defer; globals,
constants, statics, and the module body; named intrinsics through an
Intrinsics table (Intrinsics::mox maps every Mox intrinsic to an
inline fast path or a host function). Every instruction maps back to the
HIR node it came from (Compiled::origin) and to a line-table row.
Not yet: classes, declared records and sums, and typed fast paths (0.5);
each is a precise CompileError::Unsupported.
§Guarantees
- Loads. Every module it emits passes
bvm-lang’s load-time checks: registers, windows, constants, branch targets, and handlers in range. - Semantics. Differential tests run random programs through the compiler and the VM, and through a reference interpreter written in the tests, comparing results, error kinds, and error locations.
- No recursion over the input. Generation is an explicit task stack; any nesting depth compiles in bounded native stack.
- Budgeted and deterministic. Output is bounded by
Options::with_max_instructions; the same unit compiles to the same bytes.
§no_std
The crate needs only alloc. The default std feature is additive.
Structs§
- Arity
- How many operands an intrinsic takes: from
mintomax, both inclusive (at most 255, an import’s limit). - Compiled
- A compiled unit: the LSB module, its entry points, and the map from every instruction back to the HIR node it was compiled from.
- Compiler
- A configured compiler:
Optionsand, optionally, aLocatefor the line tables. - Intrinsic
Def - One entry of an
Intrinsicstable: the operands it takes and how it compiles. - Intrinsics
- The intrinsic table: named intrinsic → arity and lowering. A name that is
not in the table is
CompileError::UnknownIntrinsic. - Line
Index - A
Locatefor one source file: 1-based lines and byte columns from the file’s text, for spans that start atbasein the session byte space. - Location
- A source position for a line-table row: file, line, and column, numbered
as the
Locateimplementation numbers them. - Options
- Compilation options: the dynamic profile’s array and key semantics, the body’s role, host linkage, the intrinsic table, and budgets.
Enums§
- Array
Semantics - How arrays and maps behave when a value is copied.
- Body
Mode - What the module body (
Module.body) compiles to. - Compile
Error - Why
compilerefused a unit. - Fast
- A guarded fast path: the operand kinds where an LSB sequence computes exactly the intrinsic’s result, tested at run time; outside that domain the intrinsic’s host function is called with the same operands.
- KeyCoercion
- How map keys are normalized before a map is indexed.
- Lowering
- How one named intrinsic compiles.
- LsbOp
- An LSB instruction sequence with LSB’s own semantics, hooks included (LSB §5.6–§5.10). These are the 0.2 built-in intrinsics.
- Unsupported
- A HIR form this release does not compile, named precisely.
Traits§
- Locate
- Maps HIR spans to source positions for LSB line tables.