github.com/xyproto/u-root@v6.0.1-0.20200302025726-5528e0c77a3c+incompatible/cmds/core/elvish/eval/builtin_fn.go (about) 1 package eval 2 3 import ( 4 "errors" 5 "fmt" 6 "reflect" 7 "strings" 8 9 "github.com/u-root/u-root/cmds/core/elvish/eval/vals" 10 "github.com/u-root/u-root/cmds/core/elvish/hash" 11 ) 12 13 var ErrArgs = errors.New("args error") 14 15 // BuiltinFn uses reflection to wrap Go functions into Elvish functions. 16 // Functions with simple signatures are handled by commonCallable, 17 // more elaborate cases are handled by CustomCallable interface, e.g. 18 // when importing the necessary types would have created a dependency loop. 19 // 20 // Parameters are converted using ScanToGo. 21 // 22 // Return values go to the channel part of the stdout port, after being 23 // converted using goToElv. If the last return value has type error and is not 24 // nil, it is turned into an exception and no ouputting happens. If the last 25 // return value is a nil error, it is ignored. 26 // 27 // Note: reflect.Call is deliberately not used as it disables DCE 28 // (see https://github.com/u-root/u-root/issues/1477). 29 type BuiltinFn struct { 30 name string 31 impl CustomCallable 32 33 // Type information of impl. 34 35 frame bool 36 options bool 37 inputs bool 38 // Type of "normal" (non-Frame, non-Options, non-variadic) arguments. 39 normalArgs []reflect.Type 40 // Type of variadic arguments, nil if function is non-variadic 41 variadicArg reflect.Type 42 } 43 44 var _ Callable = &BuiltinFn{} 45 46 // CustomCallable is an interface for functions that have complex signatures 47 // not covered by commonCallable. 48 type CustomCallable interface { 49 // Target returns the callable's target function, needed to examine arguments. 50 Target() interface{} 51 // Call invokes the target function. 52 Call(f *Frame, args []interface{}, opts RawOptions, inputs Inputs) ([]interface{}, error) 53 } 54 55 type ( 56 Inputs func(func(interface{})) 57 ) 58 59 var ( 60 frameType = reflect.TypeOf((*Frame)(nil)) 61 rawOptionsType = reflect.TypeOf(RawOptions(nil)) 62 inputsType = reflect.TypeOf(Inputs(nil)) 63 ) 64 65 // NewBuiltinFnCustom creates a new ReflectBuiltinFn instance. 66 func NewBuiltinFnCustom(name string, impl CustomCallable) *BuiltinFn { 67 implType := reflect.TypeOf(impl.Target()) 68 b := &BuiltinFn{name: name, impl: impl} 69 70 i := 0 71 if i < implType.NumIn() && implType.In(i) == frameType { 72 b.frame = true 73 i++ 74 } 75 if i < implType.NumIn() && implType.In(i) == rawOptionsType { 76 b.options = true 77 i++ 78 } 79 for ; i < implType.NumIn(); i++ { 80 paramType := implType.In(i) 81 if i == implType.NumIn()-1 { 82 if implType.IsVariadic() { 83 b.variadicArg = paramType.Elem() 84 break 85 } else if paramType == inputsType { 86 b.inputs = true 87 break 88 } 89 } 90 b.normalArgs = append(b.normalArgs, paramType) 91 } 92 return b 93 } 94 95 // NewBuiltinFn creates a new ReflectBuiltinFn instance. 96 func NewBuiltinFn(name string, impl interface{}) *BuiltinFn { 97 if _, err := callFunc(impl, nil, nil, nil, nil, true); err != nil { 98 panic(fmt.Sprintf("%s: %v", name, err)) 99 } 100 return NewBuiltinFnCustom(name, &commonCallable{target: impl}) 101 } 102 103 // Kind returns "fn". 104 func (*BuiltinFn) Kind() string { 105 return "fn" 106 } 107 108 // Equal compares identity. 109 func (b *BuiltinFn) Equal(rhs interface{}) bool { 110 return b == rhs 111 } 112 113 // Hash hashes the address. 114 func (b *BuiltinFn) Hash() uint32 { 115 return hash.Hash(b) 116 } 117 118 // Repr returns an opaque representation "<builtin $name>". 119 func (b *BuiltinFn) Repr(int) string { 120 return "<builtin " + b.name + ">" 121 } 122 123 // error(nil) is treated as nil by reflect.TypeOf, so we first get the type of 124 // *error and use Elem to obtain type of error. 125 var errorType = reflect.TypeOf((*error)(nil)).Elem() 126 127 var errNoOptions = errors.New("function does not accept any options") 128 129 // Call calls the implementation using reflection. 130 func (b *BuiltinFn) Call(f *Frame, args []interface{}, opts map[string]interface{}) error { 131 if b.variadicArg != nil { 132 if len(args) < len(b.normalArgs) { 133 return fmt.Errorf("%s: want %d or more arguments, got %d", 134 b.name, len(b.normalArgs), len(args)) 135 } 136 } else if b.inputs { 137 if len(args) != len(b.normalArgs) && len(args) != len(b.normalArgs)+1 { 138 return fmt.Errorf("%s: want %d or %d arguments, got %d", 139 b.name, len(b.normalArgs), len(b.normalArgs)+1, len(args)) 140 } 141 } else if len(args) != len(b.normalArgs) { 142 return fmt.Errorf("%s: want %d arguments, got %d", b.name, len(b.normalArgs), len(args)) 143 } 144 if !b.options && len(opts) > 0 { 145 return errNoOptions 146 } 147 148 var goArgs []interface{} 149 for i, arg := range args { 150 var typ reflect.Type 151 if i < len(b.normalArgs) { 152 typ = b.normalArgs[i] 153 } else if b.variadicArg != nil { 154 typ = b.variadicArg 155 } else if b.inputs { 156 break // Handled after the loop 157 } else { 158 panic("impossible") 159 } 160 ptr := reflect.New(typ) 161 err := vals.ScanToGo(arg, ptr.Interface()) 162 if err != nil { 163 return fmt.Errorf("%s: wrong type of %d'th argument: %v", b.name, i+1, err) 164 } 165 goArgs = append(goArgs, ptr.Elem().Interface()) 166 } 167 168 var inputs Inputs 169 if b.inputs { 170 if len(args) == len(b.normalArgs) { 171 inputs = Inputs(f.IterateInputs) 172 } else { 173 // Wrap an iterable argument in Inputs. 174 iterable := args[len(args)-1] 175 inputs = Inputs(func(f func(interface{})) { 176 err := vals.Iterate(iterable, func(v interface{}) bool { 177 f(v) 178 return true 179 }) 180 maybeThrow(err) 181 }) 182 } 183 } 184 185 outs, err := b.impl.Call(f, goArgs, opts, inputs) 186 if err != nil { 187 return err 188 } 189 for _, out := range outs { 190 f.OutputChan() <- vals.FromGo(out) 191 } 192 return nil 193 } 194 195 type commonCallable struct { 196 target interface{} 197 } 198 199 func (c *commonCallable) Target() interface{} { 200 return c.target 201 } 202 203 func (c *commonCallable) Call( 204 f *Frame, args []interface{}, opts RawOptions, inputs Inputs) ([]interface{}, error) { 205 return callFunc(c.target, f, args, opts, inputs, false) 206 } 207 208 func callFunc(fnp interface{}, f *Frame, args []interface{}, opts RawOptions, inputs Inputs, checkOnly bool) ([]interface{}, error) { 209 switch fn := fnp.(type) { 210 case func(): 211 if checkOnly { 212 return nil, nil 213 } 214 fn() 215 return nil, nil 216 217 case func() error: 218 if checkOnly { 219 return nil, nil 220 } 221 err := fn() 222 return nil, err 223 224 case func() int: 225 if checkOnly { 226 return nil, nil 227 } 228 out := fn() 229 return []interface{}{out}, nil 230 231 case func(*Frame): 232 if checkOnly { 233 return nil, nil 234 } 235 fn(f) 236 return nil, nil 237 238 case func(*Frame, RawOptions): 239 if checkOnly { 240 return nil, nil 241 } 242 fn(f, opts) 243 return nil, nil 244 245 case func(*Frame, RawOptions, Callable, Callable): 246 if checkOnly { 247 return nil, nil 248 } 249 fn(f, opts, args[0].(Callable), args[1].(Callable)) 250 return nil, nil 251 252 case func(*Frame, RawOptions, string, Inputs): 253 if checkOnly { 254 return nil, nil 255 } 256 fn(f, opts, args[0].(string), inputs) 257 return nil, nil 258 259 case func(*Frame, ...int): 260 if checkOnly { 261 return nil, nil 262 } 263 var vargs []int 264 for _, arg := range args { 265 vargs = append(vargs, arg.(int)) 266 } 267 fn(f, vargs...) 268 return nil, nil 269 270 case func(*Frame, ...interface{}) error: 271 if checkOnly { 272 return nil, nil 273 } 274 err := fn(f, args...) 275 return nil, err 276 277 case func(*Frame, interface{}, interface{}, interface{}): 278 if checkOnly { 279 return nil, nil 280 } 281 fn(f, args[0], args[1], args[2]) 282 return nil, nil 283 284 case func(*Frame, ...int) error: 285 if checkOnly { 286 return nil, nil 287 } 288 var vargs []int 289 for _, arg := range args { 290 vargs = append(vargs, arg.(int)) 291 } 292 err := fn(f, vargs...) 293 return nil, err 294 295 case func(*Frame, ...string) error: 296 if checkOnly { 297 return nil, nil 298 } 299 var vargs []string 300 for _, arg := range args { 301 vargs = append(vargs, arg.(string)) 302 } 303 err := fn(f, vargs...) 304 return nil, err 305 306 case func(*Frame, string): 307 if checkOnly { 308 return nil, nil 309 } 310 fn(f, args[0].(string)) 311 return nil, nil 312 313 case func(*Frame, string) error: 314 if checkOnly { 315 return nil, nil 316 } 317 err := fn(f, args[0].(string)) 318 return nil, err 319 320 case func(Inputs): 321 if checkOnly { 322 return nil, nil 323 } 324 fn(inputs) 325 return nil, nil 326 327 case func(RawOptions): 328 if checkOnly { 329 return nil, nil 330 } 331 fn(opts) 332 return nil, nil 333 334 case func(RawOptions, ...interface{}): 335 if checkOnly { 336 return nil, nil 337 } 338 fn(opts, args...) 339 return nil, nil 340 341 case func(int, float64): 342 if checkOnly { 343 return nil, nil 344 } 345 fn(args[0].(int), args[1].(float64)) 346 return nil, nil 347 348 case func(...int) error: 349 if checkOnly { 350 return nil, nil 351 } 352 var vargs []int 353 for _, arg := range args { 354 vargs = append(vargs, arg.(int)) 355 } 356 err := fn(vargs...) 357 return nil, err 358 359 case func(float64): 360 if checkOnly { 361 return nil, nil 362 } 363 fn(args[0].(float64)) 364 return nil, nil 365 366 case func(int): 367 if checkOnly { 368 return nil, nil 369 } 370 fn(args[0].(int)) 371 return nil, nil 372 373 case func(string): 374 if checkOnly { 375 return nil, nil 376 } 377 fn(args[0].(string)) 378 return nil, nil 379 380 case func(string) string: 381 if checkOnly { 382 return nil, nil 383 } 384 out := fn(args[0].(string)) 385 return []interface{}{out}, nil 386 387 case func(string, ...string): 388 if checkOnly { 389 return nil, nil 390 } 391 var vargs []string 392 for _, arg := range args[1:] { 393 vargs = append(vargs, arg.(string)) 394 } 395 fn(args[0].(string), vargs...) 396 return nil, nil 397 } 398 399 sig := fmt.Sprintf("%#v", fnp)[1:] 400 sig = sig[:strings.LastIndex(sig, "(")-1] 401 return nil, fmt.Errorf("unsupported function signature: %s", sig) 402 }