1/* 2 * gomacro - A Go interpreter with Lisp-like macros 3 * 4 * Copyright (C) 2017-2019 Massimiliano Ghilardi 5 * 6 * This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * 11 * callnret0.go 12 * 13 * Created on Apr 15, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package fast 18 19import ( 20 r "reflect" 21 "github.com/cosmos72/gomacro/base/reflect" 22) 23 24:import ( 25 "go/ast" 26 "go/token" 27 r "reflect" 28) 29 30:func upcasefirstbyte(str string) string { 31 if len(str) > 0 && str[0] >= 'a' && str[0] <= 'z' { 32 bytes := []byte(str) 33 bytes[0] -= 'a' - 'A' 34 return string(bytes) 35 } 36 return str 37} 38 39:func makekind(typ ast.Node) ast.Node { 40 t := EvalType(typ) 41 42 // go/ast.SelectorExpr requires the foo in r.foo to be an *ast.Ident, cannot unquote there 43 kind := ~"{r . foo} 44 kind.Sel = &ast.Ident{Name: upcasefirstbyte(t.Name())} 45 return kind 46} 47 48:func convertvalue1(typ, val ast.Node) ast.Node { 49 var t r.Type = EvalType(typ) 50 if t == nil { 51 // keep the result wrapped in a reflect.Value 52 return val 53 } 54 // unwrap the result 55 tname := t.Name() 56 // remove final digits from t.Name() 57 // needed to convert Uint64 -> Uint etc. to calls reflect.Value.{tname} 58 for len(tname) != 0 { 59 ch := tname[len(tname)-1] 60 if ch < '0' || ch > '9' { 61 break 62 } 63 tname = tname[0:len(tname)-1] 64 } 65 if tname == "uintptr" { 66 tname = "uint" // use reflect.Value.Uint() 67 } 68 sel := ~"{~,val . foo} // we modify it destructively 69 sel.Sel = &ast.Ident{Name: upcasefirstbyte(tname)} 70 71 switch t.Kind() { 72 case r.Bool, r.Int64, r.Uint64, r.Float64, r.Complex128, r.String: 73 // result of reflect.Value.{tname} is already the correct type 74 val = ~"{~,sel ()} 75 default: 76 // convert int64, uint64... to the correct type 77 val = ~"{~,typ ( ~,sel () )} 78 } 79 return val 80} 81 82func (c *Comp) call0ret0(call *Call, maxdepth int) func(env *Env) { 83 expr := call.Fun 84 funsym := expr.Sym 85 if funsym == nil { 86 exprfun := expr.AsX1() 87 return func(env *Env) { 88 fun := exprfun(env).Interface().(func()) 89 fun() 90 } 91 } 92 93 var cachedfunv r.Value 94 var cachedfun func() 95 96 funupn := funsym.Upn 97 funindex := funsym.Desc.Index() 98 switch funupn { 99 case maxdepth - 1: 100 return func(env *Env) { 101 funv := env.FileEnv.Vals[funindex] 102 if cachedfunv != funv { 103 cachedfunv = funv 104 cachedfun = funv.Interface().(func()) 105 } 106 cachedfun() 107 } 108 case 0: 109 return func(env *Env) { 110 fun := env.Vals[funindex].Interface().(func()) 111 fun() 112 } 113 case 1: 114 return func(env *Env) { 115 fun := env.Outer.Vals[funindex].Interface().(func()) 116 fun() 117 } 118 case 2: 119 return func(env *Env) { 120 fun := env.Outer.Outer.Vals[funindex].Interface().(func()) 121 fun() 122 } 123 default: 124 return func(env *Env) { 125 env = env.Outer.Outer.Outer.Outer 126 for i := 3; i < funupn; i++ { 127 env = env.Outer 128 } 129 fun := env.Vals[funindex].Interface().(func()) 130 fun() 131 } 132 } 133} 134 135:macro mcall1ret0(argtyp ast.Node) ast.Node { 136 137 if EvalType(argtyp) == nil { 138 return ~"{ 139 ret = func(env *Env) { 140 funv := exprfun(env) 141 // keep the argument wrapped in a reflect.Value 142 argv := []r.Value{ 143 argfun(env), 144 } 145 callxr(funv, argv) 146 } 147 } 148 } 149 150 cachefun := ~"{ 151 if cachedfunv != funv { 152 cachedfunv = funv 153 cachedfun = funv.Interface().(func(~,argtyp)) 154 } 155 } 156 157 argconv := convertvalue1(argtyp, ~'{r.ValueOf(arg.Value)}) 158 159 return ~"{ 160 if arg.Const() { 161 argconst := ~,argconv 162 if funsym != nil && funupn == maxdepth - 1 { 163 var cachedfun func(~,argtyp) 164 ret = func(env *Env) { 165 funv := env.FileEnv.Vals[funindex] 166 ~,cachefun 167 // Debugf("calling %v with args [%v]", r.TypeOf(cachedfun), argconst) 168 cachedfun(argconst) 169 } 170 } else { 171 ret = func(env *Env) { 172 fun := exprfun(env).Interface().(func(~,argtyp)) 173 // Debugf("calling %v with args [%v]", r.TypeOf(fun), argconst) 174 fun(argconst) 175 } 176 } 177 } else { 178 argfun := arg.Fun.(func(env *Env) ~,argtyp) 179 if funsym != nil && funupn == maxdepth - 1 { 180 var cachedfun func(~,argtyp) 181 ret = func(env *Env) { 182 funv := env.FileEnv.Vals[funindex] 183 ~,cachefun 184 arg := argfun(env) 185 // Debugf("calling %v with args [%v]", r.TypeOf(cachedfun), arg) 186 cachedfun(arg) 187 } 188 } else { 189 ret = func(env *Env) { 190 fun := exprfun(env).Interface().(func(~,argtyp)) 191 arg := argfun(env) 192 // Debugf("calling %v with args [%v]", r.TypeOf(fun), arg) 193 fun(arg) 194 } 195 } 196 } 197 } 198} 199 200 201 202func (c *Comp) call1ret0(call *Call, maxdepth int) func(env *Env) { 203 expr := call.Fun 204 exprfun := expr.AsX1() 205 funsym := expr.Sym 206 funupn, funindex := -1, -1 207 if funsym != nil { 208 funupn = funsym.Upn 209 funindex = funsym.Desc.Index() 210 if funindex == NoIndex { 211 c.Errorf("internal error: call1ret0() invoked for constant function %#v. use call_builtin() instead", expr) 212 } 213 } 214 arg := call.Args[0] 215 argfun := call.MakeArgfunsX1()[0] 216 217 var cachedfunv r.Value 218 var ret func(env *Env) 219 220 t := expr.Type.In(0) 221 k := t.Kind() 222 if reflect.KindToType(k) == t.ReflectType() { 223 switch k { 224 case r.Bool: {mcall1ret0; bool} 225 case r.Int: {mcall1ret0; int} 226 case r.Int8: {mcall1ret0; int8} 227 case r.Int16: {mcall1ret0; int16} 228 case r.Int32: {mcall1ret0; int32} 229 case r.Int64: {mcall1ret0; int64} 230 case r.Uint: {mcall1ret0; uint} 231 case r.Uint8: {mcall1ret0; uint8} 232 case r.Uint16: {mcall1ret0; uint16} 233 case r.Uint32: {mcall1ret0; uint32} 234 case r.Uint64: {mcall1ret0; uint64} 235 case r.Uintptr: {mcall1ret0; uintptr} 236 case r.Float32: {mcall1ret0; float32} 237 case r.Float64: {mcall1ret0; float64} 238 case r.Complex64: {mcall1ret0; complex64} 239 case r.Complex128:{mcall1ret0; complex128} 240 case r.String: {mcall1ret0; string} 241 } 242 } 243 if ret == nil { 244 {mcall1ret0; nil} 245 } 246 return ret 247} 248 249:macro mcall2ret0(arg0typ, arg1typ ast.Node) ast.Node { 250 251 if EvalType(arg0typ) == nil || EvalType(arg1typ) == nil { 252 return ~"{ 253 ret = func(env *Env) { 254 funv := exprfun(env) 255 // keep the arguments wrapped in a reflect.Value 256 argv := []r.Value{ 257 argfuns[0](env), 258 argfuns[1](env), 259 } 260 callxr(funv, argv) 261 } 262 } 263 } 264 265 cachefun := ~"{ 266 if cachedfunv != funv { 267 cachedfunv = funv 268 cachedfun = funv.Interface().(func(~,arg0typ, ~,arg1typ)) 269 } 270 } 271 272 return ~"{ 273 arg0fun := args[0].WithFun().(func(*Env) ~,arg0typ) 274 arg1fun := args[1].WithFun().(func(*Env) ~,arg0typ) 275 276 if funsym != nil && funupn == maxdepth - 1 { 277 var cachedfun func(~,arg0typ, ~,arg1typ) 278 ret = func(env *Env) { 279 funv := env.FileEnv.Vals[funindex] 280 ~,cachefun 281 arg0 := arg0fun(env) 282 arg1 := arg1fun(env) 283 cachedfun(arg0, arg1) 284 } 285 } else { 286 ret = func(env *Env) { 287 fun := exprfun(env).Interface().(func(~,arg0typ, ~,arg1typ)) 288 arg0 := arg0fun(env) 289 arg1 := arg1fun(env) 290 fun(arg0, arg1) 291 } 292 } 293 } 294} 295 296 297func (c *Comp) call2ret0(call *Call, maxdepth int) func(env *Env) { 298 expr := call.Fun 299 exprfun := expr.AsX1() 300 funsym := expr.Sym 301 funupn, funindex := -1, -1 302 if funsym != nil { 303 funupn = funsym.Upn 304 funindex = funsym.Desc.Index() 305 if funindex == NoIndex { 306 c.Errorf("internal error: call2ret0() invoked for constant function %#v. use call_builtin() instead", expr) 307 } 308 } 309 args := call.Args 310 argfunsX1 := call.MakeArgfunsX1() 311 argfuns := [2]func(*Env)r.Value { 312 argfunsX1[0], 313 argfunsX1[1], 314 } 315 var cachedfunv r.Value 316 var ret func(env *Env) 317 318 t := expr.Type.In(0) 319 rt := t.ReflectType() 320 k := t.Kind() 321 if reflect.KindToType(k) == rt && expr.Type.In(1).ReflectType() == rt { 322 switch k { 323 case r.Bool: {mcall2ret0; bool; bool} 324 case r.Int: {mcall2ret0; int; int} 325 case r.Int8: {mcall2ret0; int8; int8} 326 case r.Int16: {mcall2ret0; int16; int16} 327 case r.Int32: {mcall2ret0; int32; int32} 328 case r.Int64: {mcall2ret0; int64; int64} 329 case r.Uint: {mcall2ret0; uint; uint} 330 case r.Uint8: {mcall2ret0; uint8; uint8} 331 case r.Uint16: {mcall2ret0; uint16; uint16} 332 case r.Uint32: {mcall2ret0; uint32; uint32} 333 case r.Uint64: {mcall2ret0; uint64; uint64} 334 case r.Uintptr: {mcall2ret0; uintptr; uintptr} 335 case r.Float32: {mcall2ret0; float32; float32} 336 case r.Float64: {mcall2ret0; float64; float64} 337 case r.Complex64: {mcall2ret0; complex64; complex64} 338 case r.Complex128:{mcall2ret0; complex128; complex128} 339 case r.String: {mcall2ret0; string; string} 340 } 341 } 342 if ret == nil { 343 {mcall2ret0; nil; nil} 344 } 345 return ret 346} 347