Skip to content

Commit 2e014f4

Browse files
author
Bob Uhl
committed
Handle variadic functions & return values
1 parent 15b66c7 commit 2e014f4

3 files changed

Lines changed: 51 additions & 7 deletions

File tree

interpreter.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ void _gotk_c_tcl_set_result(Tcl_Interp *interp, char *result) {
88
Tcl_SetResult(interp, result, free_string);
99
}
1010

11+
void _gotk_c_tcl_set_obj_result(Tcl_Interp *interp, Tcl_Obj *result) {
12+
Tcl_SetObjResult(interp, result);
13+
}
14+
1115
GoTkClientData *_gotk_c_client_data_new(int go_interp, int h0, int h1) {
1216
GoTkClientData *cd = malloc(sizeof(GoTkClientData));
1317
cd->go_interp = go_interp;

interpreter.go

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -435,8 +435,7 @@ func (ir *interpreter) eval_as(out interface{}, script []byte) error {
435435
return ir.tcl_obj_to_go_value(C.Tcl_GetObjResult(ir.C), v)
436436
}
437437

438-
func go_value_to_tcl_obj(value interface{}) *C.Tcl_Obj {
439-
v := reflect.ValueOf(value)
438+
func go_value_to_tcl_obj(v reflect.Value) *C.Tcl_Obj {
440439
switch v.Kind() {
441440
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
442441
return C.Tcl_NewWideIntObj(C.Tcl_WideInt(v.Int()))
@@ -451,14 +450,16 @@ func go_value_to_tcl_obj(value interface{}) *C.Tcl_Obj {
451450
return C.Tcl_NewBooleanObj(0)
452451
case reflect.String:
453452
s := v.String()
454-
sh := *(*reflect.StringHeader)(unsafe.Pointer(&s))
455-
return C.Tcl_NewStringObj((*C.char)(unsafe.Pointer(sh.Data)), C.int(len(s)))
453+
b := C.CBytes([]byte(s))
454+
obj := C.Tcl_NewStringObj((*C.char)(b), C.int(len(s)))
455+
C.free(b)
456+
return obj
456457
}
457458
return nil
458459
}
459460

460461
func (ir *interpreter) set(name string, value interface{}) error {
461-
obj := go_value_to_tcl_obj(value)
462+
obj := go_value_to_tcl_obj(reflect.ValueOf(value))
462463
if obj == nil {
463464
return errors.New("gothic: cannot convert Go value to TCL object")
464465
}
@@ -593,6 +594,19 @@ func _gotk_go_command_handler(clidataup unsafe.Pointer, objc C.int, objv unsafe.
593594
for i, n := 0, ft.NumIn(); i < n; i++ {
594595
in := ft.In(i)
595596

597+
if ft.IsVariadic() && i == n-1 && in.Kind() == reflect.Slice {
598+
for i := i; i < len(args); i++ {
599+
v := reflect.New(in.Elem()).Elem()
600+
err := ir.tcl_obj_to_go_value(args[i], v)
601+
if err != nil {
602+
C._gotk_c_tcl_set_result(ir.C, C.CString(err.Error()))
603+
return C.TCL_ERROR
604+
}
605+
ir.valuesbuf = append(ir.valuesbuf, v)
606+
}
607+
break
608+
}
609+
596610
// use default value, if there is not enough args
597611
if len(args) <= i {
598612
ir.valuesbuf = append(ir.valuesbuf, reflect.New(in).Elem())
@@ -609,8 +623,33 @@ func _gotk_go_command_handler(clidataup unsafe.Pointer, objc C.int, objv unsafe.
609623
ir.valuesbuf = append(ir.valuesbuf, v)
610624
}
611625

612-
// TODO: handle return value
613-
f.Call(ir.valuesbuf)
626+
// Cycle through results. The first value result will be
627+
// returned; if a non-nil error result is encountered, an
628+
// error will be returned. If more than one non-error result
629+
// is encountered, that itself is an error.
630+
var returnValue *C.Tcl_Obj
631+
for _, result := range f.Call(ir.valuesbuf) {
632+
if result.Type().Implements(reflect.TypeOf((*error)(nil)).Elem()) {
633+
if result.IsNil() {
634+
continue
635+
}
636+
e := result.MethodByName("Error")
637+
s := e.Call(nil)
638+
C._gotk_c_tcl_set_result(ir.C, C.CString(s[0].String()))
639+
return C.TCL_ERROR
640+
}
641+
if returnValue != nil {
642+
C._gotk_c_tcl_set_result(ir.C, C.CString("gothic: cannot return multiple results to TCL"))
643+
return C.TCL_ERROR
644+
}
645+
if returnValue = go_value_to_tcl_obj(result); returnValue == nil {
646+
C._gotk_c_tcl_set_result(ir.C, C.CString("gothic: cannot convert Go value to TCL object"))
647+
return C.TCL_ERROR
648+
}
649+
}
650+
if returnValue != nil {
651+
C._gotk_c_tcl_set_obj_result(ir.C, returnValue)
652+
}
614653

615654
return C.TCL_OK
616655
}

interpreter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ typedef struct {
1010

1111

1212
void _gotk_c_tcl_set_result(Tcl_Interp *interp, char *result);
13+
void _gotk_c_tcl_set_obj_result(Tcl_Interp *interp, Tcl_Obj *result);
1314
GoTkClientData *_gotk_c_client_data_new(int go_interp, int h0, int h1);
1415

1516
//------------------------------------------------------------------------------

0 commit comments

Comments
 (0)