Fixed two seg faults and added lists:add

This commit is contained in:
Leon Mika 2025-01-24 13:25:10 +11:00
parent c6e195cbf8
commit 258d887182
6 changed files with 60 additions and 20 deletions

View file

@ -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

View file

@ -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
} }

View file

@ -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) {

View file

@ -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

View file

@ -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",

View file

@ -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()