diff --git a/hawk-inst.go b/hawk-inst.go index f9a23610..7306b7b2 100644 --- a/hawk-inst.go +++ b/hawk-inst.go @@ -9,7 +9,6 @@ import "weak" type Instance struct { c *C.hawk_t // c object - //g *Hawk // go object g weak.Pointer[Hawk] // go object } diff --git a/hawk.go b/hawk.go index 4292500f..ac8b2575 100644 --- a/hawk.go +++ b/hawk.go @@ -86,8 +86,26 @@ type Val struct { prev *Val } +type ValType int +const ( + VAL_NIL ValType = C.HAWK_VAL_NIL + VAL_CHAR ValType = C.HAWK_VAL_CHAR + VAL_BCHR ValType = C.HAWK_VAL_BCHR + VAL_INT ValType = C.HAWK_VAL_INT + VAL_FLT ValType = C.HAWK_VAL_FLT + VAL_STR ValType = C.HAWK_VAL_STR + VAL_MBS ValType = C.HAWK_VAL_MBS + VAL_FUN ValType = C.HAWK_VAL_FUN + VAL_MAP ValType = C.HAWK_VAL_MAP + VAL_ARR ValType = C.HAWK_VAL_ARR + VAL_REX ValType = C.HAWK_VAL_REX + VAL_REF ValType = C.HAWK_VAL_REF + VAL_BOB ValType = C.HAWK_VAL_BOB +) + type BitMask C.hawk_bitmask_t + func deregister_instance(h *Hawk) { fmt.Printf ("DEREGISER INSTANCE %p\n", h) for h.rtx_head != nil { @@ -269,6 +287,7 @@ func (hawk *Hawk) chain_rtx(rtx *Rtx) { rtx.next = nil hawk.rtx_tail = rtx hawk.rtx_count++ +fmt.Printf(">>>> %d\n", hawk.rtx_count) hawk.rtx_mtx.Unlock() } @@ -291,6 +310,7 @@ fmt.Printf("head %p tail %p\n", hawk.rtx_tail, hawk.rtx_tail) rtx.next = nil rtx.prev = nil hawk.rtx_count-- +fmt.Printf(">>>> %d\n", hawk.rtx_count) hawk.rtx_mtx.Unlock() } @@ -546,13 +566,19 @@ func (val *Val) Close() { } } -/*func (val* Val) ToByte() (byte, error) { +func (val *Val) Type() ValType { + var x C.int + x = C.hawk_rtx_getvaltype(val.rtx.c, val.c) + return ValType(x) } -func (val* Val) ToRune() (rune, error) { +/*func (val *Val) ToByte() (byte, error) { +} + +func (val *Val) ToRune() (rune, error) { }*/ -func (val* Val) ToInt() (int, error) { +func (val *Val) ToInt() (int, error) { var v C.hawk_int_t var x C.int @@ -562,7 +588,7 @@ func (val* Val) ToInt() (int, error) { return int(v), nil } -func (val* Val) ToFlt() (float64, error) { +func (val *Val) ToFlt() (float64, error) { var v float64 var x C.int @@ -573,7 +599,7 @@ func (val* Val) ToFlt() (float64, error) { return v, nil } -func (val* Val) ToStr() (string, error) { +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 @@ -591,7 +617,7 @@ func (val* Val) ToStr() (string, error) { return v, nil } -func (val* Val) ToByteArr() ([]byte, error) { +func (val *Val) ToByteArr() ([]byte, error) { var ptr *C.hawk_bch_t var len C.hawk_oow_t var v []byte @@ -605,6 +631,61 @@ func (val* Val) ToByteArr() ([]byte, error) { return v, nil } +func (val *Val) ArrayTally() int { + var v C.hawk_ooi_t +// TODO: if not array .. panic or return -1 or 0? + v = C.hawk_rtx_getarrvaltally(val.rtx.c, val.c) + return int(v) +} + +// TODO: function get the first index and last index or the capacity +// function to traverse? +func (val *Val) ArrayField(index int) (*Val, error) { + var v *C.hawk_val_t + v = C.hawk_rtx_getarrvalfld(val.rtx.c, val.c, C.hawk_ooi_t(index)) + if v == nil { return nil, val.rtx.make_errinfo() } + return val.rtx.make_val(func() *C.hawk_val_t { return v }) +} + +func (val *Val) MapField(key string) (*Val, error) { + var v *C.hawk_val_t + var uc []C.hawk_uch_t + uc = string_to_uchars(key) + v = C.hawk_rtx_getmapvalfld(val.rtx.c, val.c, &uc[0], C.hawk_oow_t(len(uc))) + if v == nil { return nil, val.rtx.make_errinfo() } + return val.rtx.make_val(func() *C.hawk_val_t { return v }) +} + +//func (val *Val) SetArrayField(index int, val *Val) error { +// +//} + +// TODO: map traversal.. +//func (val *Val) SetMapField(key string, val *Val) error { +//} + +// ----------------------------------------------------------- + +var val_type []string = []string{ + VAL_NIL: "NIL", + VAL_CHAR: "CHAR", + VAL_BCHR: "BCHR", + VAL_INT: "INT", + VAL_FLT: "FLT", + VAL_STR: "STR", + VAL_MBS: "MBS", + VAL_FUN: "FUN", + VAL_MAP: "MAP", + VAL_ARR: "ARR", + VAL_REX: "REX", + VAL_REF: "REF", + VAL_BOB: "BOB", +} + +func (t ValType) String() string { + return val_type[t] +} + // ----------------------------------------------------------- func ucstr_to_rune_slice(str *C.hawk_uch_t) []rune { diff --git a/hawk_test.go b/hawk_test.go index 398f4252..102f7025 100644 --- a/hawk_test.go +++ b/hawk_test.go @@ -14,53 +14,65 @@ func exit_with_error(msg string, err error) { os.Exit(1) } -func make_hawk() (*hawk.Hawk, error) { +func make_hawk(script string) (*hawk.Hawk, error) { var h *hawk.Hawk var err error h, err = hawk.New() if err != nil { return nil, err } - err = h.ParseText(`function x(a1, a2, a3) { -for (i = 0; i < 10; i++) { - printf("hello, world [%d] [%s] [%s]\n", a1, a2, a3); - ##if (i == 3) sys::sleep(1); -} -##return "welcome to the jungle 999"; -return 1.9923; -}`) - if err != nil { return nil, err } + err = h.ParseText(script) + if err != nil { + h.Close() + return nil, err + } return h, nil } -func run_hawk(h *hawk.Hawk, id int, wg *sync.WaitGroup) { - var r *hawk.Rtx +func run_hawk(h *hawk.Hawk, id int, t *testing.T, wg *sync.WaitGroup) { + var rtx *hawk.Rtx var v *hawk.Val //var ret string var ret []byte //float64 + var i int var err error defer wg.Done() - r, err = h.NewRtx(fmt.Sprintf("%d", id)) + rtx, err = h.NewRtx(fmt.Sprintf("%d", id)) if err != nil { + t.Errorf("failed to create rtx id[%d] - %s", id, err.Error()) + return } - v, err = r.Call("x", - hawk.Must(r.NewVal/*FromInt*/(id + 10)), - hawk.Must(r.NewVal([]byte{'A',66,67,68,69})), - hawk.Must(r.NewVal/*FromStr*/("this is cool"))) - if err != nil { exit_with_error("rtx call", err) } + v, err = rtx.Call("x", + hawk.Must(rtx.NewVal/*FromInt*/(id + 10)), + hawk.Must(rtx.NewVal([]byte{'A',66,67,68,69})), + hawk.Must(rtx.NewVal/*FromStr*/("this is cool"))) + if err != nil { + t.Errorf("failed to invoke function 'x' for rtx id[%d] - %s", id, err.Error()) + rtx.Close() + return + } ret, err = v.ToByteArr() if err != nil { - fmt.Printf("failed to get return value - %s\n", err.Error()) - } else { - fmt.Printf("RET[%d] => [%v]\n", id, ret) + t.Errorf("failed to get return value for rtx id[%d] - %s", id, err.Error()) + rtx.Close() + return } + fmt.Printf("RET[%d] => [%v]\n", id, ret) - r.Close() + // check if ValCount() returns the right number of values created explicitly + i = rtx.ValCount() + if i != 3 { t.Errorf("the number of val objects for rtx id[%d] must be 3. but %d was returned", id, i) } + + rtx.Close() + + // it's safe to all ValCount() after Close() has been called. + i = rtx.ValCount() + if i != 0 { t.Errorf("the number of val objects for rtx id[%d] must be 0. but %d was returned", id, i) } } func Test1(t *testing.T) { @@ -71,22 +83,130 @@ func Test1(t *testing.T) { debug.SetGCPercent(100) // enable normal GC - h, err = make_hawk() - if err != nil { exit_with_error("Failed to make hawk", err) } + h, err = make_hawk(`function x(a1, a2, a3) { +for (i = 0; i < 10; i++) { + printf("hello, world [%d] [%s] [%s]\n", a1, a2, a3); + ##if (i == 3) sys::sleep(1); +} +##return "welcome to the jungle 999"; +return 1.9923; +}`) + if err != nil { + t.Errorf("Failed to make hawk - %s", err.Error()) + return + } for i = 0; i < 10; i++ { wg.Add(1) - go run_hawk(h, i, &wg) + go run_hawk(h, i, t, &wg) } wg.Wait() - fmt.Printf ("%d RTX objects\n", h.RtxCount()) - h.Close() - h = nil + // when rtx objects are all closed, the counter must drop to 0 + i = h.RtxCount() + if i != 0 { t.Errorf("the number of rtx objects must be 0. but %d was returned", i) } + h.Close() + + h = nil fmt.Printf ("== END of run ==\n") runtime.GC() runtime.Gosched() time.Sleep(1000 * time.Millisecond) // give finalizer time to print } +func Test2(t *testing.T) { + var h *hawk.Hawk + var rtx *hawk.Rtx + var err error + + debug.SetGCPercent(100) // enable normal GC + + h, err = make_hawk(`function get_map(s) { +@local x +x["hello"] = s +x[99] = "donkey is running" +x["what"] = "rankey gankey" +x[1.239] = @b"nice value" +return x +} +function get_arr(s) { +@local x; +x = hawk::array(s, (s %% s), 10, 20.99); +for (i in x) print i, x[i]; +return x; +}`) + if err != nil { + t.Errorf("Failed to make hawk - %s", err.Error()) + return + } + + rtx, err = h.NewRtx("test2") + if err != nil { + t.Errorf("failed to create rtx - %s", err.Error()) + } else { + var v *hawk.Val + + v, err = rtx.Call("get_map", hawk.Must(rtx.NewValFromStr("hawk flies"))) + if err != nil { + t.Errorf("failed to call get_map - %s", err.Error()) + } else { + if v.Type() != hawk.VAL_MAP { + t.Errorf("the returned value must be %s. but it was %s", hawk.VAL_MAP.String(), v.Type().String()) + } else { + var f *hawk.Val + + f = hawk.Must(v.MapField("hello")) + if f.Type() != hawk.VAL_STR { + t.Errorf("the value at the hello field must be a string. but it was %s", f.Type().String()) + } else { + var sv string + sv = hawk.Must(f.ToStr()) + if sv != "hawk flies" { + t.Errorf("the value for the hello field must be 'hawk flies'. but it was %s", sv) + } + } + + f, err = v.MapField("HELLO") + if err == nil { + t.Errorf("the value at the HELLO field must not be found. but it was %s", f.Type().String()) + } + } + } + + v, err = rtx.Call("get_arr", hawk.Must(rtx.NewValFromStr("hawk flies"))) + if err != nil { + t.Errorf("failed to call get_arr - %s", err.Error()) + } else { + if v.Type() != hawk.VAL_ARR { + t.Errorf("the returned value must be %s. but it was %s", hawk.VAL_ARR.String(), v.Type().String()) + } else { + var sz int + var f *hawk.Val + + sz = v.ArrayTally() + if sz != 4 { + t.Errorf("the returned value must have 4 elements. but it had %d elements", sz) + } + + f = hawk.Must(v.ArrayField(2)) + if f.Type() != hawk.VAL_STR { + t.Errorf("the value at the hello field must be a string. but it was %s", f.Type().String()) + } else { + var sv string + sv = hawk.Must(f.ToStr()) + if sv != "hawk flieshawk flies" { + t.Errorf("the value for the hello field must be 'hawk flieshawk flies'. but it was %s", sv) + } + } + } + } + } + + h.Close() + + runtime.GC() + runtime.Gosched() + time.Sleep(1000 * time.Millisecond) // give finalizer time to print +} + diff --git a/lib/hawk.h b/lib/hawk.h index 22047054..83c270e4 100644 --- a/lib/hawk.h +++ b/lib/hawk.h @@ -3373,6 +3373,11 @@ HAWK_EXPORT hawk_val_t* hawk_rtx_getarrvalfld ( hawk_ooi_t index ); +HAWK_EXPORT hawk_ooi_t hawk_rtx_getarrvaltally ( + hawk_rtx_t* rtx, + hawk_val_t* arr +); + /** * The hawk_rtx_makerefval() function creates a reference value. * \return value on success, #HAWK_NULL on failure diff --git a/lib/val.c b/lib/val.c index 75fff087..63d245a7 100644 --- a/lib/val.c +++ b/lib/val.c @@ -1444,6 +1444,14 @@ hawk_val_t* hawk_rtx_getarrvalfld (hawk_rtx_t* rtx, hawk_val_t* arr, hawk_ooi_t return HAWK_ARR_DPTR(_arr, index); } +hawk_ooi_t hawk_rtx_getarrvaltally (hawk_rtx_t* rtx, hawk_val_t* arr) +{ + hawk_arr_t* _arr; + HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, arr) == HAWK_VAL_ARR); + _arr = ((hawk_val_arr_t*)arr)->arr; + return HAWK_ARR_TALLY(_arr); +} + hawk_val_t* hawk_rtx_makerefval (hawk_rtx_t* rtx, int id, hawk_val_t** adr) { hawk_val_ref_t* val;