2024-04-14 12:09:13 +00:00
|
|
|
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 {
|
2024-04-17 10:43:25 +00:00
|
|
|
if err := bindArg(v, ca.args.args[i]); err != nil {
|
|
|
|
return err
|
2024-04-14 12:09:13 +00:00
|
|
|
}
|
2024-04-17 10:43:25 +00:00
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (ca CallArgs) HasSwitch(name string) bool {
|
|
|
|
if ca.args.kwargs == nil {
|
|
|
|
return false
|
|
|
|
}
|
2024-04-14 12:09:13 +00:00
|
|
|
|
2024-04-17 10:43:25 +00:00
|
|
|
_, ok := ca.args.kwargs[name]
|
|
|
|
return ok
|
|
|
|
}
|
2024-04-14 12:09:13 +00:00
|
|
|
|
2024-04-17 10:43:25 +00:00
|
|
|
func (ca CallArgs) BindSwitch(name string, val interface{}) error {
|
|
|
|
if ca.args.kwargs == nil {
|
|
|
|
return nil
|
|
|
|
}
|
2024-04-14 12:09:13 +00:00
|
|
|
|
2024-04-17 10:43:25 +00:00
|
|
|
vars, ok := ca.args.kwargs[name]
|
|
|
|
if !ok || len(*vars) != 1 {
|
|
|
|
return nil
|
2024-04-14 12:09:13 +00:00
|
|
|
}
|
2024-04-17 10:43:25 +00:00
|
|
|
|
|
|
|
return bindArg(val, (*vars)[0])
|
2024-04-14 12:09:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
}
|
2024-04-17 10:43:25 +00:00
|
|
|
|
|
|
|
func bindArg(v interface{}, arg object) error {
|
|
|
|
switch t := v.(type) {
|
|
|
|
case *string:
|
|
|
|
*t = arg.String()
|
|
|
|
}
|
|
|
|
|
2024-04-24 11:09:52 +00:00
|
|
|
switch t := arg.(type) {
|
|
|
|
case proxyObject:
|
|
|
|
return bindProxyObject(v, reflect.ValueOf(t.p))
|
|
|
|
case listableProxyObject:
|
|
|
|
return bindProxyObject(v, t.v)
|
|
|
|
case structProxyObject:
|
|
|
|
return bindProxyObject(v, t.v)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2024-04-17 10:43:25 +00:00
|
|
|
|
2024-04-24 11:09:52 +00:00
|
|
|
func bindProxyObject(v interface{}, r reflect.Value) error {
|
|
|
|
argValue := reflect.ValueOf(v)
|
|
|
|
if argValue.Kind() != reflect.Ptr {
|
|
|
|
return errors.New("v must be a pointer to a struct")
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
if r.Type().AssignableTo(argValue.Elem().Type()) {
|
|
|
|
argValue.Elem().Set(r)
|
2024-04-17 10:43:25 +00:00
|
|
|
return nil
|
2024-04-24 11:09:52 +00:00
|
|
|
}
|
|
|
|
if r.Type().Kind() != reflect.Pointer {
|
2024-04-17 10:43:25 +00:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2024-04-24 11:09:52 +00:00
|
|
|
r = r.Elem()
|
2024-04-17 10:43:25 +00:00
|
|
|
}
|
|
|
|
}
|