diff --git a/docs/.pdca-status.json b/docs/.pdca-status.json index 34f3544..6c3b3db 100644 --- a/docs/.pdca-status.json +++ b/docs/.pdca-status.json @@ -1,6 +1,6 @@ { "version": "2.0", - "lastUpdated": "2026-04-01T11:59:53.709Z", + "lastUpdated": "2026-04-01T12:09:42.812Z", "activeFeatures": [ "hbrt", "hbrtl", @@ -33,9 +33,9 @@ "documents": {}, "timestamps": { "started": "2026-03-27T09:33:04.512Z", - "lastUpdated": "2026-04-01T01:50:29.560Z" + "lastUpdated": "2026-04-01T12:08:54.344Z" }, - "lastFile": "/mnt/d/charles/five/hbrt/macroeval.go" + "lastFile": "/mnt/d/charles/five/hbrt/frb.go" }, "hbrtl": { "phase": "do", @@ -137,7 +137,7 @@ "documents": {}, "timestamps": { "started": "2026-03-27T11:50:31.420Z", - "lastUpdated": "2026-04-01T08:11:30.993Z" + "lastUpdated": "2026-04-01T12:09:42.812Z" }, "lastFile": "/mnt/d/charles/five/cmd/five/main.go" }, @@ -280,7 +280,7 @@ "session": { "startedAt": "2026-03-27T06:06:49.620Z", "onboardingCompleted": false, - "lastActivity": "2026-04-01T11:59:53.709Z" + "lastActivity": "2026-04-01T12:09:42.812Z" }, "history": [ { @@ -5826,6 +5826,60 @@ "feature": "parser", "phase": "do", "action": "updated" + }, + { + "timestamp": "2026-04-01T12:05:42.359Z", + "feature": "hbrt", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:05:56.744Z", + "feature": "hbrt", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:06:26.236Z", + "feature": "hbrt", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:06:46.834Z", + "feature": "hbrt", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:07:10.287Z", + "feature": "hbrt", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:07:54.070Z", + "feature": "five", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:08:54.344Z", + "feature": "hbrt", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:09:06.847Z", + "feature": "five", + "phase": "do", + "action": "updated" + }, + { + "timestamp": "2026-04-01T12:09:42.812Z", + "feature": "five", + "phase": "do", + "action": "updated" } ] } \ No newline at end of file diff --git a/hbrt/frb.go b/hbrt/frb.go index 61faeaa..a218f0e 100644 --- a/hbrt/frb.go +++ b/hbrt/frb.go @@ -38,10 +38,16 @@ var frbMagic = []byte{0xC0, 'F', 'R', 'B'} const frbVersion = 2 -// FRB mode flags +// FRB file format constants const ( + FrbMagic0 byte = 0xC0 // magic byte 0 + FrbMagic1 byte = 'F' // magic byte 1 + FrbMagic2 byte = 'R' // magic byte 2 + FrbMagic3 byte = 'B' // magic byte 3 + FrbVersion1 byte = 1 // format version FrbModeNative byte = 0x01 // Go plugin (.so) FrbModePcode byte = 0x02 // Five pcode (interpreter) + FrbHeaderSize = 12 // header bytes before payload ) // FrbModule represents a loaded FRB module. diff --git a/hbrt/symbol.go b/hbrt/symbol.go index e60f3be..da2eb4b 100644 --- a/hbrt/symbol.go +++ b/hbrt/symbol.go @@ -30,6 +30,7 @@ type Symbol struct { type Module struct { Name string Symbols []Symbol + index map[string]int // lazy-built name → Symbols index } // Sym creates a Symbol (convenience constructor for generated code). @@ -47,12 +48,16 @@ func (m *Module) At(index int) *Symbol { return &m.Symbols[index] } -// Find returns a symbol by name within this module. +// Find returns a symbol by name within this module. O(1) via lazy index. func (m *Module) Find(name string) *Symbol { - for i := range m.Symbols { - if m.Symbols[i].Name == name { - return &m.Symbols[i] + if m.index == nil { + m.index = make(map[string]int, len(m.Symbols)) + for i := range m.Symbols { + m.index[m.Symbols[i].Name] = i } } + if idx, ok := m.index[name]; ok { + return &m.Symbols[idx] + } return nil } diff --git a/hbrt/thread.go b/hbrt/thread.go index a902fd5..48b0a52 100644 --- a/hbrt/thread.go +++ b/hbrt/thread.go @@ -10,9 +10,10 @@ import ( // Default stack/frame sizes const ( - DefaultStackSize = 2048 // initial eval stack capacity - MaxStackSize = 65536 - MaxCallDepth = 256 + DefaultStackSize = 2048 // initial eval stack capacity + MaxStackSize = 65536 + MaxCallDepth = 256 + InitialCallDepth = 32 // start small, grow if needed ) // CallFrame saves the state of a function call. @@ -94,7 +95,7 @@ func NewThread(vm *VM) *Thread { stack: make([]Value, DefaultStackSize), sp: 0, locals: make([]Value, 256), // will grow as needed - calls: make([]CallFrame, MaxCallDepth), + calls: make([]CallFrame, InitialCallDepth), callSP: 0, statics: make(map[string][]Value), vm: vm, @@ -182,6 +183,16 @@ func (t *Thread) Frame(params, locals int) { if t.callSP >= MaxCallDepth { panic(t.runtimeError("call stack overflow")) } + // Grow call stack dynamically if needed + if t.callSP >= len(t.calls) { + newSize := len(t.calls) * 2 + if newSize > MaxCallDepth { + newSize = MaxCallDepth + } + newCalls := make([]CallFrame, newSize) + copy(newCalls, t.calls) + t.calls = newCalls + } // Ensure locals slice has enough space localBase := 0