pub struct ModuleBuilder { /* private fields */ }Expand description
Builds a Module.
Strings, structural types (everything but structs), and constants are
deduplicated. Ids are dense and assigned in creation order. Functions are
declared with function, which fixes their
FuncId up front so they can call each other in any order, and are
added with add_function.
§Examples
use bytecode_lang::{Const, ExportItem, Inst, ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let greeting = m.string("hello");
let k = m.constant(Const::Str(greeting));
let mut f = m.function("greet", &[], &[ValType::Str]);
let s = f.reg(ValType::Str);
f.emit(Inst::LoadConst { dst: s, k });
f.ret(s);
let greet = m.add_function(f).unwrap();
m.export("greet", ExportItem::Func(greet));
let module = m.finish().unwrap();
assert_eq!(module.string(greeting), Some("hello"));Implementations§
Source§impl ModuleBuilder
impl ModuleBuilder
Sourcepub fn new() -> Self
pub fn new() -> Self
An empty module builder.
§Examples
use bytecode_lang::ModuleBuilder;
let module = ModuleBuilder::new().finish().unwrap();
assert!(module.functions().is_empty());Sourcepub fn string(&mut self, s: &str) -> StrId
pub fn string(&mut self, s: &str) -> StrId
The id of the string s, adding it on first use.
§Examples
use bytecode_lang::{ModuleBuilder, StrId};
let mut m = ModuleBuilder::new();
assert_eq!(m.string("a"), StrId(0));
assert_eq!(m.string("b"), StrId(1));
assert_eq!(m.string("a"), StrId(0));Sourcepub fn add_type(&mut self, def: TypeDef) -> TypeId
pub fn add_type(&mut self, def: TypeDef) -> TypeId
Adds a type and returns its id. Structural types (functions, arrays, maps, cells, iterators) are deduplicated; every struct is a new type.
§Examples
use bytecode_lang::{ModuleBuilder, StructDef, TypeDef, ValType};
let mut m = ModuleBuilder::new();
let a = m.add_type(TypeDef::Array(ValType::I64));
assert_eq!(m.add_type(TypeDef::Array(ValType::I64)), a);
let s1 = m.add_type(TypeDef::Struct(StructDef::default()));
let s2 = m.add_type(TypeDef::Struct(StructDef::default()));
assert_ne!(s1, s2);Sourcepub fn reserve_type(&mut self) -> TypeId
pub fn reserve_type(&mut self) -> TypeId
Reserves a type id to be defined later with
define_type: how a struct refers to itself
(a list node’s next field) or two structs refer to each other.
§Examples
use bytecode_lang::{Field, ModuleBuilder, StructDef, TypeDef, ValType};
let mut m = ModuleBuilder::new();
let node = m.reserve_type();
let (name, next) = (m.string("Node"), m.string("next"));
m.define_type(node, TypeDef::Struct(StructDef {
name,
parent: None,
fields: vec![Field { name: next, ty: ValType::Ref(node) }],
methods: vec![],
}));
assert!(m.finish().is_ok());Sourcepub fn define_type(&mut self, id: TypeId, def: TypeDef)
pub fn define_type(&mut self, id: TypeId, def: TypeDef)
Defines a type reserved with reserve_type.
Defining an id that was not reserved, or defining it twice, is
recorded as UndefinedType.
§Examples
use bytecode_lang::{ModuleBuilder, TypeDef, ValType};
let mut m = ModuleBuilder::new();
let t = m.reserve_type();
m.define_type(t, TypeDef::Cell(ValType::Dyn));
assert_eq!(m.finish().unwrap().type_def(t), Some(&TypeDef::Cell(ValType::Dyn)));Sourcepub fn func_type(&mut self, params: &[ValType], results: &[ValType]) -> TypeId
pub fn func_type(&mut self, params: &[ValType], results: &[ValType]) -> TypeId
The id of the function type (params) -> (results).
§Examples
use bytecode_lang::{ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let a = m.func_type(&[ValType::Dyn], &[ValType::Dyn]);
assert_eq!(m.func_type(&[ValType::Dyn], &[ValType::Dyn]), a);Sourcepub fn constant(&mut self, c: Const) -> ConstId
pub fn constant(&mut self, c: Const) -> ConstId
Adds a constant and returns its id; equal constants share one id.
An aggregate may only refer to constants that already exist
(otherwise ConstForwardRef).
§Examples
use bytecode_lang::{Const, ModuleBuilder};
let mut m = ModuleBuilder::new();
let one = m.constant(Const::Int(1));
let two = m.constant(Const::Int(2));
let list = m.constant(Const::Array(vec![one, two, one]));
assert_eq!(m.constant(Const::Int(1)), one);
assert_eq!(m.finish().unwrap().consts().len(), 3);Sourcepub fn import(&mut self, module: &str, name: &str, sig: TypeId) -> ImportId
pub fn import(&mut self, module: &str, name: &str, sig: TypeId) -> ImportId
Adds a host-function import.
§Examples
use bytecode_lang::{ImportId, ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let sig = m.func_type(&[ValType::Str], &[]);
assert_eq!(m.import("ls.io", "print", sig), ImportId(0));Sourcepub fn import_with_params(
&mut self,
module: &str,
name: &str,
sig: TypeId,
params: ParamList,
) -> ImportId
pub fn import_with_params( &mut self, module: &str, name: &str, sig: TypeId, params: ParamList, ) -> ImportId
Adds a host-function import with a dynamic-call signature, so it can
be a first-class value taking named, spread, extra, missing, and
by-reference arguments through dcall/dcall_shape (PHP’s
printf(...$args), array_push(&$a, ...$v)). sig must already be
a function type of this builder; the list is checked against it as
FunctionBuilder::set_params checks a function’s.
§Examples
use bytecode_lang::{ModuleBuilder, Param, ParamKind, ParamList, ValType};
// printf(string $format, mixed ...$values): int
let mut m = ModuleBuilder::new();
let format = m.string("format");
let sig = m.func_type(&[ValType::Dyn, ValType::Dyn], &[ValType::Dyn]);
let list = ParamList::new(vec![Param::normal(format), Param::new(ParamKind::RestMap, None)]);
let printf = m.import_with_params("php.std", "printf", sig, list);
let module = m.finish().unwrap();
assert!(module.import(printf).unwrap().params.is_some());Sourcepub fn global(
&mut self,
name: &str,
ty: ValType,
mutable: bool,
init: Option<ConstId>,
) -> GlobalId
pub fn global( &mut self, name: &str, ty: ValType, mutable: bool, init: Option<ConstId>, ) -> GlobalId
Adds a global.
§Examples
use bytecode_lang::{Const, GlobalId, ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let zero = m.constant(Const::Int(0));
assert_eq!(m.global("hits", ValType::I64, true, Some(zero)), GlobalId(0));Sourcepub fn function(
&mut self,
name: &str,
params: &[ValType],
results: &[ValType],
) -> FunctionBuilder
pub fn function( &mut self, name: &str, params: &[ValType], results: &[ValType], ) -> FunctionBuilder
Declares a function and returns its builder. The function’s id is
fixed now (FunctionBuilder::id), so other functions can call it
before it is added.
§Examples
use bytecode_lang::{FuncId, ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let even = m.function("even", &[ValType::I64], &[ValType::Bool]);
let odd = m.function("odd", &[ValType::I64], &[ValType::Bool]);
assert_eq!((even.id(), odd.id()), (FuncId(0), FuncId(1)));Sourcepub fn add_function(&mut self, f: FunctionBuilder) -> Result<FuncId, BuildError>
pub fn add_function(&mut self, f: FunctionBuilder) -> Result<FuncId, BuildError>
Resolves the function’s labels and places it in its slot.
§Errors
The first error the function builder recorded, an unbound label, a
branch target past the end, an inverted range, or
ForeignFunction if the builder was
not declared by this module builder or was already added.
§Examples
use bytecode_lang::{BuildError, Inst, ModuleBuilder, Target};
let mut m = ModuleBuilder::new();
let mut f = m.function("f", &[], &[]);
f.emit(Inst::Jmp { target: Target(5) }); // raw target past the end
assert_eq!(
m.add_function(f),
Err(BuildError::TargetOutOfRange { func: bytecode_lang::FuncId(0), target: 5 }),
);Sourcepub fn export(&mut self, name: &str, item: ExportItem)
pub fn export(&mut self, name: &str, item: ExportItem)
Exports item under name.
§Examples
use bytecode_lang::{ExportItem, ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let g = m.global("version", ValType::I32, false, None);
m.export("version", ExportItem::Global(g));
assert_eq!(m.finish().unwrap().exports().len(), 1);Sourcepub fn hook(&mut self, hook: Hook, callee: Callee)
pub fn hook(&mut self, hook: Hook, callee: Callee)
Binds a dynamic-operation hook, replacing any earlier binding.
§Examples
use bytecode_lang::{Callee, Hook, ModuleBuilder, ValType};
let mut m = ModuleBuilder::new();
let sig = m.func_type(&[ValType::Dyn, ValType::Dyn], &[ValType::Dyn]);
let loose_eq = m.import("mox.rt", "loose_eq", sig);
m.hook(Hook::Eq, Callee::Import(loose_eq));
let module = m.finish().unwrap();
assert_eq!(module.hook(Hook::Eq), Some(Callee::Import(loose_eq)));Sourcepub fn set_name(&mut self, name: &str)
pub fn set_name(&mut self, name: &str)
Names the module (the name the loader links imports against).
§Examples
use bytecode_lang::ModuleBuilder;
let mut m = ModuleBuilder::new();
m.set_name("app");
assert!(m.finish().unwrap().name().is_some());Sourcepub fn set_start(&mut self, func: FuncId)
pub fn set_start(&mut self, func: FuncId)
Sets the initializer the loader runs after binding imports.
§Examples
use bytecode_lang::{FuncId, ModuleBuilder};
let mut m = ModuleBuilder::new();
let mut f = m.function("init", &[], &[]);
f.ret_void();
let init = m.add_function(f).unwrap();
m.set_start(init);
assert_eq!(m.finish().unwrap().start(), Some(FuncId(0)));Sourcepub fn finish(self) -> Result<Module, BuildError>
pub fn finish(self) -> Result<Module, BuildError>
Produces the module.
§Errors
The first error recorded while building, a declared function never
added (UndefinedFunction), a
reserved type never defined (UndefinedType),
or a section too large to encode (TooLarge).
§Examples
use bytecode_lang::{BuildError, FuncId, ModuleBuilder};
let mut m = ModuleBuilder::new();
let _forgotten = m.function("f", &[], &[]);
assert_eq!(m.finish().unwrap_err(), BuildError::UndefinedFunction(FuncId(0)));