package cmdlang import ( "context" "errors" "fmt" "strconv" ) type object interface { String() string } type strObject string func (s strObject) String() string { return string(s) } func toGoValue(obj object) (interface{}, bool) { switch v := obj.(type) { case nil: return nil, true case strObject: return string(v), true } return nil, false } type invocationArgs struct { inst *Inst ec *evalCtx currentStream stream args []object } func (ia invocationArgs) expectArgn(x int) error { if len(ia.args) < x { return errors.New("expected at least " + strconv.Itoa(x) + " args") } 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 type invokable interface { invoke(ctx context.Context, args invocationArgs) (object, error) } type streamInvokable interface { invokable invokeWithStream(context.Context, stream, invocationArgs) (object, error) } type invokableFunc func(ctx context.Context, args invocationArgs) (object, error) func (i invokableFunc) invoke(ctx context.Context, args invocationArgs) (object, error) { return i(ctx, args) } type invokableStreamFunc func(ctx context.Context, inStream stream, args invocationArgs) (object, error) func (i invokableStreamFunc) invoke(ctx context.Context, args invocationArgs) (object, error) { return i(ctx, nil, args) } func (i invokableStreamFunc) invokeWithStream(ctx context.Context, inStream stream, args invocationArgs) (object, error) { return i(ctx, inStream, args) }