- Compiler: PP → Lexer → Parser → Analyzer → Gengo pipeline - Parser: 232/236 (98%) Harbour compatibility, registry-based dispatch - RTL: 351 Harbour-compatible functions - RDD: DBF/NTX/CDX engines with Rushmore bitmap optimization - Go Interop: IMPORT + pkg.Func() + obj:Method() with FastPath (15M calls/sec) - HB_FUNC API: Full Harbour C API compatible Go bridge - Concurrency: SPAWN/LAUNCH/GOROUTINE, <-, WATCH, PARALLEL FOR, ASYNC/AWAIT - Extensions: Multi-return, DEFER, Slice, f-string, Nil-safe ?:, CONST - Macro Compiler: Runtime AST parsing and evaluation - Debugger: TUI debugger with source display, breakpoints, stepping - FRB: Native + Pcode dual mode runtime binary - Tests: 13 packages ALL PASS Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
119 lines
2.6 KiB
Go
119 lines
2.6 KiB
Go
// 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}
|
|
}
|