Fix bugs with binding to Opaque objects and pointers
All checks were successful
Build / build (push) Successful in 2m17s
All checks were successful
Build / build (push) Successful in 2m17s
This commit is contained in:
parent
e2f471c608
commit
58195738ba
|
@ -263,6 +263,8 @@ func toGoValue(obj Object) (interface{}, bool) {
|
|||
return v, true
|
||||
case proxyObject:
|
||||
return v.p, true
|
||||
case OpaqueObject:
|
||||
return v.v, true
|
||||
case listableProxyObject:
|
||||
return v.orig.Interface(), true
|
||||
case structProxyObject:
|
||||
|
|
|
@ -163,10 +163,12 @@ func (ca CallArgs) bindArg(v interface{}, arg Object) error {
|
|||
switch t := arg.(type) {
|
||||
case proxyObject:
|
||||
return bindProxyObject(v, reflect.ValueOf(t.p))
|
||||
case OpaqueObject:
|
||||
return bindProxyObject(v, reflect.ValueOf(t.v))
|
||||
case listableProxyObject:
|
||||
return bindProxyObject(v, t.v)
|
||||
return bindProxyObject(v, t.orig)
|
||||
case structProxyObject:
|
||||
return bindProxyObject(v, t.v)
|
||||
return bindProxyObject(v, t.orig)
|
||||
}
|
||||
|
||||
return bindProxyObject(v, reflect.ValueOf(arg))
|
||||
|
@ -185,9 +187,9 @@ func canBindArg(v interface{}, arg Object) bool {
|
|||
case proxyObject:
|
||||
return canBindProxyObject(v, reflect.ValueOf(t.p))
|
||||
case listableProxyObject:
|
||||
return canBindProxyObject(v, t.v)
|
||||
return canBindProxyObject(v, t.orig)
|
||||
case structProxyObject:
|
||||
return canBindProxyObject(v, t.v)
|
||||
return canBindProxyObject(v, t.orig)
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"ucl.lmika.dev/ucl"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -29,6 +30,59 @@ func TestInst_SetBuiltin(t *testing.T) {
|
|||
assert.Equal(t, "Hello, World", res)
|
||||
})
|
||||
|
||||
t.Run("simple builtin accepting and returning pointers", func(t *testing.T) {
|
||||
type point struct {
|
||||
x, y int
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
descr string
|
||||
expr string
|
||||
want string
|
||||
}{
|
||||
{descr: "pass via args", expr: `vec 1 2 | vadd`, want: "3"},
|
||||
{descr: "pass via vars", expr: `x = (vec 2 3) ; vadd $x`, want: "5"},
|
||||
{descr: "pass twice", expr: `vadd (vadd2 (vec 1 2) (vec 3 4))`, want: "10"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.descr, func(t *testing.T) {
|
||||
inst := ucl.New()
|
||||
inst.SetBuiltin("vec", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||
var x, y int
|
||||
|
||||
if err := args.Bind(&x, &y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &point{x, y}, nil
|
||||
})
|
||||
inst.SetBuiltin("vadd", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||
var v *point
|
||||
|
||||
if err := args.Bind(&v); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return v.x + v.y, nil
|
||||
})
|
||||
inst.SetBuiltin("vadd2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||
var v, u *point
|
||||
|
||||
if err := args.Bind(&v, &u); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &point{v.x + u.x, v.y + u.y}, nil
|
||||
})
|
||||
|
||||
res, err := inst.EvalString(context.Background(), tt.expr)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, fmt.Sprint(res))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("bind shift arguments", func(t *testing.T) {
|
||||
inst := ucl.New()
|
||||
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||
|
@ -105,7 +159,7 @@ func TestInst_SetBuiltin(t *testing.T) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return pair{x, y}, nil
|
||||
return ucl.Opaque(pair{x, y}), nil
|
||||
})
|
||||
|
||||
res, err := inst.EvalString(context.Background(), `add2 "Hello" "World"`)
|
||||
|
@ -137,7 +191,7 @@ func TestInst_SetBuiltin(t *testing.T) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
return pair{x, y}, nil
|
||||
return ucl.Opaque(pair{x, y}), nil
|
||||
})
|
||||
inst.SetBuiltin("join", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||
var x pair
|
||||
|
@ -156,6 +210,49 @@ func TestInst_SetBuiltin(t *testing.T) {
|
|||
}
|
||||
})
|
||||
|
||||
t.Run("builtin operating on and returning proxy object for pointers", func(t *testing.T) {
|
||||
type pair struct {
|
||||
x, y string
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
descr string
|
||||
expr string
|
||||
want string
|
||||
}{
|
||||
{descr: "pass via args", expr: `join (add2 "left" "right")`, want: "left:right"},
|
||||
{descr: "pass via vars", expr: `x = (add2 "blue" "green") ; join $x`, want: "blue:green"},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.descr, func(t *testing.T) {
|
||||
inst := ucl.New()
|
||||
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||
var x, y string
|
||||
|
||||
if err := args.Bind(&x, &y); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ucl.Opaque(&pair{x, y}), nil
|
||||
})
|
||||
inst.SetBuiltin("join", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||
var x *pair
|
||||
|
||||
if err := args.Bind(&x); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return x.x + ":" + x.y, nil
|
||||
})
|
||||
|
||||
res, err := inst.EvalString(context.Background(), tt.expr)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, res)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("slices returned by commands treated as lists", func(t *testing.T) {
|
||||
tests := []struct {
|
||||
descr string
|
||||
|
|
Loading…
Reference in a new issue