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
|
// Handle args
|
||||||
return mapFilterStream{
|
return mapFilterStream{
|
||||||
in: inStream,
|
in: inStream,
|
||||||
mapFn: func(x object) (object, bool) {
|
mapFn: func(x object) (object, bool, error) {
|
||||||
s, ok := x.(strObject)
|
s, ok := x.(strObject)
|
||||||
if !ok {
|
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
|
}, 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) {
|
func catBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
if err := args.expectArgn(1); err != nil {
|
if err := args.expectArgn(1); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -88,6 +98,30 @@ func callBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
return inv.invoke(ctx, args.shift(1))
|
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 {
|
type fileLinesStream struct {
|
||||||
filename string
|
filename string
|
||||||
f *os.File
|
f *os.File
|
||||||
|
|
|
@ -3,9 +3,7 @@ package cmdlang
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type evaluator struct {
|
type evaluator struct {
|
||||||
|
@ -218,17 +216,15 @@ func (e evaluator) evalSub(ctx context.Context, ec *evalCtx, n *astPipeline) (ob
|
||||||
|
|
||||||
switch v := pipelineRes.(type) {
|
switch v := pipelineRes.(type) {
|
||||||
case stream:
|
case stream:
|
||||||
// TODO: use proper lists here, not a string join
|
list := listObject{}
|
||||||
sb := strings.Builder{}
|
|
||||||
if err := forEach(v, func(o object, _ int) error {
|
if err := forEach(v, func(o object, _ int) error {
|
||||||
// TODO: use o.String()
|
list = append(list, o)
|
||||||
sb.WriteString(fmt.Sprint(o))
|
|
||||||
return nil
|
return nil
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return strObject(sb.String()), nil
|
return list, nil
|
||||||
}
|
}
|
||||||
return pipelineRes, nil
|
return pipelineRes, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,13 @@ func New(opts ...InstOption) *Inst {
|
||||||
rootEC.addCmd("echo", invokableFunc(echoBuiltin))
|
rootEC.addCmd("echo", invokableFunc(echoBuiltin))
|
||||||
rootEC.addCmd("set", invokableFunc(setBuiltin))
|
rootEC.addCmd("set", invokableFunc(setBuiltin))
|
||||||
rootEC.addCmd("toUpper", invokableStreamFunc(toUpperBuiltin))
|
rootEC.addCmd("toUpper", invokableStreamFunc(toUpperBuiltin))
|
||||||
rootEC.addCmd("cat", invokableFunc(catBuiltin))
|
//rootEC.addCmd("cat", invokableFunc(catBuiltin))
|
||||||
rootEC.addCmd("call", invokableFunc(callBuiltin))
|
rootEC.addCmd("call", invokableFunc(callBuiltin))
|
||||||
|
|
||||||
|
rootEC.addCmd("map", invokableStreamFunc(mapBuiltin))
|
||||||
|
|
||||||
|
rootEC.addCmd("cat", invokableFunc(concatBuiltin))
|
||||||
|
|
||||||
rootEC.addMacro("if", macroFunc(ifBuiltin))
|
rootEC.addMacro("if", macroFunc(ifBuiltin))
|
||||||
rootEC.addMacro("foreach", macroFunc(foreachBuiltin))
|
rootEC.addMacro("foreach", macroFunc(foreachBuiltin))
|
||||||
rootEC.addMacro("proc", macroFunc(procBuiltin))
|
rootEC.addMacro("proc", macroFunc(procBuiltin))
|
||||||
|
|
|
@ -172,6 +172,25 @@ type invocationArgs struct {
|
||||||
kwargs map[string]*listObject
|
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 {
|
func (ia invocationArgs) expectArgn(x int) error {
|
||||||
if len(ia.args) < x {
|
if len(ia.args) < x {
|
||||||
return errors.New("expected at least " + strconv.Itoa(x) + " args")
|
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
|
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 {
|
func (ia invocationArgs) shift(i int) invocationArgs {
|
||||||
return invocationArgs{
|
return invocationArgs{
|
||||||
inst: ia.inst,
|
inst: ia.inst,
|
||||||
|
|
|
@ -116,7 +116,7 @@ func (s *listIterStream) close() error { return nil }
|
||||||
|
|
||||||
type mapFilterStream struct {
|
type mapFilterStream struct {
|
||||||
in stream
|
in stream
|
||||||
mapFn func(x object) (object, bool)
|
mapFn func(x object) (object, bool, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms mapFilterStream) String() string {
|
func (ms mapFilterStream) String() string {
|
||||||
|
@ -134,8 +134,10 @@ func (ms mapFilterStream) next() (object, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
t, ok := ms.mapFn(u)
|
t, ok, err := ms.mapFn(u)
|
||||||
if ok {
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else if ok {
|
||||||
return t, nil
|
return t, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue