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 * func_ret1.go 12 * 13 * Created on Apr 16, 2017 14 * Author Massimiliano Ghilardi 15 */ 16 17package fast 18 19import ( 20 r "reflect" 21 "unsafe" 22 23 . "github.com/cosmos72/gomacro/base" 24 xr "github.com/cosmos72/gomacro/xreflect" 25) 26 27:import ( 28 r "reflect" 29 "go/ast" 30) 31 32 33:func upcasefirstbyte(str string) string { 34 if len(str) > 0 && str[0] >= 'a' && str[0] <= 'z' { 35 bytes := []byte(str) 36 bytes[0] -= 'a' - 'A' 37 return string(bytes) 38 } 39 return str 40} 41 42:func makeprefixtypeident(prefix string, t r.Type) *ast.Ident { 43 name := prefix + upcasefirstbyte(t.Name()) 44 return &ast.Ident{Name: name} 45} 46 47// convert a well-known reflect.Type into one of the constants TypeOf* 48:func maketypeident(t r.Type) *ast.Ident { 49 return makeprefixtypeident("TypeOf", t) 50} 51 52:macro mcallfunc1retx1(typ ast.Node) ast.Node { 53 var t r.Type = EvalType(typ) 54 ident := makeprefixtypeident("func1ret1", t) 55 return ~"{ 56 ret = ~,ident (m, indexes, kret0, debugC) 57 } 58} 59 60:macro mcallfuncx1retx1(dummy ast.Node) ast.Node { 61 return ~"{ 62 switch karg0 { 63 case r.Bool: {mcallfunc1retx1; bool} 64 case r.Int: {mcallfunc1retx1; int} 65 case r.Int8: {mcallfunc1retx1; int8} 66 case r.Int16: {mcallfunc1retx1; int16} 67 case r.Int32: {mcallfunc1retx1; int32} 68 case r.Int64: {mcallfunc1retx1; int64} 69 case r.Uint: {mcallfunc1retx1; uint} 70 case r.Uint8: {mcallfunc1retx1; uint8} 71 case r.Uint16: {mcallfunc1retx1; uint16} 72 case r.Uint32: {mcallfunc1retx1; uint32} 73 case r.Uint64: {mcallfunc1retx1; uint64} 74 case r.Uintptr: {mcallfunc1retx1; uintptr} 75 case r.Float32: {mcallfunc1retx1; float32} 76 case r.Float64: {mcallfunc1retx1; float64} 77 case r.Complex64: {mcallfunc1retx1; complex64} 78 case r.Complex128:{mcallfunc1retx1; complex128} 79 case r.String: {mcallfunc1retx1; string} 80 } 81 } 82} 83 84// ==================================== func1ret1 ======================================== 85 86func (c *Comp) func1ret1(t xr.Type, m *funcMaker) func(*Env) r.Value { 87 var debugC *Comp 88 if c.Globals.Options&OptDebugger != 0 { 89 // keep a reference to c only if needed 90 debugC = c 91 } 92 karg0 := t.In(0).Kind() 93 kret0 := t.Out(0).Kind() 94 95 indexes := &[2]int{ 96 m.Param[0].Desc.Index(), 97 m.Result[0].Desc.Index(), 98 } 99 var ret func(*Env) r.Value 100 101 // if IsOptimizedKind(karg0) && IsOptimizedKind(kret0) 102 mcallfuncx1retx1; nil 103 104 return ret 105} 106 107// ==================================== func1ret1{Bool,Int,...} ======================================== 108 109:func fsetarg(typ, name, index ast.Node) ast.Node { 110 var t r.Type = EvalType(typ) 111 var bind ast.Node 112 typeident := maketypeident(t) 113 switch t.Kind() { 114 case r.String: 115 bind = ~"{ 116 place := r.New(~,typeident).Elem() 117 place.SetString(~,name) 118 env.Vals[~,index] = place 119 } 120 case r.Uint64: 121 bind = ~"{env.Ints[~,index] = ~,name} 122 default: 123 bind = ~"{*(*~,typ)(unsafe.Pointer(&env.Ints[~,index])) = ~,name} 124 } 125 return bind 126} 127 128:func fgetresult(typ, index ast.Node) ast.Node { 129 var t r.Type = EvalType(typ) 130 var bind ast.Node 131 if t == nil { 132 bind = ~"{env.Vals[~,index]} 133 } else { 134 typeident := maketypeident(t) 135 switch t.Kind() { 136 case r.String: 137 bind = ~"{env.Vals[~,index].String()} 138 case r.Uint64: 139 bind = ~"{env.Ints[~,index]} 140 default: 141 bind = ~"{*(*~,typ)(unsafe.Pointer(&env.Ints[~,index]))} 142 } 143 } 144 return bind 145} 146 147// ----------------- func(t0) t1 --------------------- 148 149// generate fully optimized function implementation for func(arg0typ) ret0typ 150:macro mfunc1ret1(arg0typ, ret0typ ast.Node) ast.Node { 151 arg0bind := fsetarg(arg0typ, ~'arg0, ~'{indexes[0]}) 152 ret0bind := fgetresult(ret0typ, ~'{indexes[1]}) 153 return ~"{ 154 if funcbody == nil { 155 funv := r.ValueOf(func(~,arg0typ) (ret0 ~,ret0typ) { 156 return 157 }) 158 ret = func(env *Env) r.Value { 159 return funv 160 } 161 break 162 } 163 ret = func(env *Env) r.Value { 164 // function is closed over the env used to DECLARE it 165 env.MarkUsedByClosure() 166 return r.ValueOf(func(arg0 ~,arg0typ) (ret0 ~,ret0typ) { 167 env := newEnv4Func(env, nbind, nintbind, debugC) 168 169 // copy arg into allocated binds 170 ~,arg0bind 171 172 // execute the body 173 funcbody(env) 174 175 // extract result 176 ret0 = ~,ret0bind 177 env.freeEnv4Func() 178 return 179 }) 180 } 181 } 182} 183 184:macro mfunc1retx1(arg0typ ast.Node) ast.Node { 185 return ~"{ 186 switch kret0 { 187 case r.Bool: {mfunc1ret1; ~,arg0typ; bool} 188 case r.Int: {mfunc1ret1; ~,arg0typ; int} 189 case r.Int8: {mfunc1ret1; ~,arg0typ; int8} 190 case r.Int16: {mfunc1ret1; ~,arg0typ; int16} 191 case r.Int32: {mfunc1ret1; ~,arg0typ; int32} 192 case r.Int64: {mfunc1ret1; ~,arg0typ; int64} 193 case r.Uint: {mfunc1ret1; ~,arg0typ; uint} 194 case r.Uint8: {mfunc1ret1; ~,arg0typ; uint8} 195 case r.Uint16: {mfunc1ret1; ~,arg0typ; uint16} 196 case r.Uint32: {mfunc1ret1; ~,arg0typ; uint32} 197 case r.Uint64: {mfunc1ret1; ~,arg0typ; uint64} 198 case r.Uintptr: {mfunc1ret1; ~,arg0typ; uintptr} 199 case r.Float32: {mfunc1ret1; ~,arg0typ; float32} 200 case r.Float64: {mfunc1ret1; ~,arg0typ; float64} 201 case r.Complex64: {mfunc1ret1; ~,arg0typ; complex64} 202 case r.Complex128:{mfunc1ret1; ~,arg0typ; complex128} 203 case r.String: {mfunc1ret1; ~,arg0typ; string} 204 } 205 } 206} 207 208:macro mdeclfunc1retx1(arg0typ ast.Node) ast.Node { 209 decl := ~"{ 210 ~func foo (m *funcMaker, indexes *[2]int, kret0 r.Kind, debugC *Comp) func(*Env) r.Value { 211 // do NOT keep a reference to funcMaker 212 nbind := m.nbind 213 nintbind := m.nintbind 214 funcbody := m.funcbody 215 var ret func(*Env) r.Value 216 217 mfunc1retx1; ~,arg0typ 218 219 return ret 220 } 221 } 222 var t r.Type = EvalType(arg0typ) 223 decl.Name = makeprefixtypeident("func1ret1", t) 224 return decl 225} 226 227mdeclfunc1retx1; bool 228mdeclfunc1retx1; int 229mdeclfunc1retx1; int8 230mdeclfunc1retx1; int16 231mdeclfunc1retx1; int32 232mdeclfunc1retx1; int64 233mdeclfunc1retx1; uint 234mdeclfunc1retx1; uint8 235mdeclfunc1retx1; uint16 236mdeclfunc1retx1; uint32 237mdeclfunc1retx1; uint64 238mdeclfunc1retx1; uintptr 239mdeclfunc1retx1; float32 240mdeclfunc1retx1; float64 241mdeclfunc1retx1; complex64 242mdeclfunc1retx1; complex128 243mdeclfunc1retx1; string 244