Skip to main content

Crate bcgen_lang

Crate bcgen_lang 

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

Classes (0.4): classes, interfaces, and mixins (PHP traits) compile to LSB structs with PHP’s semantics: single inheritance, constructors, properties with defaults, instance and static methods, self::, parent::, and late-bound static::, static properties, constants, new/instanceof/clone as ClassOps of the intrinsic table, visibility checked where PHP checks it (raised as TypeError with PHP’s message), objects thrown and caught by class or interface, and the destructor’s name for the VM (Compiled::destructor).

Not yet: declared records and sums, and typed fast paths (0.5); each is a precise CompileError::Unsupported, as is every class form HIR or LSB cannot express (multiple inheritance, impl blocks).

§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 min to max, 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: Options and, optionally, a Locate for the line tables.
IntrinsicDef
One entry of an Intrinsics table: 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.
LineIndex
A Locate for one source file: 1-based lines and byte columns from the file’s text, for spans that start at base in the session byte space.
Location
A source position for a line-table row: file, line, and column, numbered as the Locate implementation 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§

ArraySemantics
How arrays and maps behave when a value is copied.
BodyMode
What the module body (Module.body) compiles to.
ClassOp
A class operation: compiled inline against the classes the unit declares, with a host function for whatever the unit does not declare.
ClassProblem
A class graph or class member LSB cannot hold, or one PHP rejects at compile time.
CompileError
Why compile refused 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.

Functions§

compile
Compiles a resolved unit with the default Options (the PHP profile).