Пример #1
0
//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
}
Пример #2
0
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
}
Пример #3
0
//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
}
Пример #4
0
//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
}
Пример #5
0
//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
}