Files
hawk/hawk.go

636 lines
13 KiB
Go
Raw Normal View History

2025-10-26 23:18:23 +09:00
package hawk
/*
#include <hawk.h>
#include <stdlib.h>
static void init_parsestd_for_text_in(hawk_parsestd_t* in, hawk_bch_t* ptr, hawk_oow_t len)
{
in[0].type = HAWK_PARSESTD_BCS;
in[0].u.bcs.ptr = ptr;
in[0].u.bcs.len = len;
in[1].type = HAWK_PARSESTD_NULL;
}
static void init_parsestd_for_file_in(hawk_parsestd_t* in, hawk_bch_t* path)
{
in[0].type = HAWK_PARSESTD_FILEB;
in[0].u.fileb.path = path;
in[0].u.fileb.cmgr = HAWK_NULL;
in[1].type = HAWK_PARSESTD_NULL;
}
static hawk_ooch_t* valtostr_out_cpldup(hawk_rtx_valtostr_out_t* out, hawk_oow_t* len)
{
*len = out->u.cpldup.len;
return out->u.cpldup.ptr;
}
2025-11-01 00:08:57 +09:00
static hawk_val_t* make_flt_val(hawk_rtx_t* rtx, double v) {
return hawk_rtx_makefltval(rtx, (hawk_flt_t)v);
}
static int val_to_flt(hawk_rtx_t* rtx, hawk_val_t* v, double* ret) {
hawk_flt_t fv;
if (hawk_rtx_valtoflt(rtx, v, &fv) <= -1) return -1;
*ret = (double)fv;
return 0;
}
2025-10-26 23:18:23 +09:00
*/
import "C"
import "fmt"
2025-11-01 00:08:57 +09:00
import "reflect"
2025-10-26 23:18:23 +09:00
import "runtime"
2025-11-01 00:08:57 +09:00
import "sync"
2025-10-26 23:18:23 +09:00
import "unsafe"
type Hawk struct {
c *C.hawk_t
2025-10-26 23:18:23 +09:00
inst_no int
2025-11-01 00:08:57 +09:00
rtx_mtx sync.Mutex
rtx_count int
rtx_head *Rtx
rtx_tail *Rtx
2025-10-26 23:18:23 +09:00
}
type Ext struct {
inst_no int
}
type Err struct {
Line uint
Colm uint
File string
Msg string
}
type Rtx struct {
c *C.hawk_rtx_t
h *Hawk
next *Rtx
prev *Rtx
2025-11-01 00:08:57 +09:00
val_mtx sync.Mutex
val_count int
val_head *Val
val_tail *Val
2025-10-26 23:18:23 +09:00
}
type Val struct {
c *C.hawk_val_t
rtx *Rtx
2025-11-01 00:08:57 +09:00
next *Val
prev *Val
}
2025-10-26 23:18:23 +09:00
type BitMask C.hawk_bitmask_t
2025-10-26 23:18:23 +09:00
2025-11-01 00:08:57 +09:00
func deregister_instance(h *Hawk) {
fmt.Printf ("DEREGISER INSTANCE %p\n", h)
for h.rtx_head != nil {
//fmt.Printf ("DEREGISER CLOSING RTX %p\n", h.rtx_head)
h.rtx_head.Close()
}
2025-11-01 00:08:57 +09:00
if h.c != nil {
fmt.Printf ("CLOSING h.c\n")
C.hawk_close(h.c)
h.c = nil
}
2025-11-01 00:08:57 +09:00
if h.inst_no >= 0 {
fmt.Printf ("DELETING instance h\n")
inst_table.delete_instance(h.inst_no)
h.inst_no = -1
2025-10-26 23:18:23 +09:00
}
2025-11-01 00:08:57 +09:00
fmt.Printf ("END DEREGISER INSTANCE %p\n", h)
2025-10-26 23:18:23 +09:00
}
func New() (*Hawk, error) {
var c *C.hawk_t
var g *Hawk
var ext *Ext
var errinf C.hawk_errinf_t
c = C.hawk_openstd(C.hawk_oow_t(unsafe.Sizeof(*ext)), &errinf)
if c == nil {
var err error
err = fmt.Errorf("%s", string(ucstr_to_rune_slice(&errinf.msg[0])))
return nil, err
}
ext = (*Ext)(unsafe.Pointer(C.hawk_getxtn(c)))
g = &Hawk{c: c, inst_no: -1}
2025-11-01 00:08:57 +09:00
g.rtx_count = 0
g.rtx_head = nil
g.rtx_tail = nil
2025-10-26 23:18:23 +09:00
runtime.SetFinalizer(g, deregister_instance)
g.inst_no = inst_table.add_instance(c, g)
ext.inst_no = g.inst_no
return g, nil
}
func (hawk *Hawk) Close() {
deregister_instance(hawk)
}
func (hawk *Hawk) make_errinfo() *Err {
/*
var errinf C.hawk_erruinf_t
2025-10-26 23:18:23 +09:00
var err Err
C.hawk_geterruinf(hawk.c, &errinf)
err.Line = uint(errinf.loc.line)
err.Colm = uint(errinf.loc.colm)
if errinf.loc.file != nil {
err.File = string(ucstr_to_rune_slice(errinf.loc.file))
} else {
// TODO:
//err.File = hawk.io.cci_main
}
err.Msg = string(ucstr_to_rune_slice(&errinf.msg[0]))
return &err
*/
var loc *C.hawk_loc_t
var err Err
err.Msg = hawk.get_errmsg()
loc = C.hawk_geterrloc(hawk.c)
if loc != nil {
err.Line = uint(loc.line)
err.Colm = uint(loc.colm)
if loc.file != nil {
err.File = string(ucstr_to_rune_slice(loc.file))
} else {
// TODO:
// err.File = hawk.io.cci_main
}
}
return &err
}
func (hawk *Hawk) GetTrait() BitMask {
var x C.int
var log_mask BitMask = 0
x = C.hawk_getopt(hawk.c, C.HAWK_OPT_TRAIT, unsafe.Pointer(&log_mask))
if x <= -1 {
// this must not happen
panic(fmt.Errorf("unable to get log mask - %s", hawk.get_errmsg()))
}
return log_mask
}
func (hawk *Hawk) SetTrait(log_mask BitMask) {
var x C.int
x = C.hawk_setopt(hawk.c, C.HAWK_OPT_TRAIT, unsafe.Pointer(&log_mask))
if x <= -1 {
// this must not happen
panic(fmt.Errorf("unable to set log mask - %s", hawk.get_errmsg()))
}
}
func (hawk *Hawk) GetLogMask() BitMask {
var x C.int
var log_mask BitMask = 0
x = C.hawk_getopt(hawk.c, C.HAWK_OPT_LOG_MASK, unsafe.Pointer(&log_mask))
if x <= -1 {
// this must not happen
panic(fmt.Errorf("unable to get log mask - %s", hawk.get_errmsg()))
}
return log_mask
}
func (hawk *Hawk) SetLogMask(log_mask BitMask) {
var x C.int
x = C.hawk_setopt(hawk.c, C.HAWK_OPT_LOG_MASK, unsafe.Pointer(&log_mask))
if x <= -1 {
// this must not happen
panic(fmt.Errorf("unable to set log mask - %s", hawk.get_errmsg()))
}
}
func (hawk *Hawk) AddGlobal(name string) error {
var x C.int
x = C.hawk_addgblwithbcstr(hawk.c, C.CString(name))
if x <= -1 { return hawk.make_errinfo() }
return nil
2025-10-26 23:18:23 +09:00
}
func (hawk *Hawk) ParseFile(text string) error {
var x C.int
var in [2]C.hawk_parsestd_t
2025-10-26 23:18:23 +09:00
C.init_parsestd_for_file_in(&in[0], C.CString(text))
x = C.hawk_parsestd(hawk.c, &in[0], nil)
if x <= -1 { return hawk.make_errinfo() }
return nil
}
func (hawk *Hawk) ParseText(text string) error {
var x C.int
var in [2]C.hawk_parsestd_t
2025-10-26 23:18:23 +09:00
C.init_parsestd_for_text_in(&in[0], C.CString(text), C.hawk_oow_t(len(text)))
x = C.hawk_parsestd(hawk.c, &in[0], nil)
if x <= -1 { return hawk.make_errinfo() }
return nil
}
2025-11-01 00:08:57 +09:00
func (hawk *Hawk) RtxCount() int {
hawk.rtx_mtx.Lock()
defer hawk.rtx_mtx.Unlock()
return hawk.rtx_count
}
func (hawk *Hawk) chain_rtx(rtx *Rtx) {
2025-11-01 00:08:57 +09:00
hawk.rtx_mtx.Lock()
rtx.h = hawk
if hawk.rtx_head == nil {
rtx.prev = nil
hawk.rtx_head = rtx
} else {
rtx.prev = hawk.rtx_tail
hawk.rtx_tail.next = rtx
}
rtx.next = nil
hawk.rtx_tail = rtx
2025-11-01 00:08:57 +09:00
hawk.rtx_count++
hawk.rtx_mtx.Unlock()
}
func (hawk *Hawk) unchain_rtx(rtx *Rtx) {
2025-11-01 00:08:57 +09:00
hawk.rtx_mtx.Lock()
if rtx.prev == nil {
hawk.rtx_head = rtx.next
} else {
rtx.prev.next = rtx.next
}
if rtx.next == nil {
hawk.rtx_tail = rtx.prev
} else {
rtx.next.prev = rtx.prev
}
2025-11-01 00:08:57 +09:00
fmt.Printf("head %p tail %p\n", hawk.rtx_tail, hawk.rtx_tail)
2025-11-01 00:08:57 +09:00
rtx.h = nil
rtx.next = nil
rtx.prev = nil
2025-11-01 00:08:57 +09:00
hawk.rtx_count--
hawk.rtx_mtx.Unlock()
}
2025-10-26 23:18:23 +09:00
// -----------------------------------------------------------
func (hawk *Hawk) NewRtx(id string) (*Rtx, error) {
var rtx *C.hawk_rtx_t
var g *Rtx
rtx = C.hawk_rtx_openstdwithbcstr(hawk.c, 0, C.CString(id), nil, nil, nil)
if rtx == nil { return nil, hawk.make_errinfo() }
2025-11-01 00:08:57 +09:00
g = &Rtx{c: rtx}
hawk.chain_rtx(g)
2025-11-01 00:08:57 +09:00
// [NOTE]
// if the owning hawk is not garbaged-collected, this rtx is never
// garbaged collected as a strong pointer to a rtx object is maintained
// in the owner. i never set the runtime finalizer on this rtx object.
2025-10-26 23:18:23 +09:00
return g, nil
}
func (rtx* Rtx) Close() {
2025-11-01 00:08:57 +09:00
if rtx.h != nil {
//fmt.Printf("RTX CLOSING UNCHAIN %p\n", rtx)
rtx.h.unchain_rtx(rtx)
for rtx.val_head != nil {
fmt.Printf ("****** DEREGISER CLOSING VAL %p\n", rtx.val_head)
rtx.val_head.Close()
}
C.hawk_rtx_close(rtx.c)
//fmt.Printf("RTX CLOSING %p\n", rtx)
}
2025-10-26 23:18:23 +09:00
}
func (rtx *Rtx) make_errinfo() *Err {
var loc *C.hawk_loc_t
var err Err
err.Msg = rtx.get_errmsg()
loc = C.hawk_rtx_geterrloc(rtx.c)
if loc != nil {
err.Line = uint(loc.line)
err.Colm = uint(loc.colm)
if loc.file != nil {
err.File = string(ucstr_to_rune_slice(loc.file))
} else {
// TODO:
// err.File = hawk.io.cci_main
}
}
return &err
}
2025-11-01 00:08:57 +09:00
func (rtx *Rtx) Call(name string, args ...*Val) (*Val, error) {
2025-10-26 23:18:23 +09:00
var fun *C.hawk_fun_t
var val *C.hawk_val_t
2025-11-01 00:08:57 +09:00
var nargs int
2025-10-26 23:18:23 +09:00
fun = C.hawk_rtx_findfunwithbcstr(rtx.c, C.CString(name))
if fun == nil { return nil, rtx.make_errinfo() }
2025-11-01 00:08:57 +09:00
nargs = len(args)
if nargs > 0 {
var argv []*C.hawk_val_t
var v *Val
var i int
argv = make([]*C.hawk_val_t, nargs)
for i, v = range args { argv[i] = v.c }
val = C.hawk_rtx_callfun(rtx.c, fun, &argv[0], C.hawk_oow_t(nargs))
} else {
val = C.hawk_rtx_callfun(rtx.c, fun, nil, 0)
}
if val == nil { return nil, rtx.make_errinfo() }
// hawk_rtx_callfun() returns a value with the reference count incremented.
// i create a Val object without incrementing the reference count of val.
return &Val{rtx: rtx, c: val}, nil
2025-10-26 23:18:23 +09:00
}
2025-11-01 00:08:57 +09:00
func (rtx *Rtx) ValCount() int {
rtx.val_mtx.Lock()
defer rtx.val_mtx.Unlock()
return rtx.val_count
}
func (rtx *Rtx) chain_val(val *Val) {
rtx.val_mtx.Lock()
val.rtx = rtx
if rtx.val_head == nil {
val.prev = nil
rtx.val_head = val
} else {
val.prev = rtx.val_tail
rtx.val_tail.next = val
}
val.next = nil
rtx.val_tail = val
rtx.val_count++
rtx.val_mtx.Unlock()
}
func (rtx *Rtx) unchain_val(val *Val) {
rtx.val_mtx.Lock()
if val.prev == nil {
rtx.val_head = val.next
} else {
val.prev.next = val.next
}
if val.next == nil {
rtx.val_tail = val.prev
} else {
val.next.prev = val.prev
}
fmt.Printf("head %p tail %p\n", rtx.val_tail, rtx.val_tail)
val.rtx = nil
val.next = nil
val.prev = nil
rtx.val_count--
rtx.val_mtx.Unlock()
}
2025-10-26 23:18:23 +09:00
// -----------------------------------------------------------
func (hawk *Hawk) get_errmsg() string {
return C.GoString(C.hawk_geterrbmsg(hawk.c))
}
func (hawk *Hawk) set_errmsg(num C.hawk_errnum_t, msg string) {
var ptr *C.char
ptr = C.CString(msg)
defer C.free(unsafe.Pointer(ptr))
C.hawk_seterrbmsg(hawk.c, nil, num, ptr)
}
func (rtx *Rtx) get_errmsg() string {
return C.GoString(C.hawk_rtx_geterrbmsg(rtx.c))
}
// -----------------------------------------------------------
2025-11-01 00:08:57 +09:00
func (err* Err) Error() string {
return fmt.Sprintf("%s[%d,%d] %s", err.File, err.Line, err.Colm, err.Msg)
2025-10-26 23:18:23 +09:00
}
2025-11-01 00:08:57 +09:00
// -----------------------------------------------------------
2025-10-26 23:18:23 +09:00
2025-11-01 00:08:57 +09:00
func (rtx *Rtx) NewVal(v interface{}) (*Val, error) {
var _type reflect.Type
_type = reflect.TypeOf(v)
switch _type.Kind() {
case reflect.Int:
return rtx.NewValFromInt(v.(int))
case reflect.Float64:
return rtx.NewValFromFlt(v.(float64))
case reflect.String:
return rtx.NewValFromStr(v.(string))
case reflect.Array:
fallthrough
case reflect.Slice:
var _kind reflect.Kind
_kind = _type.Elem().Kind()
if _kind == reflect.Uint8 {
return rtx.NewValFromByteArr(v.([]byte))
}
fallthrough
default:
return nil, fmt.Errorf("invalid argument")
2025-10-26 23:18:23 +09:00
}
}
2025-11-01 00:08:57 +09:00
func (rtx *Rtx) NewValFromInt(v int) (*Val, error) {
var c *C.hawk_val_t
var vv *Val
2025-10-26 23:18:23 +09:00
2025-11-01 00:08:57 +09:00
c = C.hawk_rtx_makeintval(rtx.c, C.hawk_int_t(v))
if c == nil { return nil, rtx.make_errinfo() }
2025-10-26 23:18:23 +09:00
2025-11-01 00:08:57 +09:00
C.hawk_rtx_refupval(rtx.c, c)
vv = &Val{rtx: rtx, c: c}
rtx.chain_val(vv)
return vv, nil
2025-10-26 23:18:23 +09:00
}
2025-11-01 00:08:57 +09:00
func (rtx *Rtx) NewValFromFlt(v float64) (*Val, error) {
var c *C.hawk_val_t
var vv *Val
2025-10-26 23:18:23 +09:00
2025-11-01 00:08:57 +09:00
c = C.make_flt_val(rtx.c, C.double(v))
if c == nil { return nil, rtx.make_errinfo() }
2025-10-26 23:18:23 +09:00
2025-11-01 00:08:57 +09:00
C.hawk_rtx_refupval(rtx.c, c)
vv = &Val{rtx: rtx, c: c}
rtx.chain_val(vv)
return vv, nil
2025-10-26 23:18:23 +09:00
}
2025-11-01 00:08:57 +09:00
func (rtx *Rtx) NewValFromStr(v string) (*Val, error) {
var c *C.hawk_val_t
var vv *Val
2025-11-01 00:08:57 +09:00
c = C.hawk_rtx_makestrvalwithbchars(rtx.c, C.CString(v), C.hawk_oow_t(len(v)))
if c == nil { return nil, rtx.make_errinfo() }
C.hawk_rtx_refupval(rtx.c, c)
vv = &Val{rtx: rtx, c: c}
rtx.chain_val(vv)
return vv, nil
}
2025-11-01 00:08:57 +09:00
func (rtx *Rtx) NewValFromByteArr(v []byte) (*Val, error) {
var c *C.hawk_val_t
var vv *Val
2025-11-01 00:08:57 +09:00
c = C.hawk_rtx_makembsvalwithbchars(rtx.c, (*C.hawk_bch_t)(unsafe.Pointer(&v[0])), C.hawk_oow_t(len(v)))
if c == nil { return nil, rtx.make_errinfo() }
C.hawk_rtx_refupval(rtx.c, c)
vv = &Val{rtx: rtx, c: c}
2025-11-01 00:08:57 +09:00
rtx.chain_val(vv)
return vv, nil
}
2025-11-01 00:08:57 +09:00
func (val *Val) Close() {
if val.rtx != nil {
C.hawk_rtx_refdownval(val.rtx.c, val.c)
val.rtx.unchain_val(val)
}
}
func (val* Val) ToInt() (int, error) {
var v C.hawk_int_t
var x C.int
x = C.hawk_rtx_valtoint(val.rtx.c, val.c, &v)
if x <= -1 { return 0, val.rtx.make_errinfo() }
return int(v), nil
}
2025-11-01 00:08:57 +09:00
func (val* Val) ToFlt() (float64, error) {
var v float64
var x C.int
2025-11-01 00:08:57 +09:00
//x = C.hawk_rtx_valtoflt(val.rtx.c, val.c, &v)
x = C.val_to_flt(val.rtx.c, val.c, (*C.double)(&v))
if x <= -1 { return 0, val.rtx.make_errinfo() }
2025-11-01 00:08:57 +09:00
return v, nil
}
func (val* Val) ToStr() (string, error) {
var out C.hawk_rtx_valtostr_out_t
var ptr *C.hawk_ooch_t
var len C.hawk_oow_t
var v string
var x C.int
out._type = C.HAWK_RTX_VALTOSTR_CPLDUP
x = C.hawk_rtx_valtostr(val.rtx.c, val.c, &out)
if x <= -1 { return "", val.rtx.make_errinfo() }
ptr = C.valtostr_out_cpldup(&out, &len)
v = string(uchars_to_rune_slice(ptr, uintptr(len)))
C.hawk_rtx_freemem(val.rtx.c, unsafe.Pointer(ptr))
return v, nil
}
2025-11-01 00:08:57 +09:00
func (val* Val) ToByteArr() ([]byte, error) {
}
// -----------------------------------------------------------
func ucstr_to_rune_slice(str *C.hawk_uch_t) []rune {
return uchars_to_rune_slice(str, uintptr(C.hawk_count_ucstr(str)))
}
func uchars_to_rune_slice(str *C.hawk_uch_t, len uintptr) []rune {
var res []rune
var i uintptr
var ptr uintptr
// TODO: proper encoding...
ptr = uintptr(unsafe.Pointer(str))
res = make([]rune, len)
for i = 0; i < len; i++ {
res[i] = rune(*(*C.hawk_uch_t)(unsafe.Pointer(ptr)))
ptr += unsafe.Sizeof(*str)
}
return res
}
func string_to_uchars(str string) []C.hawk_uch_t {
var r []rune
var c []C.hawk_uch_t
var i int
// TODO: proper encoding
r = []rune(str)
c = make([]C.hawk_uch_t, len(r), len(r))
for i = 0; i < len(r); i++ {
c[i] = C.hawk_uch_t(r[i])
}
return c
}
func rune_slice_to_uchars(r []rune) []C.hawk_uch_t {
var c []C.hawk_uch_t
var i int
// TODO: proper encoding
c = make([]C.hawk_uch_t, len(r), len(r))
for i = 0; i < len(r); i++ {
c[i] = C.hawk_uch_t(r[i])
}
return c
}
func c_to_go(c *C.hawk_t) *Hawk {
var ext *Ext
var inst Instance
ext = (*Ext)(unsafe.Pointer(C.hawk_getxtn(c)))
inst = inst_table.slot_to_instance(ext.inst_no)
return inst.g.Value()
}
func Must[T any](v T, err error) T {
if err != nil { panic(err) }
return v
}