Compare commits

..

No commits in common. "6cd3e9ff0fa3ce39b0283fd987a3679d76eec876" and "27463f33c37f9cab1c377d1c6669c0441f2a092c" have entirely different histories.

5 changed files with 12 additions and 252 deletions

View File

@ -40,8 +40,8 @@ type astListOrHash struct {
} }
type astBlock struct { type astBlock struct {
Names []string `parser:"LC NL* (PIPE @Ident+ PIPE NL*)?"` Names []string `parser:"LC NL? (PIPE @Ident+ PIPE NL?)?"`
Statements []*astStatements `parser:"@@? NL* RC"` Statements []*astStatements `parser:"@@ NL? RC"`
} }
type astMaybeSub struct { type astMaybeSub struct {

View File

@ -110,8 +110,6 @@ func (b boolObject) Truthy() bool {
func toGoValue(obj object) (interface{}, bool) { func toGoValue(obj object) (interface{}, bool) {
switch v := obj.(type) { switch v := obj.(type) {
case OpaqueObject:
return v.v, true
case nil: case nil:
return nil, true return nil, true
case strObject: case strObject:
@ -141,9 +139,9 @@ func toGoValue(obj object) (interface{}, bool) {
case proxyObject: case proxyObject:
return v.p, true return v.p, true
case listableProxyObject: case listableProxyObject:
return v.orig.Interface(), true return v.v.Interface(), true
case structProxyObject: case structProxyObject:
return v.orig.Interface(), true return v.v.Interface(), true
} }
return nil, false return nil, false
@ -151,8 +149,6 @@ func toGoValue(obj object) (interface{}, bool) {
func fromGoValue(v any) (object, error) { func fromGoValue(v any) (object, error) {
switch t := v.(type) { switch t := v.(type) {
case OpaqueObject:
return t, nil
case nil: case nil:
return nil, nil return nil, nil
case string: case string:
@ -171,17 +167,10 @@ func fromGoReflectValue(resVal reflect.Value) (object, error) {
switch resVal.Kind() { switch resVal.Kind() {
case reflect.Slice: case reflect.Slice:
return listableProxyObject{v: resVal, orig: resVal}, nil return listableProxyObject{resVal}, nil
case reflect.Struct: case reflect.Struct:
return newStructProxyObject(resVal, resVal), nil return newStructProxyObject(resVal), nil
case reflect.Pointer: case reflect.Pointer:
switch resVal.Elem().Kind() {
case reflect.Slice:
return listableProxyObject{v: resVal.Elem(), orig: resVal}, nil
case reflect.Struct:
return newStructProxyObject(resVal.Elem(), resVal), nil
}
return fromGoReflectValue(resVal.Elem()) return fromGoReflectValue(resVal.Elem())
} }
@ -419,7 +408,6 @@ func (p proxyObject) Truthy() bool {
type listableProxyObject struct { type listableProxyObject struct {
v reflect.Value v reflect.Value
orig reflect.Value
} }
func (p listableProxyObject) String() string { func (p listableProxyObject) String() string {
@ -444,14 +432,12 @@ func (p listableProxyObject) Index(i int) object {
type structProxyObject struct { type structProxyObject struct {
v reflect.Value v reflect.Value
orig reflect.Value
vf []reflect.StructField vf []reflect.StructField
} }
func newStructProxyObject(v reflect.Value, orig reflect.Value) structProxyObject { func newStructProxyObject(v reflect.Value) structProxyObject {
return structProxyObject{ return structProxyObject{
v: v, v: v,
orig: orig,
vf: slices.Filter(reflect.VisibleFields(v.Type()), func(t reflect.StructField) bool { return t.IsExported() }), vf: slices.Filter(reflect.VisibleFields(v.Type()), func(t reflect.StructField) bool { return t.IsExported() }),
} }
} }
@ -502,22 +488,6 @@ func (s structProxyObject) Each(fn func(k string, v object) error) error {
return nil return nil
} }
type OpaqueObject struct {
v any
}
func Opaque(v any) OpaqueObject {
return OpaqueObject{v: v}
}
func (p OpaqueObject) String() string {
return fmt.Sprintf("opaque{%T}", p.v)
}
func (p OpaqueObject) Truthy() bool {
return p.v != nil
}
type errBreak struct { type errBreak struct {
isCont bool isCont bool
ret object ret object

View File

@ -394,36 +394,6 @@ func TestBuiltins_Return(t *testing.T) {
expr string expr string
want string want string
}{ }{
// syntax tests
{desc: "empty proc 1", expr: `
proc greet {}
greet
`, want: "(nil)\n"},
{desc: "empty proc 2", expr: `
proc greet {
}
greet
`, want: "(nil)\n"},
{desc: "empty proc 3", expr: `
proc greet {
}
greet
`, want: "(nil)\n"},
{desc: "empty proc 4", expr: `
proc greet {
# bla
# di
# bla!
}
greet
`, want: "(nil)\n"},
{desc: "nil return", expr: ` {desc: "nil return", expr: `
proc greet { proc greet {
echo "Hello" echo "Hello"
@ -433,27 +403,6 @@ func TestBuiltins_Return(t *testing.T) {
greet greet
`, want: "Hello\n(nil)\n"}, `, want: "Hello\n(nil)\n"},
{desc: "simple arg 1", expr: `
proc greet { |x|
return (cat "Hello, " $x)
}
greet "person"
`, want: "Hello, person\n"},
{desc: "simple arg 2", expr: `
proc greet {
# This will greet someone
# here are the args:
|x|
# And here is the code
return (cat "Hello, " $x)
}
greet "person"
`, want: "Hello, person\n"},
{desc: "simple return", expr: ` {desc: "simple return", expr: `
proc greet { proc greet {
return "Hello, world" return "Hello, world"
@ -462,7 +411,6 @@ func TestBuiltins_Return(t *testing.T) {
greet greet
`, want: "Hello, world\n"}, `, want: "Hello, world\n"},
{desc: "only return current frame", expr: ` {desc: "only return current frame", expr: `
proc greetWhat { proc greetWhat {
echo "Greet the" echo "Greet the"

View File

@ -125,23 +125,6 @@ func (ca CallArgs) bindArg(v interface{}, arg object) error {
} }
switch t := arg.(type) { switch t := arg.(type) {
case OpaqueObject:
if v == nil {
return errors.New("opaque object not bindable to nil")
}
vr := reflect.ValueOf(v)
tr := reflect.ValueOf(t.v)
if vr.Kind() != reflect.Pointer {
return errors.New("expected pointer for an opaque object bind")
}
if !tr.Type().AssignableTo(vr.Elem().Type()) {
return errors.New("opaque object not assignable to passed in value")
}
vr.Elem().Set(tr)
return nil
case proxyObject: case proxyObject:
return bindProxyObject(v, reflect.ValueOf(t.p)) return bindProxyObject(v, reflect.ValueOf(t.p))
case listableProxyObject: case listableProxyObject:
@ -163,18 +146,6 @@ func canBindArg(v interface{}, arg object) bool {
} }
switch t := arg.(type) { switch t := arg.(type) {
case OpaqueObject:
vr := reflect.ValueOf(v)
tr := reflect.ValueOf(t.v)
if vr.Kind() != reflect.Pointer {
return false
}
if !tr.Type().AssignableTo(vr.Elem().Type()) {
return false
}
return true
case proxyObject: case proxyObject:
return canBindProxyObject(v, reflect.ValueOf(t.p)) return canBindProxyObject(v, reflect.ValueOf(t.p))
case listableProxyObject: case listableProxyObject:

View File

@ -3,7 +3,6 @@ package ucl_test
import ( import (
"bytes" "bytes"
"context" "context"
"errors"
"fmt" "fmt"
"strings" "strings"
"testing" "testing"
@ -115,27 +114,6 @@ func TestInst_SetBuiltin(t *testing.T) {
assert.Equal(t, pair{"Hello", "World"}, res) assert.Equal(t, pair{"Hello", "World"}, res)
}) })
t.Run("builtin return proxy object ptr", func(t *testing.T) {
type pair struct {
x, y string
}
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 &pair{x, y}, nil
})
res, err := inst.Eval(context.Background(), `add2 "Hello" "World"`)
assert.NoError(t, err)
assert.Equal(t, &pair{"Hello", "World"}, res)
})
t.Run("builtin operating on and returning proxy object", func(t *testing.T) { t.Run("builtin operating on and returning proxy object", func(t *testing.T) {
type pair struct { type pair struct {
x, y string x, y string
@ -206,113 +184,6 @@ func TestInst_SetBuiltin(t *testing.T) {
}) })
} }
}) })
t.Run("opaques returned as is", func(t *testing.T) {
type opaqueThingType struct {
x string
y string
z string
}
opaqueThing := &opaqueThingType{x: "do", y: "not", z: "touch"}
tests := []struct {
descr string
expr string
wantErr bool
}{
{descr: "return as is", expr: `getOpaque`, wantErr: false},
{descr: "carry around ok", expr: `set x (getOpaque) ; $x`, wantErr: false},
{descr: "iterate over", expr: `foreach (countTo3) { |x| echo $x }`, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.descr, func(t *testing.T) {
outW := bytes.NewBuffer(nil)
inst := ucl.New(ucl.WithOut(outW))
inst.SetBuiltin("getOpaque", func(ctx context.Context, args ucl.CallArgs) (any, error) {
return ucl.Opaque(opaqueThing), nil
})
res, err := inst.Eval(context.Background(), tt.expr)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Same(t, opaqueThing, res)
}
})
}
})
t.Run("operate on opaques", func(t *testing.T) {
type opaqueThingType struct {
x string
y string
z string
}
opaqueThing := &opaqueThingType{x: "do", y: "not", z: "touch"}
tests := []struct {
descr string
expr string
want opaqueThingType
wantErr bool
}{
{descr: "return as is", expr: `getOpaque`, want: *opaqueThing},
{descr: "update pointer 1", expr: `set x (getOpaque) ; setProp $x -x "do" -y "touch" -z "this"`, want: opaqueThingType{x: "do", y: "touch", z: "this"}},
{descr: "update pointer 2", expr: `set x (getOpaque) ; setProp $x -x "yes" ; setProp $x -y "this" -z "too"`, want: opaqueThingType{x: "yes", y: "this", z: "too"}},
{descr: "bad args", expr: `set x (getOpaque) ; setProp $t -x "yes" ; setProp $bla -y "this" -z "too"`, want: *opaqueThing, wantErr: true},
}
for _, tt := range tests {
t.Run(tt.descr, func(t *testing.T) {
outW := bytes.NewBuffer(nil)
inst := ucl.New(ucl.WithOut(outW))
inst.SetBuiltin("getOpaque", func(ctx context.Context, args ucl.CallArgs) (any, error) {
return ucl.Opaque(opaqueThing), nil
})
inst.SetBuiltin("setProp", func(ctx context.Context, args ucl.CallArgs) (any, error) {
var o *opaqueThingType
if err := args.Bind(&o); err != nil {
return nil, err
} else if o == nil {
return nil, errors.New("is nil")
}
if args.HasSwitch("x") {
var s string
_ = args.BindSwitch("x", &s)
o.x = s
}
if args.HasSwitch("y") {
var s string
_ = args.BindSwitch("y", &s)
o.y = s
}
if args.HasSwitch("z") {
var s string
_ = args.BindSwitch("z", &s)
o.z = s
}
return nil, nil
})
_, err := inst.Eval(context.Background(), tt.expr)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.want, *opaqueThing)
}
})
}
})
} }
func TestCallArgs_Bind(t *testing.T) { func TestCallArgs_Bind(t *testing.T) {