- 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>
73 lines
1.7 KiB
Go
73 lines
1.7 KiB
Go
// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
|
// All rights reserved.
|
|
|
|
package hbrt
|
|
|
|
import "strings"
|
|
|
|
// pendingCall stores the symbol for the next Function/Do call.
|
|
// This avoids storing Go pointers in Value.data (which GC can't trace).
|
|
|
|
// PushSymbol records the function symbol for the next call.
|
|
// The actual symbol is stored in Thread, not on the eval stack.
|
|
// A marker NIL is pushed to keep stack positions correct.
|
|
// Harbour: hb_xvmPushSymbol
|
|
func (t *Thread) PushSymbol(sym *Symbol) {
|
|
t.pushPendingSym(sym)
|
|
t.push(MakeNil()) // placeholder for symbol position
|
|
}
|
|
|
|
// Function calls the function with nArgs arguments.
|
|
// Stack layout before: [sym_placeholder] [nil/self] [arg1] ... [argN]
|
|
// Stack after: [retval]
|
|
// Harbour: hb_xvmFunction
|
|
func (t *Thread) Function(nArgs int) {
|
|
sym := t.popPendingSym()
|
|
|
|
if sym == nil {
|
|
panic(t.runtimeError("no function symbol for call"))
|
|
}
|
|
|
|
// Resolve function
|
|
fn := sym.Func
|
|
if fn == nil && t.vm != nil {
|
|
found := t.vm.FindSymbol(strings.ToUpper(sym.Name))
|
|
if found != nil {
|
|
fn = found.Func
|
|
}
|
|
}
|
|
if fn == nil {
|
|
panic(t.runtimeError("undefined function: " + sym.Name))
|
|
}
|
|
|
|
// Collect args from stack
|
|
args := make([]Value, nArgs)
|
|
for i := nArgs - 1; i >= 0; i-- {
|
|
args[i] = t.pop()
|
|
}
|
|
t.pop() // pop NIL/self placeholder
|
|
t.pop() // pop symbol placeholder
|
|
|
|
// Push args back for Frame() to pick up
|
|
for _, arg := range args {
|
|
t.push(arg)
|
|
}
|
|
|
|
// Set pending params count and symbol for Frame()
|
|
t.pendingParams = nArgs
|
|
t.pendingCallSym = sym
|
|
|
|
// Call
|
|
fn(t)
|
|
|
|
// Push return value
|
|
t.push(t.retVal)
|
|
}
|
|
|
|
// Do calls the function but discards the return value.
|
|
// Harbour: hb_xvmDo
|
|
func (t *Thread) Do(nArgs int) {
|
|
t.Function(nArgs)
|
|
t.pop() // discard return value
|
|
}
|