package hak /* #include #include #include // for C.free extern int hak_go_cci_handler (hak_t* hak, hak_io_cmd_t cmd, void* arg); extern int hak_go_udi_handler (hak_t* hak, hak_io_cmd_t cmd, void* arg); extern int hak_go_udo_handler (hak_t* hak, hak_io_cmd_t cmd, void* arg); int hak_cci_handler_for_go (hak_t* hak, hak_io_cmd_t cmd, void* arg) { return hak_go_cci_handler(hak, cmd, arg); } int hak_udi_handler_for_go (hak_t* hak, hak_io_cmd_t cmd, void* arg) { return hak_go_udi_handler(hak, cmd, arg); } int hak_udo_handler_for_go (hak_t* hak, hak_io_cmd_t cmd, void* arg) { return hak_go_udo_handler(hak, cmd, arg); } */ import "C" import ( "bufio" "fmt" "io" "os" "runtime" "unsafe" ) type CciImpl interface { Open(g *HAK, name string) (int, error) Close(fd int) Read(fd int, buf []rune) (int, error) } type UdiImpl interface { Open(g *HAK) error Close() Read(buf []rune) (int, error) } type UdoImpl interface { Open(g *HAK) error Close() Write(data []rune) error WriteBytes(data []byte) error Flush() error } type HAK struct { c *C.hak_t inst_no int io struct { cci CciImpl cci_main string udi UdiImpl udo UdoImpl } } type Ext struct { inst_no int } type Err struct { Line uint Colm uint File string Msg string Tgt string } type BitMask C.hak_bitmask_t const TRAIT_LANG_ENABLE_EOL BitMask = C.HAK_TRAIT_LANG_ENABLE_EOL var inst_table InstanceTable func deregister_instance(g *HAK) { if g.inst_no >= 0 { inst_table.delete_instance(g.inst_no) g.inst_no = -1 } } func New() (*HAK, error) { var c *C.hak_t var g *HAK var ext *Ext var errnum C.hak_errnum_t c = C.hak_openstd(C.hak_oow_t(unsafe.Sizeof(*ext)), &errnum) if c == nil { var buf [64]C.hak_uch_t var ptr *C.hak_uch_t var err error ptr = C.hak_errnum_to_errucstr(errnum, &buf[0], C.hak_oow_t(cap(buf))) err = fmt.Errorf("%s", string(ucstr_to_rune_slice(ptr))) return nil, err } ext = (*Ext)(unsafe.Pointer(C.hak_getxtn(c))) g = &HAK{c: c, inst_no: -1} runtime.SetFinalizer(g, deregister_instance) g.inst_no = inst_table.add_instance(c, g) ext.inst_no = g.inst_no return g, nil } func (hak *HAK) Close() { C.hak_close(hak.c) deregister_instance(hak) } func (hak *HAK) make_errinfo() *Err { var loc C.hak_loc_t var err Err var errnum C.hak_errnum_t err.Msg = hak.get_errmsg() errnum = C.hak_geterrnum(hak.c) if errnum == C.HAK_ESYNERR { var synerr C.hak_synerr_t C.hak_getsynerr(hak.c, &synerr) loc = synerr.loc err.Tgt = string(uchars_to_rune_slice(&synerr.tgt.val[0], uintptr(synerr.tgt.len))) } else { C.hak_geterrloc(hak.c, &loc) } err.Line = uint(loc.line) err.Colm = uint(loc.colm) if loc.file != nil { err.File = string(ucstr_to_rune_slice(loc.file)) } else { err.File = hak.io.cci_main } return &err } func (hak *HAK) GetTrait() BitMask { var x C.int var log_mask BitMask = 0 x = C.hak_getoption(hak.c, C.HAK_TRAIT, unsafe.Pointer(&log_mask)) if x <= -1 { // this must not happen panic(fmt.Errorf("unable to get log mask - %s", hak.get_errmsg())) } return log_mask } func (hak *HAK) SetTrait(log_mask BitMask) { var x C.int x = C.hak_setoption(hak.c, C.HAK_TRAIT, unsafe.Pointer(&log_mask)) if x <= -1 { // this must not happen panic(fmt.Errorf("unable to set log mask - %s", hak.get_errmsg())) } } func (hak *HAK) GetLogMask() BitMask { var x C.int var log_mask BitMask = 0 x = C.hak_getoption(hak.c, C.HAK_LOG_MASK, unsafe.Pointer(&log_mask)) if x <= -1 { // this must not happen panic(fmt.Errorf("unable to get log mask - %s", hak.get_errmsg())) } return log_mask } func (hak *HAK) SetLogMask(log_mask BitMask) { var x C.int x = C.hak_setoption(hak.c, C.HAK_LOG_MASK, unsafe.Pointer(&log_mask)) if x <= -1 { // this must not happen panic(fmt.Errorf("unable to set log mask - %s", hak.get_errmsg())) } } func (hak *HAK) GetLogTarget() string { var x C.int var tgt *C.char x = C.hak_getoption(hak.c, C.HAK_LOG_TARGET_BCSTR, unsafe.Pointer(&tgt)) if x <= -1 { // this must not happen panic(fmt.Errorf("unable to set log target - %s", hak.get_errmsg())) } return C.GoString(tgt) } func (hak *HAK) SetLogTarget(target string) { var x C.int var tgt *C.char tgt = C.CString(target) // TODO: need error check? defer C.free(unsafe.Pointer(tgt)) x = C.hak_setoption(hak.c, C.HAK_LOG_TARGET_BCSTR, unsafe.Pointer(tgt)) if x <= -1 { // this must not happen panic(fmt.Errorf("unable to set log target - %s", hak.get_errmsg())) } } func (hak *HAK) Ignite(memsize uintptr) error { var x C.int x = C.hak_ignite(hak.c, C.hak_oow_t(memsize)) if x <= -1 { //return fmt.Errorf("unable to ignite - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) AddBuiltinPrims() error { var x C.int x = C.hak_addbuiltinprims(hak.c) if x <= -1 { //return fmt.Errorf("unable to add built-in primitives - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } // the name of the main cci stream is required because: // - the main stream is not handled by this IO handler // - the feeder must read the main stream and pass data. // - the inclusion of another file from the main stream requires the path information of the main strea. func (hak *HAK) AttachCCIO(cci CciImpl, main_cci_name string) error { var x C.int var old_cci CciImpl var old_cci_name string old_cci = hak.io.cci old_cci_name = hak.io.cci_main hak.io.cci = cci hak.io.cci_main = main_cci_name x = C.hak_attachccio(hak.c, C.hak_io_impl_t(C.hak_cci_handler_for_go)) if x <= -1 { // restore the io handler set due to attachment failure hak.io.cci_main = old_cci_name hak.io.cci = old_cci //return fmt.Errorf("unable to attach source input stream handler - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) AttachUDIO(udi UdiImpl, udo UdoImpl) error { var x C.int var os UdiImpl var op UdoImpl os = hak.io.udi op = hak.io.udo hak.io.udi = udi hak.io.udo = udo x = C.hak_attachudio(hak.c, C.hak_io_impl_t(C.hak_udi_handler_for_go), C.hak_io_impl_t(C.hak_udo_handler_for_go)) if x <= -1 { //restore the io handlers set due to attachment failure hak.io.udi = os hak.io.udo = op //return fmt.Errorf("unable to attach user data stream handlers - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) BeginFeed() error { var x C.int x = C.hak_beginfeed(hak.c, nil) if x <= -1 { //return fmt.Errorf("unable to begin feeding - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) EndFeed() error { var x C.int x = C.hak_endfeed(hak.c) if x <= -1 { //return fmt.Errorf("unable to end feeding - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) FeedString(str string) error { var x C.int var q []C.hak_uch_t q = string_to_uchars(str) x = C.hak_feed(hak.c, &q[0], C.hak_oow_t(len(q))) if x <= -1 { //return fmt.Errorf("unable to feed string - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) FeedRunes(str []rune) error { var x C.int var q []C.hak_uch_t q = rune_slice_to_uchars(str) x = C.hak_feed(hak.c, &q[0], C.hak_oow_t(len(q))) if x <= -1 { //return fmt.Errorf("unable to feed runes - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) FeedFromReader(rdr io.Reader) error { var err error var n int var x C.int var buf [1024]byte for { n, err = rdr.Read(buf[:]) if err == io.EOF { break } else if err != nil { //return fmt.Errorf("unable to read bytes - %s", err.Error()) return &Err{File: hak.io.cci_main, Msg: err.Error()} } x = C.hak_feedbchars(hak.c, (*C.hak_bch_t)(unsafe.Pointer(&buf[0])), C.hak_oow_t(n)) if x <= -1 { //return fmt.Errorf("unable to feed bytes - %s", hak.get_errmsg()) return hak.make_errinfo() } } return nil } func (hak *HAK) FeedFromFile(file string) error { var f *os.File var err error f, err = os.Open(file) if err != nil { //return fmt.Errorf("unable to open %s - %s", file, err.Error()) return &Err{File: file, Msg: err.Error()} } defer f.Close() return hak.FeedFromReader(bufio.NewReader(f)) } func (hak *HAK) Execute() error { var x C.hak_oop_t x = C.hak_execute(hak.c) if x == nil { //return fmt.Errorf("unable to execute - %s", hak.get_errmsg()) return hak.make_errinfo() } // TODO: wrap C.hak_oop_t in a go type // and make this function to return 'x' in the wrapper return nil } func (hak *HAK) Decode() error { var x C.int x = C.hak_decode(hak.c, C.hak_getcode(hak.c), 0, C.hak_getbclen(hak.c)) if x <= -1 { //return fmt.Errorf("unable to decode byte codes - %s", hak.get_errmsg()) return hak.make_errinfo() } return nil } func (hak *HAK) get_errmsg() string { return C.GoString(C.hak_geterrbmsg(hak.c)) } func (hak *HAK) set_errmsg(num C.hak_errnum_t, msg string) { var ptr *C.char ptr = C.CString(msg) defer C.free(unsafe.Pointer(ptr)) C.hak_seterrbmsg(hak.c, num, ptr) } // ----------------------------------------------------------- func ucstr_to_rune_slice(str *C.hak_uch_t) []rune { return uchars_to_rune_slice(str, uintptr(C.hak_count_ucstr(str))) } func uchars_to_rune_slice(str *C.hak_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.hak_uch_t)(unsafe.Pointer(ptr))) ptr += unsafe.Sizeof(*str) } return res } func string_to_uchars(str string) []C.hak_uch_t { var r []rune var c []C.hak_uch_t var i int // TODO: proper encoding r = []rune(str) c = make([]C.hak_uch_t, len(r), len(r)) for i = 0; i < len(r); i++ { c[i] = C.hak_uch_t(r[i]) } return c } func rune_slice_to_uchars(r []rune) []C.hak_uch_t { var c []C.hak_uch_t var i int // TODO: proper encoding c = make([]C.hak_uch_t, len(r), len(r)) for i = 0; i < len(r); i++ { c[i] = C.hak_uch_t(r[i]) } return c } func c_to_go(c *C.hak_t) *HAK { var ext *Ext var inst Instance ext = (*Ext)(unsafe.Pointer(C.hak_getxtn(c))) inst = inst_table.slot_to_instance(ext.inst_no) return inst.g } // ----------------------------------------------------------- func (err* Err) Error() string { if err.Tgt == "" { return fmt.Sprintf("%s[%d,%d] %s", err.File, err.Line, err.Colm, err.Msg) } else { } return fmt.Sprintf("%s[%d,%d] %s - %s", err.File, err.Line, err.Colm, err.Msg, err.Tgt) }