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 * call1ret1.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 maketypevar(typ ast.Node) ast.Node { 40 t := EvalType(typ) 41 return &ast.Ident{Name: "TypeOf" + upcasefirstbyte(t.Name())} 42} 43 44:func convertvalue1(typ, val ast.Node) ast.Node { 45 var t r.Type = EvalType(typ) 46 if t == nil { 47 // keep the result wrapped in a reflect.Value 48 return val 49 } 50 // unwrap the result 51 tname := t.Name() 52 // remove final digits from t.Name() 53 // needed to convert Uint64 -> Uint etc. to calls reflect.Value.{tname} 54 for len(tname) != 0 { 55 ch := tname[len(tname)-1] 56 if ch < '0' || ch > '9' { 57 break 58 } 59 tname = tname[0:len(tname)-1] 60 } 61 if tname == "uintptr" { 62 tname = "uint" // use reflect.Value.Uint() 63 } 64 sel := ~"{~,val . foo} // we modify it destructively 65 sel.Sel = &ast.Ident{Name: upcasefirstbyte(tname)} 66 67 switch t.Kind() { 68 case r.Bool, r.Int64, r.Uint64, r.Float64, r.Complex128, r.String: 69 // result of reflect.Value.{tname} is already the correct type 70 val = ~"{~,sel ()} 71 default: 72 // convert int64, uint64... to the correct type 73 val = ~"{~,typ ( ~,sel () )} 74 } 75 return val 76} 77 78:macro mcall1ret1(argtyp, rettyp ast.Node) ast.Node { 79 if EvalType(rettyp) == nil { 80 // keep the arguments and result wrapped in a reflect.Value 81 return ~"{ 82 ret = func(env *Env) r.Value { 83 funv := exprfun(env) 84 argv := []r.Value{ 85 argfun(env), 86 } 87 return callxr(funv, argv)[0] 88 } 89 } 90 } 91 if EvalType(argtyp) == nil { 92 ret0 := convertvalue1(rettyp, ~'ret0) 93 94 return ~"{ 95 ret = func(env *Env) ~,rettyp { 96 funv := exprfun(env) 97 argv := []r.Value{ 98 argfun(env), 99 } 100 // Debugf("calling %v with args [%v]", r.TypeOf(funv), argv) 101 ret0 := callxr(funv, argv)[0] 102 return ~,ret0 103 } 104 } 105 } 106 107 cachefun := ~"{ 108 if cachedfunv != funv { 109 cachedfunv = funv 110 cachedfun = funv.Interface().(func(~,argtyp) ~,rettyp) 111 } 112 } 113 114 argconv := convertvalue1(argtyp, ~'{r.ValueOf(arg.Value)}) 115 116 return ~"{ 117 // Debugf("compiling call to %v, funsym=%p, funupn=%v, maxdepth=%v", r.TypeOf((func(~,argtyp) ~,rettyp)(nil)), funsym, funupn, maxdepth) 118 if funsym != nil && funupn == maxdepth - 1 { 119 var cachedfun func(~,argtyp) ~,rettyp 120 if arg.Const() { 121 argconst := ~,argconv 122 ret = func(env *Env) ~,rettyp { 123 funv := env.FileEnv.Vals[funindex] 124 ~,cachefun 125 // Debugf("calling %v with args [%v]", r.TypeOf(cachedfun), argconst) 126 return cachedfun(argconst) 127 } 128 } else { 129 argfun := arg.Fun.(func(env *Env) ~,argtyp) 130 ret = func(env *Env) ~,rettyp { 131 funv := env.FileEnv.Vals[funindex] 132 ~,cachefun 133 arg := argfun(env) 134 // Debugf("calling %v with args [%v]", r.TypeOf(fun), arg) 135 return cachedfun(arg) 136 } 137 } 138 } else { 139 argfun := arg.WithFun().(func(env *Env) ~,argtyp) 140 if funsym != nil && funupn == 0 { 141 ret = func(env *Env) ~,rettyp { 142 fun := env.Vals[funindex].Interface().(func(~,argtyp) ~,rettyp) 143 arg := argfun(env) 144 // Debugf("calling %v with args [%v]", r.TypeOf(fun), arg) 145 return fun(arg) 146 } 147 } else if funsym != nil && funupn == 1 { 148 ret = func(env *Env) ~,rettyp { 149 fun := env.Outer.Vals[funindex].Interface().(func(~,argtyp) ~,rettyp) 150 arg := argfun(env) 151 // Debugf("calling %v with args [%v]", r.TypeOf(fun), arg) 152 return fun(arg) 153 } 154 } else { 155 ret = func(env *Env) ~,rettyp { 156 fun := exprfun(env).Interface().(func(~,argtyp) ~,rettyp) 157 arg := argfun(env) 158 // Debugf("calling %v with args [%v]", r.TypeOf(fun), arg) 159 return fun(arg) 160 } 161 } 162 } 163 } 164} 165 166:macro mcall1ret1compact(argtyp, rettyp ast.Node) ast.Node { 167 if EvalType(rettyp) == nil || EvalType(argtyp) == nil { 168 // nothing to optimize... 169 return ~"{mcall1ret1; ~,argtyp; ~,rettyp} 170 } 171 172 return ~"{ 173 argfun := arg.WithFun().(func(env *Env) ~,argtyp) 174 ret = func(env *Env) ~,rettyp { 175 fun := exprfun(env).Interface().(func(~,argtyp) ~,rettyp) 176 arg := argfun(env) 177 // Debugf("calling %v with args [%v]", r.TypeOf(fun), argconst) 178 return fun(arg) 179 } 180 } 181} 182 183:macro mcallx1ret1(rettyp ast.Node) ast.Node { 184 return ~"{ 185 switch karg { 186 case r.Bool: {mcall1ret1; bool; ~,rettyp} 187 case r.Int: {mcall1ret1; int; ~,rettyp} 188 case r.Int8: {mcall1ret1; int8; ~,rettyp} 189 case r.Int16: {mcall1ret1; int16; ~,rettyp} 190 case r.Int32: {mcall1ret1; int32; ~,rettyp} 191 case r.Int64: {mcall1ret1; int64; ~,rettyp} 192 case r.Uint: {mcall1ret1; uint; ~,rettyp} 193 case r.Uint8: {mcall1ret1; uint8; ~,rettyp} 194 case r.Uint16: {mcall1ret1; uint16; ~,rettyp} 195 case r.Uint32: {mcall1ret1; uint32; ~,rettyp} 196 case r.Uint64: {mcall1ret1; uint64; ~,rettyp} 197 case r.Uintptr: {mcall1ret1; uintptr; ~,rettyp} 198 case r.Float32: {mcall1ret1; float32; ~,rettyp} 199 case r.Float64: {mcall1ret1; float64; ~,rettyp} 200 case r.Complex64: {mcall1ret1; complex64; ~,rettyp} 201 case r.Complex128:{mcall1ret1; complex128; ~,rettyp} 202 case r.String: {mcall1ret1; string; ~,rettyp} 203 default: {mcall1ret1; nil; ~,rettyp} 204 } 205 } 206} 207 208:macro mcallx1ret1compact(rettyp ast.Node) ast.Node { 209 return ~"{ 210 switch karg { 211 case r.Bool: {mcall1ret1compact; bool; ~,rettyp} 212 case r.Int: {mcall1ret1compact; int; ~,rettyp} 213 case r.Int8: {mcall1ret1compact; int8; ~,rettyp} 214 case r.Int16: {mcall1ret1compact; int16; ~,rettyp} 215 case r.Int32: {mcall1ret1compact; int32; ~,rettyp} 216 case r.Int64: {mcall1ret1compact; int64; ~,rettyp} 217 case r.Uint: {mcall1ret1compact; uint; ~,rettyp} 218 case r.Uint8: {mcall1ret1compact; uint8; ~,rettyp} 219 case r.Uint16: {mcall1ret1compact; uint16; ~,rettyp} 220 case r.Uint32: {mcall1ret1compact; uint32; ~,rettyp} 221 case r.Uint64: {mcall1ret1compact; uint64; ~,rettyp} 222 case r.Uintptr: {mcall1ret1compact; uintptr; ~,rettyp} 223 case r.Float32: {mcall1ret1compact; float32; ~,rettyp} 224 case r.Float64: {mcall1ret1compact; float64; ~,rettyp} 225 case r.Complex64: {mcall1ret1compact; complex64; ~,rettyp} 226 case r.Complex128:{mcall1ret1compact; complex128; ~,rettyp} 227 case r.String: {mcall1ret1compact; string; ~,rettyp} 228 default: {mcall1ret1compact; nil; ~,rettyp} 229 } 230 } 231} 232 233:macro mcallx1ret1minimal(rettyp ast.Node) ast.Node { 234 return ~"{ 235 if karg == kret { 236 mcall1ret1; ~,rettyp; ~,rettyp 237 } else { 238 mcall1ret1; nil; ~,rettyp 239 } 240 } 241} 242 243func (c *Comp) call1ret1(call *Call, maxdepth int) I { 244 expr := call.Fun 245 exprfun := expr.AsX1() 246 funsym := expr.Sym 247 funupn, funindex := -1, -1 248 if funsym != nil { 249 funupn = funsym.Upn 250 funindex = funsym.Desc.Index() 251 if funindex == NoIndex { 252 c.Errorf("internal error: call1ret1() invoked for constant function %v. use call_builtin() instead", expr) 253 } 254 } 255 t := expr.Type 256 targ, tret := t.In(0), t.Out(0) 257 karg, kret := targ.Kind(), tret.Kind() 258 var ret I 259 if reflect.KindToType(karg) != targ.ReflectType() || reflect.KindToType(kret) != tret.ReflectType() { 260 return c.call1ret1namedtype(call, maxdepth) 261 } 262 arg := call.Args[0] 263 argfun := arg.AsX1() 264 var cachedfunv r.Value 265 266 switch kret { 267 // do NOT optimize all cases... too many combinations 268 case r.Bool: {mcallx1ret1; bool} 269 case r.Int: {mcallx1ret1; int} 270 case r.Int8: {mcallx1ret1minimal; int8} 271 case r.Int16: {mcallx1ret1minimal; int16} 272 case r.Int32: {mcallx1ret1minimal; int32} 273 case r.Int64: {mcallx1ret1; int64} 274 case r.Uint: {mcallx1ret1; uint} 275 case r.Uint8: {mcallx1ret1minimal; uint8} 276 case r.Uint16: {mcallx1ret1minimal; uint16} 277 case r.Uint32: {mcallx1ret1minimal; uint32} 278 case r.Uint64: {mcallx1ret1; uint64} 279 case r.Uintptr: {mcallx1ret1minimal; uintptr} 280 case r.Float32: {mcallx1ret1minimal; float32} 281 case r.Float64: {mcallx1ret1compact; float64} 282 case r.Complex64: {mcallx1ret1minimal; complex64} 283 case r.Complex128:{mcallx1ret1compact; complex128} 284 case r.String: {mcallx1ret1; string} 285 } 286 if ret == nil { 287 {mcall1ret1; nil; nil} // cannot optimize more this one... 288 } 289 return ret 290} 291 292:macro mcallx1ret1namedtype(rettyp ast.Node) ast.Node { 293 retconv := convertvalue1(rettyp, ~'retv) 294 295 return ~"{ 296 ret = func(env *Env) ~,rettyp { 297 funv := exprfun(env) 298 argv := []r.Value{ 299 argfun(env), 300 } 301 retv := callxr(funv, argv)[0] 302 return ~,retconv 303 } 304 } 305} 306 307func (c *Comp) call1ret1namedtype(call *Call, maxdepth int) I { 308 expr := call.Fun 309 exprfun := expr.AsX1() 310 t := expr.Type 311 kret := t.Out(0).Kind() 312 313 argfun := call.Args[0].AsX1() 314 var ret I 315 316 switch kret { 317 case r.Bool: {mcallx1ret1namedtype; bool} 318 case r.Int: {mcallx1ret1namedtype; int} 319 case r.Int8: {mcallx1ret1namedtype; int8} 320 case r.Int16: {mcallx1ret1namedtype; int16} 321 case r.Int32: {mcallx1ret1namedtype; int32} 322 case r.Int64: {mcallx1ret1namedtype; int64} 323 case r.Uint: {mcallx1ret1namedtype; uint} 324 case r.Uint8: {mcallx1ret1namedtype; uint8} 325 case r.Uint16: {mcallx1ret1namedtype; uint16} 326 case r.Uint32: {mcallx1ret1namedtype; uint32} 327 case r.Uint64: {mcallx1ret1namedtype; uint64} 328 case r.Uintptr: {mcallx1ret1namedtype; uintptr} 329 case r.Float32: {mcallx1ret1namedtype; float32} 330 case r.Float64: {mcallx1ret1namedtype; float64} 331 case r.Complex64: {mcallx1ret1namedtype; complex64} 332 case r.Complex128:{mcallx1ret1namedtype; complex128} 333 case r.String: {mcallx1ret1namedtype; string} 334 } 335 if ret == nil { 336 {mcall1ret1; nil; nil} // cannot optimize more this one... 337 } 338 return ret 339} 340 341