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  // ----------------------------------------------------------------------------