//export _gotk_go_channel_handler func _gotk_go_channel_handler(clidataup unsafe.Pointer, objc int, objv unsafe.Pointer) int { clidata := (*C.GoTkClientData)(clidataup) ir := (*Interpreter)(clidata.go_interp) args := (*(*[alot]*C.Tcl_Obj)(objv))[1:objc] if len(args) != 2 { msg := C.CString("Argument count mismatch, expected two: <- VALUE") C._gotk_c_tcl_set_result(ir.C, msg) return C.TCL_ERROR } name := _CGoStringToGoString(clidata.p, clidata.n) var ch interface{} var ok bool if ch, ok = ir.channels[name]; !ok { msg := C.CString("Trying to send to a non-existent channel") C._gotk_c_tcl_set_result(ir.C, msg) return C.TCL_ERROR } val := reflect.ValueOf(ch) arg, status := ir.tclObjToGoValue(args[1], val.Type().Elem()) if status != C.TCL_OK { return C.TCL_ERROR } val.Send(arg) return C.TCL_OK }
func (ir *Interpreter) tclObjToGoValue(obj *C.Tcl_Obj, typ reflect.Type) (reflect.Value, C.int) { var status C.int v := reflect.New(typ).Elem() switch typ.Kind() { case reflect.Int: var out C.Tcl_WideInt status = C.Tcl_GetWideIntFromObj(ir.C, obj, &out) if status == C.TCL_OK { v.SetInt(int64(out)) } case reflect.String: v.SetString(C.GoString(C.Tcl_GetString(obj))) case reflect.Float32, reflect.Float64: var out C.double status = C.Tcl_GetDoubleFromObj(ir.C, obj, &out) if status == C.TCL_OK { v.SetFloat(float64(out)) } default: msg := C.CString(fmt.Sprintf("Cannot convert Tcl object to Go type: %s", typ)) C._gotk_c_tcl_set_result(ir.C, msg) status = C.TCL_ERROR } return v, status }
//export _gotk_go_method_handler func _gotk_go_method_handler(clidataup unsafe.Pointer, objc C.int, objv unsafe.Pointer) C.int { // TODO: There is an idea of optimizing everything by a large margin, // we can preprocess the type of a command in RegisterCommand function // and then avoid calling reflect.New for every argument passed to that // function. And we can even do additional error checks for unsupported // argument types and handle multiple return values case. clidata := (*C.GoTkClientData)(clidataup) ir := global_handles.get(int(clidata.go_interp)).(*interpreter) args := (*(*[alot]*C.Tcl_Obj)(objv))[1:objc] recv := ir.handles[clidata.h0].Value meth := ir.handles[clidata.h1].Value f := reflect.ValueOf(meth) ft := f.Type() ir.valuesbuf = ir.valuesbuf[:0] ir.valuesbuf = append(ir.valuesbuf, reflect.ValueOf(recv)) for i, n := 1, ft.NumIn(); i < n; i++ { ia := i - 1 in := ft.In(i) // use default value, if there is not enough args if len(args) <= ia { ir.valuesbuf = append(ir.valuesbuf, reflect.New(in).Elem()) continue } v := reflect.New(in).Elem() err := ir.tcl_obj_to_go_value(args[ia], v) if err != nil { C._gotk_c_tcl_set_result(ir.C, C.CString(err.Error())) return C.TCL_ERROR } ir.valuesbuf = append(ir.valuesbuf, v) } ret := f.Call(ir.valuesbuf) if len(ret) == 1 { C.Tcl_SetObjResult(ir.C, go_value_to_tcl_obj(ret[0].Interface(), ir)) } else if len(ret) > 1 { C.Tcl_SetObjResult(ir.C, go_value_to_tcl_obj(ret, ir)) } return C.TCL_OK }
//export _gotk_go_command_handler func _gotk_go_command_handler(clidataup unsafe.Pointer, objc int, objv unsafe.Pointer) int { // TODO: There is an idea of optimizing everything by a large margin, // we can preprocess the type of a command in RegisterCommand function // and then avoid calling reflect.New for every argument passed to that // function. And we can even do additional error checks for unsupported // argument types and handle multiple return values case. clidata := (*C.GoTkClientData)(clidataup) ir := (*interpreter)(clidata.go_interp) args := (*(*[alot]*C.Tcl_Obj)(objv))[1:objc] cb := c_interface_to_go_interface(clidata.iface) f := reflect.ValueOf(cb) ft := f.Type() ir.valuesbuf = ir.valuesbuf[:0] for i, n := 0, ft.NumIn(); i < n; i++ { in := ft.In(i) // use default value, if there is not enough args if len(args) <= i { ir.valuesbuf = append(ir.valuesbuf, reflect.New(in).Elem()) continue } v := reflect.New(in).Elem() err := ir.tcl_obj_to_go_value(args[i], v) if err != nil { C._gotk_c_tcl_set_result(ir.C, C.CString(err.Error())) return C.TCL_ERROR } ir.valuesbuf = append(ir.valuesbuf, v) } // TODO: handle return value f.Call(ir.valuesbuf) return C.TCL_OK }
//export _gotk_go_callback_handler func _gotk_go_callback_handler(clidataup unsafe.Pointer, objc int, objv unsafe.Pointer) int { clidata := (*C.GoTkClientData)(clidataup) ir := (*Interpreter)(clidata.go_interp) args := (*(*[alot]*C.Tcl_Obj)(objv))[1:objc] cb, ok := ir.callbacks[_CGoStringToGoString(clidata.p, clidata.n)] if !ok { msg := C.CString("Trying to invoke a non-existent callback") C._gotk_c_tcl_set_result(ir.C, msg) return C.TCL_ERROR } ir.valuesbuf = ir.valuesbuf[:0] f := reflect.ValueOf(cb) ft := f.Type() for i, n := 0, ft.NumIn(); i < n; i++ { in := ft.In(i) // use default value, if there is not enough args if len(args) <= i { ir.valuesbuf = append(ir.valuesbuf, reflect.New(in).Elem()) continue } v, status := ir.tclObjToGoValue(args[i], in) if status != C.TCL_OK { return C.TCL_ERROR } ir.valuesbuf = append(ir.valuesbuf, v) } f.Call(ir.valuesbuf) return C.TCL_OK }