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
|
return v, true
|
||||||
case proxyObject:
|
case proxyObject:
|
||||||
return v.p, true
|
return v.p, true
|
||||||
|
case OpaqueObject:
|
||||||
|
return v.v, true
|
||||||
case listableProxyObject:
|
case listableProxyObject:
|
||||||
return v.orig.Interface(), true
|
return v.orig.Interface(), true
|
||||||
case structProxyObject:
|
case structProxyObject:
|
||||||
|
|
|
@ -163,10 +163,12 @@ func (ca CallArgs) bindArg(v interface{}, arg Object) error {
|
||||||
switch t := arg.(type) {
|
switch t := arg.(type) {
|
||||||
case proxyObject:
|
case proxyObject:
|
||||||
return bindProxyObject(v, reflect.ValueOf(t.p))
|
return bindProxyObject(v, reflect.ValueOf(t.p))
|
||||||
|
case OpaqueObject:
|
||||||
|
return bindProxyObject(v, reflect.ValueOf(t.v))
|
||||||
case listableProxyObject:
|
case listableProxyObject:
|
||||||
return bindProxyObject(v, t.v)
|
return bindProxyObject(v, t.orig)
|
||||||
case structProxyObject:
|
case structProxyObject:
|
||||||
return bindProxyObject(v, t.v)
|
return bindProxyObject(v, t.orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
return bindProxyObject(v, reflect.ValueOf(arg))
|
return bindProxyObject(v, reflect.ValueOf(arg))
|
||||||
|
@ -185,9 +187,9 @@ func canBindArg(v interface{}, arg Object) bool {
|
||||||
case proxyObject:
|
case proxyObject:
|
||||||
return canBindProxyObject(v, reflect.ValueOf(t.p))
|
return canBindProxyObject(v, reflect.ValueOf(t.p))
|
||||||
case listableProxyObject:
|
case listableProxyObject:
|
||||||
return canBindProxyObject(v, t.v)
|
return canBindProxyObject(v, t.orig)
|
||||||
case structProxyObject:
|
case structProxyObject:
|
||||||
return canBindProxyObject(v, t.v)
|
return canBindProxyObject(v, t.orig)
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"ucl.lmika.dev/ucl"
|
"ucl.lmika.dev/ucl"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
@ -29,6 +30,59 @@ func TestInst_SetBuiltin(t *testing.T) {
|
||||||
assert.Equal(t, "Hello, World", res)
|
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) {
|
t.Run("bind shift arguments", func(t *testing.T) {
|
||||||
inst := ucl.New()
|
inst := ucl.New()
|
||||||
inst.SetBuiltin("add2", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
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 nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return pair{x, y}, nil
|
return ucl.Opaque(pair{x, y}), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
res, err := inst.EvalString(context.Background(), `add2 "Hello" "World"`)
|
res, err := inst.EvalString(context.Background(), `add2 "Hello" "World"`)
|
||||||
|
@ -137,7 +191,7 @@ func TestInst_SetBuiltin(t *testing.T) {
|
||||||
return nil, err
|
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) {
|
inst.SetBuiltin("join", func(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var x pair
|
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) {
|
t.Run("slices returned by commands treated as lists", func(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
descr string
|
descr string
|
||||||
|
|
Loading…
Reference in a new issue