///|
/// Bytecode builder helpers (constant/name pooling and jump patching).
///|
pub(all) struct BcBuilder {
code : BcCode
}
///|
pub fn BcBuilder::new(name : String, filename : String) -> BcBuilder {
BcBuilder::{ code: BcCode::empty(name, filename), }
}
///|
pub fn BcBuilder::emit(self : BcBuilder, op : BcOp, span : Span?) -> Int32 {
let pc = self.code.ops.length()
self.code.ops.push(op)
self.code.spans.push(span)
pc
}
///|
pub fn BcBuilder::intern_name(self : BcBuilder, name : String) -> Int32 {
for i = 0; i < self.code.names.length(); i = i + 1 {
if self.code.names[i] == name {
return i
}
}
let idx = self.code.names.length()
self.code.names.push(name)
idx
}
///|
pub fn BcBuilder::add_pattern(self : BcBuilder, pattern : Pattern) -> Int32 {
let idx = self.code.patterns.length()
self.code.patterns.push(pattern)
idx
}
///|
pub fn BcBuilder::add_genexp(self : BcBuilder, spec : GenExpSpec) -> Int32 {
let idx = self.code.genexps.length()
self.code.genexps.push(spec)
idx
}
///|
pub fn BcBuilder::add_const(self : BcBuilder, value : Value) -> Int32 {
let idx = self.code.consts.length()
self.code.consts.push(value)
idx
}
///|
pub fn bc_patch_jump(code : BcCode, pc : Int32, target : Int32) -> Unit {
match code.ops[pc] {
BcOp::Jump(_) => code.ops[pc] = BcOp::Jump(target)
BcOp::JumpIfFalse(_) => code.ops[pc] = BcOp::JumpIfFalse(target)
BcOp::JumpIfTrue(_) => code.ops[pc] = BcOp::JumpIfTrue(target)
BcOp::JumpIfFalseOrPop(_) => code.ops[pc] = BcOp::JumpIfFalseOrPop(target)
BcOp::JumpIfTrueOrPop(_) => code.ops[pc] = BcOp::JumpIfTrueOrPop(target)
BcOp::UnwindJump(_, n) => code.ops[pc] = BcOp::UnwindJump(target, n)
BcOp::ForIter(_) => code.ops[pc] = BcOp::ForIter(target)
BcOp::SetupExcept(_) => code.ops[pc] = BcOp::SetupExcept(target)
BcOp::SetupFinally(_) => code.ops[pc] = BcOp::SetupFinally(target)
BcOp::EnterFinally(_) => code.ops[pc] = BcOp::EnterFinally(target)
_ => ()
}
}