Started working on map functions
This commit is contained in:
parent
fe15730769
commit
4b91bff641
|
@ -52,16 +52,26 @@ func toUpperBuiltin(ctx context.Context, inStream stream, args invocationArgs) (
|
|||
// Handle args
|
||||
return mapFilterStream{
|
||||
in: inStream,
|
||||
mapFn: func(x object) (object, bool) {
|
||||
mapFn: func(x object) (object, bool, error) {
|
||||
s, ok := x.(strObject)
|
||||
if !ok {
|
||||
return nil, false
|
||||
return nil, false, nil
|
||||
}
|
||||
return strObject(strings.ToUpper(string(s))), true
|
||||
return strObject(strings.ToUpper(string(s))), true, nil
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func concatBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||
var sb strings.Builder
|
||||
|
||||
for _, a := range args.args {
|
||||
sb.WriteString(a.String())
|
||||
}
|
||||
|
||||
return strObject(sb.String()), nil
|
||||
}
|
||||
|
||||
func catBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||
if err := args.expectArgn(1); err != nil {
|
||||
return nil, err
|
||||
|
@ -88,6 +98,30 @@ func callBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
|||
return inv.invoke(ctx, args.shift(1))
|
||||
}
|
||||
|
||||
func mapBuiltin(ctx context.Context, inStream stream, args invocationArgs) (object, error) {
|
||||
args, strm, err := args.streamableSource(inStream)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := args.expectArgn(1); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
inv, ok := args.args[0].(invokable)
|
||||
if !ok {
|
||||
return nil, errors.New("expected invokable")
|
||||
}
|
||||
|
||||
return mapFilterStream{
|
||||
in: strm,
|
||||
mapFn: func(x object) (object, bool, error) {
|
||||
y, err := inv.invoke(ctx, args.fork(nil, []object{x}))
|
||||
return y, true, err
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
type fileLinesStream struct {
|
||||
filename string
|
||||
f *os.File
|
||||
|
|
|
@ -3,9 +3,7 @@ package cmdlang
|
|||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type evaluator struct {
|
||||
|
@ -218,17 +216,15 @@ func (e evaluator) evalSub(ctx context.Context, ec *evalCtx, n *astPipeline) (ob
|
|||
|
||||
switch v := pipelineRes.(type) {
|
||||
case stream:
|
||||
// TODO: use proper lists here, not a string join
|
||||
sb := strings.Builder{}
|
||||
list := listObject{}
|
||||
if err := forEach(v, func(o object, _ int) error {
|
||||
// TODO: use o.String()
|
||||
sb.WriteString(fmt.Sprint(o))
|
||||
list = append(list, o)
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return strObject(sb.String()), nil
|
||||
return list, nil
|
||||
}
|
||||
return pipelineRes, nil
|
||||
}
|
||||
|
|
|
@ -30,9 +30,13 @@ func New(opts ...InstOption) *Inst {
|
|||
rootEC.addCmd("echo", invokableFunc(echoBuiltin))
|
||||
rootEC.addCmd("set", invokableFunc(setBuiltin))
|
||||
rootEC.addCmd("toUpper", invokableStreamFunc(toUpperBuiltin))
|
||||
rootEC.addCmd("cat", invokableFunc(catBuiltin))
|
||||
//rootEC.addCmd("cat", invokableFunc(catBuiltin))
|
||||
rootEC.addCmd("call", invokableFunc(callBuiltin))
|
||||
|
||||
rootEC.addCmd("map", invokableStreamFunc(mapBuiltin))
|
||||
|
||||
rootEC.addCmd("cat", invokableFunc(concatBuiltin))
|
||||
|
||||
rootEC.addMacro("if", macroFunc(ifBuiltin))
|
||||
rootEC.addMacro("foreach", macroFunc(foreachBuiltin))
|
||||
rootEC.addMacro("proc", macroFunc(procBuiltin))
|
||||
|
|
|
@ -172,6 +172,25 @@ type invocationArgs struct {
|
|||
kwargs map[string]*listObject
|
||||
}
|
||||
|
||||
// streamableSource takes a stream. If the stream is set, the inStream and invocation arguments are consumed as is.
|
||||
// If not, then the first argument is consumed and returned as a stream.
|
||||
func (ia invocationArgs) streamableSource(inStream stream) (invocationArgs, stream, error) {
|
||||
if inStream != nil {
|
||||
return ia, inStream, nil
|
||||
}
|
||||
|
||||
if len(ia.args) < 1 {
|
||||
return ia, nil, errors.New("expected at least 1 argument")
|
||||
}
|
||||
|
||||
switch v := ia.args[0].(type) {
|
||||
case listObject:
|
||||
return ia.shift(1), &listIterStream{list: v}, nil
|
||||
}
|
||||
|
||||
return ia, nil, errors.New("expected arg 0 to be streamable")
|
||||
}
|
||||
|
||||
func (ia invocationArgs) expectArgn(x int) error {
|
||||
if len(ia.args) < x {
|
||||
return errors.New("expected at least " + strconv.Itoa(x) + " args")
|
||||
|
@ -190,6 +209,16 @@ func (ia invocationArgs) stringArg(i int) (string, error) {
|
|||
return s.String(), nil
|
||||
}
|
||||
|
||||
func (ia invocationArgs) fork(currentStr stream, args []object) invocationArgs {
|
||||
return invocationArgs{
|
||||
inst: ia.inst,
|
||||
ec: ia.ec,
|
||||
currentStream: currentStr,
|
||||
args: args,
|
||||
kwargs: make(map[string]*listObject),
|
||||
}
|
||||
}
|
||||
|
||||
func (ia invocationArgs) shift(i int) invocationArgs {
|
||||
return invocationArgs{
|
||||
inst: ia.inst,
|
||||
|
|
|
@ -116,7 +116,7 @@ func (s *listIterStream) close() error { return nil }
|
|||
|
||||
type mapFilterStream struct {
|
||||
in stream
|
||||
mapFn func(x object) (object, bool)
|
||||
mapFn func(x object) (object, bool, error)
|
||||
}
|
||||
|
||||
func (ms mapFilterStream) String() string {
|
||||
|
@ -134,8 +134,10 @@ func (ms mapFilterStream) next() (object, error) {
|
|||
return nil, err
|
||||
}
|
||||
|
||||
t, ok := ms.mapFn(u)
|
||||
if ok {
|
||||
t, ok, err := ms.mapFn(u)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
} else if ok {
|
||||
return t, nil
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue