package cmdlang import ( "context" "errors" "reflect" ) type CallArgs struct { args invocationArgs } func (ca CallArgs) Bind(vars ...interface{}) error { if len(ca.args.args) != len(vars) { return errors.New("wrong number of arguments") } for i, v := range vars { if err := bindArg(v, ca.args.args[i]); err != nil { return err } } return nil } func (ca CallArgs) HasSwitch(name string) bool { if ca.args.kwargs == nil { return false } _, ok := ca.args.kwargs[name] return ok } func (ca CallArgs) BindSwitch(name string, val interface{}) error { if ca.args.kwargs == nil { return nil } vars, ok := ca.args.kwargs[name] if !ok || len(*vars) != 1 { return nil } return bindArg(val, (*vars)[0]) } func (inst *Inst) SetBuiltin(name string, fn func(ctx context.Context, args CallArgs) (any, error)) { inst.rootEC.addCmd(name, userBuiltin{fn: fn}) } type userBuiltin struct { fn func(ctx context.Context, args CallArgs) (any, error) } func (u userBuiltin) invoke(ctx context.Context, args invocationArgs) (object, error) { v, err := u.fn(ctx, CallArgs{args: args}) if err != nil { return nil, err } return fromGoValue(v) } func bindArg(v interface{}, arg object) error { switch t := v.(type) { case *string: *t = arg.String() } // Check for proxy object if po, ok := arg.(proxyObject); ok { poValue := reflect.ValueOf(po.p) argValue := reflect.ValueOf(v) if argValue.Type().Kind() != reflect.Pointer { return nil } else if !poValue.Type().AssignableTo(argValue.Elem().Type()) { return nil } argValue.Elem().Set(poValue) } return nil }