perf: EndProcFast — eliminate defer recover() from RTL hot paths
Problem: every RTL function calls defer t.EndProc() which does recover(). 50K SEEK loop = 250K recover() calls = ~12ms wasted. Solution: EndProcFast() skips recover (only needs endFrame restore). Applied to ALL RTL functions in strings.go, rdd.go, missing.go, database.go. EndProc() with recover kept for generated PRG code (needs BEGIN SEQUENCE). Analysis (50K sequential SEEK breakdown): Go NTX Seek direct: 7ms (faster than Harbour 27ms!) PRG VM overhead: 38ms (Frame + RTL calls + key generation) Key generation: 25ms (Str+LTrim+PadL+PadR = 5 RTL Frame/EndProc per iter) With EndProcFast: RTL overhead reduced ~30%. CDX SCOPE: 2ms (Harbour 4ms — 2x FASTER!) 82/82 stress PASS. 14 packages ALL PASS. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -283,7 +283,8 @@ func (idx *Index) remapFile() {
|
||||
idx.mmapFile()
|
||||
}
|
||||
|
||||
func (idx *Index) KeyLen() int { return idx.keyLen }
|
||||
func (idx *Index) KeyLen() int { return idx.keyLen }
|
||||
func (idx *Index) TestGetMmap() []byte { return idx.mmapData }
|
||||
|
||||
func (idx *Index) Close() error {
|
||||
if idx.mmapData != nil {
|
||||
|
||||
@@ -250,12 +250,21 @@ func (t *Thread) EndProc() {
|
||||
if hbErr, ok := r.(*HbError); ok {
|
||||
t.handleSequenceError(hbErr)
|
||||
} else {
|
||||
// Print error to stderr before re-panic
|
||||
fmt.Fprintf(os.Stderr, "Five runtime error: %v\n", r)
|
||||
panic(r)
|
||||
}
|
||||
}
|
||||
t.endFrame()
|
||||
}
|
||||
|
||||
// EndProcFast is called by RTL functions that don't need recover().
|
||||
// ~3x faster than EndProc (no defer recover overhead).
|
||||
func (t *Thread) EndProcFast() {
|
||||
t.endFrame()
|
||||
}
|
||||
|
||||
// endFrame restores the previous call frame.
|
||||
func (t *Thread) endFrame() {
|
||||
if t.callSP > 0 {
|
||||
t.callSP--
|
||||
if t.callSP > 0 {
|
||||
|
||||
@@ -15,7 +15,7 @@ import (
|
||||
// FIELDPUT(nField, xValue) → xValue
|
||||
func rtlFieldPut(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -36,7 +36,7 @@ func rtlFieldPut(t *hbrt.Thread) {
|
||||
func rtlAlias(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetString("")
|
||||
@@ -54,7 +54,7 @@ func rtlAlias(t *hbrt.Thread) {
|
||||
func rtlDbEval(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
@@ -141,7 +141,7 @@ func rtlDbEval(t *hbrt.Thread) {
|
||||
func rtlDbUseArea(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -174,7 +174,7 @@ func rtlDbUseArea(t *hbrt.Thread) {
|
||||
// DBCLOSEAREA() → NIL
|
||||
func rtlDbCloseArea(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam != nil {
|
||||
wam.Close()
|
||||
@@ -185,7 +185,7 @@ func rtlDbCloseArea(t *hbrt.Thread) {
|
||||
// DBGOTO(nRecNo) → NIL
|
||||
func rtlDbGoTo(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -202,7 +202,7 @@ func rtlDbGoTo(t *hbrt.Thread) {
|
||||
func rtlDbSkip(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -224,7 +224,7 @@ func rtlDbSkip(t *hbrt.Thread) {
|
||||
// DBGOTOP() → NIL
|
||||
func rtlDbGoTop(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -240,7 +240,7 @@ func rtlDbGoTop(t *hbrt.Thread) {
|
||||
// DBGOBOTTOM() → NIL
|
||||
func rtlDbGoBottom(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -257,7 +257,7 @@ func rtlDbGoBottom(t *hbrt.Thread) {
|
||||
func rtlDbAppend(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -273,7 +273,7 @@ func rtlDbAppend(t *hbrt.Thread) {
|
||||
// DBDELETE() → NIL
|
||||
func rtlDbDelete(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -289,7 +289,7 @@ func rtlDbDelete(t *hbrt.Thread) {
|
||||
// DBRECALL() → NIL
|
||||
func rtlDbRecall(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -305,7 +305,7 @@ func rtlDbRecall(t *hbrt.Thread) {
|
||||
// DBCOMMIT() → NIL
|
||||
func rtlDbCommit(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -322,7 +322,7 @@ func rtlDbCommit(t *hbrt.Thread) {
|
||||
func rtlDbSeek(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetBool(false)
|
||||
@@ -354,7 +354,7 @@ func rtlDbSeek(t *hbrt.Thread) {
|
||||
// DBSELECTAREA(nArea | cAlias) → NIL
|
||||
func rtlDbSelectArea(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -372,7 +372,7 @@ func rtlDbSelectArea(t *hbrt.Thread) {
|
||||
// DBPACK() → NIL
|
||||
func rtlDbPack(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -388,7 +388,7 @@ func rtlDbPack(t *hbrt.Thread) {
|
||||
// DBZAP() → NIL
|
||||
func rtlDbZap(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
t.RetNil()
|
||||
@@ -408,7 +408,7 @@ func rtlDbZap(t *hbrt.Thread) {
|
||||
func rtlDbLocate(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
@@ -507,7 +507,7 @@ func rtlDbLocate(t *hbrt.Thread) {
|
||||
// Harbour: __dbContinue()
|
||||
func rtlDbContinue(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
@@ -548,7 +548,7 @@ func rtlDbContinue(t *hbrt.Thread) {
|
||||
func rtlDbSetFilter(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
@@ -579,7 +579,7 @@ func rtlDbSetFilter(t *hbrt.Thread) {
|
||||
// DBCLEARFILTER()
|
||||
func rtlDbClearFilter(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
wam := getWA(t)
|
||||
if wam == nil {
|
||||
@@ -595,7 +595,7 @@ func rtlDbClearFilter(t *hbrt.Thread) {
|
||||
// DBFILTER() → cFilterExpression
|
||||
func rtlDbFilter(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
// TODO: return stored filter expression from area
|
||||
t.RetString("")
|
||||
|
||||
@@ -16,7 +16,7 @@ import (
|
||||
// At returns position of cSearch in cTarget (1-based, 0 if not found).
|
||||
func At(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
search := t.Local(1).AsString()
|
||||
target := t.Local(2).AsString()
|
||||
idx := strings.Index(target, search)
|
||||
@@ -30,7 +30,7 @@ func At(t *hbrt.Thread) {
|
||||
// Left returns leftmost n characters.
|
||||
func Left(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := t.Local(1).AsString()
|
||||
n := int(t.Local(2).AsNumInt())
|
||||
if n >= len(s) {
|
||||
@@ -46,7 +46,7 @@ func Left(t *hbrt.Thread) {
|
||||
// Right returns rightmost n characters.
|
||||
func Right(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := t.Local(1).AsString()
|
||||
n := int(t.Local(2).AsNumInt())
|
||||
if n >= len(s) {
|
||||
@@ -62,7 +62,7 @@ func Right(t *hbrt.Thread) {
|
||||
// Asc returns ASCII code of first character.
|
||||
func Asc(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := t.Local(1).AsString()
|
||||
if len(s) > 0 {
|
||||
t.RetInt(int64(s[0]))
|
||||
@@ -74,7 +74,7 @@ func Asc(t *hbrt.Thread) {
|
||||
// Chr returns character from ASCII code.
|
||||
func Chr(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
n := int(t.Local(1).AsNumInt())
|
||||
t.PushString(string([]byte{byte(n)}))
|
||||
t.RetValue()
|
||||
@@ -84,7 +84,7 @@ func Chr(t *hbrt.Thread) {
|
||||
func StrTran(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := t.Local(1).AsString()
|
||||
search := t.Local(2).AsString()
|
||||
replace := ""
|
||||
@@ -98,7 +98,7 @@ func StrTran(t *hbrt.Thread) {
|
||||
// Stuff inserts/replaces characters in string.
|
||||
func Stuff(t *hbrt.Thread) {
|
||||
t.Frame(4, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := t.Local(1).AsString()
|
||||
start := int(t.Local(2).AsNumInt()) - 1 // 1-based
|
||||
nDel := int(t.Local(3).AsNumInt())
|
||||
@@ -120,7 +120,7 @@ func Stuff(t *hbrt.Thread) {
|
||||
// PadC pads string centered.
|
||||
func PadC(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := valueToDisplay(t.Local(1))
|
||||
n := int(t.Local(2).AsNumInt())
|
||||
if len(s) >= n {
|
||||
@@ -138,7 +138,7 @@ func PadC(t *hbrt.Thread) {
|
||||
// Round rounds a number to specified decimal places.
|
||||
func Round(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
val := t.Local(1).AsNumDouble()
|
||||
dec := int(t.Local(2).AsNumInt())
|
||||
mult := math.Pow(10, float64(dec))
|
||||
@@ -150,7 +150,7 @@ func Round(t *hbrt.Thread) {
|
||||
// Max returns larger of two values.
|
||||
func Max(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
a := t.Local(1)
|
||||
b := t.Local(2)
|
||||
if a.IsNumeric() && b.IsNumeric() {
|
||||
@@ -174,7 +174,7 @@ func Max(t *hbrt.Thread) {
|
||||
// Min returns smaller of two values.
|
||||
func Min(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
a := t.Local(1)
|
||||
b := t.Local(2)
|
||||
if a.IsNumeric() && b.IsNumeric() {
|
||||
@@ -198,7 +198,7 @@ func Min(t *hbrt.Thread) {
|
||||
// Sqrt returns square root.
|
||||
func Sqrt(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
t.PushValue(hbrt.MakeDoubleAuto(math.Sqrt(t.Local(1).AsNumDouble())))
|
||||
t.RetValue()
|
||||
}
|
||||
@@ -206,7 +206,7 @@ func Sqrt(t *hbrt.Thread) {
|
||||
// Log returns natural logarithm.
|
||||
func Log(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
t.PushValue(hbrt.MakeDoubleAuto(math.Log(t.Local(1).AsNumDouble())))
|
||||
t.RetValue()
|
||||
}
|
||||
@@ -214,7 +214,7 @@ func Log(t *hbrt.Thread) {
|
||||
// Exp returns e^x.
|
||||
func Exp(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
t.PushValue(hbrt.MakeDoubleAuto(math.Exp(t.Local(1).AsNumDouble())))
|
||||
t.RetValue()
|
||||
}
|
||||
@@ -222,7 +222,7 @@ func Exp(t *hbrt.Thread) {
|
||||
// Mod returns modulus (same as %).
|
||||
func Mod(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
a := t.Local(1).AsNumDouble()
|
||||
b := t.Local(2).AsNumDouble()
|
||||
if b == 0 {
|
||||
@@ -240,7 +240,7 @@ func Mod(t *hbrt.Thread) {
|
||||
// Type returns type of an expression (as string).
|
||||
func TypeFunc(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
var c string
|
||||
switch {
|
||||
@@ -272,7 +272,7 @@ func TypeFunc(t *hbrt.Thread) {
|
||||
// PCount returns number of parameters passed.
|
||||
func PCount(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
t.RetInt(int64(t.ParamCount()))
|
||||
}
|
||||
|
||||
@@ -281,7 +281,7 @@ func PCount(t *hbrt.Thread) {
|
||||
// Array creates array of given size.
|
||||
func ArrayFunc(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
n := int(t.Local(1).AsNumInt())
|
||||
t.PushValue(hbrt.MakeArray(n))
|
||||
t.RetValue()
|
||||
@@ -290,7 +290,7 @@ func ArrayFunc(t *hbrt.Thread) {
|
||||
// FCount returns number of fields in current workarea.
|
||||
func FCount(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
wam := getWA(t)
|
||||
if wam != nil {
|
||||
if area := wam.Current(); area != nil {
|
||||
@@ -304,7 +304,7 @@ func FCount(t *hbrt.Thread) {
|
||||
// FieldName returns field name by position (1-based).
|
||||
func FieldName(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
nField := int(t.Local(1).AsNumInt())
|
||||
wam := getWA(t)
|
||||
if wam != nil {
|
||||
@@ -322,7 +322,7 @@ func FieldName(t *hbrt.Thread) {
|
||||
// Select returns current workarea number.
|
||||
func SelectFunc(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
// TODO: integrate with RDD
|
||||
t.RetInt(0)
|
||||
}
|
||||
@@ -330,7 +330,7 @@ func SelectFunc(t *hbrt.Thread) {
|
||||
// File checks if file exists.
|
||||
func FileFunc(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
// Simple implementation
|
||||
t.PushBool(false)
|
||||
t.RetValue()
|
||||
@@ -342,7 +342,7 @@ func FileFunc(t *hbrt.Thread) {
|
||||
func Inkey(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
// Check keyboard buffer first
|
||||
if k := PopKeyBuffer(); k >= 0 {
|
||||
@@ -390,7 +390,7 @@ func Inkey(t *hbrt.Thread) {
|
||||
func Transform(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
val := t.Local(1)
|
||||
pic := ""
|
||||
if nParams >= 2 && !t.Local(2).IsNil() {
|
||||
@@ -402,7 +402,7 @@ func Transform(t *hbrt.Thread) {
|
||||
// hb_StrReplace replaces multiple substrings.
|
||||
func HbStrReplace(t *hbrt.Thread) {
|
||||
t.Frame(3, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := t.Local(1).AsString()
|
||||
search := t.Local(2) // array of search strings
|
||||
replace := t.Local(3) // array of replace strings
|
||||
@@ -420,7 +420,7 @@ func HbStrReplace(t *hbrt.Thread) {
|
||||
// hb_NToS converts number to string without leading spaces.
|
||||
func HbNToS(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsNumInt() {
|
||||
t.PushString(fmt_int64(v.AsNumInt()))
|
||||
|
||||
14
hbrtl/rdd.go
14
hbrtl/rdd.go
@@ -12,7 +12,7 @@ import (
|
||||
|
||||
func rtlEOF(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
if wa := getWA(t); wa != nil {
|
||||
if area := wa.Current(); area != nil {
|
||||
t.PushBool(area.EOF())
|
||||
@@ -26,7 +26,7 @@ func rtlEOF(t *hbrt.Thread) {
|
||||
|
||||
func rtlBOF(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
if wa := getWA(t); wa != nil {
|
||||
if area := wa.Current(); area != nil {
|
||||
t.PushBool(area.BOF())
|
||||
@@ -40,7 +40,7 @@ func rtlBOF(t *hbrt.Thread) {
|
||||
|
||||
func rtlFound(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
if wa := getWA(t); wa != nil {
|
||||
if area := wa.Current(); area != nil {
|
||||
t.PushBool(area.Found())
|
||||
@@ -54,7 +54,7 @@ func rtlFound(t *hbrt.Thread) {
|
||||
|
||||
func rtlRecNo(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
if wa := getWA(t); wa != nil {
|
||||
if area := wa.Current(); area != nil {
|
||||
t.RetInt(int64(area.RecNo()))
|
||||
@@ -66,7 +66,7 @@ func rtlRecNo(t *hbrt.Thread) {
|
||||
|
||||
func rtlRecCount(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
if wa := getWA(t); wa != nil {
|
||||
if area := wa.Current(); area != nil {
|
||||
rc, _ := area.RecCount()
|
||||
@@ -79,7 +79,7 @@ func rtlRecCount(t *hbrt.Thread) {
|
||||
|
||||
func rtlDeleted(t *hbrt.Thread) {
|
||||
t.Frame(0, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
if wa := getWA(t); wa != nil {
|
||||
if area := wa.Current(); area != nil {
|
||||
t.PushBool(area.Deleted())
|
||||
@@ -93,7 +93,7 @@ func rtlDeleted(t *hbrt.Thread) {
|
||||
|
||||
func rtlFieldGet(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
n := int(t.Local(1).AsNumInt())
|
||||
if wa := getWA(t); wa != nil {
|
||||
if area := wa.Current(); area != nil {
|
||||
|
||||
@@ -38,7 +38,7 @@ func spaces(n int) string {
|
||||
func Str(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
v := t.Local(1)
|
||||
if !v.IsNumeric() {
|
||||
@@ -85,7 +85,7 @@ func Str(t *hbrt.Thread) {
|
||||
// Harbour: Val(cString) → nValue
|
||||
func Val(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
v := t.Local(1)
|
||||
if !v.IsString() {
|
||||
@@ -129,7 +129,7 @@ func Val(t *hbrt.Thread) {
|
||||
// Harbour: Len(xValue) → nLen
|
||||
func Len(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
v := t.Local(1)
|
||||
switch {
|
||||
@@ -149,7 +149,7 @@ func Len(t *hbrt.Thread) {
|
||||
func SubStr(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
|
||||
v := t.Local(1)
|
||||
if !v.IsString() {
|
||||
@@ -197,7 +197,7 @@ func SubStr(t *hbrt.Thread) {
|
||||
// Harbour: Upper(cString) → cString
|
||||
func Upper(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsString() {
|
||||
t.PushString(strings.ToUpper(v.AsString()))
|
||||
@@ -210,7 +210,7 @@ func Upper(t *hbrt.Thread) {
|
||||
// Lower converts string to lowercase.
|
||||
func Lower(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsString() {
|
||||
t.PushString(strings.ToLower(v.AsString()))
|
||||
@@ -223,7 +223,7 @@ func Lower(t *hbrt.Thread) {
|
||||
// AllTrim removes leading and trailing spaces.
|
||||
func AllTrim(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsString() {
|
||||
t.PushString(strings.TrimSpace(v.AsString()))
|
||||
@@ -236,7 +236,7 @@ func AllTrim(t *hbrt.Thread) {
|
||||
// LTrim trims leading spaces only. Harbour: LTRIM(cString) → cString
|
||||
func LTrim(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsString() {
|
||||
t.PushString(strings.TrimLeft(v.AsString(), " "))
|
||||
@@ -249,7 +249,7 @@ func LTrim(t *hbrt.Thread) {
|
||||
// RTrim trims trailing spaces only. Harbour: RTRIM(cString) / TRIM(cString)
|
||||
func RTrim(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsString() {
|
||||
t.PushString(strings.TrimRight(v.AsString(), " "))
|
||||
@@ -263,7 +263,7 @@ func RTrim(t *hbrt.Thread) {
|
||||
// Harbour: Space(nCount) → cString
|
||||
func Space(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
n := t.Local(1).AsNumInt()
|
||||
if n < 0 {
|
||||
n = 0
|
||||
@@ -276,7 +276,7 @@ func Space(t *hbrt.Thread) {
|
||||
func PadR(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := valueToDisplay(t.Local(1))
|
||||
n := int(t.Local(2).AsNumInt())
|
||||
fill := " "
|
||||
@@ -303,7 +303,7 @@ func PadR(t *hbrt.Thread) {
|
||||
func PadL(t *hbrt.Thread) {
|
||||
nParams := t.ParamCount()
|
||||
t.Frame(nParams, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := valueToDisplay(t.Local(1))
|
||||
n := int(t.Local(2).AsNumInt())
|
||||
fill := " "
|
||||
@@ -329,7 +329,7 @@ func PadL(t *hbrt.Thread) {
|
||||
// Replicate repeats a string n times.
|
||||
func Replicate(t *hbrt.Thread) {
|
||||
t.Frame(2, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
s := t.Local(1).AsString()
|
||||
n := int(t.Local(2).AsNumInt())
|
||||
if n < 0 {
|
||||
@@ -345,7 +345,7 @@ func Replicate(t *hbrt.Thread) {
|
||||
// Harbour: ValType(xValue) → cType
|
||||
func ValType(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
var c string
|
||||
switch {
|
||||
@@ -382,7 +382,7 @@ func ValType(t *hbrt.Thread) {
|
||||
// Harbour: Empty(xValue) → lEmpty
|
||||
func Empty(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
var empty bool
|
||||
switch {
|
||||
@@ -412,7 +412,7 @@ func Empty(t *hbrt.Thread) {
|
||||
// Abs returns the absolute value.
|
||||
func Abs(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsNumInt() {
|
||||
n := v.AsNumInt()
|
||||
@@ -432,7 +432,7 @@ func Abs(t *hbrt.Thread) {
|
||||
// Int returns the integer part of a numeric value.
|
||||
func Int(t *hbrt.Thread) {
|
||||
t.Frame(1, 0)
|
||||
defer t.EndProc()
|
||||
defer t.EndProcFast()
|
||||
v := t.Local(1)
|
||||
if v.IsNumInt() {
|
||||
t.PushValue(v)
|
||||
|
||||
Reference in New Issue
Block a user