Files
five/hbrtl/register.go
CharlesKWON 8aaed994f4 perf(FiveSql2): hybrid fast path — 11x speedup on string WHERE scans
Implements hybrid execution model: keep AST tree-walk for SQL:2013+
features (Window, Recursive CTE, JOIN, aggregates) while compiling
simple SELECT hot paths to Go + pcode. See docs/FiveSql2-Hybrid-Plan.md
for the full architecture rationale (why not SQLite-style VDBE).

Hot path (single table, no joins/groups/aggregates):
  - TryBuildFieldPositions: resolves SELECT column list to FieldPos
    array once per query (bails to PRG loop on any complex expr).
  - TryCompileWhere + SqlExprToPrg: walks WHERE AST, emits equivalent
    PRG source, runs it through PcCompile to get a PcodeFunc.
  - SqlScan RTL: Go-native scan loop — GoTop/EOF/Skip/GetValue
    direct, ExecPcode per row for WHERE, result array pre-alloc.

WHERE compiler scope:
  - ND_LIT numeric/logical/string (string literals AllTrim'd to match
    SqlCmpEq CHAR-padding semantics; rejects embedded quotes/newlines)
  - ND_COL: CHAR fields auto-wrapped with AllTrim(FieldGet(n)) based
    on dbStruct() lookup cached once per query in aCompileStruct
  - ND_BIN: = <> != < <= > >= AND OR + - * /
  - ND_UNI: NOT -
  - Anything else (ND_FN, ND_CASE, ND_SUB, ND_PAR, LIKE, IN, IS NULL,
    BETWEEN, dates) returns NIL → falls back to PRG tree-walk.

Bench (50k rows, ~/tmp ext4):
                        Before      After     Speedup
  Numeric WHERE         ~150ms     11.7ms     ~13x
  String WHERE          119.3ms    10.5ms     11.4x
  No WHERE               -         14.6ms      -
  Raw RDD baseline        6.8ms     6.8ms      1.0x

Remaining gap to raw RDD (~1.5x) is structural: Value boxing, result
array construction, per-row ExecPcode frame overhead. Would need a
Value-pool or SoA refactor to close further.

Side fixes bundled:
  - TSqlIndex:FindExclusive short-circuited. Originally called
    dbInfo(DBI_FULLPATH)/DBI_SHARED which are unresolved symbols in
    Five (dbInfo is a stub, DBI_* never defined). Panic'd with
    "local variable index out of range: 0" whenever a standalone PRG
    had a workarea Used before calling five_SQL. 43-test masked the
    bug because it only reached FindExclusive with no open workareas.
    Restore the scan once dbInfo lands in hbrtl.
  - cmd/five/main.go: FIVE_KEEP_BUILD=1 env var keeps the temp Go
    project around for debugging gengo output.

Validation:
  - FiveSql2 43/43
  - Harbour compat 51/51
  - go test ./... ALL PASS

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 09:15:08 +09:00

688 lines
27 KiB
Go

// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
// All rights reserved.
// RTL registration for the Five runtime library.
// Centralized registration following tsgo's NodeFactory pattern.
package hbrtl
import (
"five/hbrt"
"five/hbrdd"
)
// RegisterRTL registers all standard library functions with the VM.
func RegisterRTL(vm *hbrt.VM) {
// Auto-create WorkAreaManager for each thread
vm.SetWAFactory(func() interface{} {
return hbrdd.NewWorkAreaManager()
})
// Restore terminal on exit
vm.SetOnExit(func() {
RestoreTerminal()
})
mod := hbrt.NewModule("_RTL",
// Console
hbrt.Sym("QOUT", hbrt.FsPublic, rtlQOut),
hbrt.Sym("QQOUT", hbrt.FsPublic, rtlQQOut),
hbrt.Sym("OUTSTD", hbrt.FsPublic, rtlOutStd),
hbrt.Sym("OUTERR", hbrt.FsPublic, rtlOutErr),
// Strings / Conversion
hbrt.Sym("STR", hbrt.FsPublic, Str),
hbrt.Sym("VAL", hbrt.FsPublic, Val),
hbrt.Sym("LEN", hbrt.FsPublic, Len),
hbrt.Sym("SUBSTR", hbrt.FsPublic, SubStr),
hbrt.Sym("UPPER", hbrt.FsPublic, Upper),
hbrt.Sym("LOWER", hbrt.FsPublic, Lower),
hbrt.Sym("ALLTRIM", hbrt.FsPublic, AllTrim),
hbrt.Sym("LTRIM", hbrt.FsPublic, LTrim),
hbrt.Sym("RTRIM", hbrt.FsPublic, RTrim),
hbrt.Sym("TRIM", hbrt.FsPublic, RTrim), // TRIM = RTRIM in Harbour
hbrt.Sym("SPACE", hbrt.FsPublic, Space),
hbrt.Sym("PADR", hbrt.FsPublic, PadR),
hbrt.Sym("PADL", hbrt.FsPublic, PadL),
hbrt.Sym("REPLICATE", hbrt.FsPublic, Replicate),
// Type / Conversion
hbrt.Sym("VALTYPE", hbrt.FsPublic, ValType),
hbrt.Sym("EMPTY", hbrt.FsPublic, Empty),
hbrt.Sym("ABS", hbrt.FsPublic, Abs),
hbrt.Sym("INT", hbrt.FsPublic, Int),
// Array
hbrt.Sym("AADD", hbrt.FsPublic, AAdd),
hbrt.Sym("ADEL", hbrt.FsPublic, ADel),
hbrt.Sym("AINS", hbrt.FsPublic, AIns),
hbrt.Sym("ASIZE", hbrt.FsPublic, ASize),
hbrt.Sym("ACLONE", hbrt.FsPublic, AClone),
hbrt.Sym("ACOPY", hbrt.FsPublic, ACopy),
hbrt.Sym("AFILL", hbrt.FsPublic, AFill),
hbrt.Sym("ASORT", hbrt.FsPublic, ASort),
hbrt.Sym("AEVAL", hbrt.FsPublic, AEval),
hbrt.Sym("ASCAN", hbrt.FsPublic, AScan),
hbrt.Sym("ATAIL", hbrt.FsPublic, ATail),
// Hash
hbrt.Sym("HB_HASH", hbrt.FsPublic, HbHash),
hbrt.Sym("HB_HGET", hbrt.FsPublic, HbHGet),
hbrt.Sym("HB_HSET", hbrt.FsPublic, HbHSet),
hbrt.Sym("HB_HDEL", hbrt.FsPublic, HbHDel),
hbrt.Sym("HB_HHASKEY", hbrt.FsPublic, HbHHasKey),
hbrt.Sym("HB_HKEYS", hbrt.FsPublic, HbHKeys),
hbrt.Sym("HB_HVALUES", hbrt.FsPublic, HbHValues),
// Date / Time
hbrt.Sym("DATE", hbrt.FsPublic, Date),
hbrt.Sym("TIME", hbrt.FsPublic, Time),
hbrt.Sym("YEAR", hbrt.FsPublic, Year),
hbrt.Sym("MONTH", hbrt.FsPublic, Month),
hbrt.Sym("DAY", hbrt.FsPublic, Day),
hbrt.Sym("DOW", hbrt.FsPublic, DOW),
hbrt.Sym("SECONDS", hbrt.FsPublic, Seconds),
hbrt.Sym("DTOC", hbrt.FsPublic, DToC),
hbrt.Sym("DTOS", hbrt.FsPublic, DToS),
hbrt.Sym("STOD", hbrt.FsPublic, SToD),
// Eval
hbrt.Sym("EVAL", hbrt.FsPublic, rtlEval),
// String (new)
hbrt.Sym("AT", hbrt.FsPublic, At),
hbrt.Sym("LEFT", hbrt.FsPublic, Left),
hbrt.Sym("RIGHT", hbrt.FsPublic, Right),
hbrt.Sym("ASC", hbrt.FsPublic, Asc),
hbrt.Sym("CHR", hbrt.FsPublic, Chr),
hbrt.Sym("STRTRAN", hbrt.FsPublic, StrTran),
hbrt.Sym("STUFF", hbrt.FsPublic, Stuff),
hbrt.Sym("PADC", hbrt.FsPublic, PadC),
hbrt.Sym("HB_STRREPLACE", hbrt.FsPublic, HbStrReplace),
hbrt.Sym("HB_NTOS", hbrt.FsPublic, HbNToS),
// Math (new)
hbrt.Sym("ROUND", hbrt.FsPublic, Round),
hbrt.Sym("MAX", hbrt.FsPublic, Max),
hbrt.Sym("MIN", hbrt.FsPublic, Min),
hbrt.Sym("SQRT", hbrt.FsPublic, Sqrt),
hbrt.Sym("LOG", hbrt.FsPublic, Log),
hbrt.Sym("EXP", hbrt.FsPublic, Exp),
hbrt.Sym("MOD", hbrt.FsPublic, Mod),
// Date (new)
hbrt.Sym("CTOD", hbrt.FsPublic, CToD),
hbrt.Sym("CDOW", hbrt.FsPublic, CDoW),
hbrt.Sym("CMONTH", hbrt.FsPublic, CMonth),
// Misc (new)
hbrt.Sym("TYPE", hbrt.FsPublic, TypeFunc),
hbrt.Sym("PCOUNT", hbrt.FsPublic, PCount),
hbrt.Sym("BREAK", hbrt.FsPublic, Break),
hbrt.Sym("ARRAY", hbrt.FsPublic, ArrayFunc),
hbrt.Sym("FCOUNT", hbrt.FsPublic, FCount),
hbrt.Sym("FIELDNAME", hbrt.FsPublic, FieldName),
hbrt.Sym("SELECT", hbrt.FsPublic, SelectFunc),
hbrt.Sym("FILE", hbrt.FsPublic, FileFunc),
hbrt.Sym("INKEY", hbrt.FsPublic, Inkey),
hbrt.Sym("TRANSFORM", hbrt.FsPublic, Transform),
hbrt.Sym("SETDATEFORMAT", hbrt.FsPublic, rtlSetDateFormat),
hbrt.Sym("SETEPOCH", hbrt.FsPublic, rtlSetEpoch),
hbrt.Sym("SETCENTURY", hbrt.FsPublic, rtlSetCentury),
// Terminal
hbrt.Sym("SETPOS", hbrt.FsPublic, SetPos),
hbrt.Sym("ROW", hbrt.FsPublic, Row),
hbrt.Sym("COL", hbrt.FsPublic, Col),
hbrt.Sym("DEVPOS", hbrt.FsPublic, DevPos),
hbrt.Sym("DEVOUT", hbrt.FsPublic, DevOut),
hbrt.Sym("DISPOUT", hbrt.FsPublic, DispOut),
hbrt.Sym("DEVOUTPICT", hbrt.FsPublic, DevOutPict),
hbrt.Sym("DISPBOX", hbrt.FsPublic, DispBox),
hbrt.Sym("CLS", hbrt.FsPublic, Cls),
hbrt.Sym("SCROLL", hbrt.FsPublic, Scroll),
hbrt.Sym("SETCOLOR", hbrt.FsPublic, SetColor),
hbrt.Sym("SETCURSOR", hbrt.FsPublic, SetCursor),
hbrt.Sym("MAXROW", hbrt.FsPublic, MaxRow),
hbrt.Sym("MAXCOL", hbrt.FsPublic, MaxCol),
// dbEdit / Browse / TBrowse
hbrt.Sym("DBEDIT", hbrt.FsPublic, DbEdit),
hbrt.Sym("TBROWSEDB", hbrt.FsPublic, rtlTBrowseDB),
hbrt.Sym("TBROWSENEW", hbrt.FsPublic, rtlTBrowseNew),
hbrt.Sym("TBCOLUMNNEW", hbrt.FsPublic, rtlTBColumnNew),
// RDD functions
hbrt.Sym("EOF", hbrt.FsPublic, rtlEOF),
hbrt.Sym("BOF", hbrt.FsPublic, rtlBOF),
hbrt.Sym("FOUND", hbrt.FsPublic, rtlFound),
hbrt.Sym("RECNO", hbrt.FsPublic, rtlRecNo),
hbrt.Sym("RECCOUNT", hbrt.FsPublic, rtlRecCount),
hbrt.Sym("LASTREC", hbrt.FsPublic, rtlRecCount), // alias
hbrt.Sym("DELETED", hbrt.FsPublic, rtlDeleted),
hbrt.Sym("FIELDGET", hbrt.FsPublic, rtlFieldGet),
// Database callable functions
hbrt.Sym("FIELDPUT", hbrt.FsPublic, rtlFieldPut),
hbrt.Sym("ALIAS", hbrt.FsPublic, rtlAlias),
hbrt.Sym("DBEVAL", hbrt.FsPublic, rtlDbEval),
hbrt.Sym("USED", hbrt.FsPublic, Used),
hbrt.Sym("DBUSEAREA", hbrt.FsPublic, rtlDbUseArea),
hbrt.Sym("DBCLOSEAREA", hbrt.FsPublic, rtlDbCloseArea),
hbrt.Sym("DBCLOSEALL", hbrt.FsPublic, rtlDbCloseAll),
hbrt.Sym("DBGOTO", hbrt.FsPublic, rtlDbGoTo),
hbrt.Sym("DBSKIP", hbrt.FsPublic, rtlDbSkip),
hbrt.Sym("DBGOTOP", hbrt.FsPublic, rtlDbGoTop),
hbrt.Sym("DBGOBOTTOM", hbrt.FsPublic, rtlDbGoBottom),
hbrt.Sym("DBAPPEND", hbrt.FsPublic, rtlDbAppend),
hbrt.Sym("DBDELETE", hbrt.FsPublic, rtlDbDelete),
hbrt.Sym("DBRECALL", hbrt.FsPublic, rtlDbRecall),
hbrt.Sym("DBCOMMIT", hbrt.FsPublic, rtlDbCommit),
hbrt.Sym("DBRLOCK", hbrt.FsPublic, rtlDbRLock),
hbrt.Sym("DBRUNLOCK", hbrt.FsPublic, rtlDbRUnlock),
hbrt.Sym("FLOCK", hbrt.FsPublic, rtlFLock),
hbrt.Sym("DBUNLOCK", hbrt.FsPublic, rtlDbUnlock),
hbrt.Sym("DBSEEK", hbrt.FsPublic, rtlDbSeek),
hbrt.Sym("DBSELECTAREA", hbrt.FsPublic, rtlDbSelectArea),
hbrt.Sym("DBPACK", hbrt.FsPublic, rtlDbPack),
hbrt.Sym("DBZAP", hbrt.FsPublic, rtlDbZap),
hbrt.Sym("RECALL", hbrt.FsPublic, rtlDbRecall),
hbrt.Sym("PACK", hbrt.FsPublic, rtlDbPack),
hbrt.Sym("ZAP", hbrt.FsPublic, rtlDbZap),
hbrt.Sym("__DBPACK", hbrt.FsPublic, rtlDbPack),
hbrt.Sym("__DBZAP", hbrt.FsPublic, rtlDbZap),
hbrt.Sym("DBRECALL", hbrt.FsPublic, rtlDbRecall),
// Locate / Filter
hbrt.Sym("DBLOCATE", hbrt.FsPublic, rtlDbLocate),
hbrt.Sym("__DBLOCATE", hbrt.FsPublic, rtlDbLocate),
hbrt.Sym("__DBCONTINUE", hbrt.FsPublic, rtlDbContinue),
hbrt.Sym("DBSETFILTER", hbrt.FsPublic, rtlDbSetFilter),
hbrt.Sym("DBCLEARFILTER", hbrt.FsPublic, rtlDbClearFilter),
hbrt.Sym("DBFILTER", hbrt.FsPublic, rtlDbFilter),
// Encoding / Hashing (Go stdlib)
hbrt.Sym("HB_MD5", hbrt.FsPublic, HbMD5),
hbrt.Sym("HB_SHA256", hbrt.FsPublic, HbSHA256),
hbrt.Sym("HB_BASE64ENCODE", hbrt.FsPublic, HbBase64Encode),
hbrt.Sym("HB_BASE64DECODE", hbrt.FsPublic, HbBase64Decode),
hbrt.Sym("HB_CRC32", hbrt.FsPublic, HbCRC32),
// Bit operations (Go native)
hbrt.Sym("HB_BITAND", hbrt.FsPublic, HbBitAnd),
hbrt.Sym("HB_BITOR", hbrt.FsPublic, HbBitOr),
hbrt.Sym("HB_BITXOR", hbrt.FsPublic, HbBitXor),
hbrt.Sym("HB_BITNOT", hbrt.FsPublic, HbBitNot),
hbrt.Sym("HB_BITSHIFT", hbrt.FsPublic, HbBitShift),
hbrt.Sym("HB_BITTEST", hbrt.FsPublic, HbBitTest),
hbrt.Sym("HB_BITSET", hbrt.FsPublic, HbBitSet),
hbrt.Sym("HB_BITRESET", hbrt.FsPublic, HbBitReset),
// Regex (Go regexp)
hbrt.Sym("HB_REGEXCOMP", hbrt.FsPublic, HbRegexComp),
hbrt.Sym("HB_REGEXMATCH", hbrt.FsPublic, HbRegexMatch),
hbrt.Sym("HB_REGEXSPLIT", hbrt.FsPublic, HbRegexSplit),
hbrt.Sym("HB_REGEXALL", hbrt.FsPublic, HbRegexAll),
hbrt.Sym("HB_REGEXREPLACE", hbrt.FsPublic, HbRegexReplace),
// String (additional)
hbrt.Sym("RAT", hbrt.FsPublic, Rat),
hbrt.Sym("STRZERO", hbrt.FsPublic, StrZero),
hbrt.Sym("DESCEND", hbrt.FsPublic, Descend),
hbrt.Sym("HB_VALTOSTR", hbrt.FsPublic, HbValToStr),
hbrt.Sym("HB_VALTOEXP", hbrt.FsPublic, HbValToExp),
hbrt.Sym("HB_CSTR", hbrt.FsPublic, HbCStr),
hbrt.Sym("HB_NTOS", hbrt.FsPublic, HbNtos),
hbrt.Sym("MEMOREAD", hbrt.FsPublic, MemoRead),
hbrt.Sym("MEMOWRIT", hbrt.FsPublic, MemoWrit),
hbrt.Sym("MEMOTRAN", hbrt.FsPublic, MemoTran),
// Binary conversion
hbrt.Sym("BIN2I", hbrt.FsPublic, Bin2I),
hbrt.Sym("BIN2L", hbrt.FsPublic, Bin2L),
hbrt.Sym("BIN2W", hbrt.FsPublic, Bin2W),
hbrt.Sym("I2BIN", hbrt.FsPublic, I2Bin),
hbrt.Sym("L2BIN", hbrt.FsPublic, L2Bin),
hbrt.Sym("W2BIN", hbrt.FsPublic, W2Bin),
// Keyboard
hbrt.Sym("LASTKEY", hbrt.FsPublic, LastKey),
hbrt.Sym("NEXTKEY", hbrt.FsPublic, NextKey),
hbrt.Sym("READKEY", hbrt.FsPublic, ReadKeyFunc),
hbrt.Sym("SETKEY", hbrt.FsPublic, SetKeyFunc),
hbrt.Sym("KEYBOARD", hbrt.FsPublic, Keyboard),
hbrt.Sym("HB_KEYPUT", hbrt.FsPublic, HbKeyPut),
// Display
hbrt.Sym("DISPBEGIN", hbrt.FsPublic, DispBegin),
hbrt.Sym("DISPEND", hbrt.FsPublic, DispEnd),
hbrt.Sym("DISPCOUNT", hbrt.FsPublic, DispCount),
hbrt.Sym("SAVESCREEN", hbrt.FsPublic, SaveScreen),
hbrt.Sym("RESTSCREEN", hbrt.FsPublic, RestScreen),
hbrt.Sym("ALERT", hbrt.FsPublic, Alert),
// Error handling
hbrt.Sym("ERRORBLOCK", hbrt.FsPublic, ErrorBlock),
hbrt.Sym("ERRORNEW", hbrt.FsPublic, ErrorNew),
hbrt.Sym("DOSERROR", hbrt.FsPublic, DosError),
hbrt.Sym("FERROR", hbrt.FsPublic, FError),
// SET commands
hbrt.Sym("SET", hbrt.FsPublic, SetFunc),
hbrt.Sym("__SETDATEFORMAT", hbrt.FsPublic, SetDateFunc),
hbrt.Sym("__SETDECIMALS", hbrt.FsPublic, SetDecimalsFunc),
hbrt.Sym("__SETEPOCH", hbrt.FsPublic, SetEpochFunc),
// SET toggle functions
hbrt.Sym("SETDELETED", hbrt.FsPublic, SetDeletedFunc),
hbrt.Sym("SETEXACT", hbrt.FsPublic, SetExactFunc),
hbrt.Sym("SETSOFTSEEK", hbrt.FsPublic, SetSoftSeekFunc),
hbrt.Sym("SETEXCLUSIVE", hbrt.FsPublic, SetExclusiveFunc),
hbrt.Sym("SETFIXED", hbrt.FsPublic, SetFixedFunc),
hbrt.Sym("SETCANCEL", hbrt.FsPublic, SetCancelFunc),
hbrt.Sym("SETBELL", hbrt.FsPublic, SetBellFunc),
hbrt.Sym("SETCONFIRM", hbrt.FsPublic, SetConfirmFunc),
hbrt.Sym("SETINSERT", hbrt.FsPublic, SetInsertFunc),
hbrt.Sym("SETESCAPE", hbrt.FsPublic, SetEscapeFunc),
hbrt.Sym("SETWRAP", hbrt.FsPublic, SetWrapFunc),
// SET constants
hbrt.Sym("_SET_EXACT", hbrt.FsPublic, SetConstExact),
hbrt.Sym("_SET_DELETED", hbrt.FsPublic, SetConstDeleted),
hbrt.Sym("_SET_SOFTSEEK", hbrt.FsPublic, SetConstSoftSeek),
hbrt.Sym("_SET_EXCLUSIVE", hbrt.FsPublic, SetConstExclusive),
hbrt.Sym("_SET_DATEFORMAT", hbrt.FsPublic, SetConstDateFmt),
hbrt.Sym("_SET_DECIMALS", hbrt.FsPublic, SetConstDecimals),
hbrt.Sym("_SET_EPOCH", hbrt.FsPublic, SetConstEpoch),
// Error handling
hbrt.Sym("ERRORBLOCK", hbrt.FsPublic, ErrorBlock),
hbrt.Sym("ERRORNEW", hbrt.FsPublic, ErrorNew),
hbrt.Sym("DOSERROR", hbrt.FsPublic, DosError),
hbrt.Sym("FERROR", hbrt.FsPublic, FError),
hbrt.Sym("BREAK", hbrt.FsPublic, Break),
// File I/O
hbrt.Sym("FOPEN", hbrt.FsPublic, FOpen),
hbrt.Sym("FCREATE", hbrt.FsPublic, FCreate),
hbrt.Sym("FCLOSE", hbrt.FsPublic, FClose),
hbrt.Sym("FREAD", hbrt.FsPublic, FRead),
hbrt.Sym("FWRITE", hbrt.FsPublic, FWrite),
hbrt.Sym("FSEEK", hbrt.FsPublic, FSeek),
hbrt.Sym("FERASE", hbrt.FsPublic, FErase),
hbrt.Sym("FRENAME", hbrt.FsPublic, FRename),
hbrt.Sym("HB_FILEEXISTS", hbrt.FsPublic, HbFileExists),
// Directory/Disk
hbrt.Sym("CURDIR", hbrt.FsPublic, CurDir),
hbrt.Sym("DIRCHANGE", hbrt.FsPublic, DirChange),
hbrt.Sym("DIRECTORY", hbrt.FsPublic, Directory),
hbrt.Sym("DIRMAKE", hbrt.FsPublic, DirMake),
hbrt.Sym("DIRREMOVE", hbrt.FsPublic, DirRemove),
// Type checking (HB_IS*)
hbrt.Sym("HB_ISARRAY", hbrt.FsPublic, HbIsArray),
hbrt.Sym("HB_ISBLOCK", hbrt.FsPublic, HbIsBlock),
hbrt.Sym("HB_ISCHAR", hbrt.FsPublic, HbIsChar),
hbrt.Sym("HB_ISSTRING", hbrt.FsPublic, HbIsString),
hbrt.Sym("HB_ISDATE", hbrt.FsPublic, HbIsDate),
hbrt.Sym("HB_ISDATETIME", hbrt.FsPublic, HbIsDateTime),
hbrt.Sym("HB_ISLOGICAL", hbrt.FsPublic, HbIsLogical),
hbrt.Sym("HB_ISNUMERIC", hbrt.FsPublic, HbIsNumeric),
hbrt.Sym("HB_ISOBJECT", hbrt.FsPublic, HbIsObject),
hbrt.Sym("HB_ISHASH", hbrt.FsPublic, HbIsHash),
hbrt.Sym("HB_ISNIL", hbrt.FsPublic, HbIsNil),
hbrt.Sym("HB_ISPOINTER", hbrt.FsPublic, HbIsPointer),
// OS/Environment
hbrt.Sym("GETENV", hbrt.FsPublic, GetEnv),
hbrt.Sym("HB_GETENV", hbrt.FsPublic, HbGetEnv),
hbrt.Sym("SETENV", hbrt.FsPublic, SetEnvFunc),
hbrt.Sym("OS", hbrt.FsPublic, OSFunc),
hbrt.Sym("VERSION", hbrt.FsPublic, VersionFunc),
hbrt.Sym("HB_RUN", hbrt.FsPublic, HbRun),
hbrt.Sym("HB_FNAMEDIR", hbrt.FsPublic, HbFNameDir),
hbrt.Sym("HB_FNAMEEXT", hbrt.FsPublic, HbFNameExt),
hbrt.Sym("HB_FNAMENAME", hbrt.FsPublic, HbFNameName),
hbrt.Sym("HB_FNAMEMERGE", hbrt.FsPublic, HbFNameMerge),
// Character classification
hbrt.Sym("ISDIGIT", hbrt.FsPublic, IsDigit),
hbrt.Sym("ISALPHA", hbrt.FsPublic, IsAlpha),
hbrt.Sym("ISALNUM", hbrt.FsPublic, IsAlnum),
hbrt.Sym("ISUPPER", hbrt.FsPublic, IsUpper),
hbrt.Sym("ISLOWER", hbrt.FsPublic, IsLower),
hbrt.Sym("ISSPACE", hbrt.FsPublic, IsSpace),
// Harbour extension functions
hbrt.Sym("HB_ISEVALITEM", hbrt.FsPublic, HbIsEvalItem),
hbrt.Sym("HB_ASCIIUPPER", hbrt.FsPublic, HbAsciiUpper),
hbrt.Sym("HB_ASCIILOWER", hbrt.FsPublic, HbAsciiLower),
hbrt.Sym("HB_DEFAULT", hbrt.FsPublic, HbDefault),
hbrt.Sym("HB_DEFAULTVALUE", hbrt.FsPublic, HbDefaultValue),
hbrt.Sym("HB_DISPOUTAT", hbrt.FsPublic, HbDispOutAt),
hbrt.Sym("HB_COLORINDEX", hbrt.FsPublic, HbColorIndex),
hbrt.Sym("HB_LEFTEQ", hbrt.FsPublic, HbLeftEq),
hbrt.Sym("HB_VAL", hbrt.FsPublic, HbVal),
hbrt.Sym("HB_KEYCHAR", hbrt.FsPublic, HbKeyChar),
hbrt.Sym("HB_KEYINS", hbrt.FsPublic, HbKeyIns),
hbrt.Sym("FIELDWBLOCK", hbrt.FsPublic, FieldWBlock),
hbrt.Sym("MEMVARBLOCK", hbrt.FsPublic, MemVarBlock),
hbrt.Sym("__DEFAULTNIL", hbrt.FsPublic, DefaultNIL),
hbrt.Sym("HB_DISPOUTATBOX", hbrt.FsPublic, HbDispOutAtBox),
hbrt.Sym("HB_DISPBOX", hbrt.FsPublic, HbDispBox),
hbrt.Sym("HB_TOKENGET", hbrt.FsPublic, HbTokenGet),
hbrt.Sym("HB_TOKENCOUNT", hbrt.FsPublic, HbTokenCount),
// Bitmap/Rushmore
hbrt.Sym("BM_DBSETFILTER", hbrt.FsPublic, BmDbSetFilter),
hbrt.Sym("BM_DBSEEKWILD", hbrt.FsPublic, BmDbSeekWild),
hbrt.Sym("BM_TURBO", hbrt.FsPublic, BmTurbo),
hbrt.Sym("BM_DBGETFILTERARRAY", hbrt.FsPublic, BmDbGetFilterArray),
hbrt.Sym("BM_DBSETFILTERARRAY", hbrt.FsPublic, BmDbSetFilterArray),
hbrt.Sym("BM_DBSETFILTERARRAYADD", hbrt.FsPublic, BmDbSetFilterArrayAdd),
hbrt.Sym("BM_DBSETFILTERARRAYDEL", hbrt.FsPublic, BmDbSetFilterArrayDel),
// HBSIX compatibility
hbrt.Sym("SX_SETTAG", hbrt.FsPublic, SxSetTag),
hbrt.Sym("SX_INDEXTAG", hbrt.FsPublic, SxIndexTag),
hbrt.Sym("SX_TAGORDER", hbrt.FsPublic, SxTagOrder),
hbrt.Sym("SX_TAGCOUNT", hbrt.FsPublic, SxTagCount),
hbrt.Sym("SX_TAGS", hbrt.FsPublic, SxTags),
hbrt.Sym("SX_SETFILEORD", hbrt.FsPublic, SxSetFileOrd),
hbrt.Sym("SX_ISDBT", hbrt.FsPublic, SxIsDBT),
hbrt.Sym("SX_ISFPT", hbrt.FsPublic, SxIsFPT),
hbrt.Sym("SX_ISSMT", hbrt.FsPublic, SxIsSMT),
hbrt.Sym("SX_AUTOOPEN", hbrt.FsPublic, SxAutoOpen),
hbrt.Sym("SX_AUTOSHARE", hbrt.FsPublic, SxAutoShare),
hbrt.Sym("SX_BLOB2FILE", hbrt.FsPublic, SxBlob2File),
hbrt.Sym("SX_FILE2BLOB", hbrt.FsPublic, SxFile2Blob),
hbrt.Sym("SX_SETTRIGGER", hbrt.FsPublic, SxSetTrigger),
hbrt.Sym("SX_VFGET", hbrt.FsPublic, SxVFGet),
hbrt.Sym("SX_DBFENCRYPT", hbrt.FsPublic, SxDbfEncrypt),
hbrt.Sym("SX_DBFDECRYPT", hbrt.FsPublic, SxDbfDecrypt),
hbrt.Sym("SX_COMPRESS", hbrt.FsPublic, SxCompress),
hbrt.Sym("SX_DECOMPRESS", hbrt.FsPublic, SxDecompress),
hbrt.Sym("RDDINFO", hbrt.FsPublic, RddInfo),
hbrt.Sym("RDDNAME", hbrt.FsPublic, RddName),
hbrt.Sym("RDDLIST", hbrt.FsPublic, RddList),
// Timestamp
hbrt.Sym("HB_DATETIME", hbrt.FsPublic, HbDateTime),
hbrt.Sym("HB_HOUR", hbrt.FsPublic, HbHour),
hbrt.Sym("HB_MINUTE", hbrt.FsPublic, HbMinute),
hbrt.Sym("HB_SEC", hbrt.FsPublic, HbSec),
hbrt.Sym("HB_TTOC", hbrt.FsPublic, HbTToC),
hbrt.Sym("HB_CTOT", hbrt.FsPublic, HbCToT),
hbrt.Sym("HB_SECOND", hbrt.FsPublic, HbSecond),
hbrt.Sym("HB_ATOKENS", hbrt.FsPublic, HbATokens),
hbrt.Sym("HB_CDPSELECT", hbrt.FsPublic, HbCdpSelect),
hbrt.Sym("DBSETINDEX", hbrt.FsPublic, rtlDbSetIndex),
hbrt.Sym("HB_TTOS", hbrt.FsPublic, HbTToS),
hbrt.Sym("HB_STOT", hbrt.FsPublic, HbSToT),
hbrt.Sym("HB_MILLISECONDS", hbrt.FsPublic, HbMilliseconds),
// Index / DB introspection
hbrt.Sym("INDEXORD", hbrt.FsPublic, IndexOrd),
hbrt.Sym("INDEXKEY", hbrt.FsPublic, IndexKey),
hbrt.Sym("ORDSETFOCUS", hbrt.FsPublic, OrdSetFocus),
hbrt.Sym("ORDCOUNT", hbrt.FsPublic, OrdCount),
hbrt.Sym("ORDNAME", hbrt.FsPublic, OrdName),
hbrt.Sym("ORDKEY", hbrt.FsPublic, OrdKey),
hbrt.Sym("ORDFOR", hbrt.FsPublic, OrdFor),
hbrt.Sym("DBINFO", hbrt.FsPublic, DbInfo),
hbrt.Sym("ORDINFO", hbrt.FsPublic, OrdInfo),
hbrt.Sym("ORDSCOPE", hbrt.FsPublic, OrdScope),
hbrt.Sym("DBORDERINFO", hbrt.FsPublic, DbOrderInfo),
hbrt.Sym("RDDSETDEFAULT", hbrt.FsPublic, RddSetDefault),
hbrt.Sym("DBCREATE", hbrt.FsPublic, DbCreate),
// Directory / Temp file (session 1)
hbrt.Sym("HB_DIREXISTS", hbrt.FsPublic, HbDirExists),
hbrt.Sym("HB_DIRCREATE", hbrt.FsPublic, HbDirCreate),
hbrt.Sym("HB_FTEMPCREATE", hbrt.FsPublic, HbFTempCreate),
hbrt.Sym("HB_FNAMESPLIT", hbrt.FsPublic, HbFNameSplit),
// File extended (session 2)
hbrt.Sym("HB_FSIZE", hbrt.FsPublic, HbFSize),
hbrt.Sym("HB_FCOPY", hbrt.FsPublic, HbFCopy),
hbrt.Sym("HB_FEOF", hbrt.FsPublic, HbFEof),
hbrt.Sym("HB_FCOMMIT", hbrt.FsPublic, HbFCommit),
hbrt.Sym("HB_FREADLEN", hbrt.FsPublic, HbFReadLen),
hbrt.Sym("HB_FGETATTR", hbrt.FsPublic, HbFGetAttr),
hbrt.Sym("HB_FSETATTR", hbrt.FsPublic, HbFSetAttr),
hbrt.Sym("HB_FGETDATETIME", hbrt.FsPublic, HbFGetDateTime),
hbrt.Sym("HB_FSETDATETIME", hbrt.FsPublic, HbFSetDateTime),
hbrt.Sym("HB_FLOCK", hbrt.FsPublic, HbFLock),
hbrt.Sym("HB_FUNLOCK", hbrt.FsPublic, HbFUnlock),
hbrt.Sym("HB_FILEDELETE", hbrt.FsPublic, HbFileDelete),
hbrt.Sym("HB_FILEMATCH", hbrt.FsPublic, HbFileMatch),
hbrt.Sym("HB_FNAMEEXISTS", hbrt.FsPublic, HbFNameExists),
hbrt.Sym("HB_FNAMEEXTSET", hbrt.FsPublic, HbFNameExtSet),
hbrt.Sym("HB_FNAMENAMEEXT", hbrt.FsPublic, HbFNameNameExt),
hbrt.Sym("HB_MEMOREAD", hbrt.FsPublic, HbMemoRead),
hbrt.Sym("HB_MEMOWRIT", hbrt.FsPublic, HbMemoWrit),
hbrt.Sym("HB_DIRTEMP", hbrt.FsPublic, HbDirTemp),
hbrt.Sym("HB_DISKSPACE", hbrt.FsPublic, HbDiskSpace),
hbrt.Sym("DISKSPACE", hbrt.FsPublic, DiskSpaceFunc),
// String extended (session 2)
hbrt.Sym("HB_AT", hbrt.FsPublic, HbAt),
hbrt.Sym("HB_RAT", hbrt.FsPublic, HbRat),
hbrt.Sym("HB_ATI", hbrt.FsPublic, HbAtI),
hbrt.Sym("HB_ATX", hbrt.FsPublic, HbAtX),
hbrt.Sym("HB_LEFTEQI", hbrt.FsPublic, HbLeftEqI),
hbrt.Sym("HB_ASCIIISALPHA", hbrt.FsPublic, HbAsciiIsAlpha),
hbrt.Sym("HB_ASCIIISDIGIT", hbrt.FsPublic, HbAsciiIsDigit),
hbrt.Sym("HB_ASCIIISLOWER", hbrt.FsPublic, HbAsciiIsLower),
hbrt.Sym("HB_ASCIIISUPPER", hbrt.FsPublic, HbAsciiIsUpper),
hbrt.Sym("HB_STRISUTF8", hbrt.FsPublic, HbStrIsUtf8),
hbrt.Sym("HB_STRDECODESCAPE", hbrt.FsPublic, HbStrDecodeEscape),
hbrt.Sym("HB_STRXOR", hbrt.FsPublic, HbStrXor),
hbrt.Sym("HB_WILDMATCH", hbrt.FsPublic, HbWildMatch),
hbrt.Sym("HB_WILDMATCHI", hbrt.FsPublic, HbWildMatchI),
hbrt.Sym("HARDCR", hbrt.FsPublic, HardCR),
// DateTime extended (session 2)
hbrt.Sym("HB_DATE", hbrt.FsPublic, HbDate),
hbrt.Sym("HB_CTOD", hbrt.FsPublic, HbCToD),
hbrt.Sym("HB_DTOC", hbrt.FsPublic, HbDToC),
hbrt.Sym("HB_STOD", hbrt.FsPublic, HbSToD),
hbrt.Sym("HB_DTOT", hbrt.FsPublic, HbDToT),
hbrt.Sym("HB_TTOD", hbrt.FsPublic, HbTToD),
hbrt.Sym("HB_TTOHOUR", hbrt.FsPublic, HbTToHour),
hbrt.Sym("HB_TTOMIN", hbrt.FsPublic, HbTToMin),
hbrt.Sym("HB_TTOSEC", hbrt.FsPublic, HbTToSec),
hbrt.Sym("HB_TTOMSEC", hbrt.FsPublic, HbTToMsec),
hbrt.Sym("HB_TTON", hbrt.FsPublic, HbTToN),
hbrt.Sym("HB_NTOT", hbrt.FsPublic, HbNToT),
hbrt.Sym("HB_NTOHOUR", hbrt.FsPublic, HbNToHour),
hbrt.Sym("HB_NTOMIN", hbrt.FsPublic, HbNToMin),
hbrt.Sym("HB_NTOSEC", hbrt.FsPublic, HbNToSec),
hbrt.Sym("HB_WEEK", hbrt.FsPublic, HbWeek),
hbrt.Sym("HB_CDAY", hbrt.FsPublic, HbCDay),
hbrt.Sym("DAYS", hbrt.FsPublic, Days),
hbrt.Sym("ELAPTIME", hbrt.FsPublic, ElapTime),
hbrt.Sym("AMPM", hbrt.FsPublic, AMPM),
hbrt.Sym("SECS", hbrt.FsPublic, Secs),
// Utilities (session 2)
hbrt.Sym("HB_SETENV", hbrt.FsPublic, HbSetEnv),
hbrt.Sym("HB_PS", hbrt.FsPublic, HbPS),
hbrt.Sym("HB_EOL", hbrt.FsPublic, HbEOL),
hbrt.Sym("HB_ISNULL", hbrt.FsPublic, HbIsNull),
hbrt.Sym("ERRORSYS", hbrt.FsPublic, ErrorSys),
// Token
hbrt.Sym("TOKEN", hbrt.FsPublic, Token),
hbrt.Sym("NUMTOKEN", hbrt.FsPublic, NumToken),
// Hex conversion
hbrt.Sym("HB_NUMTOHEX", hbrt.FsPublic, HbNumToHex),
hbrt.Sym("HB_HEXTONUM", hbrt.FsPublic, HbHexToNum),
// Hash position access
hbrt.Sym("HB_HPOS", hbrt.FsPublic, HbHPos),
hbrt.Sym("HB_HKEYAT", hbrt.FsPublic, HbHKeyAt),
hbrt.Sym("HB_HVALUEAT", hbrt.FsPublic, HbHValueAt),
hbrt.Sym("HB_HCLONE", hbrt.FsPublic, HbHClone),
// Sleep
hbrt.Sym("HB_IDLESLEEP", hbrt.FsPublic, HbIdleSleep),
// UTF-8
hbrt.Sym("HB_UTF8TOSTR", hbrt.FsPublic, HbUTF8ToStr),
hbrt.Sym("HB_STRTOUTF8", hbrt.FsPublic, HbStrToUTF8),
hbrt.Sym("HB_UTF8LEN", hbrt.FsPublic, HbUTF8Len),
hbrt.Sym("HB_UTF8SUBSTR", hbrt.FsPublic, HbUTF8SubStr),
// Stack introspection
hbrt.Sym("PROCNAME", hbrt.FsPublic, ProcName),
hbrt.Sym("PROCLINE", hbrt.FsPublic, ProcLine),
hbrt.Sym("PROCFILE", hbrt.FsPublic, ProcFile),
hbrt.Sym("ERRORLEVEL", hbrt.FsPublic, ErrorLevel),
// Field/DB introspection
hbrt.Sym("FIELDPOS", hbrt.FsPublic, FieldPos),
hbrt.Sym("FIELDBLOCK", hbrt.FsPublic, FieldBlockFunc),
hbrt.Sym("FIELDNAME", hbrt.FsPublic, FieldNameFunc),
hbrt.Sym("AFIELDS", hbrt.FsPublic, AFields),
hbrt.Sym("DBSTRUCT", hbrt.FsPublic, DbStruct),
// Misc
hbrt.Sym("TONE", hbrt.FsPublic, Tone),
hbrt.Sym("CENTER", hbrt.FsPublic, Center),
hbrt.Sym("SOUNDEX", hbrt.FsPublic, Soundex),
// JSON — Harbour compatible
hbrt.Sym("HB_JSONENCODE", hbrt.FsPublic, HbJsonEncode),
hbrt.Sym("HB_JSONDECODE", hbrt.FsPublic, HbJsonDecode),
// JSON — Five extensions (Go-native)
hbrt.Sym("JSONPRETTY", hbrt.FsPublic, JsonPretty),
hbrt.Sym("JSONTO", hbrt.FsPublic, JsonTo),
hbrt.Sym("JSONFROM", hbrt.FsPublic, JsonFrom),
hbrt.Sym("JSONPATH", hbrt.FsPublic, JsonPath),
hbrt.Sym("JSONMERGE", hbrt.FsPublic, JsonMerge),
hbrt.Sym("JSONTYPE", hbrt.FsPublic, JsonType),
hbrt.Sym("JSONVALID", hbrt.FsPublic, JsonValid),
hbrt.Sym("JSONHTTPGET", hbrt.FsPublic, JsonHttpGet),
hbrt.Sym("JSONHTTPPOST", hbrt.FsPublic, JsonHttpPost),
// Random
hbrt.Sym("HB_RANDOM", hbrt.FsPublic, HbRandom),
hbrt.Sym("HB_RANDOMINT", hbrt.FsPublic, HbRandomInt),
hbrt.Sym("HB_RANDOMSEED", hbrt.FsPublic, HbRandomSeed),
hbrt.Sym("HB_RANDSTR", hbrt.FsPublic, HbRandStr),
// OS Info
hbrt.Sym("HB_VERSION", hbrt.FsPublic, HbVersion),
hbrt.Sym("HB_COMPILER", hbrt.FsPublic, HbCompiler),
hbrt.Sym("HB_OSNEWLINE", hbrt.FsPublic, HbOsNewLine),
hbrt.Sym("HB_OSPATHSEPARATOR", hbrt.FsPublic, HbOsPathSeparator),
hbrt.Sym("HB_CWD", hbrt.FsPublic, HbCwd),
hbrt.Sym("HB_DIRBASE", hbrt.FsPublic, HbDirBase),
hbrt.Sym("HB_PROGNAME", hbrt.FsPublic, HbProgName),
hbrt.Sym("HB_USERNAME", hbrt.FsPublic, HbUserName),
hbrt.Sym("HB_GETHOSTNAME", hbrt.FsPublic, HbGetHostName),
// Process
hbrt.Sym("HB_PROCESSRUN", hbrt.FsPublic, HbProcessRun),
hbrt.Sym("WAIT", hbrt.FsPublic, WaitCmd),
// UTF-8 String
hbrt.Sym("HB_UTF8LEN", hbrt.FsPublic, HbUtf8Len),
hbrt.Sym("HB_UTF8SUBSTR", hbrt.FsPublic, HbUtf8Substr),
hbrt.Sym("HB_UTF8LEFT", hbrt.FsPublic, HbUtf8Left),
hbrt.Sym("HB_UTF8RIGHT", hbrt.FsPublic, HbUtf8Right),
hbrt.Sym("HB_UTF8AT", hbrt.FsPublic, HbUtf8At),
hbrt.Sym("HB_STRTOHEX", hbrt.FsPublic, HbStrToHex),
hbrt.Sym("HB_HEXTOSTR", hbrt.FsPublic, HbHexToStr),
hbrt.Sym("HB_STRFORMAT", hbrt.FsPublic, HbStrFormat),
// Memo line
hbrt.Sym("MEMOLINE", hbrt.FsPublic, MemoLine),
hbrt.Sym("MLCOUNT", hbrt.FsPublic, MlCount),
// FRB (Five Runtime Binary)
hbrt.Sym("FRBLOAD", hbrt.FsPublic, FrbLoadFunc),
hbrt.Sym("FRBDO", hbrt.FsPublic, FrbDoFunc),
hbrt.Sym("FRBUNLOAD", hbrt.FsPublic, FrbUnloadFunc),
hbrt.Sym("FRBRUN", hbrt.FsPublic, FrbRunFunc),
hbrt.Sym("FRBCOMPILE", hbrt.FsPublic, FrbCompileFunc),
hbrt.Sym("FRBEXEC", hbrt.FsPublic, FrbExecFunc),
// Expression bytecode compilation (FiveSql2 hot-path optimization)
hbrt.Sym("PCCOMPILE", hbrt.FsPublic, PcCompile),
hbrt.Sym("PCEVAL", hbrt.FsPublic, PcEval),
// Go-native SQL scan loop (bypasses PRG interpreter for hot path)
hbrt.Sym("SQLSCAN", hbrt.FsPublic, SqlScan),
// Goroutine / Concurrency
hbrt.Sym("GO", hbrt.FsPublic, GoFunc),
hbrt.Sym("CHANNEL", hbrt.FsPublic, ChannelFunc),
hbrt.Sym("CHSEND", hbrt.FsPublic, ChSend),
hbrt.Sym("CHRECEIVE", hbrt.FsPublic, ChReceive),
hbrt.Sym("CHCLOSE", hbrt.FsPublic, ChClose),
hbrt.Sym("WAITGROUP", hbrt.FsPublic, WaitGroupFunc),
hbrt.Sym("WGDONE", hbrt.FsPublic, WgDone),
hbrt.Sym("WGWAIT", hbrt.FsPublic, WgWait),
hbrt.Sym("WGADD", hbrt.FsPublic, WgAdd),
hbrt.Sym("MUTEX", hbrt.FsPublic, MutexFunc),
hbrt.Sym("LOCK", hbrt.FsPublic, LockFunc),
hbrt.Sym("UNLOCK", hbrt.FsPublic, UnlockFunc),
hbrt.Sym("SLEEP", hbrt.FsPublic, SleepFunc),
)
vm.RegisterModule(mod)
}
// rtlQOut implements ? command as a variadic function.
func rtlQOut(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
args := make([]hbrt.Value, nParams)
for i := 0; i < nParams; i++ {
args[i] = t.Local(i + 1)
}
qoutImpl(args)
t.RetNil()
}
// rtlQQOut implements ?? command.
func rtlQQOut(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
args := make([]hbrt.Value, nParams)
for i := 0; i < nParams; i++ {
args[i] = t.Local(i + 1)
}
qqoutImpl(args)
t.RetNil()
}
// rtlEval evaluates a code block.
// Harbour: Eval(bBlock, [xArg1, ...]) → xResult
func rtlEval(t *hbrt.Thread) {
nParams := t.ParamCount()
t.Frame(nParams, 0)
defer t.EndProc()
blkVal := t.Local(1)
if !blkVal.IsBlock() {
t.RetNil()
return
}
blk := blkVal.AsBlock()
// Push block args onto stack for the block's Frame() to pick up
blockArgs := nParams - 1
for i := 2; i <= nParams; i++ {
t.PushValue(t.Local(i))
}
// Call block function — it will call Frame(N, 0) internally
t.PendingParams2(blockArgs)
blk.Fn(t)
// Return block's result
t.PushValue(t.GetRetValue())
t.RetValue()
}