Fixed two seg faults and added lists:add
This commit is contained in:
parent
c6e195cbf8
commit
258d887182
|
@ -517,7 +517,7 @@ func keysBuiltin(ctx context.Context, args invocationArgs) (Object, error) {
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return keys, nil
|
return &keys, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
@ -545,7 +545,7 @@ func mapBuiltin(ctx context.Context, args invocationArgs) (Object, error) {
|
||||||
}
|
}
|
||||||
newList = append(newList, m)
|
newList = append(newList, m)
|
||||||
}
|
}
|
||||||
return newList, nil
|
return &newList, nil
|
||||||
}
|
}
|
||||||
return nil, errors.New("expected listable")
|
return nil, errors.New("expected listable")
|
||||||
}
|
}
|
||||||
|
@ -569,17 +569,17 @@ func filterBuiltin(ctx context.Context, args invocationArgs) (Object, error) {
|
||||||
m, err := inv.invoke(ctx, args.fork([]Object{v}))
|
m, err := inv.invoke(ctx, args.fork([]Object{v}))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
} else if m.Truthy() {
|
} else if m != nil && m.Truthy() {
|
||||||
newList = append(newList, v)
|
newList = append(newList, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return newList, nil
|
return &newList, nil
|
||||||
case hashable:
|
case hashable:
|
||||||
newHash := hashObject{}
|
newHash := hashObject{}
|
||||||
if err := t.Each(func(k string, v Object) error {
|
if err := t.Each(func(k string, v Object) error {
|
||||||
if m, err := inv.invoke(ctx, args.fork([]Object{StringObject(k), v})); err != nil {
|
if m, err := inv.invoke(ctx, args.fork([]Object{StringObject(k), v})); err != nil {
|
||||||
return err
|
return err
|
||||||
} else if m.Truthy() {
|
} else if m != nil && m.Truthy() {
|
||||||
newHash[k] = v
|
newHash[k] = v
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"ucl.lmika.dev/ucl"
|
"ucl.lmika.dev/ucl"
|
||||||
)
|
)
|
||||||
|
@ -25,6 +26,13 @@ func CSV(fs fs.FS) ucl.Module {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h csvHandlers) openFile(name string) (fs.File, error) {
|
||||||
|
if h.fs == nil {
|
||||||
|
return os.Open(name)
|
||||||
|
}
|
||||||
|
return h.fs.Open(name)
|
||||||
|
}
|
||||||
|
|
||||||
func (h csvHandlers) eachRecord(ctx context.Context, args ucl.CallArgs) (any, error) {
|
func (h csvHandlers) eachRecord(ctx context.Context, args ucl.CallArgs) (any, error) {
|
||||||
var (
|
var (
|
||||||
filename string
|
filename string
|
||||||
|
@ -35,7 +43,7 @@ func (h csvHandlers) eachRecord(ctx context.Context, args ucl.CallArgs) (any, er
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
f, err := h.fs.Open(filename)
|
f, err := h.openFile(filename)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -203,7 +203,7 @@ func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (Objec
|
||||||
|
|
||||||
func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astListOrHash) (Object, error) {
|
func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astListOrHash) (Object, error) {
|
||||||
if loh.EmptyList {
|
if loh.EmptyList {
|
||||||
return listObject{}, nil
|
return &listObject{}, nil
|
||||||
} else if loh.EmptyHash {
|
} else if loh.EmptyHash {
|
||||||
return hashObject{}, nil
|
return hashObject{}, nil
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ func (e evaluator) evalListOrHash(ctx context.Context, ec *evalCtx, loh *astList
|
||||||
}
|
}
|
||||||
l = append(l, v)
|
l = append(l, v)
|
||||||
}
|
}
|
||||||
return l, nil
|
return &l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e evaluator) evalLiteral(ctx context.Context, ec *evalCtx, n *astLiteral) (Object, error) {
|
func (e evaluator) evalLiteral(ctx context.Context, ec *evalCtx, n *astLiteral) (Object, error) {
|
||||||
|
|
44
ucl/objs.go
44
ucl/objs.go
|
@ -22,6 +22,16 @@ type Listable interface {
|
||||||
Index(i int) Object
|
Index(i int) Object
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ModListable interface {
|
||||||
|
Listable
|
||||||
|
|
||||||
|
// Insert adds a new item to the list. idx can be a positive
|
||||||
|
// number from 0 to len(), in which case the object will be inserted
|
||||||
|
// at that position. If idx is negative, then the item will be inserted
|
||||||
|
// at that position from the right.
|
||||||
|
Insert(idx int, obj Object) error
|
||||||
|
}
|
||||||
|
|
||||||
type hashable interface {
|
type hashable interface {
|
||||||
Len() int
|
Len() int
|
||||||
Value(k string) Object
|
Value(k string) Object
|
||||||
|
@ -34,20 +44,32 @@ func (lo *listObject) Append(o Object) {
|
||||||
*lo = append(*lo, o)
|
*lo = append(*lo, o)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s listObject) String() string {
|
func (lo *listObject) Insert(idx int, obj Object) error {
|
||||||
return fmt.Sprintf("%v", []Object(s))
|
if idx != -1 {
|
||||||
|
return errors.New("not supported")
|
||||||
|
}
|
||||||
|
*lo = append(*lo, obj)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s listObject) Truthy() bool {
|
func (s *listObject) String() string {
|
||||||
return len(s) > 0
|
return fmt.Sprintf("%v", []Object(*s))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s listObject) Len() int {
|
func (s *listObject) Truthy() bool {
|
||||||
return len(s)
|
return len(*s) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s listObject) Index(i int) Object {
|
func (s *listObject) Len() int {
|
||||||
return s[i]
|
return len(*s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *listObject) Index(i int) Object {
|
||||||
|
return (*s)[i]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *listObject) Add(o Object) {
|
||||||
|
*s = append(*s, o)
|
||||||
}
|
}
|
||||||
|
|
||||||
type hashObject map[string]Object
|
type hashObject map[string]Object
|
||||||
|
@ -149,9 +171,9 @@ func toGoValue(obj Object) (interface{}, bool) {
|
||||||
return bool(v), true
|
return bool(v), true
|
||||||
case timeObject:
|
case timeObject:
|
||||||
return time.Time(v), true
|
return time.Time(v), true
|
||||||
case listObject:
|
case *listObject:
|
||||||
xs := make([]interface{}, 0, len(v))
|
xs := make([]interface{}, 0, len(*v))
|
||||||
for _, va := range v {
|
for _, va := range *v {
|
||||||
x, ok := toGoValue(va)
|
x, ok := toGoValue(va)
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -38,7 +38,9 @@ func WithTestBuiltin() InstOption {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
i.rootEC.addCmd("list", invokableFunc(func(ctx context.Context, args invocationArgs) (Object, error) {
|
i.rootEC.addCmd("list", invokableFunc(func(ctx context.Context, args invocationArgs) (Object, error) {
|
||||||
return listObject(args.args), nil
|
var a listObject = make([]Object, len(args.args))
|
||||||
|
copy(a, args.args)
|
||||||
|
return &a, nil
|
||||||
}))
|
}))
|
||||||
|
|
||||||
i.rootEC.addCmd("error", invokableFunc(func(ctx context.Context, args invocationArgs) (Object, error) {
|
i.rootEC.addCmd("error", invokableFunc(func(ctx context.Context, args invocationArgs) (Object, error) {
|
||||||
|
@ -1170,6 +1172,8 @@ func TestBuiltins_Filter(t *testing.T) {
|
||||||
{desc: "filter list 1", expr: `filter [1 2 3] { |x| eq $x 2 }`, want: []any{2}},
|
{desc: "filter list 1", expr: `filter [1 2 3] { |x| eq $x 2 }`, want: []any{2}},
|
||||||
{desc: "filter list 2", expr: `filter ["flim" "flam" "fla"] { |x| eq $x "flam" }`, want: []any{"flam"}},
|
{desc: "filter list 2", expr: `filter ["flim" "flam" "fla"] { |x| eq $x "flam" }`, want: []any{"flam"}},
|
||||||
{desc: "filter list 3", expr: `filter ["flim" "flam" "fla"] { |x| eq $x "bogie" }`, want: []any{}},
|
{desc: "filter list 3", expr: `filter ["flim" "flam" "fla"] { |x| eq $x "bogie" }`, want: []any{}},
|
||||||
|
{desc: "filter list 4", expr: `filter [() () ()] { |x| $x }`, want: []any{}},
|
||||||
|
{desc: "filter list 5", expr: `filter [] { |x| $x }`, want: []any{}},
|
||||||
|
|
||||||
{desc: "filter map 1", expr: `filter [alpha:"hello" bravo:"world"] { |k v| eq $k "alpha" }`, want: map[string]any{
|
{desc: "filter map 1", expr: `filter [alpha:"hello" bravo:"world"] { |k v| eq $k "alpha" }`, want: map[string]any{
|
||||||
"alpha": "hello",
|
"alpha": "hello",
|
||||||
|
|
|
@ -121,6 +121,12 @@ func (ca CallArgs) bindArg(v interface{}, arg Object) error {
|
||||||
}
|
}
|
||||||
*t = i
|
*t = i
|
||||||
return nil
|
return nil
|
||||||
|
case *ModListable:
|
||||||
|
if i, ok := arg.(ModListable); ok {
|
||||||
|
*t = i
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return errors.New("exepected listable")
|
||||||
case *string:
|
case *string:
|
||||||
if arg != nil {
|
if arg != nil {
|
||||||
*t = arg.String()
|
*t = arg.String()
|
||||||
|
|
Loading…
Reference in a new issue