github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/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 gox 15 16 import ( 17 "fmt" 18 "go/ast" 19 "go/token" 20 "go/types" 21 "log" 22 23 "github.com/goplus/gox/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 func (p *Package) NewFuncDecl(pos token.Pos, name string, sig *types.Signature) *Func { 136 f, err := p.NewFuncWith(pos, name, sig, nil) 137 if err != nil { 138 panic(err) 139 } 140 fn := f.decl 141 fn.Name, fn.Type = ident(name), toFuncType(p, sig) 142 return f 143 } 144 145 // NewFunc func 146 func (p *Package) NewFunc(recv *Param, name string, params, results *Tuple, variadic bool) *Func { 147 sig := types.NewSignatureType(recv, nil, nil, params, results, variadic) 148 f, err := p.NewFuncWith(token.NoPos, name, sig, nil) 149 if err != nil { 150 panic(err) 151 } 152 return f 153 } 154 155 func getRecv(recvTypePos func() token.Pos) token.Pos { 156 if recvTypePos != nil { 157 return recvTypePos() 158 } 159 return token.NoPos 160 } 161 162 // NewFuncWith func 163 func (p *Package) NewFuncWith( 164 pos token.Pos, name string, sig *types.Signature, recvTypePos func() token.Pos) (*Func, error) { 165 if name == "" { 166 panic("no func name") 167 } 168 cb := p.cb 169 fn := &Func{Func: types.NewFunc(pos, p.Types, name, sig)} 170 if recv := sig.Recv(); IsMethodRecv(recv) { // add method to this type 171 var t *types.Named 172 var ok bool 173 var typ = recv.Type() 174 switch tt := typ.(type) { 175 case *types.Named: 176 t, ok = tt, true 177 case *types.Pointer: 178 typ = tt.Elem() 179 t, ok = typ.(*types.Named) 180 } 181 if !ok { 182 return nil, cb.newCodeErrorf( 183 getRecv(recvTypePos), "invalid receiver type %v (%v is not a defined type)", typ, typ) 184 } 185 switch getUnderlying(p, t.Obj().Type()).(type) { 186 case *types.Interface: 187 return nil, cb.newCodeErrorf( 188 getRecv(recvTypePos), "invalid receiver type %v (%v is an interface type)", typ, typ) 189 case *types.Pointer: 190 return nil, cb.newCodeErrorf( 191 getRecv(recvTypePos), "invalid receiver type %v (%v is a pointer type)", typ, typ) 192 } 193 if name != "_" { // skip underscore 194 t.AddMethod(fn.Func) 195 } 196 } else if name == "init" { // init is not a normal func 197 if sig.Params() != nil || sig.Results() != nil { 198 return nil, cb.newCodeErrorf( 199 pos, "func init must have no arguments and no return values") 200 } 201 } else if name != "_" { // skip underscore 202 old := p.Types.Scope().Insert(fn.Obj()) 203 if old != nil { 204 if !(p.allowRedecl && types.Identical(old.Type(), sig)) { // for c2go 205 oldPos := cb.fset.Position(old.Pos()) 206 return nil, cb.newCodeErrorf( 207 pos, "%s redeclared in this block\n\t%v: other declaration of %s", name, oldPos, name) 208 } 209 } 210 p.useName(name) 211 } 212 213 if isGopFunc(name) { 214 p.isGopPkg = true 215 } 216 if token.IsExported(name) { 217 p.expObjTypes = append(p.expObjTypes, sig) 218 } 219 220 fn.decl = &ast.FuncDecl{} 221 p.file.decls = append(p.file.decls, fn.decl) 222 return fn, nil 223 } 224 225 func (p *Package) newClosure(sig *types.Signature) *Func { 226 fn := types.NewFunc(token.NoPos, p.Types, "", sig) 227 return &Func{Func: fn} 228 } 229 230 func (p *Package) newInlineClosure(sig *types.Signature, arity int) *Func { 231 fn := types.NewFunc(token.NoPos, p.Types, "", sig) 232 return &Func{Func: fn, arity1: arity + 1} 233 } 234 235 func (p *Func) isInline() bool { 236 return p.arity1 != 0 237 } 238 239 func (p *Func) getInlineCallArity() int { 240 return p.arity1 - 1 241 } 242 243 // ---------------------------------------------------------------------------- 244 245 type Element = internal.Elem 246 type InstrFlags token.Pos 247 248 const ( 249 InstrFlagEllipsis InstrFlags = 1 << iota 250 InstrFlagTwoValue 251 252 instrFlagApproxType // restricts to all types whose underlying type is T 253 instrFlagGopxFunc // call Gopx_xxx function 254 instrFlagGoptFunc // call Gopt_xxx function 255 instrFlagOpFunc // from callOpFunc 256 instrFlagBinaryOp // from cb.BinaryOp 257 ) 258 259 type Instruction interface { 260 Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) 261 } 262 263 // ----------------------------------------------------------------------------