github.com/mattn/anko@v0.1.10/vm/vmExprFunction.go (about) 1 package vm 2 3 import ( 4 "context" 5 "fmt" 6 "reflect" 7 8 "github.com/mattn/anko/ast" 9 ) 10 11 // funcExpr creates a function that reflect Call can use. 12 // When called, it will run runVMFunction, to run the function statements 13 func (runInfo *runInfoStruct) funcExpr() { 14 funcExpr := runInfo.expr.(*ast.FuncExpr) 15 16 // create the inTypes needed by reflect.FuncOf 17 inTypes := make([]reflect.Type, len(funcExpr.Params)+1) 18 // for runVMFunction first arg is always context 19 inTypes[0] = contextType 20 for i := 1; i < len(inTypes); i++ { 21 inTypes[i] = reflectValueType 22 } 23 if funcExpr.VarArg { 24 inTypes[len(inTypes)-1] = interfaceSliceType 25 } 26 // create funcType, output is always slice of reflect.Type with two values 27 funcType := reflect.FuncOf(inTypes, []reflect.Type{reflectValueType, reflectValueType}, funcExpr.VarArg) 28 29 // for adding env into saved function 30 envFunc := runInfo.env 31 32 // create a function that can be used by reflect.MakeFunc 33 // this function is a translator that converts a function call into a vm run 34 // returns slice of reflect.Type with two values: 35 // return value of the function and error value of the run 36 runVMFunction := func(in []reflect.Value) []reflect.Value { 37 runInfo := runInfoStruct{ctx: in[0].Interface().(context.Context), options: runInfo.options, env: envFunc.NewEnv(), stmt: funcExpr.Stmt, rv: nilValue} 38 39 // add Params to newEnv, except last Params 40 for i := 0; i < len(funcExpr.Params)-1; i++ { 41 runInfo.rv = in[i+1].Interface().(reflect.Value) 42 runInfo.env.DefineValue(funcExpr.Params[i], runInfo.rv) 43 } 44 // add last Params to newEnv 45 if len(funcExpr.Params) > 0 { 46 if funcExpr.VarArg { 47 // function is variadic, add last Params to newEnv without convert to Interface and then reflect.Value 48 runInfo.rv = in[len(funcExpr.Params)] 49 runInfo.env.DefineValue(funcExpr.Params[len(funcExpr.Params)-1], runInfo.rv) 50 } else { 51 // function is not variadic, add last Params to newEnv 52 runInfo.rv = in[len(funcExpr.Params)].Interface().(reflect.Value) 53 runInfo.env.DefineValue(funcExpr.Params[len(funcExpr.Params)-1], runInfo.rv) 54 } 55 } 56 57 // run function statements 58 runInfo.runSingleStmt() 59 if runInfo.err != nil && runInfo.err != ErrReturn { 60 runInfo.err = newError(funcExpr, runInfo.err) 61 // return nil value and error 62 // need to do single reflect.ValueOf because nilValue is already reflect.Value of nil 63 // need to do double reflect.ValueOf of newError in order to match 64 return []reflect.Value{reflectValueNilValue, reflect.ValueOf(reflect.ValueOf(newError(funcExpr, runInfo.err)))} 65 } 66 67 // the reflect.ValueOf of rv is needed to work in the reflect.Value slice 68 // reflectValueErrorNilValue is already a double reflect.ValueOf 69 return []reflect.Value{reflect.ValueOf(runInfo.rv), reflectValueErrorNilValue} 70 } 71 72 // make the reflect.Value function that calls runVMFunction 73 runInfo.rv = reflect.MakeFunc(funcType, runVMFunction) 74 75 // if function name is not empty, define it in the env 76 if funcExpr.Name != "" { 77 runInfo.env.DefineValue(funcExpr.Name, runInfo.rv) 78 } 79 } 80 81 // anonCallExpr handles ast.AnonCallExpr which calls a function anonymously 82 func (runInfo *runInfoStruct) anonCallExpr() { 83 anonCallExpr := runInfo.expr.(*ast.AnonCallExpr) 84 85 runInfo.expr = anonCallExpr.Expr 86 runInfo.expr.SetPosition(anonCallExpr.Expr.Position()) 87 runInfo.invokeExpr() 88 if runInfo.err != nil { 89 return 90 } 91 92 if runInfo.rv.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 93 runInfo.rv = runInfo.rv.Elem() 94 } 95 if runInfo.rv.Kind() != reflect.Func { 96 runInfo.err = newStringError(anonCallExpr, "cannot call type "+runInfo.rv.Kind().String()) 97 runInfo.rv = nilValue 98 return 99 } 100 101 runInfo.expr = &ast.CallExpr{Func: runInfo.rv, SubExprs: anonCallExpr.SubExprs, VarArg: anonCallExpr.VarArg, Go: anonCallExpr.Go} 102 runInfo.expr.SetPosition(anonCallExpr.Expr.Position()) 103 runInfo.invokeExpr() 104 } 105 106 // callExpr handles *ast.CallExpr which calls a function 107 func (runInfo *runInfoStruct) callExpr() { 108 // Note that if the function type looks the same as the VM function type, the returned values will probably be wrong 109 110 callExpr := runInfo.expr.(*ast.CallExpr) 111 112 f := callExpr.Func 113 if !f.IsValid() { 114 // if function is not valid try to get by function name 115 f, runInfo.err = runInfo.env.GetValue(callExpr.Name) 116 if runInfo.err != nil { 117 runInfo.err = newError(callExpr, runInfo.err) 118 runInfo.rv = nilValue 119 return 120 } 121 } 122 123 if f.Kind() == reflect.Interface && !f.IsNil() { 124 f = f.Elem() 125 } 126 if f.Kind() != reflect.Func { 127 runInfo.err = newStringError(callExpr, "cannot call type "+f.Kind().String()) 128 runInfo.rv = nilValue 129 return 130 } 131 132 var rvs []reflect.Value 133 var args []reflect.Value 134 var useCallSlice bool 135 fType := f.Type() 136 // check if this is a runVMFunction type 137 isRunVMFunction := checkIfRunVMFunction(fType) 138 // create/convert the args to the function 139 args, useCallSlice = runInfo.makeCallArgs(fType, isRunVMFunction, callExpr) 140 if runInfo.err != nil { 141 return 142 } 143 144 if !runInfo.options.Debug { 145 // captures panic 146 defer recoverFunc(runInfo) 147 } 148 149 runInfo.rv = nilValue 150 151 // useCallSlice lets us know to use CallSlice instead of Call because of the format of the args 152 if useCallSlice { 153 if callExpr.Go { 154 go f.CallSlice(args) 155 return 156 } 157 rvs = f.CallSlice(args) 158 } else { 159 if callExpr.Go { 160 go f.Call(args) 161 return 162 } 163 rvs = f.Call(args) 164 } 165 166 // TOFIX: how VM pointers/addressing work 167 // Until then, this is a work around to set pointers back to VM variables 168 // This will probably panic for some functions and/or calls that are variadic 169 if !isRunVMFunction { 170 for i, expr := range callExpr.SubExprs { 171 if addrExpr, ok := expr.(*ast.AddrExpr); ok { 172 if identExpr, ok := addrExpr.Expr.(*ast.IdentExpr); ok { 173 runInfo.rv = args[i].Elem() 174 runInfo.expr = identExpr 175 runInfo.invokeLetExpr() 176 } 177 } 178 } 179 } 180 181 // processCallReturnValues to get/convert return values to normal rv form 182 runInfo.rv, runInfo.err = processCallReturnValues(rvs, isRunVMFunction, true) 183 } 184 185 // checkIfRunVMFunction checking the number and types of the reflect.Type. 186 // If it matches the types for a runVMFunction this will return true, otherwise false 187 func checkIfRunVMFunction(rt reflect.Type) bool { 188 if rt.NumIn() < 1 || rt.NumOut() != 2 || rt.In(0) != contextType || rt.Out(0) != reflectValueType || rt.Out(1) != reflectValueType { 189 return false 190 } 191 if rt.NumIn() > 1 { 192 if rt.IsVariadic() { 193 if rt.In(rt.NumIn()-1) != interfaceSliceType { 194 return false 195 } 196 } else { 197 if rt.In(rt.NumIn()-1) != reflectValueType { 198 return false 199 } 200 } 201 for i := 1; i < rt.NumIn()-1; i++ { 202 if rt.In(i) != reflectValueType { 203 return false 204 } 205 } 206 } 207 return true 208 } 209 210 // makeCallArgs creates the arguments reflect.Value slice for the four different kinds of functions. 211 // Also returns true if CallSlice should be used on the arguments, or false if Call should be used. 212 func (runInfo *runInfoStruct) makeCallArgs(rt reflect.Type, isRunVMFunction bool, callExpr *ast.CallExpr) ([]reflect.Value, bool) { 213 // number of arguments 214 numInReal := rt.NumIn() 215 numIn := numInReal 216 if isRunVMFunction { 217 // for runVMFunction the first arg is context so does not count against number of SubExprs 218 numIn-- 219 } 220 if numIn < 1 { 221 // no arguments needed 222 if isRunVMFunction { 223 // for runVMFunction first arg is always context 224 return []reflect.Value{reflect.ValueOf(runInfo.ctx)}, false 225 } 226 return []reflect.Value{}, false 227 } 228 229 // number of expressions 230 numExprs := len(callExpr.SubExprs) 231 // checks to short circuit wrong number of arguments 232 if (!rt.IsVariadic() && !callExpr.VarArg && numIn != numExprs) || 233 (rt.IsVariadic() && callExpr.VarArg && (numIn < numExprs || numIn > numExprs+1)) || 234 (rt.IsVariadic() && !callExpr.VarArg && numIn > numExprs+1) || 235 (!rt.IsVariadic() && callExpr.VarArg && numIn < numExprs) { 236 runInfo.err = newStringError(callExpr, fmt.Sprintf("function wants %v arguments but received %v", numIn, numExprs)) 237 runInfo.rv = nilValue 238 return nil, false 239 } 240 if rt.IsVariadic() && rt.In(numInReal-1).Kind() != reflect.Slice && rt.In(numInReal-1).Kind() != reflect.Array { 241 runInfo.err = newStringError(callExpr, "function is variadic but last parameter is of type "+rt.In(numInReal-1).String()) 242 runInfo.rv = nilValue 243 return nil, false 244 } 245 246 var args []reflect.Value 247 indexIn := 0 248 indexInReal := 0 249 indexExpr := 0 250 251 if numInReal > numExprs { 252 args = make([]reflect.Value, 0, numInReal) 253 } else { 254 args = make([]reflect.Value, 0, numExprs) 255 } 256 if isRunVMFunction { 257 // for runVMFunction first arg is always context 258 args = append(args, reflect.ValueOf(runInfo.ctx)) 259 indexInReal++ 260 } 261 262 // create arguments except the last one 263 for indexInReal < numInReal-1 && indexExpr < numExprs-1 { 264 runInfo.expr = callExpr.SubExprs[indexExpr] 265 runInfo.invokeExpr() 266 if runInfo.err != nil { 267 return nil, false 268 } 269 if isRunVMFunction { 270 args = append(args, reflect.ValueOf(runInfo.rv)) 271 } else { 272 runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, rt.In(indexInReal)) 273 if runInfo.err != nil { 274 runInfo.err = newStringError(callExpr.SubExprs[indexExpr], 275 "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) 276 runInfo.rv = nilValue 277 return nil, false 278 } 279 args = append(args, runInfo.rv) 280 } 281 indexIn++ 282 indexInReal++ 283 indexExpr++ 284 } 285 286 if !rt.IsVariadic() && !callExpr.VarArg { 287 // function is not variadic and call is not variadic 288 // add last arguments and return 289 runInfo.expr = callExpr.SubExprs[indexExpr] 290 runInfo.invokeExpr() 291 if runInfo.err != nil { 292 return nil, false 293 } 294 if runInfo.err != nil { 295 return nil, false 296 } 297 if isRunVMFunction { 298 args = append(args, reflect.ValueOf(runInfo.rv)) 299 } else { 300 runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, rt.In(indexInReal)) 301 if runInfo.err != nil { 302 runInfo.err = newStringError(callExpr.SubExprs[indexExpr], 303 "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) 304 runInfo.rv = nilValue 305 return nil, false 306 } 307 args = append(args, runInfo.rv) 308 } 309 return args, false 310 } 311 312 if !rt.IsVariadic() && callExpr.VarArg { 313 // function is not variadic and call is variadic 314 runInfo.expr = callExpr.SubExprs[indexExpr] 315 runInfo.invokeExpr() 316 if runInfo.err != nil { 317 return nil, false 318 } 319 if runInfo.rv.Kind() != reflect.Slice && runInfo.rv.Kind() != reflect.Array { 320 runInfo.err = newStringError(callExpr, "call is variadic but last parameter is of type "+runInfo.rv.Type().String()) 321 runInfo.rv = nilValue 322 return nil, false 323 } 324 if runInfo.rv.Len() < numIn-indexIn { 325 runInfo.err = newStringError(callExpr, fmt.Sprintf("function wants %v arguments but received %v", numIn, numExprs+runInfo.rv.Len()-1)) 326 runInfo.rv = nilValue 327 return nil, false 328 } 329 330 indexSlice := 0 331 for indexInReal < numInReal { 332 if isRunVMFunction { 333 args = append(args, reflect.ValueOf(runInfo.rv.Index(indexSlice))) 334 } else { 335 runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv.Index(indexSlice), rt.In(indexInReal)) 336 if runInfo.err != nil { 337 runInfo.err = newStringError(callExpr.SubExprs[indexExpr], 338 "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) 339 runInfo.rv = nilValue 340 return nil, false 341 } 342 args = append(args, runInfo.rv) 343 } 344 indexIn++ 345 indexInReal++ 346 indexSlice++ 347 } 348 return args, false 349 } 350 351 // function is variadic and call may or may not be variadic 352 353 if indexExpr == numExprs { 354 // no more expressions, return what we have and let reflect Call handle if call is variadic or not 355 return args, false 356 } 357 358 if numIn > numExprs { 359 // there are more arguments after this one, so does not matter if call is variadic or not 360 // add the last argument then return what we have and let reflect Call handle if call is variadic or not 361 runInfo.expr = callExpr.SubExprs[indexExpr] 362 runInfo.invokeExpr() 363 if runInfo.err != nil { 364 return nil, false 365 } 366 if isRunVMFunction { 367 args = append(args, reflect.ValueOf(runInfo.rv)) 368 } else { 369 runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, rt.In(indexInReal)) 370 if runInfo.err != nil { 371 runInfo.err = newStringError(callExpr.SubExprs[indexExpr], 372 "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) 373 runInfo.rv = nilValue 374 return nil, false 375 } 376 args = append(args, runInfo.rv) 377 } 378 return args, false 379 } 380 381 if rt.IsVariadic() && !callExpr.VarArg { 382 // function is variadic and call is not variadic 383 sliceType := rt.In(numInReal - 1).Elem() 384 for indexExpr < numExprs { 385 runInfo.expr = callExpr.SubExprs[indexExpr] 386 runInfo.invokeExpr() 387 if runInfo.err != nil { 388 return nil, false 389 } 390 runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, sliceType) 391 if runInfo.err != nil { 392 runInfo.err = newStringError(callExpr.SubExprs[indexExpr], 393 "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) 394 runInfo.rv = nilValue 395 return nil, false 396 } 397 args = append(args, runInfo.rv) 398 indexExpr++ 399 } 400 return args, false 401 402 } 403 404 // function is variadic and call is variadic 405 // the only time we return CallSlice is true 406 sliceType := rt.In(numInReal - 1) 407 if sliceType.Kind() == reflect.Interface && !runInfo.rv.IsNil() { 408 sliceType = sliceType.Elem() 409 } 410 runInfo.expr = callExpr.SubExprs[indexExpr] 411 runInfo.invokeExpr() 412 if runInfo.err != nil { 413 return nil, false 414 } 415 runInfo.rv, runInfo.err = convertReflectValueToType(runInfo.rv, sliceType) 416 if runInfo.err != nil { 417 runInfo.err = newStringError(callExpr.SubExprs[indexExpr], 418 "function wants argument type "+rt.In(indexInReal).String()+" but received type "+runInfo.rv.Type().String()) 419 runInfo.rv = nilValue 420 return nil, false 421 } 422 args = append(args, runInfo.rv) 423 424 return args, true 425 } 426 427 // processCallReturnValues get/converts the values returned from a function call into our normal reflect.Value, error 428 func processCallReturnValues(rvs []reflect.Value, isRunVMFunction bool, convertToInterfaceSlice bool) (reflect.Value, error) { 429 // check if it is not runVMFunction 430 if !isRunVMFunction { 431 // the function was a Go function, convert to our normal reflect.Value, error 432 switch len(rvs) { 433 case 0: 434 // no return values so return nil reflect.Value and nil error 435 return nilValue, nil 436 case 1: 437 // one return value but need to add nil error 438 return rvs[0], nil 439 } 440 if convertToInterfaceSlice { 441 // need to convert from a slice of reflect.Value to slice of interface 442 return reflectValueSlicetoInterfaceSlice(rvs), nil 443 } 444 // need to keep as slice of reflect.Value 445 return reflect.ValueOf(rvs), nil 446 } 447 448 // is a runVMFunction, expect return in the runVMFunction format 449 // convertToInterfaceSlice is ignored 450 // some of the below checks probably can be removed because they are done in checkIfRunVMFunction 451 452 if len(rvs) != 2 { 453 return nilValue, fmt.Errorf("VM function did not return 2 values but returned %v values", len(rvs)) 454 } 455 if rvs[0].Type() != reflectValueType { 456 return nilValue, fmt.Errorf("VM function value 1 did not return reflect value type but returned %v type", rvs[0].Type().String()) 457 } 458 if rvs[1].Type() != reflectValueType { 459 return nilValue, fmt.Errorf("VM function value 2 did not return reflect value type but returned %v type", rvs[1].Type().String()) 460 } 461 462 rvError := rvs[1].Interface().(reflect.Value) 463 if rvError.Type() != errorType && rvError.Type() != vmErrorType { 464 return nilValue, fmt.Errorf("VM function error type is %v", rvError.Type()) 465 } 466 467 if rvError.IsNil() { 468 // no error, so return the normal VM reflect.Value form 469 return rvs[0].Interface().(reflect.Value), nil 470 } 471 472 // VM returns two types of errors, check to see which type 473 if rvError.Type() == vmErrorType { 474 // convert to VM *Error 475 return nilValue, rvError.Interface().(*Error) 476 } 477 // convert to error 478 return nilValue, rvError.Interface().(error) 479 }