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
The dynamic profile: every value is an LSB dyn. Functions with
defaults (per call or once), named, variadic, and by-reference
parameters; locals in registers, shared variables in cells; closures with
explicit, implicit, and recursive captures; if, the loop primitive with
its step, labeled break/continue, return; match by a sequential
decision procedure; direct, dynamic, host, and method calls; maps and
arrays with PHP value semantics and key coercion (or shared references);
every OPS operation with its policy, promote included; throw and
try/catch/finally by LSB’s canonical lowering, defer; globals,
constants, statics, and the module body. Every instruction maps back to
the HIR node it came from (Compiled::origin) and to a line-table row.
Not yet: coroutines, 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§
- 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. - 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, 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. - KeyCoercion
- How map keys are normalized before a map is indexed.
- Unsupported
- A HIR form this release does not compile, named precisely.
Traits§
- Locate
- Maps HIR spans to source positions for LSB line tables.