- 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>
403 lines
6.7 KiB
Go
403 lines
6.7 KiB
Go
// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
|
// All rights reserved.
|
|
|
|
// Database callable functions: FIELDPUT, ALIAS, DBEVAL, DBUSEAREA, DBCLOSEAREA,
|
|
// DBGOTO, DBSKIP, DBAPPEND, DBDELETE, DBRECALL, DBCOMMIT, DBSEEK,
|
|
// DBGOTOP, DBGOBOTTOM, DBRLOCKLIST, DBSETFILTER, DBCLEARFILTER
|
|
|
|
package hbrtl
|
|
|
|
import (
|
|
"five/hbrt"
|
|
"five/hbrdd"
|
|
)
|
|
|
|
// FIELDPUT(nField, xValue) → xValue
|
|
func rtlFieldPut(t *hbrt.Thread) {
|
|
t.Frame(2, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
nField := t.Local(1).AsInt()
|
|
val := t.Local(2)
|
|
area.PutValue(nField-1, val) // 1-based to 0-based
|
|
t.RetVal(val)
|
|
}
|
|
|
|
// ALIAS([nWorkArea]) → cAlias
|
|
func rtlAlias(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetString("")
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
t.RetString(area.Alias())
|
|
} else {
|
|
t.RetString("")
|
|
}
|
|
}
|
|
|
|
// DBEVAL(bBlock [, bFor [, bWhile [, nCount [, nRecord [, lRest]]]]]) → NIL
|
|
func rtlDbEval(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
|
|
block := t.Local(1)
|
|
if !block.IsBlock() {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
|
|
var bFor, bWhile hbrt.Value
|
|
nCount := -1
|
|
lRest := false
|
|
|
|
if nParams >= 2 {
|
|
bFor = t.Local(2)
|
|
}
|
|
if nParams >= 3 {
|
|
bWhile = t.Local(3)
|
|
}
|
|
if nParams >= 4 && !t.Local(4).IsNil() {
|
|
nCount = t.Local(4).AsInt()
|
|
}
|
|
if nParams >= 5 && !t.Local(5).IsNil() {
|
|
nRec := t.Local(5).AsInt()
|
|
area.GoTo(uint32(nRec))
|
|
}
|
|
if nParams >= 6 && !t.Local(6).IsNil() {
|
|
lRest = t.Local(6).AsBool()
|
|
}
|
|
|
|
// If not lRest and no record specified, go top
|
|
if !lRest && (nParams < 5 || t.Local(5).IsNil()) {
|
|
area.GoTop()
|
|
}
|
|
|
|
count := 0
|
|
for !area.EOF() {
|
|
if nCount >= 0 && count >= nCount {
|
|
break
|
|
}
|
|
|
|
// While condition
|
|
if !bWhile.IsNil() && bWhile.IsBlock() {
|
|
blk := bWhile.AsBlock()
|
|
t.PendingParams2(0)
|
|
blk.Fn(t)
|
|
if !t.GetRetValue().AsBool() {
|
|
break
|
|
}
|
|
}
|
|
|
|
// For condition
|
|
doBlock := true
|
|
if !bFor.IsNil() && bFor.IsBlock() {
|
|
blk := bFor.AsBlock()
|
|
t.PendingParams2(0)
|
|
blk.Fn(t)
|
|
doBlock = t.GetRetValue().AsBool()
|
|
}
|
|
|
|
if doBlock {
|
|
blk := block.AsBlock()
|
|
t.PendingParams2(0)
|
|
blk.Fn(t)
|
|
}
|
|
|
|
area.Skip(1)
|
|
count++
|
|
}
|
|
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBUSEAREA([lNewArea], [cDriver], cName, [cAlias], [lShared], [lReadOnly]) → NIL
|
|
func rtlDbUseArea(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
cName := ""
|
|
cAlias := ""
|
|
cDriver := "DBFNTX"
|
|
if nParams >= 3 && !t.Local(3).IsNil() {
|
|
cName = t.Local(3).AsString()
|
|
}
|
|
if nParams >= 4 && !t.Local(4).IsNil() {
|
|
cAlias = t.Local(4).AsString()
|
|
}
|
|
if nParams >= 2 && !t.Local(2).IsNil() {
|
|
cDriver = t.Local(2).AsString()
|
|
}
|
|
shared := false
|
|
readOnly := false
|
|
if nParams >= 5 && !t.Local(5).IsNil() {
|
|
shared = t.Local(5).AsBool()
|
|
}
|
|
if nParams >= 6 && !t.Local(6).IsNil() {
|
|
readOnly = t.Local(6).AsBool()
|
|
}
|
|
wam.Open(cDriver, cName, cAlias, shared, readOnly)
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBCLOSEAREA() → NIL
|
|
func rtlDbCloseArea(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam != nil {
|
|
wam.Close()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBGOTO(nRecNo) → NIL
|
|
func rtlDbGoTo(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.GoTo(uint32(t.Local(1).AsLong()))
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBSKIP([nRecords]) → NIL
|
|
func rtlDbSkip(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
n := int64(1)
|
|
if nParams >= 1 && !t.Local(1).IsNil() {
|
|
n = t.Local(1).AsLong()
|
|
}
|
|
area.Skip(n)
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBGOTOP() → NIL
|
|
func rtlDbGoTop(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.GoTop()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBGOBOTTOM() → NIL
|
|
func rtlDbGoBottom(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.GoBottom()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBAPPEND([lUnlock]) → NIL
|
|
func rtlDbAppend(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.Append()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBDELETE() → NIL
|
|
func rtlDbDelete(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.Delete()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBRECALL() → NIL
|
|
func rtlDbRecall(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.Recall()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBCOMMIT() → NIL
|
|
func rtlDbCommit(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.Flush()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBSEEK(xValue [, lSoftSeek [, lLast]]) → lFound
|
|
func rtlDbSeek(t *hbrt.Thread) {
|
|
nParams := t.ParamCount()
|
|
t.Frame(nParams, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetBool(false)
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area == nil {
|
|
t.RetBool(false)
|
|
return
|
|
}
|
|
val := t.Local(1)
|
|
softSeek := false
|
|
findLast := false
|
|
if nParams >= 2 && !t.Local(2).IsNil() {
|
|
softSeek = t.Local(2).AsBool()
|
|
}
|
|
if nParams >= 3 && !t.Local(3).IsNil() {
|
|
findLast = t.Local(3).AsBool()
|
|
}
|
|
// Check if area implements Indexer
|
|
if idx, ok := area.(hbrdd.Indexer); ok {
|
|
found, _ := idx.Seek(val, softSeek, findLast)
|
|
t.RetBool(found)
|
|
} else {
|
|
t.RetBool(false)
|
|
}
|
|
}
|
|
|
|
// DBSELECTAREA(nArea | cAlias) → NIL
|
|
func rtlDbSelectArea(t *hbrt.Thread) {
|
|
t.Frame(1, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
v := t.Local(1)
|
|
if v.IsString() {
|
|
wam.Select(v.AsString())
|
|
} else {
|
|
wam.Select(uint16(v.AsInt()))
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBPACK() → NIL
|
|
func rtlDbPack(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.Pack()
|
|
}
|
|
t.RetNil()
|
|
}
|
|
|
|
// DBZAP() → NIL
|
|
func rtlDbZap(t *hbrt.Thread) {
|
|
t.Frame(0, 0)
|
|
defer t.EndProc()
|
|
wam := getWA(t)
|
|
if wam == nil {
|
|
t.RetNil()
|
|
return
|
|
}
|
|
area := wam.Current()
|
|
if area != nil {
|
|
area.Zap()
|
|
}
|
|
t.RetNil()
|
|
}
|