- 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>
664 lines
18 KiB
Go
664 lines
18 KiB
Go
// Copyright (c) 2026 Charles KWON OhJun (charleskwonohjun@gmail.com)
|
|
// All rights reserved.
|
|
|
|
// hbfunc.go — Harbour HB_FUNC compatible Go API for #pragma BEGINDUMP.
|
|
//
|
|
// This provides the complete Harbour C extension API in Go,
|
|
// allowing PRG code to call inline Go functions seamlessly.
|
|
//
|
|
// Usage in PRG:
|
|
//
|
|
// #pragma BEGINDUMP
|
|
// func init() {
|
|
// hbrt.HB_FUNC("MYFUNC", MyFunc)
|
|
// }
|
|
// func MyFunc(ctx *hbrt.HBContext) {
|
|
// name := ctx.ParC(1)
|
|
// age := ctx.ParNI(2)
|
|
// ctx.RetC("Hello " + name)
|
|
// }
|
|
// #pragma ENDDUMP
|
|
//
|
|
// Then in PRG:
|
|
//
|
|
// ? MyFunc("Charles", 30) // → "Hello Charles"
|
|
package hbrt
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
// HBContext wraps Thread for Harbour-compatible C API access.
|
|
// Maps 1:1 to Harbour's hb_par*/hb_ret*/hb_stor* functions.
|
|
type HBContext struct {
|
|
T *Thread
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// HB_FUNC registration — called from init() in #pragma BEGINDUMP
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// HB_FUNC registers a Go function as a Harbour-callable function.
|
|
// Equivalent to Harbour's HB_FUNC(name) macro.
|
|
func HB_FUNC(name string, fn func(ctx *HBContext)) {
|
|
RegisterDynamicFunc(strings.ToUpper(name), func(t *Thread) {
|
|
ctx := &HBContext{T: t}
|
|
fn(ctx)
|
|
})
|
|
}
|
|
|
|
// HB_FUNC_STATIC is same as HB_FUNC but marks as static scope.
|
|
func HB_FUNC_STATIC(name string, fn func(ctx *HBContext)) {
|
|
HB_FUNC(name, fn)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Parameter count — Harbour: hb_pcount()
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func (c *HBContext) PCount() int {
|
|
return c.T.ParamCount()
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Parameter access (1-based index)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func (c *HBContext) param(n int) Value {
|
|
if n < 1 || n > c.PCount() {
|
|
return MakeNil()
|
|
}
|
|
return c.T.Local(n)
|
|
}
|
|
|
|
// Param returns raw Value of parameter n.
|
|
func (c *HBContext) Param(n int) Value { return c.param(n) }
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Type checking — Harbour: HB_IS*(n) macros
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func (c *HBContext) IsNil(n int) bool { return c.param(n).IsNil() }
|
|
func (c *HBContext) IsChar(n int) bool { return c.param(n).IsString() }
|
|
func (c *HBContext) IsString(n int) bool { return c.param(n).IsString() }
|
|
func (c *HBContext) IsNum(n int) bool { return c.param(n).IsNumeric() }
|
|
func (c *HBContext) IsNumeric(n int) bool { return c.param(n).IsNumeric() }
|
|
func (c *HBContext) IsLog(n int) bool { return c.param(n).IsLogical() }
|
|
func (c *HBContext) IsLogical(n int) bool { return c.param(n).IsLogical() }
|
|
func (c *HBContext) IsDate(n int) bool { return c.param(n).IsDate() }
|
|
func (c *HBContext) IsDateTime(n int) bool { return c.param(n).IsDateTime() }
|
|
func (c *HBContext) IsArray(n int) bool { return c.param(n).IsArray() }
|
|
func (c *HBContext) IsHash(n int) bool { return c.param(n).IsHash() }
|
|
func (c *HBContext) IsBlock(n int) bool { return c.param(n).IsBlock() }
|
|
func (c *HBContext) IsObject(n int) bool { return c.param(n).IsObject() }
|
|
func (c *HBContext) IsPointer(n int) bool { return c.param(n).IsPointer() }
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// String parameters — Harbour: hb_parc, hb_parclen
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ParC returns string parameter n. Harbour: hb_parc(n)
|
|
func (c *HBContext) ParC(n int) string {
|
|
v := c.param(n)
|
|
if v.IsString() {
|
|
return v.AsString()
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// ParCLen returns length of string parameter n. Harbour: hb_parclen(n)
|
|
func (c *HBContext) ParCLen(n int) int {
|
|
v := c.param(n)
|
|
if v.IsString() {
|
|
return len(v.AsString())
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Numeric parameters — Harbour: hb_parni, hb_parnl, hb_parnd
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ParNI returns int parameter. Harbour: hb_parni(n)
|
|
func (c *HBContext) ParNI(n int) int {
|
|
v := c.param(n)
|
|
if v.IsNumeric() {
|
|
return v.AsInt()
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ParNIDef returns int parameter with default. Harbour: hb_parnidef(n, def)
|
|
func (c *HBContext) ParNIDef(n int, def int) int {
|
|
v := c.param(n)
|
|
if v.IsNumeric() {
|
|
return v.AsInt()
|
|
}
|
|
return def
|
|
}
|
|
|
|
// ParNL returns int64 parameter. Harbour: hb_parnl(n)
|
|
func (c *HBContext) ParNL(n int) int64 {
|
|
v := c.param(n)
|
|
if v.IsNumeric() {
|
|
return v.AsLong()
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ParNLDef returns int64 parameter with default. Harbour: hb_parnldef(n, def)
|
|
func (c *HBContext) ParNLDef(n int, def int64) int64 {
|
|
v := c.param(n)
|
|
if v.IsNumeric() {
|
|
return v.AsLong()
|
|
}
|
|
return def
|
|
}
|
|
|
|
// ParND returns float64 parameter. Harbour: hb_parnd(n)
|
|
func (c *HBContext) ParND(n int) float64 {
|
|
v := c.param(n)
|
|
if v.IsNumeric() {
|
|
return v.AsNumDouble()
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ParNDDef returns float64 parameter with default.
|
|
func (c *HBContext) ParNDDef(n int, def float64) float64 {
|
|
v := c.param(n)
|
|
if v.IsNumeric() {
|
|
return v.AsNumDouble()
|
|
}
|
|
return def
|
|
}
|
|
|
|
// ParNInt returns HB_MAXINT parameter. Harbour: hb_parnint(n)
|
|
func (c *HBContext) ParNInt(n int) int64 { return c.ParNL(n) }
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Logical parameters — Harbour: hb_parl
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ParL returns bool parameter. Harbour: hb_parl(n)
|
|
func (c *HBContext) ParL(n int) bool {
|
|
v := c.param(n)
|
|
if v.IsLogical() {
|
|
return v.AsBool()
|
|
}
|
|
return false
|
|
}
|
|
|
|
// ParLDef returns bool parameter with default. Harbour: hb_parldef(n, def)
|
|
func (c *HBContext) ParLDef(n int, def bool) bool {
|
|
v := c.param(n)
|
|
if v.IsLogical() {
|
|
return v.AsBool()
|
|
}
|
|
return def
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Date parameters — Harbour: hb_pards, hb_pardl
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// julianToYMD converts Julian day to year, month, day.
|
|
func julianToYMD(julian int64) (int, int, int) {
|
|
if julian <= 0 {
|
|
return 0, 0, 0
|
|
}
|
|
l := julian + 68569
|
|
n := 4 * l / 146097
|
|
l = l - (146097*n+3)/4
|
|
i := 4000 * (l + 1) / 1461001
|
|
l = l - 1461*i/4 + 31
|
|
j := 80 * l / 2447
|
|
d := l - 2447*j/80
|
|
l = j / 11
|
|
m := j + 2 - 12*l
|
|
y := 100*(n-49) + i + l
|
|
return int(y), int(m), int(d)
|
|
}
|
|
|
|
// ymdToJulian converts year, month, day to Julian day number.
|
|
func ymdToJulian(y, m, d int) int64 {
|
|
if y == 0 && m == 0 && d == 0 {
|
|
return 0
|
|
}
|
|
mm := int64(m)
|
|
yy := int64(y)
|
|
dd := int64(d)
|
|
return dd - 32075 +
|
|
1461*(yy+4800+(mm-14)/12)/4 +
|
|
367*(mm-2-(mm-14)/12*12)/12 -
|
|
3*((yy+4900+(mm-14)/12)/100)/4
|
|
}
|
|
|
|
// ParDS returns date as "YYYYMMDD" string. Harbour: hb_pards(n)
|
|
func (c *HBContext) ParDS(n int) string {
|
|
v := c.param(n)
|
|
if v.IsDate() {
|
|
y, m, d := julianToYMD(v.AsJulian())
|
|
return fmt.Sprintf("%04d%02d%02d", y, m, d)
|
|
}
|
|
return " "
|
|
}
|
|
|
|
// ParDL returns date as Julian day number. Harbour: hb_pardl(n)
|
|
func (c *HBContext) ParDL(n int) int64 {
|
|
v := c.param(n)
|
|
if v.IsDate() {
|
|
return v.AsJulian()
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ParDate returns date as Go time.Time (Five extension).
|
|
func (c *HBContext) ParDate(n int) time.Time {
|
|
v := c.param(n)
|
|
if v.IsDate() {
|
|
y, m, d := julianToYMD(v.AsJulian())
|
|
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local)
|
|
}
|
|
return time.Time{}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Array parameters
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ParArray returns array items. Five extension.
|
|
func (c *HBContext) ParArray(n int) []Value {
|
|
v := c.param(n)
|
|
if v.IsArray() {
|
|
return v.AsArray().Items
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ParArrayLen returns array length. Harbour: hb_parinfa(n, 0)
|
|
func (c *HBContext) ParArrayLen(n int) int {
|
|
v := c.param(n)
|
|
if v.IsArray() {
|
|
return len(v.AsArray().Items)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ParHash returns hash. Five extension.
|
|
func (c *HBContext) ParHash(n int) *HbHash {
|
|
v := c.param(n)
|
|
if v.IsHash() {
|
|
return v.AsHash()
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Return values — Harbour: hb_ret*
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// Ret returns NIL. Harbour: hb_ret()
|
|
func (c *HBContext) Ret() {
|
|
c.T.PushNil()
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetNil returns NIL explicitly.
|
|
func (c *HBContext) RetNil() {
|
|
c.T.PushNil()
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetC returns string. Harbour: hb_retc(s)
|
|
func (c *HBContext) RetC(s string) {
|
|
c.T.PushString(s)
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetCLen returns string of specific length. Harbour: hb_retclen(s, n)
|
|
func (c *HBContext) RetCLen(s string, n int) {
|
|
if n < len(s) {
|
|
s = s[:n]
|
|
}
|
|
c.T.PushString(s)
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetNI returns integer. Harbour: hb_retni(n)
|
|
func (c *HBContext) RetNI(n int) {
|
|
c.T.PushInt(n)
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetNL returns long. Harbour: hb_retnl(n)
|
|
func (c *HBContext) RetNL(n int64) {
|
|
c.T.PushLong(n)
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetND returns double. Harbour: hb_retnd(d)
|
|
func (c *HBContext) RetND(d float64) {
|
|
c.T.PushDouble(d, 0, 0)
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetNDLen returns double with width/decimals. Harbour: hb_retndlen(d, w, dec)
|
|
func (c *HBContext) RetNDLen(d float64, width, dec int) {
|
|
c.T.PushDouble(d, uint16(width), uint16(dec))
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetL returns logical. Harbour: hb_retl(b)
|
|
func (c *HBContext) RetL(b bool) {
|
|
c.T.PushBool(b)
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetDS returns date from "YYYYMMDD". Harbour: hb_retds(s)
|
|
func (c *HBContext) RetDS(s string) {
|
|
if len(s) >= 8 {
|
|
y, m, d := 0, 0, 0
|
|
fmt.Sscanf(s, "%04d%02d%02d", &y, &m, &d)
|
|
c.T.PushValue(MakeDate(ymdToJulian(y, m, d)))
|
|
} else {
|
|
c.T.PushValue(MakeDate(0))
|
|
}
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetDL returns date from Julian. Harbour: hb_retdl(n)
|
|
func (c *HBContext) RetDL(julian int64) {
|
|
c.T.PushValue(MakeDate(julian))
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetD returns date from y/m/d. Harbour: hb_retd(y, m, d)
|
|
func (c *HBContext) RetD(y, m, d int) {
|
|
c.T.PushValue(MakeDate(ymdToJulian(y, m, d)))
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetValue returns raw Value. Five extension.
|
|
func (c *HBContext) RetVal(v Value) {
|
|
c.T.PushValue(v)
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetA returns empty array of size n. Harbour: hb_reta(n)
|
|
func (c *HBContext) RetA(size int) {
|
|
c.T.PushValue(MakeArray(size))
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetArray returns populated array. Five extension.
|
|
func (c *HBContext) RetArray(items []Value) {
|
|
c.T.PushValue(MakeArrayFrom(items))
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// RetHash returns hash. Five extension.
|
|
func (c *HBContext) RetHash(h *HbHash) {
|
|
c.T.PushValue(MakeHashFrom(h))
|
|
c.T.RetValue()
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// By-reference storage — Harbour: hb_stor*
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// StorNil stores NIL into by-ref param. Harbour: hb_stor(n)
|
|
func (c *HBContext) StorNil(n int) {
|
|
if n >= 1 && n <= c.PCount() {
|
|
c.T.SetLocal(n, MakeNil())
|
|
}
|
|
}
|
|
|
|
// StorC stores string into by-ref param. Harbour: hb_storc(s, n)
|
|
func (c *HBContext) StorC(s string, n int) {
|
|
if n >= 1 && n <= c.PCount() {
|
|
c.T.SetLocal(n, MakeString(s))
|
|
}
|
|
}
|
|
|
|
// StorNI stores int into by-ref param. Harbour: hb_storni(v, n)
|
|
func (c *HBContext) StorNI(v int, n int) {
|
|
if n >= 1 && n <= c.PCount() {
|
|
c.T.SetLocal(n, MakeInt(v))
|
|
}
|
|
}
|
|
|
|
// StorNL stores int64 into by-ref param. Harbour: hb_stornl(v, n)
|
|
func (c *HBContext) StorNL(v int64, n int) {
|
|
if n >= 1 && n <= c.PCount() {
|
|
c.T.SetLocal(n, MakeLong(v))
|
|
}
|
|
}
|
|
|
|
// StorND stores float64 into by-ref param. Harbour: hb_stornd(v, n)
|
|
func (c *HBContext) StorND(v float64, n int) {
|
|
if n >= 1 && n <= c.PCount() {
|
|
c.T.SetLocal(n, MakeDouble(v, 0, 0))
|
|
}
|
|
}
|
|
|
|
// StorL stores bool into by-ref param. Harbour: hb_storl(v, n)
|
|
func (c *HBContext) StorL(v bool, n int) {
|
|
if n >= 1 && n <= c.PCount() {
|
|
c.T.SetLocal(n, MakeBool(v))
|
|
}
|
|
}
|
|
|
|
// StorDS stores date string into by-ref param. Harbour: hb_stords(s, n)
|
|
func (c *HBContext) StorDS(s string, n int) {
|
|
if n >= 1 && n <= c.PCount() && len(s) >= 8 {
|
|
y, m, d := 0, 0, 0
|
|
fmt.Sscanf(s, "%04d%02d%02d", &y, &m, &d)
|
|
c.T.SetLocal(n, MakeDate(ymdToJulian(y, m, d)))
|
|
}
|
|
}
|
|
|
|
// StorDL stores Julian date into by-ref param. Harbour: hb_stordl(v, n)
|
|
func (c *HBContext) StorDL(v int64, n int) {
|
|
if n >= 1 && n <= c.PCount() {
|
|
c.T.SetLocal(n, MakeDate(v))
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Array manipulation — Harbour: hb_array*
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ArrayNew creates empty array. Harbour: hb_arrayNew()
|
|
func (c *HBContext) ArrayNew(size int) Value {
|
|
return MakeArray(size)
|
|
}
|
|
|
|
// ArrayLen returns array length. Harbour: hb_arrayLen()
|
|
func (c *HBContext) ArrayLen(v Value) int {
|
|
if v.IsArray() {
|
|
return len(v.AsArray().Items)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// ArrayGet gets element at 1-based index. Harbour: hb_arrayGet()
|
|
func (c *HBContext) ArrayGet(v Value, index int) Value {
|
|
if v.IsArray() {
|
|
items := v.AsArray().Items
|
|
if index >= 1 && index <= len(items) {
|
|
return items[index-1]
|
|
}
|
|
}
|
|
return MakeNil()
|
|
}
|
|
|
|
// ArrayGetC gets string at index. Harbour: hb_arrayGetC()
|
|
func (c *HBContext) ArrayGetC(v Value, index int) string {
|
|
return c.ArrayGet(v, index).AsString()
|
|
}
|
|
|
|
// ArrayGetNI gets int at index. Harbour: hb_arrayGetNI()
|
|
func (c *HBContext) ArrayGetNI(v Value, index int) int {
|
|
return c.ArrayGet(v, index).AsInt()
|
|
}
|
|
|
|
// ArrayGetND gets double at index. Harbour: hb_arrayGetND()
|
|
func (c *HBContext) ArrayGetND(v Value, index int) float64 {
|
|
return c.ArrayGet(v, index).AsNumDouble()
|
|
}
|
|
|
|
// ArrayGetL gets bool at index. Harbour: hb_arrayGetL()
|
|
func (c *HBContext) ArrayGetL(v Value, index int) bool {
|
|
return c.ArrayGet(v, index).AsBool()
|
|
}
|
|
|
|
// ArraySet sets element at 1-based index. Harbour: hb_arraySet()
|
|
func (c *HBContext) ArraySet(v Value, index int, item Value) {
|
|
if v.IsArray() {
|
|
items := v.AsArray().Items
|
|
if index >= 1 && index <= len(items) {
|
|
items[index-1] = item
|
|
}
|
|
}
|
|
}
|
|
|
|
// ArraySetC sets string at index. Harbour: hb_arraySetC()
|
|
func (c *HBContext) ArraySetC(v Value, index int, s string) {
|
|
c.ArraySet(v, index, MakeString(s))
|
|
}
|
|
|
|
// ArraySetNI sets int at index. Harbour: hb_arraySetNI()
|
|
func (c *HBContext) ArraySetNI(v Value, index int, n int) {
|
|
c.ArraySet(v, index, MakeInt(n))
|
|
}
|
|
|
|
// ArraySetND sets double at index. Harbour: hb_arraySetND()
|
|
func (c *HBContext) ArraySetND(v Value, index int, d float64) {
|
|
c.ArraySet(v, index, MakeDouble(d, 0, 0))
|
|
}
|
|
|
|
// ArraySetL sets bool at index. Harbour: hb_arraySetL()
|
|
func (c *HBContext) ArraySetL(v Value, index int, b bool) {
|
|
c.ArraySet(v, index, MakeBool(b))
|
|
}
|
|
|
|
// ArrayAdd appends to array. Harbour: hb_arrayAdd()
|
|
func (c *HBContext) ArrayAdd(v Value, item Value) {
|
|
if v.IsArray() {
|
|
arr := v.AsArray()
|
|
arr.Items = append(arr.Items, item)
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Hash manipulation — Harbour: hb_hash*
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// HashNew creates empty hash.
|
|
func (c *HBContext) HashNew() Value {
|
|
return MakeHash()
|
|
}
|
|
|
|
// HashLen returns hash size.
|
|
func (c *HBContext) HashLen(v Value) int {
|
|
if v.IsHash() {
|
|
return len(v.AsHash().Keys)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
// HashAdd adds key-value pair. Harbour: hb_hashAdd()
|
|
func (c *HBContext) HashAdd(v Value, key, val Value) {
|
|
if v.IsHash() {
|
|
h := v.AsHash()
|
|
h.Keys = append(h.Keys, key)
|
|
h.Values = append(h.Values, val)
|
|
}
|
|
}
|
|
|
|
// HashGetC gets value by string key. Five extension.
|
|
func (c *HBContext) HashGetC(v Value, key string) Value {
|
|
if v.IsHash() {
|
|
h := v.AsHash()
|
|
for i, k := range h.Keys {
|
|
if k.IsString() && k.AsString() == key {
|
|
return h.Values[i]
|
|
}
|
|
}
|
|
}
|
|
return MakeNil()
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Error handling — Harbour: hb_errRT_BASE
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ErrRT_BASE raises a BASE runtime error.
|
|
func (c *HBContext) ErrRT_BASE(subCode int, description, operation string) {
|
|
panic(fmt.Sprintf("BASE/%04d: %s: %s", subCode, description, operation))
|
|
}
|
|
|
|
// ErrRT_BASE_SubstR raises a substitution error.
|
|
func (c *HBContext) ErrRT_BASE_SubstR(subCode int, description, operation string) {
|
|
c.ErrRT_BASE(subCode, description, operation)
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ParInfo — Harbour: hb_parinfo(n)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
const (
|
|
HB_IT_NIL = 0x00001
|
|
HB_IT_INTEGER = 0x00002
|
|
HB_IT_LONG = 0x00008
|
|
HB_IT_DOUBLE = 0x00010
|
|
HB_IT_DATE = 0x00020
|
|
HB_IT_TIMESTAMP = 0x00040
|
|
HB_IT_LOGICAL = 0x00080
|
|
HB_IT_SYMBOL = 0x00100
|
|
HB_IT_POINTER = 0x00200
|
|
HB_IT_STRING = 0x00400
|
|
HB_IT_MEMO = 0x00800
|
|
HB_IT_BLOCK = 0x01000
|
|
HB_IT_BYREF = 0x02000
|
|
HB_IT_ARRAY = 0x04000
|
|
HB_IT_HASH = 0x08000
|
|
HB_IT_OBJECT = 0x10000
|
|
HB_IT_NUMERIC = HB_IT_INTEGER | HB_IT_LONG | HB_IT_DOUBLE
|
|
)
|
|
|
|
// ParInfo returns type flags for parameter n. Harbour: hb_parinfo(n)
|
|
func (c *HBContext) ParInfo(n int) int {
|
|
v := c.param(n)
|
|
switch {
|
|
case v.IsNil():
|
|
return HB_IT_NIL
|
|
case v.IsString():
|
|
return HB_IT_STRING
|
|
case v.IsLogical():
|
|
return HB_IT_LOGICAL
|
|
case v.IsDate():
|
|
return HB_IT_DATE
|
|
case v.IsTimestamp():
|
|
return HB_IT_TIMESTAMP
|
|
case v.IsArray():
|
|
if v.IsObject() {
|
|
return HB_IT_OBJECT
|
|
}
|
|
return HB_IT_ARRAY
|
|
case v.IsHash():
|
|
return HB_IT_HASH
|
|
case v.IsBlock():
|
|
return HB_IT_BLOCK
|
|
case v.IsPointer():
|
|
return HB_IT_POINTER
|
|
case v.IsNumeric():
|
|
return HB_IT_NUMERIC
|
|
default:
|
|
return HB_IT_NIL
|
|
}
|
|
}
|