github.com/goplus/gogen@v1.16.0/func.go (about) 1 /* 2 Copyright 2021 The GoPlus Authors (goplus.org) 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 http://www.apache.org/licenses/LICENSE-2.0 7 Unless required by applicable law or agreed to in writing, software 8 distributed under the License is distributed on an "AS IS" BASIS, 9 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 See the License for the specific language governing permissions and 11 limitations under the License. 12 */ 13 14 package gogen 15 16 import ( 17 "fmt" 18 "go/ast" 19 "go/token" 20 "go/types" 21 "log" 22 23 "github.com/goplus/gogen/internal" 24 ) 25 26 // ---------------------------------------------------------------------------- 27 28 // A Param represents a function parameters and results. 29 type Param = types.Var 30 31 // NewAutoParam returns a new variable representing a function result parameter with auto type. 32 func (p *Package) NewAutoParam(name string) *Param { 33 return p.NewAutoParamEx(token.NoPos, name) 34 } 35 36 // NewAutoParamEx returns a new variable representing a function result parameter with auto type. 37 func (p *Package) NewAutoParamEx(pos token.Pos, name string) *Param { 38 return types.NewParam(pos, p.Types, name, &unboundType{}) 39 } 40 41 // NewParam returns a new variable representing a function parameter. 42 func (p *Package) NewParam(pos token.Pos, name string, typ types.Type) *Param { 43 return types.NewParam(pos, p.Types, name, typ) 44 } 45 46 // ---------------------------------------------------------------------------- 47 48 // A Tuple represents an ordered list of variables; a nil *Tuple is a valid (empty) tuple. 49 // Tuples are used as components of signatures and to represent the type of multiple 50 // assignments; they are not first class types of Go. 51 type Tuple = types.Tuple 52 53 // NewTuple returns a new tuple for the given parameters. 54 func NewTuple(x ...*Param) *Tuple { 55 return types.NewTuple(x...) 56 } 57 58 // ---------------------------------------------------------------------------- 59 60 // Func type 61 type Func struct { 62 *types.Func 63 decl *ast.FuncDecl 64 old funcBodyCtx 65 arity1 int // 0 for normal, (arity+1) for inlineClosure 66 } 67 68 // Obj returns this function object. 69 func (p *Func) Obj() types.Object { 70 return p.Func 71 } 72 73 // Comments returns associated documentation. 74 func (p *Func) Comments() *ast.CommentGroup { 75 return p.decl.Doc 76 } 77 78 // SetComments sets associated documentation. 79 func (p *Func) SetComments(pkg *Package, doc *ast.CommentGroup) *Func { 80 p.decl.Doc = doc 81 pkg.setDoc(p.Func, doc) 82 return p 83 } 84 85 // Ancestor returns ancestor of a closure function. 86 // It returns itself if the specified func is a normal function. 87 func (p *Func) Ancestor() *Func { 88 for { 89 if fn := p.old.fn; fn != nil { 90 p = fn 91 continue 92 } 93 return p 94 } 95 } 96 97 // BodyStart func 98 func (p *Func) BodyStart(pkg *Package, src ...ast.Node) *CodeBuilder { 99 if debugInstr { 100 var recv string 101 tag := "NewFunc " 102 name := p.Name() 103 sig := p.Type().(*types.Signature) 104 if v := sig.Recv(); IsMethodRecv(v) { 105 recv = fmt.Sprintf(" (%v)", v.Type()) 106 } 107 if name == "" { 108 tag = "NewClosure" 109 } 110 log.Printf("%v%v%v %v\n", tag, name, recv, sig) 111 } 112 return pkg.cb.startFuncBody(p, src, &p.old) 113 } 114 115 // End is for internal use. 116 func (p *Func) End(cb *CodeBuilder, src ast.Node) { 117 if p.isInline() { 118 p.inlineClosureEnd(cb) 119 return 120 } 121 pkg := cb.pkg 122 body := &ast.BlockStmt{List: cb.endFuncBody(p.old)} 123 t, _ := toNormalizeSignature(nil, p.Type().(*types.Signature)) 124 if fn := p.decl; fn == nil { // is closure 125 expr := &ast.FuncLit{Type: toFuncType(pkg, t), Body: body} 126 cb.stk.Push(&internal.Elem{Val: expr, Type: t, Src: src}) 127 } else { 128 fn.Name, fn.Type, fn.Body = ident(p.Name()), toFuncType(pkg, t), body 129 if recv := t.Recv(); IsMethodRecv(recv) { 130 fn.Recv = toRecv(pkg, recv) 131 } 132 } 133 } 134 135 // NewFuncDecl creates a new function without function body (declaration only). 136 func (p *Package) NewFuncDecl(pos token.Pos, name string, sig *types.Signature) *Func { 137 f, err := p.NewFuncWith(pos, name, sig, nil) 138 if err != nil { 139 panic(err) 140 } 141 fn := f.decl 142 fn.Name, fn.Type = ident(name), toFuncType(p, sig) 143 return f 144 } 145 146 // NewFunc creates a new function (should have a function body). 147 func (p *Package) NewFunc(recv *Param, name string, params, results *Tuple, variadic bool) *Func { 148 sig := types.NewSignatureType(recv, nil, nil, params, results, variadic) 149 f, err := p.NewFuncWith(token.NoPos, name, sig, nil) 150 if err != nil { 151 panic(err) 152 } 153 return f 154 } 155 156 func getRecv(recvTypePos func() token.Pos) token.Pos { 157 if recvTypePos != nil { 158 return recvTypePos() 159 } 160 return token.NoPos 161 } 162 163 func IsMethodRecv(recv *types.Var) bool { 164 return recv != nil 165 } 166 167 // NewFuncWith creates a new function (should have a function body). 168 func (p *Package) NewFuncWith( 169 pos token.Pos, name string, sig *types.Signature, recvTypePos func() token.Pos) (*Func, error) { 170 if name == "" { 171 panic("no func name") 172 } 173 cb := p.cb 174 fn := &Func{Func: types.NewFunc(pos, p.Types, name, sig)} 175 if recv := sig.Recv(); IsMethodRecv(recv) { // add method to this type 176 var t *types.Named 177 var ok bool 178 var typ = recv.Type() 179 switch tt := typ.(type) { 180 case *types.Named: 181 t, ok = tt, true 182 case *types.Pointer: 183 typ = tt.Elem() 184 t, ok = typ.(*types.Named) 185 } 186 if !ok { 187 return nil, cb.newCodeErrorf( 188 getRecv(recvTypePos), "invalid receiver type %v (%v is not a defined type)", typ, typ) 189 } 190 switch getUnderlying(p, t.Obj().Type()).(type) { 191 case *types.Interface: 192 return nil, cb.newCodeErrorf( 193 getRecv(recvTypePos), "invalid receiver type %v (%v is an interface type)", typ, typ) 194 case *types.Pointer: 195 return nil, cb.newCodeErrorf( 196 getRecv(recvTypePos), "invalid receiver type %v (%v is a pointer type)", typ, typ) 197 } 198 if name != "_" { // skip underscore 199 t.AddMethod(fn.Func) 200 } 201 } else if name == "init" { // init is not a normal func 202 if sig.Params() != nil || sig.Results() != nil { 203 return nil, cb.newCodeErrorf( 204 pos, "func init must have no arguments and no return values") 205 } 206 } else if name != "_" { // skip underscore 207 old := p.Types.Scope().Insert(fn.Obj()) 208 if old != nil { 209 if !(p.allowRedecl && types.Identical(old.Type(), sig)) { // for c2go 210 oldPos := cb.fset.Position(old.Pos()) 211 return nil, cb.newCodeErrorf( 212 pos, "%s redeclared in this block\n\t%v: other declaration of %s", name, oldPos, name) 213 } 214 } 215 p.useName(name) 216 } 217 218 if isGopFunc(name) { 219 p.isGopPkg = true 220 } 221 if token.IsExported(name) { 222 p.expObjTypes = append(p.expObjTypes, sig) 223 } 224 225 fn.decl = &ast.FuncDecl{} 226 p.file.decls = append(p.file.decls, fn.decl) 227 return fn, nil 228 } 229 230 func (p *Package) newClosure(sig *types.Signature) *Func { 231 fn := types.NewFunc(token.NoPos, p.Types, "", sig) 232 return &Func{Func: fn} 233 } 234 235 func (p *Package) newInlineClosure(sig *types.Signature, arity int) *Func { 236 fn := types.NewFunc(token.NoPos, p.Types, "", sig) 237 return &Func{Func: fn, arity1: arity + 1} 238 } 239 240 func (p *Func) isInline() bool { 241 return p.arity1 != 0 242 } 243 244 func (p *Func) getInlineCallArity() int { 245 return p.arity1 - 1 246 } 247 248 // ---------------------------------------------------------------------------- 249 250 type Element = internal.Elem 251 type InstrFlags token.Pos 252 253 const ( 254 InstrFlagEllipsis InstrFlags = 1 << iota 255 InstrFlagTwoValue 256 257 instrFlagApproxType // restricts to all types whose underlying type is T 258 instrFlagGopxFunc // call Gopx_xxx function 259 instrFlagGoptFunc // call Gopt_xxx function 260 instrFlagOpFunc // from callOpFunc 261 instrFlagBinaryOp // from cb.BinaryOp 262 ) 263 264 type Instruction interface { 265 Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) 266 } 267 268 // ----------------------------------------------------------------------------