Started working on placeholders
This commit is contained in:
parent
3b3bac4a7f
commit
fd177280d2
|
@ -11,7 +11,8 @@ type astLiteral struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type astCmdArg struct {
|
type astCmdArg struct {
|
||||||
Literal astLiteral `parser:"@@"`
|
Literal *astLiteral `parser:"@@"`
|
||||||
|
Sub *astPipeline `parser:"| '[' @@ ']'"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type astCmd struct {
|
type astCmd struct {
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -16,7 +17,9 @@ func echoBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
|
|
||||||
var line strings.Builder
|
var line strings.Builder
|
||||||
for _, arg := range args.args {
|
for _, arg := range args.args {
|
||||||
line.WriteString(arg)
|
if s, ok := arg.(fmt.Stringer); ok {
|
||||||
|
line.WriteString(s.String())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return asStream(line.String()), nil
|
return asStream(line.String()), nil
|
||||||
|
@ -41,7 +44,12 @@ func catBuiltin(ctx context.Context, args invocationArgs) (object, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return &fileLinesStream{filename: args.args[0]}, nil
|
filename, err := args.stringArg(0)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &fileLinesStream{filename: filename}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type fileLinesStream struct {
|
type fileLinesStream struct {
|
||||||
|
|
|
@ -3,8 +3,10 @@ package cmdlang
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"github.com/lmika/gopkgs/fp/slices"
|
"github.com/lmika/gopkgs/fp/slices"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
type evaluator struct {
|
type evaluator struct {
|
||||||
|
@ -36,7 +38,7 @@ func (e evaluator) evalCmd(ctx context.Context, ec *evalCtx, ast *astCmd) (objec
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
args, err := slices.MapWithError(ast.Args, func(a astCmdArg) (string, error) {
|
args, err := slices.MapWithError(ast.Args, func(a astCmdArg) (object, error) {
|
||||||
return e.evalArg(ctx, ec, a)
|
return e.evalArg(ctx, ec, a)
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -49,20 +51,49 @@ func (e evaluator) evalCmd(ctx context.Context, ec *evalCtx, ast *astCmd) (objec
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (string, error) {
|
func (e evaluator) evalArg(ctx context.Context, ec *evalCtx, n astCmdArg) (object, error) {
|
||||||
|
switch {
|
||||||
|
case n.Literal != nil:
|
||||||
return e.evalLiteral(ctx, ec, n.Literal)
|
return e.evalLiteral(ctx, ec, n.Literal)
|
||||||
|
case n.Sub != nil:
|
||||||
|
return e.evalSub(ctx, ec, n.Sub)
|
||||||
|
}
|
||||||
|
return nil, errors.New("unhandled arg type")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e evaluator) evalLiteral(ctx context.Context, ec *evalCtx, n astLiteral) (string, error) {
|
func (e evaluator) evalLiteral(ctx context.Context, ec *evalCtx, n *astLiteral) (object, error) {
|
||||||
switch {
|
switch {
|
||||||
case n.Str != nil:
|
case n.Str != nil:
|
||||||
uq, err := strconv.Unquote(*n.Str)
|
uq, err := strconv.Unquote(*n.Str)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
return uq, nil
|
return strObject(uq), nil
|
||||||
case n.Ident != nil:
|
case n.Ident != nil:
|
||||||
return *n.Ident, nil
|
return strObject(*n.Ident), nil
|
||||||
}
|
}
|
||||||
return "", errors.New("unhandled literal type")
|
return "", errors.New("unhandled literal type")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e evaluator) evalSub(ctx context.Context, ec *evalCtx, n *astPipeline) (object, error) {
|
||||||
|
pipelineRes, err := e.evaluate(ctx, ec, n)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
switch v := pipelineRes.(type) {
|
||||||
|
case stream:
|
||||||
|
// TODO: use proper lists here, not a string join
|
||||||
|
sb := strings.Builder{}
|
||||||
|
if err := forEach(v, func(o object) error {
|
||||||
|
// TODO: use o.String()
|
||||||
|
sb.WriteString(fmt.Sprint(o))
|
||||||
|
return nil
|
||||||
|
}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return strObject(sb.String()), nil
|
||||||
|
}
|
||||||
|
return pipelineRes, nil
|
||||||
|
}
|
||||||
|
|
|
@ -3,13 +3,21 @@ package cmdlang
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
type object = any
|
type object interface {
|
||||||
|
}
|
||||||
|
|
||||||
|
type strObject string
|
||||||
|
|
||||||
|
func (s strObject) String() string {
|
||||||
|
return string(s)
|
||||||
|
}
|
||||||
|
|
||||||
type invocationArgs struct {
|
type invocationArgs struct {
|
||||||
args []string
|
args []object
|
||||||
inStream stream
|
inStream stream
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +28,17 @@ func (ia invocationArgs) expectArgn(x int) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ia invocationArgs) stringArg(i int) (string, error) {
|
||||||
|
if len(ia.args) < i {
|
||||||
|
return "", errors.New("expected at least " + strconv.Itoa(i) + " args")
|
||||||
|
}
|
||||||
|
s, ok := ia.args[i].(fmt.Stringer)
|
||||||
|
if !ok {
|
||||||
|
return "", errors.New("expected a string arg")
|
||||||
|
}
|
||||||
|
return s.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
// invokable is an object that can be executed as a command
|
// invokable is an object that can be executed as a command
|
||||||
type invokable interface {
|
type invokable interface {
|
||||||
invoke(ctx context.Context, args invocationArgs) (object, error)
|
invoke(ctx context.Context, args invocationArgs) (object, error)
|
||||||
|
|
Loading…
Reference in a new issue