// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com) // All rights reserved. // Pcode serialization/deserialization for FRB files. package hbrt import ( "encoding/binary" "fmt" ) // SerializePcodeModule writes a PcodeModule to bytes. // Format: // uint16 funcCount // for each func: // uint16 nameLen + name // uint16 params // uint16 locals // uint32 codeLen + code func SerializePcodeModule(mod *PcodeModule) []byte { var buf []byte // Function count var tmp [2]byte binary.LittleEndian.PutUint16(tmp[:], uint16(len(mod.Funcs))) buf = append(buf, tmp[:]...) for name, fn := range mod.Funcs { // Name binary.LittleEndian.PutUint16(tmp[:], uint16(len(name))) buf = append(buf, tmp[:]...) buf = append(buf, []byte(name)...) // Params + Locals binary.LittleEndian.PutUint16(tmp[:], uint16(fn.Params)) buf = append(buf, tmp[:]...) binary.LittleEndian.PutUint16(tmp[:], uint16(fn.Locals)) buf = append(buf, tmp[:]...) // Code var tmp4 [4]byte binary.LittleEndian.PutUint32(tmp4[:], uint32(len(fn.Code))) buf = append(buf, tmp4[:]...) buf = append(buf, fn.Code...) } return buf } // DeserializePcodeModule reads a PcodeModule from bytes. func DeserializePcodeModule(data []byte) (*PcodeModule, error) { if len(data) < 2 { return nil, fmt.Errorf("pcode data too short") } mod := &PcodeModule{ Funcs: make(map[string]*PcodeFunc), } pos := 0 funcCount := int(binary.LittleEndian.Uint16(data[pos:])) pos += 2 for i := 0; i < funcCount; i++ { if pos+2 > len(data) { return nil, fmt.Errorf("truncated pcode at func %d", i) } // Name nameLen := int(binary.LittleEndian.Uint16(data[pos:])) pos += 2 name := string(data[pos : pos+nameLen]) pos += nameLen // Params + Locals params := int(binary.LittleEndian.Uint16(data[pos:])) pos += 2 locals := int(binary.LittleEndian.Uint16(data[pos:])) pos += 2 // Code codeLen := int(binary.LittleEndian.Uint32(data[pos:])) pos += 4 code := make([]byte, codeLen) copy(code, data[pos:pos+codeLen]) pos += codeLen mod.Funcs[name] = &PcodeFunc{ Name: name, Code: code, Params: params, Locals: locals, } } return mod, nil } // SymDef is a helper for creating modules from pcode. type SymDef struct { Name string Scope uint16 Fn func(*Thread) } // NewModuleFromDefs creates a Module from SymDef slice. func NewModuleFromDefs(name string, defs []SymDef) *Module { syms := make([]Symbol, len(defs)) for i, d := range defs { syms[i] = Symbol{ Name: d.Name, Scope: d.Scope, Func: d.Fn, } } return &Module{Name: name, Symbols: syms} }