github.com/goplus/gox@v1.14.13-0.20240308130321-6ff7f61cfae8/codebuild.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  	"errors"
    18  	"fmt"
    19  	"go/ast"
    20  	"go/constant"
    21  	"go/token"
    22  	"go/types"
    23  	"log"
    24  	"math/big"
    25  	"reflect"
    26  	"strconv"
    27  	"strings"
    28  	"syscall"
    29  
    30  	"github.com/goplus/gox/internal"
    31  	xtoken "github.com/goplus/gox/token"
    32  	"golang.org/x/tools/go/types/typeutil"
    33  )
    34  
    35  func getSrc(node []ast.Node) ast.Node {
    36  	if node != nil {
    37  		return node[0]
    38  	}
    39  	return nil
    40  }
    41  
    42  func getSrcPos(node ast.Node) token.Pos {
    43  	if node != nil {
    44  		return node.Pos()
    45  	}
    46  	return token.NoPos
    47  }
    48  
    49  func getPos(src []ast.Node) token.Pos {
    50  	if src == nil {
    51  		return token.NoPos
    52  	}
    53  	return getSrcPos(src[0])
    54  }
    55  
    56  // ----------------------------------------------------------------------------
    57  
    58  type posNode struct {
    59  	pos, end token.Pos
    60  }
    61  
    62  func NewPosNode(pos token.Pos, end ...token.Pos) ast.Node {
    63  	ret := &posNode{pos: pos, end: pos}
    64  	if end != nil {
    65  		ret.end = end[0]
    66  	}
    67  	return ret
    68  }
    69  
    70  func (p *posNode) Pos() token.Pos { return p.pos }
    71  func (p *posNode) End() token.Pos { return p.end }
    72  
    73  // ----------------------------------------------------------------------------
    74  
    75  type codeBlock interface {
    76  	End(cb *CodeBuilder, src ast.Node)
    77  }
    78  
    79  type vblockCtx struct {
    80  	codeBlock
    81  	scope *types.Scope
    82  }
    83  
    84  type codeBlockCtx struct {
    85  	codeBlock
    86  	scope *types.Scope
    87  	base  int
    88  	stmts []ast.Stmt
    89  	label *ast.LabeledStmt
    90  	flows int // flow flags
    91  }
    92  
    93  const (
    94  	flowFlagBreak = 1 << iota
    95  	flowFlagContinue
    96  	flowFlagReturn
    97  	flowFlagGoto
    98  	flowFlagWithLabel
    99  )
   100  
   101  type Label struct {
   102  	types.Label
   103  	used bool
   104  }
   105  
   106  type funcBodyCtx struct {
   107  	codeBlockCtx
   108  	fn     *Func
   109  	labels map[string]*Label
   110  }
   111  
   112  func (p *funcBodyCtx) checkLabels(cb *CodeBuilder) {
   113  	for name, l := range p.labels {
   114  		if !l.used {
   115  			cb.handleCodeErrorf(l.Pos(), "label %s defined and not used", name)
   116  		}
   117  	}
   118  }
   119  
   120  type CodeError struct {
   121  	Fset dbgPositioner
   122  	Pos  token.Pos
   123  	Msg  string
   124  }
   125  
   126  func (p *CodeError) Error() string {
   127  	pos := p.Fset.Position(p.Pos)
   128  	return fmt.Sprintf("%v: %s", pos, p.Msg)
   129  }
   130  
   131  // CodeBuilder type
   132  type CodeBuilder struct {
   133  	stk       internal.Stack
   134  	current   funcBodyCtx
   135  	fset      dbgPositioner
   136  	comments  *ast.CommentGroup
   137  	pkg       *Package
   138  	btiMap    *typeutil.Map
   139  	valDecl   *ValueDecl
   140  	ctxt      *typesContext
   141  	interp    NodeInterpreter
   142  	rec       Recorder
   143  	loadNamed LoadNamedFunc
   144  	handleErr func(err error)
   145  	closureParamInsts
   146  	vFieldsMgr
   147  	iotav       int
   148  	commentOnce bool
   149  	noSkipConst bool
   150  }
   151  
   152  func (p *CodeBuilder) init(pkg *Package) {
   153  	conf := pkg.conf
   154  	p.pkg = pkg
   155  	p.fset = conf.DbgPositioner
   156  	if p.fset == nil {
   157  		p.fset = conf.Fset
   158  	}
   159  	p.noSkipConst = conf.NoSkipConstant
   160  	p.handleErr = conf.HandleErr
   161  	if p.handleErr == nil {
   162  		p.handleErr = defaultHandleErr
   163  	}
   164  	p.rec = conf.Recorder
   165  	p.interp = conf.NodeInterpreter
   166  	if p.interp == nil {
   167  		p.interp = nodeInterp{}
   168  	}
   169  	p.ctxt = newTypesContext()
   170  	p.loadNamed = conf.LoadNamed
   171  	if p.loadNamed == nil {
   172  		p.loadNamed = defaultLoadNamed
   173  	}
   174  	p.current.scope = pkg.Types.Scope()
   175  	p.stk.Init()
   176  	p.closureParamInsts.init()
   177  }
   178  
   179  func defaultLoadNamed(at *Package, t *types.Named) {
   180  	// no delay-loaded named types
   181  }
   182  
   183  func defaultHandleErr(err error) {
   184  	panic(err)
   185  }
   186  
   187  type nodeInterp struct{}
   188  
   189  func (p nodeInterp) LoadExpr(expr ast.Node) string {
   190  	return ""
   191  }
   192  
   193  func getFunExpr(fn *internal.Elem) (caller string, pos token.Pos) {
   194  	if fn == nil {
   195  		return "the closure call", token.NoPos
   196  	}
   197  	caller = types.ExprString(fn.Val)
   198  	pos = getSrcPos(fn.Src)
   199  	return
   200  }
   201  
   202  func getCaller(expr *internal.Elem) string {
   203  	if ce, ok := expr.Val.(*ast.CallExpr); ok {
   204  		return types.ExprString(ce.Fun)
   205  	}
   206  	return "the function call"
   207  }
   208  
   209  func (p *CodeBuilder) loadExpr(expr ast.Node) (string, token.Pos) {
   210  	if expr == nil {
   211  		return "", token.NoPos
   212  	}
   213  	return p.interp.LoadExpr(expr), expr.Pos()
   214  }
   215  
   216  func (p *CodeBuilder) newCodeError(pos token.Pos, msg string) *CodeError {
   217  	return &CodeError{Msg: msg, Pos: pos, Fset: p.fset}
   218  }
   219  
   220  func (p *CodeBuilder) newCodeErrorf(pos token.Pos, format string, args ...interface{}) *CodeError {
   221  	return p.newCodeError(pos, fmt.Sprintf(format, args...))
   222  }
   223  
   224  func (p *CodeBuilder) handleCodeError(pos token.Pos, msg string) {
   225  	p.handleErr(p.newCodeError(pos, msg))
   226  }
   227  
   228  func (p *CodeBuilder) handleCodeErrorf(pos token.Pos, format string, args ...interface{}) {
   229  	p.handleErr(p.newCodeError(pos, fmt.Sprintf(format, args...)))
   230  }
   231  
   232  func (p *CodeBuilder) panicCodeError(pos token.Pos, msg string) {
   233  	panic(p.newCodeError(pos, msg))
   234  }
   235  
   236  func (p *CodeBuilder) panicCodeErrorf(pos token.Pos, format string, args ...interface{}) {
   237  	panic(p.newCodeError(pos, fmt.Sprintf(format, args...)))
   238  }
   239  
   240  // Scope returns current scope.
   241  func (p *CodeBuilder) Scope() *types.Scope {
   242  	return p.current.scope
   243  }
   244  
   245  // Func returns current func (nil means in global scope).
   246  func (p *CodeBuilder) Func() *Func {
   247  	return p.current.fn
   248  }
   249  
   250  // Pkg returns the package instance.
   251  func (p *CodeBuilder) Pkg() *Package {
   252  	return p.pkg
   253  }
   254  
   255  func (p *CodeBuilder) startFuncBody(fn *Func, src []ast.Node, old *funcBodyCtx) *CodeBuilder {
   256  	p.current.fn, old.fn = fn, p.current.fn
   257  	p.current.labels, old.labels = nil, p.current.labels
   258  	p.startBlockStmt(fn, src, "func "+fn.Name(), &old.codeBlockCtx)
   259  	scope := p.current.scope
   260  	sig := fn.Type().(*types.Signature)
   261  	insertParams(scope, sig.Params())
   262  	insertParams(scope, sig.Results())
   263  	if recv := sig.Recv(); recv != nil {
   264  		scope.Insert(recv)
   265  	}
   266  	return p
   267  }
   268  
   269  func insertParams(scope *types.Scope, params *types.Tuple) {
   270  	for i, n := 0, params.Len(); i < n; i++ {
   271  		v := params.At(i)
   272  		if name := v.Name(); name != "" && name != "_" {
   273  			scope.Insert(v)
   274  		}
   275  	}
   276  }
   277  
   278  func (p *CodeBuilder) endFuncBody(old funcBodyCtx) []ast.Stmt {
   279  	p.current.checkLabels(p)
   280  	p.current.fn = old.fn
   281  	p.current.labels = old.labels
   282  	stmts, _ := p.endBlockStmt(&old.codeBlockCtx)
   283  	return stmts
   284  }
   285  
   286  func (p *CodeBuilder) startBlockStmt(current codeBlock, src []ast.Node, comment string, old *codeBlockCtx) *CodeBuilder {
   287  	var start, end token.Pos
   288  	if src != nil {
   289  		start, end = src[0].Pos(), src[0].End()
   290  	}
   291  	scope := types.NewScope(p.current.scope, start, end, comment)
   292  	p.current.codeBlockCtx, *old = codeBlockCtx{current, scope, p.stk.Len(), nil, nil, 0}, p.current.codeBlockCtx
   293  	return p
   294  }
   295  
   296  func (p *CodeBuilder) endBlockStmt(old *codeBlockCtx) ([]ast.Stmt, int) {
   297  	flows := p.current.flows
   298  	if p.current.label != nil {
   299  		p.emitStmt(&ast.EmptyStmt{})
   300  	}
   301  	stmts := p.current.stmts
   302  	p.stk.SetLen(p.current.base)
   303  	p.current.codeBlockCtx = *old
   304  	return stmts, flows
   305  }
   306  
   307  func (p *CodeBuilder) clearBlockStmt() []ast.Stmt {
   308  	stmts := p.current.stmts
   309  	p.current.stmts = nil
   310  	return stmts
   311  }
   312  
   313  func (p *CodeBuilder) startVBlockStmt(current codeBlock, comment string, old *vblockCtx) *CodeBuilder {
   314  	*old = vblockCtx{codeBlock: p.current.codeBlock, scope: p.current.scope}
   315  	scope := types.NewScope(p.current.scope, token.NoPos, token.NoPos, comment)
   316  	p.current.codeBlock, p.current.scope = current, scope
   317  	return p
   318  }
   319  
   320  func (p *CodeBuilder) endVBlockStmt(old *vblockCtx) {
   321  	p.current.codeBlock, p.current.scope = old.codeBlock, old.scope
   322  }
   323  
   324  func (p *CodeBuilder) popStmt() ast.Stmt {
   325  	stmts := p.current.stmts
   326  	n := len(stmts) - 1
   327  	stmt := stmts[n]
   328  	p.current.stmts = stmts[:n]
   329  	return stmt
   330  }
   331  
   332  func (p *CodeBuilder) startStmtAt(stmt ast.Stmt) int {
   333  	idx := len(p.current.stmts)
   334  	p.emitStmt(stmt)
   335  	return idx
   336  }
   337  
   338  // Usage:
   339  //
   340  //	idx := cb.startStmtAt(stmt)
   341  //	...
   342  //	cb.commitStmt(idx)
   343  func (p *CodeBuilder) commitStmt(idx int) {
   344  	stmts := p.current.stmts
   345  	n := len(stmts) - 1
   346  	if n > idx {
   347  		stmt := stmts[idx]
   348  		copy(stmts[idx:], stmts[idx+1:])
   349  		stmts[n] = stmt
   350  	}
   351  }
   352  
   353  func (p *CodeBuilder) emitStmt(stmt ast.Stmt) {
   354  	if p.comments != nil {
   355  		p.pkg.setStmtComments(stmt, p.comments)
   356  		if p.commentOnce {
   357  			p.comments = nil
   358  		}
   359  	}
   360  	if p.current.label != nil {
   361  		p.current.label.Stmt = stmt
   362  		stmt, p.current.label = p.current.label, nil
   363  	}
   364  	p.current.stmts = append(p.current.stmts, stmt)
   365  }
   366  
   367  func (p *CodeBuilder) startInitExpr(current codeBlock) (old codeBlock) {
   368  	p.current.codeBlock, old = current, p.current.codeBlock
   369  	return
   370  }
   371  
   372  func (p *CodeBuilder) endInitExpr(old codeBlock) {
   373  	p.current.codeBlock = old
   374  }
   375  
   376  // Comments returns the comments of next statement.
   377  func (p *CodeBuilder) Comments() *ast.CommentGroup {
   378  	return p.comments
   379  }
   380  
   381  func (p *CodeBuilder) BackupComments() (*ast.CommentGroup, bool) {
   382  	return p.comments, p.commentOnce
   383  }
   384  
   385  // SetComments sets comments to next statement.
   386  func (p *CodeBuilder) SetComments(comments *ast.CommentGroup, once bool) *CodeBuilder {
   387  	if debugComments && comments != nil {
   388  		for i, c := range comments.List {
   389  			log.Println("SetComments", i, c.Text)
   390  		}
   391  	}
   392  	p.comments, p.commentOnce = comments, once
   393  	return p
   394  }
   395  
   396  // ReturnErr func
   397  func (p *CodeBuilder) ReturnErr(outer bool) *CodeBuilder {
   398  	if debugInstr {
   399  		log.Println("ReturnErr", outer)
   400  	}
   401  	fn := p.current.fn
   402  	if outer {
   403  		if !fn.isInline() {
   404  			panic("only support ReturnOuterErr in an inline call")
   405  		}
   406  		fn = fn.old.fn
   407  	}
   408  	results := fn.Type().(*types.Signature).Results()
   409  	n := results.Len()
   410  	if n > 0 {
   411  		last := results.At(n - 1)
   412  		if last.Type() == TyError { // last result is error
   413  			err := p.stk.Pop()
   414  			for i := 0; i < n-1; i++ {
   415  				p.doZeroLit(results.At(i).Type(), false)
   416  			}
   417  			p.stk.Push(err)
   418  			p.returnResults(n)
   419  			p.current.flows |= flowFlagReturn
   420  			return p
   421  		}
   422  	}
   423  	panic("TODO: last result type isn't an error")
   424  }
   425  
   426  func (p *CodeBuilder) returnResults(n int) {
   427  	var rets []ast.Expr
   428  	if n > 0 {
   429  		args := p.stk.GetArgs(n)
   430  		rets = make([]ast.Expr, n)
   431  		for i := 0; i < n; i++ {
   432  			rets[i] = args[i].Val
   433  		}
   434  		p.stk.PopN(n)
   435  	}
   436  	p.emitStmt(&ast.ReturnStmt{Results: rets})
   437  }
   438  
   439  // Return func
   440  func (p *CodeBuilder) Return(n int, src ...ast.Node) *CodeBuilder {
   441  	if debugInstr {
   442  		log.Println("Return", n)
   443  	}
   444  	fn := p.current.fn
   445  	results := fn.Type().(*types.Signature).Results()
   446  	checkFuncResults(p.pkg, p.stk.GetArgs(n), results, getSrc(src))
   447  	if fn.isInline() {
   448  		for i := n - 1; i >= 0; i-- {
   449  			key := closureParamInst{fn, results.At(i)}
   450  			elem := p.stk.Pop()
   451  			p.doVarRef(p.paramInsts[key], nil, false)
   452  			p.stk.Push(elem)
   453  			p.doAssignWith(1, 1, nil)
   454  		}
   455  		p.Goto(p.getEndingLabel(fn))
   456  	} else {
   457  		p.current.flows |= flowFlagReturn
   458  		p.returnResults(n)
   459  	}
   460  	return p
   461  }
   462  
   463  // Call func
   464  func (p *CodeBuilder) Call(n int, ellipsis ...bool) *CodeBuilder {
   465  	var flags InstrFlags
   466  	if ellipsis != nil && ellipsis[0] {
   467  		flags = InstrFlagEllipsis
   468  	}
   469  	return p.CallWith(n, flags)
   470  }
   471  
   472  // CallWith always panics on error, while CallWithEx returns err if match function call failed.
   473  func (p *CodeBuilder) CallWith(n int, flags InstrFlags, src ...ast.Node) *CodeBuilder {
   474  	if err := p.CallWithEx(n, flags, src...); err != nil {
   475  		panic(err)
   476  	}
   477  	return p
   478  }
   479  
   480  // CallWith always panics on error, while CallWithEx returns err if match function call failed.
   481  // If an error ocurs, CallWithEx pops all function arguments from the CodeBuilder stack.
   482  // In most case, you should call CallWith instead of CallWithEx.
   483  func (p *CodeBuilder) CallWithEx(n int, flags InstrFlags, src ...ast.Node) error {
   484  	fn := p.stk.Get(-(n + 1))
   485  	if t, ok := fn.Type.(*btiMethodType); ok {
   486  		n++
   487  		fn.Type = t.Type
   488  		fn = p.stk.Get(-(n + 1))
   489  		if t.eargs != nil {
   490  			for _, arg := range t.eargs {
   491  				p.Val(arg)
   492  			}
   493  			n += len(t.eargs)
   494  		}
   495  	}
   496  	args := p.stk.GetArgs(n)
   497  	if debugInstr {
   498  		log.Println("Call", n, int(flags), "//", fn.Type)
   499  	}
   500  	s := getSrc(src)
   501  	fn.Src = s
   502  	ret, err := matchFuncCall(p.pkg, fn, args, flags)
   503  	if err != nil {
   504  		p.stk.PopN(n)
   505  		return err
   506  	}
   507  	ret.Src = s
   508  	p.stk.Ret(n+1, ret)
   509  	return nil
   510  }
   511  
   512  type closureParamInst struct {
   513  	inst  *Func
   514  	param *types.Var
   515  }
   516  
   517  type closureParamInsts struct {
   518  	paramInsts map[closureParamInst]*types.Var
   519  }
   520  
   521  func (p *closureParamInsts) init() {
   522  	p.paramInsts = make(map[closureParamInst]*types.Var)
   523  }
   524  
   525  func (p *CodeBuilder) getEndingLabel(fn *Func) *Label {
   526  	key := closureParamInst{fn, nil}
   527  	if v, ok := p.paramInsts[key]; ok {
   528  		return p.current.labels[v.Name()]
   529  	}
   530  	ending := p.pkg.autoName()
   531  	p.paramInsts[key] = types.NewParam(token.NoPos, nil, ending, nil)
   532  	return p.NewLabel(token.NoPos, ending)
   533  }
   534  
   535  func (p *CodeBuilder) needEndingLabel(fn *Func) (*Label, bool) {
   536  	key := closureParamInst{fn, nil}
   537  	if v, ok := p.paramInsts[key]; ok {
   538  		return p.current.labels[v.Name()], true
   539  	}
   540  	return nil, false
   541  }
   542  
   543  func (p *Func) inlineClosureEnd(cb *CodeBuilder) {
   544  	if ending, ok := cb.needEndingLabel(p); ok {
   545  		cb.Label(ending)
   546  	}
   547  	sig := p.Type().(*types.Signature)
   548  	cb.emitStmt(&ast.BlockStmt{List: cb.endFuncBody(p.old)})
   549  	cb.stk.PopN(p.getInlineCallArity())
   550  	results := sig.Results()
   551  	for i, n := 0, results.Len(); i < n; i++ { // return results & clean env
   552  		key := closureParamInst{p, results.At(i)}
   553  		cb.pushVal(cb.paramInsts[key], nil)
   554  		delete(cb.paramInsts, key)
   555  	}
   556  	for i, n := 0, getParamLen(sig); i < n; i++ { // clean env
   557  		key := closureParamInst{p, getParam(sig, i)}
   558  		delete(cb.paramInsts, key)
   559  	}
   560  }
   561  
   562  // CallInlineClosureStart func
   563  func (p *CodeBuilder) CallInlineClosureStart(sig *types.Signature, arity int, ellipsis bool) *CodeBuilder {
   564  	if debugInstr {
   565  		log.Println("CallInlineClosureStart", arity, ellipsis)
   566  	}
   567  	pkg := p.pkg
   568  	closure := pkg.newInlineClosure(sig, arity)
   569  	results := sig.Results()
   570  	for i, n := 0, results.Len(); i < n; i++ {
   571  		p.emitVar(pkg, closure, results.At(i), false)
   572  	}
   573  	p.startFuncBody(closure, nil, &closure.old)
   574  	args := p.stk.GetArgs(arity)
   575  	var flags InstrFlags
   576  	if ellipsis {
   577  		flags = InstrFlagEllipsis
   578  	}
   579  	if err := matchFuncType(pkg, args, flags, sig, nil); err != nil {
   580  		panic(err)
   581  	}
   582  	n1 := getParamLen(sig) - 1
   583  	if sig.Variadic() && !ellipsis {
   584  		p.SliceLit(getParam(sig, n1).Type().(*types.Slice), arity-n1)
   585  	}
   586  	for i := n1; i >= 0; i-- {
   587  		p.emitVar(pkg, closure, getParam(sig, i), true)
   588  	}
   589  	return p
   590  }
   591  
   592  func (p *CodeBuilder) emitVar(pkg *Package, closure *Func, param *types.Var, withInit bool) {
   593  	name := pkg.autoName()
   594  	if withInit {
   595  		p.NewVarStart(param.Type(), name).EndInit(1)
   596  	} else {
   597  		p.NewVar(param.Type(), name)
   598  	}
   599  	key := closureParamInst{closure, param}
   600  	p.paramInsts[key] = p.current.scope.Lookup(name).(*types.Var)
   601  }
   602  
   603  // NewClosure func
   604  func (p *CodeBuilder) NewClosure(params, results *Tuple, variadic bool) *Func {
   605  	sig := types.NewSignatureType(nil, nil, nil, params, results, variadic)
   606  	return p.NewClosureWith(sig)
   607  }
   608  
   609  // NewClosureWith func
   610  func (p *CodeBuilder) NewClosureWith(sig *types.Signature) *Func {
   611  	if debugInstr {
   612  		t := sig.Params()
   613  		for i, n := 0, t.Len(); i < n; i++ {
   614  			v := t.At(i)
   615  			if _, ok := v.Type().(*unboundType); ok {
   616  				panic("can't use unbound type in func parameters")
   617  			}
   618  		}
   619  	}
   620  	return p.pkg.newClosure(sig)
   621  }
   622  
   623  // NewType func
   624  func (p *CodeBuilder) NewType(name string, src ...ast.Node) *TypeDecl {
   625  	return p.NewTypeDefs().NewType(name, src...)
   626  }
   627  
   628  // AliasType func
   629  func (p *CodeBuilder) AliasType(name string, typ types.Type, src ...ast.Node) *types.Named {
   630  	decl := p.NewTypeDefs().AliasType(name, typ, src...)
   631  	return decl.typ
   632  }
   633  
   634  // NewConstStart func
   635  func (p *CodeBuilder) NewConstStart(typ types.Type, names ...string) *CodeBuilder {
   636  	if debugInstr {
   637  		log.Println("NewConstStart", names)
   638  	}
   639  	defs := p.valueDefs(token.CONST)
   640  	return p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.CONST, typ, names...).InitStart(p.pkg)
   641  }
   642  
   643  // NewVar func
   644  func (p *CodeBuilder) NewVar(typ types.Type, names ...string) *CodeBuilder {
   645  	if debugInstr {
   646  		log.Println("NewVar", names)
   647  	}
   648  	defs := p.valueDefs(token.VAR)
   649  	p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.VAR, typ, names...)
   650  	return p
   651  }
   652  
   653  // NewVarStart func
   654  func (p *CodeBuilder) NewVarStart(typ types.Type, names ...string) *CodeBuilder {
   655  	if debugInstr {
   656  		log.Println("NewVarStart", names)
   657  	}
   658  	defs := p.valueDefs(token.VAR)
   659  	return p.pkg.newValueDecl(defs.NewPos(), defs.scope, token.NoPos, token.VAR, typ, names...).InitStart(p.pkg)
   660  }
   661  
   662  // DefineVarStart func
   663  func (p *CodeBuilder) DefineVarStart(pos token.Pos, names ...string) *CodeBuilder {
   664  	if debugInstr {
   665  		log.Println("DefineVarStart", names)
   666  	}
   667  	return p.pkg.newValueDecl(
   668  		ValueAt{}, p.current.scope, pos, token.DEFINE, nil, names...).InitStart(p.pkg)
   669  }
   670  
   671  // NewAutoVar func
   672  func (p *CodeBuilder) NewAutoVar(pos token.Pos, name string, pv **types.Var) *CodeBuilder {
   673  	spec := &ast.ValueSpec{Names: []*ast.Ident{ident(name)}}
   674  	decl := &ast.GenDecl{Tok: token.VAR, Specs: []ast.Spec{spec}}
   675  	stmt := &ast.DeclStmt{
   676  		Decl: decl,
   677  	}
   678  	if debugInstr {
   679  		log.Println("NewAutoVar", name)
   680  	}
   681  	p.emitStmt(stmt)
   682  	typ := &unboundType{ptypes: []*ast.Expr{&spec.Type}}
   683  	*pv = types.NewVar(pos, p.pkg.Types, name, typ)
   684  	if old := p.current.scope.Insert(*pv); old != nil {
   685  		oldPos := p.fset.Position(old.Pos())
   686  		p.panicCodeErrorf(
   687  			pos, "%s redeclared in this block\n\tprevious declaration at %v", name, oldPos)
   688  	}
   689  	return p
   690  }
   691  
   692  // VarRef func: p.VarRef(nil) means underscore (_)
   693  func (p *CodeBuilder) VarRef(ref interface{}, src ...ast.Node) *CodeBuilder {
   694  	return p.doVarRef(ref, getSrc(src), true)
   695  }
   696  
   697  func (p *CodeBuilder) doVarRef(ref interface{}, src ast.Node, allowDebug bool) *CodeBuilder {
   698  	if ref == nil {
   699  		if allowDebug && debugInstr {
   700  			log.Println("VarRef _")
   701  		}
   702  		p.stk.Push(&internal.Elem{
   703  			Val: underscore, // _
   704  		})
   705  	} else {
   706  		switch v := ref.(type) {
   707  		case *types.Var:
   708  			if allowDebug && debugInstr {
   709  				log.Println("VarRef", v.Name(), v.Type())
   710  			}
   711  			fn := p.current.fn
   712  			if fn != nil && fn.isInline() { // is in an inline call
   713  				key := closureParamInst{fn, v}
   714  				if arg, ok := p.paramInsts[key]; ok { // replace param with arg
   715  					v = arg
   716  				}
   717  			}
   718  			p.stk.Push(&internal.Elem{
   719  				Val: toObjectExpr(p.pkg, v), Type: &refType{typ: v.Type()}, Src: src,
   720  			})
   721  		default:
   722  			code, pos := p.loadExpr(src)
   723  			p.panicCodeErrorf(pos, "%s is not a variable", code)
   724  		}
   725  	}
   726  	return p
   727  }
   728  
   729  var (
   730  	elemNone = &internal.Elem{}
   731  )
   732  
   733  // None func
   734  func (p *CodeBuilder) None() *CodeBuilder {
   735  	if debugInstr {
   736  		log.Println("None")
   737  	}
   738  	p.stk.Push(elemNone)
   739  	return p
   740  }
   741  
   742  // ZeroLit func
   743  func (p *CodeBuilder) ZeroLit(typ types.Type) *CodeBuilder {
   744  	return p.doZeroLit(typ, true)
   745  }
   746  
   747  func (p *CodeBuilder) doZeroLit(typ types.Type, allowDebug bool) *CodeBuilder {
   748  	typ0 := typ
   749  	if allowDebug && debugInstr {
   750  		log.Println("ZeroLit //", typ)
   751  	}
   752  retry:
   753  	switch t := typ.(type) {
   754  	case *types.Basic:
   755  		switch kind := t.Kind(); kind {
   756  		case types.Bool:
   757  			return p.Val(false)
   758  		case types.String:
   759  			return p.Val("")
   760  		case types.UnsafePointer:
   761  			return p.Val(nil)
   762  		default:
   763  			return p.Val(0)
   764  		}
   765  	case *types.Interface, *types.Map, *types.Slice, *types.Pointer, *types.Signature, *types.Chan:
   766  		return p.Val(nil)
   767  	case *types.Named:
   768  		typ = p.getUnderlying(t)
   769  		goto retry
   770  	}
   771  	ret := &ast.CompositeLit{}
   772  	switch t := typ.(type) {
   773  	case *unboundType:
   774  		if t.tBound == nil {
   775  			t.ptypes = append(t.ptypes, &ret.Type)
   776  		} else {
   777  			typ = t.tBound
   778  			typ0 = typ
   779  			ret.Type = toType(p.pkg, typ)
   780  		}
   781  	default:
   782  		ret.Type = toType(p.pkg, typ)
   783  	}
   784  	p.stk.Push(&internal.Elem{Type: typ0, Val: ret})
   785  	return p
   786  }
   787  
   788  // MapLit func
   789  func (p *CodeBuilder) MapLit(typ types.Type, arity int, src ...ast.Node) *CodeBuilder {
   790  	if err := p.MapLitEx(typ, arity, src...); err != nil {
   791  		panic(err)
   792  	}
   793  	return p
   794  }
   795  
   796  // MapLit func
   797  func (p *CodeBuilder) MapLitEx(typ types.Type, arity int, src ...ast.Node) error {
   798  	if debugInstr {
   799  		log.Println("MapLit", typ, arity)
   800  	}
   801  	var t *types.Map
   802  	var typExpr ast.Expr
   803  	var pkg = p.pkg
   804  	if typ != nil {
   805  		var ok bool
   806  		switch tt := typ.(type) {
   807  		case *types.Named:
   808  			typExpr = toNamedType(pkg, tt)
   809  			t, ok = p.getUnderlying(tt).(*types.Map)
   810  		case *types.Map:
   811  			typExpr = toMapType(pkg, tt)
   812  			t, ok = tt, true
   813  		}
   814  		if !ok {
   815  			return p.newCodeErrorf(getPos(src), "type %v isn't a map", typ)
   816  		}
   817  	}
   818  	if arity == 0 {
   819  		if t == nil {
   820  			t = types.NewMap(types.Typ[types.String], TyEmptyInterface)
   821  			typ = t
   822  			typExpr = toMapType(pkg, t)
   823  		}
   824  		ret := &ast.CompositeLit{Type: typExpr}
   825  		p.stk.Push(&internal.Elem{Type: typ, Val: ret, Src: getSrc(src)})
   826  		return nil
   827  	}
   828  	if (arity & 1) != 0 {
   829  		return p.newCodeErrorf(getPos(src), "MapLit: invalid arity, can't be odd - %d", arity)
   830  	}
   831  	var key, val types.Type
   832  	var args = p.stk.GetArgs(arity)
   833  	var check = (t != nil)
   834  	if check {
   835  		key, val = t.Key(), t.Elem()
   836  	} else {
   837  		key = boundElementType(pkg, args, 0, arity, 2)
   838  		val = boundElementType(pkg, args, 1, arity, 2)
   839  		t = types.NewMap(Default(pkg, key), Default(pkg, val))
   840  		typ = t
   841  		typExpr = toMapType(pkg, t)
   842  	}
   843  	elts := make([]ast.Expr, arity>>1)
   844  	for i := 0; i < arity; i += 2 {
   845  		elts[i>>1] = &ast.KeyValueExpr{Key: args[i].Val, Value: args[i+1].Val}
   846  		if check {
   847  			if !AssignableTo(pkg, args[i].Type, key) {
   848  				src, pos := p.loadExpr(args[i].Src)
   849  				return p.newCodeErrorf(
   850  					pos, "cannot use %s (type %v) as type %v in map key", src, args[i].Type, key)
   851  			} else if !AssignableTo(pkg, args[i+1].Type, val) {
   852  				src, pos := p.loadExpr(args[i+1].Src)
   853  				return p.newCodeErrorf(
   854  					pos, "cannot use %s (type %v) as type %v in map value", src, args[i+1].Type, val)
   855  			}
   856  		}
   857  	}
   858  	p.stk.Ret(arity, &internal.Elem{
   859  		Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src),
   860  	})
   861  	return nil
   862  }
   863  
   864  func (p *CodeBuilder) toBoundArrayLen(elts []*internal.Elem, arity, limit int) int {
   865  	n := -1
   866  	max := -1
   867  	for i := 0; i < arity; i += 2 {
   868  		if elts[i].Val != nil {
   869  			n = p.toIntVal(elts[i], "index which must be non-negative integer constant")
   870  		} else {
   871  			n++
   872  		}
   873  		if limit >= 0 && n >= limit { // error message
   874  			if elts[i].Src == nil {
   875  				pos := getSrcPos(elts[i+1].Src)
   876  				p.panicCodeErrorf(pos, "array index %d out of bounds [0:%d]", n, limit)
   877  			}
   878  			src, pos := p.loadExpr(elts[i].Src)
   879  			p.panicCodeErrorf(pos, "array index %s (value %d) out of bounds [0:%d]", src, n, limit)
   880  		}
   881  		if max < n {
   882  			max = n
   883  		}
   884  	}
   885  	return max + 1
   886  }
   887  
   888  func (p *CodeBuilder) toIntVal(v *internal.Elem, msg string) int {
   889  	if cval := v.CVal; cval != nil && cval.Kind() == constant.Int {
   890  		if v, ok := constant.Int64Val(cval); ok {
   891  			return int(v)
   892  		}
   893  	}
   894  	code, pos := p.loadExpr(v.Src)
   895  	p.panicCodeErrorf(pos, "cannot use %s as %s", code, msg)
   896  	return 0
   897  }
   898  
   899  func (p *CodeBuilder) indexElemExpr(args []*internal.Elem, i int) ast.Expr {
   900  	key := args[i].Val
   901  	if key == nil { // none
   902  		return args[i+1].Val
   903  	}
   904  	p.toIntVal(args[i], "index which must be non-negative integer constant")
   905  	return &ast.KeyValueExpr{Key: key, Value: args[i+1].Val}
   906  }
   907  
   908  // SliceLit func
   909  func (p *CodeBuilder) SliceLit(typ types.Type, arity int, keyVal ...bool) *CodeBuilder {
   910  	var keyValMode = (keyVal != nil && keyVal[0])
   911  	return p.SliceLitEx(typ, arity, keyValMode)
   912  }
   913  
   914  // SliceLitEx func
   915  func (p *CodeBuilder) SliceLitEx(typ types.Type, arity int, keyVal bool, src ...ast.Node) *CodeBuilder {
   916  	var elts []ast.Expr
   917  	if debugInstr {
   918  		log.Println("SliceLit", typ, arity, keyVal)
   919  	}
   920  	var t *types.Slice
   921  	var typExpr ast.Expr
   922  	var pkg = p.pkg
   923  	if typ != nil {
   924  		switch tt := typ.(type) {
   925  		case *types.Named:
   926  			typExpr = toNamedType(pkg, tt)
   927  			t = p.getUnderlying(tt).(*types.Slice)
   928  		case *types.Slice:
   929  			typExpr = toSliceType(pkg, tt)
   930  			t = tt
   931  		default:
   932  			log.Panicln("SliceLit: typ isn't a slice type -", reflect.TypeOf(typ))
   933  		}
   934  	}
   935  	if keyVal { // in keyVal mode
   936  		if (arity & 1) != 0 {
   937  			log.Panicln("SliceLit: invalid arity, can't be odd in keyVal mode -", arity)
   938  		}
   939  		args := p.stk.GetArgs(arity)
   940  		val := t.Elem()
   941  		n := arity >> 1
   942  		elts = make([]ast.Expr, n)
   943  		for i := 0; i < arity; i += 2 {
   944  			arg := args[i+1]
   945  			if !AssignableConv(pkg, arg.Type, val, arg) {
   946  				src, pos := p.loadExpr(args[i+1].Src)
   947  				p.panicCodeErrorf(
   948  					pos, "cannot use %s (type %v) as type %v in slice literal", src, args[i+1].Type, val)
   949  			}
   950  			elts[i>>1] = p.indexElemExpr(args, i)
   951  		}
   952  	} else {
   953  		if arity == 0 {
   954  			if t == nil {
   955  				t = types.NewSlice(TyEmptyInterface)
   956  				typ = t
   957  				typExpr = toSliceType(pkg, t)
   958  			}
   959  			p.stk.Push(&internal.Elem{
   960  				Type: typ, Val: &ast.CompositeLit{Type: typExpr}, Src: getSrc(src),
   961  			})
   962  			return p
   963  		}
   964  		var val types.Type
   965  		var args = p.stk.GetArgs(arity)
   966  		var check = (t != nil)
   967  		if check {
   968  			val = t.Elem()
   969  		} else {
   970  			val = boundElementType(pkg, args, 0, arity, 1)
   971  			t = types.NewSlice(Default(pkg, val))
   972  			typ = t
   973  			typExpr = toSliceType(pkg, t)
   974  		}
   975  		elts = make([]ast.Expr, arity)
   976  		for i, arg := range args {
   977  			elts[i] = arg.Val
   978  			if check {
   979  				if !AssignableConv(pkg, arg.Type, val, arg) {
   980  					src, pos := p.loadExpr(arg.Src)
   981  					p.panicCodeErrorf(
   982  						pos, "cannot use %s (type %v) as type %v in slice literal", src, arg.Type, val)
   983  				}
   984  			}
   985  		}
   986  	}
   987  	p.stk.Ret(arity, &internal.Elem{
   988  		Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src),
   989  	})
   990  	return p
   991  }
   992  
   993  // ArrayLit func
   994  func (p *CodeBuilder) ArrayLit(typ types.Type, arity int, keyVal ...bool) *CodeBuilder {
   995  	var keyValMode = (keyVal != nil && keyVal[0])
   996  	return p.ArrayLitEx(typ, arity, keyValMode)
   997  }
   998  
   999  // ArrayLitEx func
  1000  func (p *CodeBuilder) ArrayLitEx(typ types.Type, arity int, keyVal bool, src ...ast.Node) *CodeBuilder {
  1001  	var elts []ast.Expr
  1002  	if debugInstr {
  1003  		log.Println("ArrayLit", typ, arity, keyVal)
  1004  	}
  1005  	var t *types.Array
  1006  	var typExpr ast.Expr
  1007  	var pkg = p.pkg
  1008  	switch tt := typ.(type) {
  1009  	case *types.Named:
  1010  		typExpr = toNamedType(pkg, tt)
  1011  		t = p.getUnderlying(tt).(*types.Array)
  1012  	case *types.Array:
  1013  		typExpr = toArrayType(pkg, tt)
  1014  		t = tt
  1015  	default:
  1016  		log.Panicln("ArrayLit: typ isn't a array type -", reflect.TypeOf(typ))
  1017  	}
  1018  	if keyVal { // in keyVal mode
  1019  		if (arity & 1) != 0 {
  1020  			log.Panicln("ArrayLit: invalid arity, can't be odd in keyVal mode -", arity)
  1021  		}
  1022  		n := int(t.Len())
  1023  		args := p.stk.GetArgs(arity)
  1024  		max := p.toBoundArrayLen(args, arity, n)
  1025  		val := t.Elem()
  1026  		if n < 0 {
  1027  			t = types.NewArray(val, int64(max))
  1028  			typ = t
  1029  		}
  1030  		elts = make([]ast.Expr, arity>>1)
  1031  		for i := 0; i < arity; i += 2 {
  1032  			if !AssignableTo(pkg, args[i+1].Type, val) {
  1033  				src, pos := p.loadExpr(args[i+1].Src)
  1034  				p.panicCodeErrorf(
  1035  					pos, "cannot use %s (type %v) as type %v in array literal", src, args[i+1].Type, val)
  1036  			}
  1037  			elts[i>>1] = p.indexElemExpr(args, i)
  1038  		}
  1039  	} else {
  1040  		args := p.stk.GetArgs(arity)
  1041  		val := t.Elem()
  1042  		if n := t.Len(); n < 0 {
  1043  			t = types.NewArray(val, int64(arity))
  1044  			typ = t
  1045  		} else if int(n) < arity {
  1046  			pos := getSrcPos(args[n].Src)
  1047  			p.panicCodeErrorf(pos, "array index %d out of bounds [0:%d]", n, n)
  1048  		}
  1049  		elts = make([]ast.Expr, arity)
  1050  		for i, arg := range args {
  1051  			elts[i] = arg.Val
  1052  			if !AssignableConv(pkg, arg.Type, val, arg) {
  1053  				src, pos := p.loadExpr(arg.Src)
  1054  				p.panicCodeErrorf(
  1055  					pos, "cannot use %s (type %v) as type %v in array literal", src, arg.Type, val)
  1056  			}
  1057  		}
  1058  	}
  1059  	p.stk.Ret(arity, &internal.Elem{
  1060  		Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src),
  1061  	})
  1062  	return p
  1063  }
  1064  
  1065  // StructLit func
  1066  func (p *CodeBuilder) StructLit(typ types.Type, arity int, keyVal bool, src ...ast.Node) *CodeBuilder {
  1067  	if debugInstr {
  1068  		log.Println("StructLit", typ, arity, keyVal)
  1069  	}
  1070  	var t *types.Struct
  1071  	var typExpr ast.Expr
  1072  	var pkg = p.pkg
  1073  	switch tt := typ.(type) {
  1074  	case *types.Named:
  1075  		typExpr = toNamedType(pkg, tt)
  1076  		t = p.getUnderlying(tt).(*types.Struct)
  1077  	case *types.Struct:
  1078  		typExpr = toStructType(pkg, tt)
  1079  		t = tt
  1080  	default:
  1081  		log.Panicln("StructLit: typ isn't a struct type -", reflect.TypeOf(typ))
  1082  	}
  1083  	var elts []ast.Expr
  1084  	var n = t.NumFields()
  1085  	var args = p.stk.GetArgs(arity)
  1086  	if keyVal {
  1087  		if (arity & 1) != 0 {
  1088  			log.Panicln("StructLit: invalid arity, can't be odd in keyVal mode -", arity)
  1089  		}
  1090  		elts = make([]ast.Expr, arity>>1)
  1091  		for i := 0; i < arity; i += 2 {
  1092  			idx := p.toIntVal(args[i], "field which must be non-negative integer constant")
  1093  			if idx >= n {
  1094  				panic("invalid struct field index")
  1095  			}
  1096  			elt := t.Field(idx)
  1097  			eltTy, eltName := elt.Type(), elt.Name()
  1098  			if !AssignableTo(pkg, args[i+1].Type, eltTy) {
  1099  				src, pos := p.loadExpr(args[i+1].Src)
  1100  				p.panicCodeErrorf(
  1101  					pos, "cannot use %s (type %v) as type %v in value of field %s",
  1102  					src, args[i+1].Type, eltTy, eltName)
  1103  			}
  1104  			elts[i>>1] = &ast.KeyValueExpr{Key: ident(eltName), Value: args[i+1].Val}
  1105  		}
  1106  	} else if arity != n {
  1107  		if arity != 0 {
  1108  			fewOrMany := "few"
  1109  			if arity > n {
  1110  				fewOrMany = "many"
  1111  			}
  1112  			pos := getSrcPos(args[arity-1].Src)
  1113  			p.panicCodeErrorf(pos, "too %s values in %v{...}", fewOrMany, typ)
  1114  		}
  1115  	} else {
  1116  		elts = make([]ast.Expr, arity)
  1117  		for i, arg := range args {
  1118  			elts[i] = arg.Val
  1119  			eltTy := t.Field(i).Type()
  1120  			if !AssignableTo(pkg, arg.Type, eltTy) {
  1121  				src, pos := p.loadExpr(arg.Src)
  1122  				p.panicCodeErrorf(
  1123  					pos, "cannot use %s (type %v) as type %v in value of field %s",
  1124  					src, arg.Type, eltTy, t.Field(i).Name())
  1125  			}
  1126  		}
  1127  	}
  1128  	p.stk.Ret(arity, &internal.Elem{
  1129  		Type: typ, Val: &ast.CompositeLit{Type: typExpr, Elts: elts}, Src: getSrc(src),
  1130  	})
  1131  	return p
  1132  }
  1133  
  1134  // Slice func
  1135  func (p *CodeBuilder) Slice(slice3 bool, src ...ast.Node) *CodeBuilder { // a[i:j:k]
  1136  	if debugInstr {
  1137  		log.Println("Slice", slice3)
  1138  	}
  1139  	n := 3
  1140  	if slice3 {
  1141  		n++
  1142  	}
  1143  	srcExpr := getSrc(src)
  1144  	args := p.stk.GetArgs(n)
  1145  	x := args[0]
  1146  	typ := x.Type
  1147  	switch t := typ.(type) {
  1148  	case *types.Slice:
  1149  		// nothing to do
  1150  	case *types.Basic:
  1151  		if t.Kind() == types.String || t.Kind() == types.UntypedString {
  1152  			if slice3 {
  1153  				code, pos := p.loadExpr(srcExpr)
  1154  				p.panicCodeErrorf(pos, "invalid operation %s (3-index slice of string)", code)
  1155  			}
  1156  		} else {
  1157  			code, pos := p.loadExpr(x.Src)
  1158  			p.panicCodeErrorf(pos, "cannot slice %s (type %v)", code, typ)
  1159  		}
  1160  	case *types.Array:
  1161  		typ = types.NewSlice(t.Elem())
  1162  	case *types.Pointer:
  1163  		if tt, ok := t.Elem().(*types.Array); ok {
  1164  			typ = types.NewSlice(tt.Elem())
  1165  		} else {
  1166  			code, pos := p.loadExpr(x.Src)
  1167  			p.panicCodeErrorf(pos, "cannot slice %s (type %v)", code, typ)
  1168  		}
  1169  	}
  1170  	var exprMax ast.Expr
  1171  	if slice3 {
  1172  		exprMax = args[3].Val
  1173  	}
  1174  	// TODO: check type
  1175  	elem := &internal.Elem{
  1176  		Val: &ast.SliceExpr{
  1177  			X: x.Val, Low: args[1].Val, High: args[2].Val, Max: exprMax, Slice3: slice3,
  1178  		},
  1179  		Type: typ, Src: srcExpr,
  1180  	}
  1181  	p.stk.Ret(n, elem)
  1182  	return p
  1183  }
  1184  
  1185  // Index func:
  1186  //   - a[i]
  1187  //   - fn[T1, T2, ..., Tn]
  1188  //   - G[T1, T2, ..., Tn]
  1189  func (p *CodeBuilder) Index(nidx int, twoValue bool, src ...ast.Node) *CodeBuilder {
  1190  	if debugInstr {
  1191  		log.Println("Index", nidx, twoValue)
  1192  	}
  1193  	args := p.stk.GetArgs(nidx + 1)
  1194  	if nidx > 0 {
  1195  		if _, ok := args[1].Type.(*TypeType); ok {
  1196  			return p.instantiate(nidx, args, src...)
  1197  		}
  1198  	}
  1199  	if nidx != 1 {
  1200  		panic("Index doesn't support a[i, j...] yet")
  1201  	}
  1202  	srcExpr := getSrc(src)
  1203  	typs, allowTwoValue := p.getIdxValTypes(args[0].Type, false, srcExpr)
  1204  	var tyRet types.Type
  1205  	if twoValue { // elem, ok = a[key]
  1206  		if !allowTwoValue {
  1207  			pos := getSrcPos(srcExpr)
  1208  			p.panicCodeError(pos, "assignment mismatch: 2 variables but 1 values")
  1209  		}
  1210  		pkg := p.pkg
  1211  		tyRet = types.NewTuple(
  1212  			pkg.NewParam(token.NoPos, "", typs[1]),
  1213  			pkg.NewParam(token.NoPos, "", types.Typ[types.Bool]))
  1214  	} else { // elem = a[key]
  1215  		tyRet = typs[1]
  1216  	}
  1217  	elem := &internal.Elem{
  1218  		Val: &ast.IndexExpr{X: args[0].Val, Index: args[1].Val}, Type: tyRet, Src: srcExpr,
  1219  	}
  1220  	// TODO: check index type
  1221  	p.stk.Ret(2, elem)
  1222  	return p
  1223  }
  1224  
  1225  // IndexRef func
  1226  func (p *CodeBuilder) IndexRef(nidx int, src ...ast.Node) *CodeBuilder {
  1227  	if debugInstr {
  1228  		log.Println("IndexRef", nidx)
  1229  	}
  1230  	if nidx != 1 {
  1231  		panic("IndexRef doesn't support a[i, j...] = val yet")
  1232  	}
  1233  	args := p.stk.GetArgs(2)
  1234  	typ := args[0].Type
  1235  	elemRef := &internal.Elem{
  1236  		Val: &ast.IndexExpr{X: args[0].Val, Index: args[1].Val},
  1237  		Src: getSrc(src),
  1238  	}
  1239  	if t, ok := typ.(*unboundType); ok {
  1240  		tyMapElem := &unboundMapElemType{key: args[1].Type, typ: t}
  1241  		elemRef.Type = &refType{typ: tyMapElem}
  1242  	} else {
  1243  		typs, _ := p.getIdxValTypes(typ, true, elemRef.Src)
  1244  		elemRef.Type = &refType{typ: typs[1]}
  1245  		// TODO: check index type
  1246  	}
  1247  	p.stk.Ret(2, elemRef)
  1248  	return p
  1249  }
  1250  
  1251  func (p *CodeBuilder) getIdxValTypes(typ types.Type, ref bool, idxSrc ast.Node) ([]types.Type, bool) {
  1252  retry:
  1253  	switch t := typ.(type) {
  1254  	case *types.Slice:
  1255  		return []types.Type{tyInt, t.Elem()}, false
  1256  	case *types.Map:
  1257  		return []types.Type{t.Key(), t.Elem()}, true
  1258  	case *types.Array:
  1259  		return []types.Type{tyInt, t.Elem()}, false
  1260  	case *types.Pointer:
  1261  		elem := t.Elem()
  1262  		if named, ok := elem.(*types.Named); ok {
  1263  			elem = p.getUnderlying(named)
  1264  		}
  1265  		if e, ok := elem.(*types.Array); ok {
  1266  			return []types.Type{tyInt, e.Elem()}, false
  1267  		}
  1268  	case *types.Basic:
  1269  		if (t.Info() & types.IsString) != 0 {
  1270  			if ref {
  1271  				src, pos := p.loadExpr(idxSrc)
  1272  				p.panicCodeErrorf(pos, "cannot assign to %s (strings are immutable)", src)
  1273  			}
  1274  			return []types.Type{tyInt, TyByte}, false
  1275  		}
  1276  	case *types.Named:
  1277  		typ = p.getUnderlying(t)
  1278  		goto retry
  1279  	}
  1280  	src, pos := p.loadExpr(idxSrc)
  1281  	p.panicCodeErrorf(pos, "invalid operation: %s (type %v does not support indexing)", src, typ)
  1282  	return nil, false
  1283  }
  1284  
  1285  var (
  1286  	tyInt = types.Typ[types.Int]
  1287  )
  1288  
  1289  // Typ func
  1290  func (p *CodeBuilder) Typ(typ types.Type, src ...ast.Node) *CodeBuilder {
  1291  	if debugInstr {
  1292  		log.Println("Typ", typ)
  1293  	}
  1294  	p.stk.Push(&internal.Elem{
  1295  		Val:  toType(p.pkg, typ),
  1296  		Type: NewTypeType(typ),
  1297  		Src:  getSrc(src),
  1298  	})
  1299  	return p
  1300  }
  1301  
  1302  // UntypedBigInt func
  1303  func (p *CodeBuilder) UntypedBigInt(v *big.Int, src ...ast.Node) *CodeBuilder {
  1304  	pkg := p.pkg
  1305  	bigPkg := pkg.big()
  1306  	if v.IsInt64() {
  1307  		val := &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(v.Int64(), 10)}
  1308  		p.Val(bigPkg.Ref("NewInt")).Val(val).Call(1)
  1309  	} else {
  1310  		/*
  1311  			func() *typ {
  1312  				v, _ := new(typ).SetString(strVal, 10)
  1313  				return v
  1314  			}()
  1315  		*/
  1316  		typ := bigPkg.Ref("Int").Type()
  1317  		retTyp := types.NewPointer(typ)
  1318  		ret := pkg.NewParam(token.NoPos, "", retTyp)
  1319  		p.NewClosure(nil, types.NewTuple(ret), false).BodyStart(pkg).
  1320  			DefineVarStart(token.NoPos, "v", "_").
  1321  			Val(pkg.builtin.Ref("new")).Typ(typ).Call(1).
  1322  			MemberVal("SetString").Val(v.String()).Val(10).Call(2).EndInit(1).
  1323  			Val(p.Scope().Lookup("v")).Return(1).
  1324  			End().Call(0)
  1325  	}
  1326  	ret := p.stk.Get(-1)
  1327  	ret.Type, ret.CVal, ret.Src = pkg.utBigInt, constant.Make(v), getSrc(src)
  1328  	return p
  1329  }
  1330  
  1331  // UntypedBigRat func
  1332  func (p *CodeBuilder) UntypedBigRat(v *big.Rat, src ...ast.Node) *CodeBuilder {
  1333  	pkg := p.pkg
  1334  	bigPkg := pkg.big()
  1335  	a, b := v.Num(), v.Denom()
  1336  	if a.IsInt64() && b.IsInt64() {
  1337  		va := &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(a.Int64(), 10)}
  1338  		vb := &ast.BasicLit{Kind: token.INT, Value: strconv.FormatInt(b.Int64(), 10)}
  1339  		p.Val(bigPkg.Ref("NewRat")).Val(va).Val(vb).Call(2)
  1340  	} else {
  1341  		// new(big.Rat).SetFrac(a, b)
  1342  		p.Val(p.pkg.builtin.Ref("new")).Typ(bigPkg.Ref("Rat").Type()).Call(1).
  1343  			MemberVal("SetFrac").UntypedBigInt(a).UntypedBigInt(b).Call(2)
  1344  	}
  1345  	ret := p.stk.Get(-1)
  1346  	ret.Type, ret.CVal, ret.Src = pkg.utBigRat, constant.Make(v), getSrc(src)
  1347  	return p
  1348  }
  1349  
  1350  func (p *CodeBuilder) VarVal(name string, src ...ast.Node) *CodeBuilder {
  1351  	_, o := p.Scope().LookupParent(name, token.NoPos)
  1352  	if o == nil {
  1353  		log.Panicf("VarVal: variable `%v` not found\n", name)
  1354  	}
  1355  	return p.Val(o, src...)
  1356  }
  1357  
  1358  // Val func
  1359  func (p *CodeBuilder) Val(v interface{}, src ...ast.Node) *CodeBuilder {
  1360  	if debugInstr {
  1361  		if o, ok := v.(types.Object); ok {
  1362  			log.Println("Val", o.Name(), o.Type())
  1363  		} else {
  1364  			log.Println("Val", v, reflect.TypeOf(v))
  1365  		}
  1366  	}
  1367  	fn := p.current.fn
  1368  	if fn != nil && fn.isInline() { // is in an inline call
  1369  		if param, ok := v.(*types.Var); ok {
  1370  			key := closureParamInst{fn, param}
  1371  			if arg, ok := p.paramInsts[key]; ok { // replace param with arg
  1372  				v = arg
  1373  			}
  1374  		}
  1375  	}
  1376  	return p.pushVal(v, getSrc(src))
  1377  }
  1378  
  1379  func (p *CodeBuilder) pushVal(v interface{}, src ast.Node) *CodeBuilder {
  1380  	p.stk.Push(toExpr(p.pkg, v, src))
  1381  	return p
  1382  }
  1383  
  1384  // Star func
  1385  func (p *CodeBuilder) Star(src ...ast.Node) *CodeBuilder {
  1386  	if debugInstr {
  1387  		log.Println("Star")
  1388  	}
  1389  	arg := p.stk.Get(-1)
  1390  	ret := &internal.Elem{Val: &ast.StarExpr{X: arg.Val}, Src: getSrc(src)}
  1391  	argType := arg.Type
  1392  retry:
  1393  	switch t := argType.(type) {
  1394  	case *TypeType:
  1395  		ret.Type = t.Pointer()
  1396  	case *types.Pointer:
  1397  		ret.Type = t.Elem()
  1398  	case *types.Named:
  1399  		argType = p.getUnderlying(t)
  1400  		goto retry
  1401  	default:
  1402  		code, pos := p.loadExpr(arg.Src)
  1403  		p.panicCodeErrorf(pos, "invalid indirect of %s (type %v)", code, t)
  1404  	}
  1405  	p.stk.Ret(1, ret)
  1406  	return p
  1407  }
  1408  
  1409  // Elem func
  1410  func (p *CodeBuilder) Elem(src ...ast.Node) *CodeBuilder {
  1411  	if debugInstr {
  1412  		log.Println("Elem")
  1413  	}
  1414  	arg := p.stk.Get(-1)
  1415  	t, ok := arg.Type.(*types.Pointer)
  1416  	if !ok {
  1417  		code, pos := p.loadExpr(arg.Src)
  1418  		p.panicCodeErrorf(pos, "invalid indirect of %s (type %v)", code, arg.Type)
  1419  	}
  1420  	p.stk.Ret(1, &internal.Elem{Val: &ast.StarExpr{X: arg.Val}, Type: t.Elem(), Src: getSrc(src)})
  1421  	return p
  1422  }
  1423  
  1424  // ElemRef func
  1425  func (p *CodeBuilder) ElemRef(src ...ast.Node) *CodeBuilder {
  1426  	if debugInstr {
  1427  		log.Println("ElemRef")
  1428  	}
  1429  	arg := p.stk.Get(-1)
  1430  	t, ok := arg.Type.(*types.Pointer)
  1431  	if !ok {
  1432  		code, pos := p.loadExpr(arg.Src)
  1433  		p.panicCodeErrorf(pos, "invalid indirect of %s (type %v)", code, arg.Type)
  1434  	}
  1435  	p.stk.Ret(1, &internal.Elem{
  1436  		Val: &ast.StarExpr{X: arg.Val}, Type: &refType{typ: t.Elem()}, Src: getSrc(src),
  1437  	})
  1438  	return p
  1439  }
  1440  
  1441  // MemberVal func
  1442  func (p *CodeBuilder) MemberVal(name string, src ...ast.Node) *CodeBuilder {
  1443  	_, err := p.Member(name, MemberFlagVal, src...)
  1444  	if err != nil {
  1445  		panic(err)
  1446  	}
  1447  	return p
  1448  }
  1449  
  1450  // MemberRef func
  1451  func (p *CodeBuilder) MemberRef(name string, src ...ast.Node) *CodeBuilder {
  1452  	_, err := p.Member(name, MemberFlagRef, src...)
  1453  	if err != nil {
  1454  		panic(err)
  1455  	}
  1456  	return p
  1457  }
  1458  
  1459  func (p *CodeBuilder) refMember(typ types.Type, name string, argVal ast.Expr, src ast.Node) MemberKind {
  1460  	switch o := indirect(typ).(type) {
  1461  	case *types.Named:
  1462  		if struc, ok := p.getUnderlying(o).(*types.Struct); ok {
  1463  			name = p.getFieldName(o, name)
  1464  			if p.fieldRef(argVal, struc, name, src) {
  1465  				return MemberField
  1466  			}
  1467  			return p.refVField(o, name, argVal)
  1468  		}
  1469  	case *types.Struct:
  1470  		if p.fieldRef(argVal, o, name, src) {
  1471  			return MemberField
  1472  		}
  1473  	}
  1474  	return MemberInvalid
  1475  }
  1476  
  1477  func (p *CodeBuilder) fieldRef(x ast.Expr, o *types.Struct, name string, src ast.Node) bool {
  1478  	for i, n := 0, o.NumFields(); i < n; i++ {
  1479  		fld := o.Field(i)
  1480  		if fld.Name() == name {
  1481  			if p.rec != nil {
  1482  				p.rec.Member(src, fld)
  1483  			}
  1484  			p.stk.Ret(1, &internal.Elem{
  1485  				Val:  &ast.SelectorExpr{X: x, Sel: ident(name)},
  1486  				Type: &refType{typ: fld.Type()},
  1487  			})
  1488  			return true
  1489  		} else if fld.Embedded() {
  1490  			fldt := fld.Type()
  1491  			if o, ok := fldt.(*types.Pointer); ok {
  1492  				fldt = o.Elem()
  1493  			}
  1494  			if t, ok := fldt.(*types.Named); ok {
  1495  				u := p.getUnderlying(t)
  1496  				if struc, ok := u.(*types.Struct); ok {
  1497  					if p.fieldRef(x, struc, name, src) || p.refVField(t, name, nil) != MemberInvalid {
  1498  						return true
  1499  					}
  1500  				}
  1501  			}
  1502  		}
  1503  	}
  1504  	return false
  1505  }
  1506  
  1507  type (
  1508  	MemberKind int
  1509  	MemberFlag int
  1510  )
  1511  
  1512  const (
  1513  	MemberInvalid MemberKind = iota
  1514  	MemberMethod
  1515  	MemberAutoProperty
  1516  	MemberField
  1517  	memberBad MemberKind = -1
  1518  )
  1519  
  1520  const (
  1521  	MemberFlagVal MemberFlag = iota
  1522  	MemberFlagMethodAlias
  1523  	MemberFlagAutoProperty
  1524  	MemberFlagRef MemberFlag = -1
  1525  
  1526  	// private state
  1527  	memberFlagMethodToFunc MemberFlag = -2
  1528  )
  1529  
  1530  func aliasNameOf(name string, flag MemberFlag) (string, MemberFlag) {
  1531  	// flag > 0: (flag == MemberFlagMethodAlias || flag == MemberFlagAutoProperty)
  1532  	if flag > 0 && name != "" {
  1533  		if c := name[0]; c >= 'a' && c <= 'z' {
  1534  			return string(rune(c)+('A'-'a')) + name[1:], flag
  1535  		}
  1536  		flag = MemberFlagVal
  1537  	}
  1538  	return "", flag
  1539  }
  1540  
  1541  // Member access member by its name.
  1542  // src should point to the full source node `x.sel`
  1543  func (p *CodeBuilder) Member(name string, flag MemberFlag, src ...ast.Node) (kind MemberKind, err error) {
  1544  	srcExpr := getSrc(src)
  1545  	arg := p.stk.Get(-1)
  1546  	if debugInstr {
  1547  		log.Println("Member", name, flag, "//", arg.Type)
  1548  	}
  1549  	switch arg.Type {
  1550  	case p.pkg.utBigInt, p.pkg.utBigRat, p.pkg.utBigFlt:
  1551  		arg.Type = DefaultConv(p.pkg, arg.Type, arg)
  1552  	}
  1553  	at := arg.Type
  1554  	if flag == MemberFlagRef {
  1555  		kind = p.refMember(at, name, arg.Val, srcExpr)
  1556  	} else {
  1557  		t, isType := at.(*TypeType)
  1558  		if isType { // (T).method or (*T).method
  1559  			at = t.Type()
  1560  			flag = memberFlagMethodToFunc
  1561  		}
  1562  		aliasName, flag := aliasNameOf(name, flag)
  1563  		kind = p.findMember(at, name, aliasName, flag, arg, srcExpr)
  1564  		if isType && kind != MemberMethod {
  1565  			code, pos := p.loadExpr(srcExpr)
  1566  			return MemberInvalid, p.newCodeError(
  1567  				pos, fmt.Sprintf("%s undefined (type %v has no method %s)", code, at, name))
  1568  		}
  1569  	}
  1570  	if kind > 0 {
  1571  		return
  1572  	}
  1573  	code, pos := p.loadExpr(srcExpr)
  1574  	return MemberInvalid, p.newCodeError(
  1575  		pos, fmt.Sprintf("%s undefined (type %v has no field or method %s)", code, arg.Type, name))
  1576  }
  1577  
  1578  func (p *CodeBuilder) getUnderlying(t *types.Named) types.Type {
  1579  	u := t.Underlying()
  1580  	if u == nil {
  1581  		p.loadNamed(p.pkg, t)
  1582  		u = t.Underlying()
  1583  	}
  1584  	return u
  1585  }
  1586  
  1587  func (p *CodeBuilder) ensureLoaded(typ types.Type) {
  1588  	if t, ok := typ.(*types.Pointer); ok {
  1589  		typ = t.Elem()
  1590  	}
  1591  	if t, ok := typ.(*types.Named); ok && (t.NumMethods() == 0 || t.Underlying() == nil) {
  1592  		if debugMatch {
  1593  			log.Println("==> EnsureLoaded", typ)
  1594  		}
  1595  		p.loadNamed(p.pkg, t)
  1596  	}
  1597  }
  1598  
  1599  func getUnderlying(pkg *Package, typ types.Type) types.Type {
  1600  	u := typ.Underlying()
  1601  	if u == nil {
  1602  		if t, ok := typ.(*types.Named); ok {
  1603  			pkg.cb.loadNamed(pkg, t)
  1604  			u = t.Underlying()
  1605  		}
  1606  	}
  1607  	return u
  1608  }
  1609  
  1610  func (p *CodeBuilder) findMember(
  1611  	typ types.Type, name, aliasName string, flag MemberFlag, arg *Element, srcExpr ast.Node) MemberKind {
  1612  	var named *types.Named
  1613  retry:
  1614  	switch o := typ.(type) {
  1615  	case *types.Pointer:
  1616  		switch t := o.Elem().(type) {
  1617  		case *types.Named:
  1618  			u := p.getUnderlying(t) // may cause to loadNamed (delay-loaded)
  1619  			struc, fstruc := u.(*types.Struct)
  1620  			if fstruc {
  1621  				name = p.getFieldName(t, name)
  1622  				if kind := p.normalField(struc, name, arg, srcExpr); kind != MemberInvalid {
  1623  					return kind
  1624  				}
  1625  			}
  1626  			if kind := p.method(t, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid {
  1627  				return kind
  1628  			}
  1629  			if fstruc {
  1630  				if kind := p.findVField(t, name, arg, srcExpr); kind != MemberInvalid {
  1631  					return kind
  1632  				}
  1633  				return p.embeddedField(struc, name, aliasName, flag, arg, srcExpr)
  1634  			}
  1635  		case *types.Struct:
  1636  			if kind := p.field(t, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid {
  1637  				return kind
  1638  			}
  1639  		}
  1640  	case *types.Named:
  1641  		named, typ = o, p.getUnderlying(o) // may cause to loadNamed (delay-loaded)
  1642  		if kind := p.method(o, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid {
  1643  			return kind
  1644  		}
  1645  		if _, ok := typ.(*types.Struct); ok {
  1646  			name = p.getFieldName(o, name)
  1647  		}
  1648  		goto retry
  1649  	case *types.Struct:
  1650  		if kind := p.field(o, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid {
  1651  			return kind
  1652  		}
  1653  		if named != nil {
  1654  			return p.findVField(named, name, arg, srcExpr)
  1655  		}
  1656  	case *types.Interface:
  1657  		o.Complete()
  1658  		if kind := p.method(o, name, aliasName, flag, arg, srcExpr); kind != MemberInvalid {
  1659  			return kind
  1660  		}
  1661  	case *types.Basic, *types.Slice, *types.Map, *types.Chan:
  1662  		return p.btiMethod(p.getBuiltinTI(o), name, aliasName, flag, srcExpr)
  1663  	}
  1664  	return MemberInvalid
  1665  }
  1666  
  1667  type methodList interface {
  1668  	NumMethods() int
  1669  	Method(i int) *types.Func
  1670  }
  1671  
  1672  func selector(arg *Element, name string) *ast.SelectorExpr {
  1673  	denoted := &ast.Object{Data: arg}
  1674  	return &ast.SelectorExpr{X: arg.Val, Sel: &ast.Ident{Name: name, Obj: denoted}}
  1675  }
  1676  
  1677  func denoteRecv(v *ast.SelectorExpr) *Element {
  1678  	if o := v.Sel.Obj; o != nil {
  1679  		if e, ok := o.Data.(*Element); ok {
  1680  			return e
  1681  		}
  1682  	}
  1683  	return nil
  1684  }
  1685  
  1686  func getDenoted(expr ast.Expr) *ast.Object {
  1687  	switch v := expr.(type) {
  1688  	case *ast.SelectorExpr:
  1689  		return v.Sel.Obj
  1690  	case *ast.Ident:
  1691  		return v.Obj
  1692  	default:
  1693  		return nil
  1694  	}
  1695  }
  1696  
  1697  func setDenoted(expr ast.Expr, denoted *ast.Object) {
  1698  	switch v := expr.(type) {
  1699  	case *ast.SelectorExpr:
  1700  		v.Sel.Obj = denoted
  1701  	case *ast.Ident:
  1702  		v.Obj = denoted
  1703  	}
  1704  }
  1705  
  1706  func (p *CodeBuilder) allowAccess(pkg *types.Package, name string) bool {
  1707  	if !ast.IsExported(name) && pkg != nil && pkg.Path() != p.pkg.Path() {
  1708  		return false
  1709  	}
  1710  	return true
  1711  }
  1712  
  1713  func (p *CodeBuilder) method(
  1714  	o methodList, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) (kind MemberKind) {
  1715  	var found *types.Func
  1716  	var exact bool
  1717  	for i, n := 0, o.NumMethods(); i < n; i++ {
  1718  		method := o.Method(i)
  1719  		v := method.Name()
  1720  		if !p.allowAccess(method.Pkg(), v) {
  1721  			continue
  1722  		}
  1723  		if v == name {
  1724  			found, exact = method, true
  1725  			break
  1726  		} else if flag > 0 && v == aliasName {
  1727  			found = method
  1728  			if method.Pkg() != p.pkg.Types {
  1729  				break
  1730  			}
  1731  		}
  1732  	}
  1733  	if found != nil {
  1734  		autoprop := !exact && flag == MemberFlagAutoProperty
  1735  		typ := found.Type()
  1736  		if autoprop && !methodHasAutoProperty(typ, 0) {
  1737  			return memberBad
  1738  		}
  1739  		sel := selector(arg, found.Name())
  1740  		p.stk.Ret(1, &internal.Elem{
  1741  			Val:  sel,
  1742  			Type: methodSigOf(typ, flag, arg, sel),
  1743  			Src:  src,
  1744  		})
  1745  		if p.rec != nil {
  1746  			p.rec.Member(src, found)
  1747  		}
  1748  		if autoprop {
  1749  			p.CallWith(0, 0, src)
  1750  			return MemberAutoProperty
  1751  		}
  1752  		return MemberMethod
  1753  	}
  1754  	if t, ok := o.(*types.Named); ok {
  1755  		kind = p.btiMethod(p.getBuiltinTI(t), name, aliasName, flag, src)
  1756  	}
  1757  	return
  1758  }
  1759  
  1760  func isTypeConvert(otyp, typ types.Type) (string, bool) {
  1761  	if otyp != typ {
  1762  		if t, ok := typ.Underlying().(*types.Basic); ok &&
  1763  			(t.Info()&types.IsUntyped) == 0 {
  1764  			return t.Name(), true
  1765  		}
  1766  	}
  1767  	return "", false
  1768  }
  1769  
  1770  func (p *CodeBuilder) btiMethod(
  1771  	o *builtinTI, name, aliasName string, flag MemberFlag, src ast.Node) MemberKind {
  1772  	if o != nil {
  1773  		for i, n := 0, o.NumMethods(); i < n; i++ {
  1774  			method := o.Method(i)
  1775  			v := method.name
  1776  			if v == name || (flag > 0 && v == aliasName) {
  1777  				autoprop := flag == MemberFlagAutoProperty && v == aliasName
  1778  				this := p.stk.Pop()
  1779  				if fn, ok := isTypeConvert(o.typ, this.Type); ok {
  1780  					this.Val = &ast.CallExpr{
  1781  						Fun:  ast.NewIdent(fn),
  1782  						Args: []ast.Expr{this.Val},
  1783  					}
  1784  					this.Type = &btiMethodType{Type: o.typ, eargs: method.eargs}
  1785  				} else {
  1786  					this.Type = &btiMethodType{Type: this.Type, eargs: method.eargs}
  1787  				}
  1788  				p.Val(method.fn, src)
  1789  				p.stk.Push(this)
  1790  				if p.rec != nil {
  1791  					p.rec.Member(src, method.fn)
  1792  				}
  1793  				if autoprop {
  1794  					p.CallWith(0, 0, src)
  1795  					return MemberAutoProperty
  1796  				}
  1797  				return MemberMethod
  1798  			}
  1799  		}
  1800  	}
  1801  	return MemberInvalid
  1802  }
  1803  
  1804  func (p *CodeBuilder) normalField(
  1805  	o *types.Struct, name string, arg *Element, src ast.Node) MemberKind {
  1806  	for i, n := 0, o.NumFields(); i < n; i++ {
  1807  		fld := o.Field(i)
  1808  		v := fld.Name()
  1809  		if !p.allowAccess(fld.Pkg(), v) {
  1810  			continue
  1811  		}
  1812  		if v == name {
  1813  			p.stk.Ret(1, &internal.Elem{
  1814  				Val:  selector(arg, name),
  1815  				Type: fld.Type(),
  1816  				Src:  src,
  1817  			})
  1818  			if p.rec != nil {
  1819  				p.rec.Member(src, fld)
  1820  			}
  1821  			return MemberField
  1822  		}
  1823  	}
  1824  	return MemberInvalid
  1825  }
  1826  
  1827  func (p *CodeBuilder) embeddedField(
  1828  	o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) MemberKind {
  1829  	for i, n := 0, o.NumFields(); i < n; i++ {
  1830  		if fld := o.Field(i); fld.Embedded() {
  1831  			if kind := p.findMember(fld.Type(), name, aliasName, flag, arg, src); kind != MemberInvalid {
  1832  				return kind
  1833  			}
  1834  		}
  1835  	}
  1836  	return MemberInvalid
  1837  }
  1838  
  1839  func (p *CodeBuilder) field(
  1840  	o *types.Struct, name, aliasName string, flag MemberFlag, arg *Element, src ast.Node) MemberKind {
  1841  	if kind := p.normalField(o, name, arg, src); kind != MemberInvalid {
  1842  		return kind
  1843  	}
  1844  	return p.embeddedField(o, name, aliasName, flag, arg, src)
  1845  }
  1846  
  1847  func toFuncSig(sig *types.Signature, recv *types.Var) *types.Signature {
  1848  	sp := sig.Params()
  1849  	spLen := sp.Len()
  1850  	vars := make([]*types.Var, spLen+1)
  1851  	vars[0] = recv
  1852  	for i := 0; i < spLen; i++ {
  1853  		vars[i+1] = sp.At(i)
  1854  	}
  1855  	return types.NewSignatureType(nil, nil, nil, types.NewTuple(vars...), sig.Results(), sig.Variadic())
  1856  }
  1857  
  1858  func methodToFuncSig(pkg *Package, o types.Object, fn *Element) *types.Signature {
  1859  	sig := o.Type().(*types.Signature)
  1860  	recv := sig.Recv()
  1861  	if recv == nil {
  1862  		fn.Val = toObjectExpr(pkg, o)
  1863  		return sig
  1864  	}
  1865  
  1866  	sel := fn.Val.(*ast.SelectorExpr)
  1867  	sel.Sel = ident(o.Name())
  1868  	sel.X = &ast.ParenExpr{X: sel.X}
  1869  	return toFuncSig(sig, recv)
  1870  }
  1871  
  1872  func methodSigOf(typ types.Type, flag MemberFlag, arg *Element, sel *ast.SelectorExpr) types.Type {
  1873  	if flag != memberFlagMethodToFunc {
  1874  		return methodCallSig(typ)
  1875  	}
  1876  
  1877  	sig := typ.(*types.Signature)
  1878  	if _, ok := CheckFuncEx(sig); ok {
  1879  		return typ
  1880  	}
  1881  
  1882  	at := arg.Type.(*TypeType).typ
  1883  	recv := sig.Recv().Type()
  1884  	_, isPtr := recv.(*types.Pointer) // recv is a pointer
  1885  	if t, ok := at.(*types.Pointer); ok {
  1886  		if !isPtr {
  1887  			if _, ok := recv.Underlying().(*types.Interface); !ok { // and recv isn't a interface
  1888  				log.Panicf("recv of method %v.%s isn't a pointer\n", t.Elem(), sel.Sel.Name)
  1889  			}
  1890  		}
  1891  	} else if isPtr { // use *T
  1892  		at = types.NewPointer(at)
  1893  		sel.X = &ast.StarExpr{X: sel.X}
  1894  	}
  1895  	sel.X = &ast.ParenExpr{X: sel.X}
  1896  
  1897  	return toFuncSig(sig, types.NewVar(token.NoPos, nil, "", at))
  1898  }
  1899  
  1900  func methodCallSig(typ types.Type) types.Type {
  1901  	sig := typ.(*types.Signature)
  1902  	if _, ok := CheckFuncEx(sig); ok {
  1903  		return typ
  1904  	}
  1905  	return types.NewSignatureType(nil, nil, nil, sig.Params(), sig.Results(), sig.Variadic())
  1906  }
  1907  
  1908  func indirect(typ types.Type) types.Type {
  1909  	if t, ok := typ.(*types.Pointer); ok {
  1910  		typ = t.Elem()
  1911  	}
  1912  	return typ
  1913  }
  1914  
  1915  // IncDec func
  1916  func (p *CodeBuilder) IncDec(op token.Token, src ...ast.Node) *CodeBuilder {
  1917  	name := goxPrefix + incdecOps[op]
  1918  	if debugInstr {
  1919  		log.Println("IncDec", op)
  1920  	}
  1921  	pkg := p.pkg
  1922  	arg := p.stk.Pop()
  1923  	if t, ok := arg.Type.(*refType).typ.(*types.Named); ok {
  1924  		op := lookupMethod(t, name)
  1925  		if op != nil {
  1926  			fn := &internal.Elem{
  1927  				Val:  &ast.SelectorExpr{X: arg.Val, Sel: ident(name)},
  1928  				Type: realType(op.Type()),
  1929  			}
  1930  			ret := toFuncCall(pkg, fn, []*Element{arg}, 0)
  1931  			if ret.Type != nil {
  1932  				p.shouldNoResults(name, src)
  1933  			}
  1934  			p.emitStmt(&ast.ExprStmt{X: ret.Val})
  1935  			return p
  1936  		}
  1937  	}
  1938  	fn := pkg.builtin.Ref(name)
  1939  	t := fn.Type().(*TyInstruction)
  1940  	if _, err := t.instr.Call(pkg, []*Element{arg}, 0, nil); err != nil {
  1941  		panic(err)
  1942  	}
  1943  	return p
  1944  }
  1945  
  1946  var (
  1947  	incdecOps = [...]string{
  1948  		token.INC: "Inc",
  1949  		token.DEC: "Dec",
  1950  	}
  1951  )
  1952  
  1953  // AssignOp func
  1954  func (p *CodeBuilder) AssignOp(op token.Token, src ...ast.Node) *CodeBuilder {
  1955  	args := p.stk.GetArgs(2)
  1956  	stmt := callAssignOp(p.pkg, op, args, src)
  1957  	p.emitStmt(stmt)
  1958  	p.stk.PopN(2)
  1959  	return p
  1960  }
  1961  
  1962  func checkDivisionByZero(cb *CodeBuilder, a, b *internal.Elem) {
  1963  	if a.CVal == nil {
  1964  		if isNormalInt(cb, a) {
  1965  			if c := b.CVal; c != nil {
  1966  				switch c.Kind() {
  1967  				case constant.Int, constant.Float, constant.Complex:
  1968  					if constant.Sign(c) == 0 {
  1969  						pos := getSrcPos(b.Src)
  1970  						cb.panicCodeError(pos, "invalid operation: division by zero")
  1971  					}
  1972  				}
  1973  			}
  1974  		}
  1975  	} else if c := b.CVal; c != nil {
  1976  		switch c.Kind() {
  1977  		case constant.Int, constant.Float, constant.Complex:
  1978  			if constant.Sign(c) == 0 {
  1979  				pos := getSrcPos(b.Src)
  1980  				cb.panicCodeError(pos, "invalid operation: division by zero")
  1981  			}
  1982  		}
  1983  	}
  1984  }
  1985  
  1986  func callAssignOp(pkg *Package, tok token.Token, args []*internal.Elem, src []ast.Node) ast.Stmt {
  1987  	name := goxPrefix + assignOps[tok]
  1988  	if debugInstr {
  1989  		log.Println("AssignOp", tok, name)
  1990  	}
  1991  	if t, ok := args[0].Type.(*refType).typ.(*types.Named); ok {
  1992  		op := lookupMethod(t, name)
  1993  		if op != nil {
  1994  			fn := &internal.Elem{
  1995  				Val:  &ast.SelectorExpr{X: args[0].Val, Sel: ident(name)},
  1996  				Type: realType(op.Type()),
  1997  			}
  1998  			ret := toFuncCall(pkg, fn, args, 0)
  1999  			if ret.Type != nil {
  2000  				pkg.cb.shouldNoResults(name, src)
  2001  			}
  2002  			return &ast.ExprStmt{X: ret.Val}
  2003  		}
  2004  	}
  2005  	op := pkg.builtin.Ref(name)
  2006  	if tok == token.QUO_ASSIGN {
  2007  		checkDivisionByZero(&pkg.cb, &internal.Elem{Val: args[0].Val, Type: args[0].Type.(*refType).typ}, args[1])
  2008  	}
  2009  	fn := &internal.Elem{
  2010  		Val: ident(op.Name()), Type: op.Type(),
  2011  	}
  2012  	toFuncCall(pkg, fn, args, 0)
  2013  	return &ast.AssignStmt{
  2014  		Tok: tok,
  2015  		Lhs: []ast.Expr{args[0].Val},
  2016  		Rhs: []ast.Expr{args[1].Val},
  2017  	}
  2018  }
  2019  
  2020  func (p *CodeBuilder) shouldNoResults(name string, src []ast.Node) {
  2021  	pos := token.NoPos
  2022  	if src != nil {
  2023  		pos = src[0].Pos()
  2024  	}
  2025  	p.panicCodeErrorf(pos, "operator %s should return no results\n", name)
  2026  }
  2027  
  2028  var (
  2029  	assignOps = [...]string{
  2030  		token.ADD_ASSIGN: "AddAssign", // +=
  2031  		token.SUB_ASSIGN: "SubAssign", // -=
  2032  		token.MUL_ASSIGN: "MulAssign", // *=
  2033  		token.QUO_ASSIGN: "QuoAssign", // /=
  2034  		token.REM_ASSIGN: "RemAssign", // %=
  2035  
  2036  		token.AND_ASSIGN:     "AndAssign",    // &=
  2037  		token.OR_ASSIGN:      "OrAssign",     // |=
  2038  		token.XOR_ASSIGN:     "XorAssign",    // ^=
  2039  		token.AND_NOT_ASSIGN: "AndNotAssign", // &^=
  2040  		token.SHL_ASSIGN:     "LshAssign",    // <<=
  2041  		token.SHR_ASSIGN:     "RshAssign",    // >>=
  2042  	}
  2043  )
  2044  
  2045  // Assign func
  2046  func (p *CodeBuilder) Assign(lhs int, rhs ...int) *CodeBuilder {
  2047  	var v int
  2048  	if rhs != nil {
  2049  		v = rhs[0]
  2050  	} else {
  2051  		v = lhs
  2052  	}
  2053  	if debugInstr {
  2054  		log.Println("Assign", lhs, v)
  2055  	}
  2056  	return p.doAssignWith(lhs, v, nil)
  2057  }
  2058  
  2059  // AssignWith func
  2060  func (p *CodeBuilder) AssignWith(lhs, rhs int, src ...ast.Node) *CodeBuilder {
  2061  	if debugInstr {
  2062  		log.Println("Assign", lhs, rhs)
  2063  	}
  2064  	return p.doAssignWith(lhs, rhs, getSrc(src))
  2065  }
  2066  
  2067  func (p *CodeBuilder) doAssignWith(lhs, rhs int, src ast.Node) *CodeBuilder {
  2068  	mkBlockStmt := false
  2069  	args := p.stk.GetArgs(lhs + rhs)
  2070  	stmt := &ast.AssignStmt{
  2071  		Tok: token.ASSIGN,
  2072  		Lhs: make([]ast.Expr, lhs),
  2073  		Rhs: make([]ast.Expr, rhs),
  2074  	}
  2075  	if rhs == 1 {
  2076  		if rhsVals, ok := args[lhs].Type.(*types.Tuple); ok {
  2077  			if lhs != rhsVals.Len() {
  2078  				pos := getSrcPos(src)
  2079  				caller := getCaller(args[lhs])
  2080  				p.panicCodeErrorf(
  2081  					pos, "assignment mismatch: %d variables but %v returns %d values",
  2082  					lhs, caller, rhsVals.Len())
  2083  			}
  2084  			for i := 0; i < lhs; i++ {
  2085  				val := &internal.Elem{Type: rhsVals.At(i).Type()}
  2086  				checkAssignType(p.pkg, args[i].Type, val)
  2087  				stmt.Lhs[i] = args[i].Val
  2088  			}
  2089  			stmt.Rhs[0] = args[lhs].Val
  2090  			goto done
  2091  		}
  2092  	}
  2093  	if lhs == rhs {
  2094  		mkBlockStmt = hasBfRefType(args)
  2095  		if mkBlockStmt { // {
  2096  			args = copyArgs(args)
  2097  			p.stk.PopN(lhs << 1)
  2098  			p.Block()
  2099  		}
  2100  		for i := 0; i < lhs; i++ {
  2101  			lhsType := args[i].Type
  2102  			bfr, bfAssign := lhsType.(*bfRefType)
  2103  			if bfAssign {
  2104  				lhsType = &refType{typ: bfr.typ}
  2105  			}
  2106  			checkAssignType(p.pkg, lhsType, args[lhs+i])
  2107  			stmt.Lhs[i] = args[i].Val
  2108  			stmt.Rhs[i] = args[lhs+i].Val
  2109  			if bfAssign {
  2110  				bfr.assign(p, &stmt.Lhs[i], &stmt.Rhs[i])
  2111  			}
  2112  		}
  2113  	} else {
  2114  		pos := getSrcPos(src)
  2115  		p.panicCodeErrorf(
  2116  			pos, "assignment mismatch: %d variables but %d values", lhs, rhs)
  2117  	}
  2118  done:
  2119  	p.emitStmt(stmt)
  2120  	if mkBlockStmt { // }
  2121  		p.End()
  2122  	} else {
  2123  		p.stk.PopN(lhs + rhs)
  2124  	}
  2125  	return p
  2126  }
  2127  
  2128  func hasBfRefType(args []*internal.Elem) bool {
  2129  	for _, arg := range args {
  2130  		if _, ok := arg.Type.(*bfRefType); ok {
  2131  			return true
  2132  		}
  2133  	}
  2134  	return false
  2135  }
  2136  
  2137  func lookupMethod(t *types.Named, name string) types.Object {
  2138  	for i, n := 0, t.NumMethods(); i < n; i++ {
  2139  		m := t.Method(i)
  2140  		if m.Name() == name {
  2141  			return m
  2142  		}
  2143  	}
  2144  	return nil
  2145  }
  2146  
  2147  func doUnaryOp(cb *CodeBuilder, op token.Token, args []*internal.Elem, flags InstrFlags) (ret *internal.Elem, err error) {
  2148  	name := goxPrefix + unaryOps[op]
  2149  	pkg := cb.pkg
  2150  	typ := args[0].Type
  2151  retry:
  2152  	switch t := typ.(type) {
  2153  	case *types.Named:
  2154  		lm := lookupMethod(t, name)
  2155  		if lm != nil {
  2156  			fn := &internal.Elem{
  2157  				Val:  &ast.SelectorExpr{X: args[0].Val, Sel: ident(name)},
  2158  				Type: realType(lm.Type()),
  2159  			}
  2160  			return matchFuncCall(pkg, fn, args, flags|instrFlagOpFunc)
  2161  		}
  2162  	case *types.Pointer:
  2163  		typ = t.Elem()
  2164  		goto retry
  2165  	}
  2166  	lm := pkg.builtin.Ref(name)
  2167  	return matchFuncCall(pkg, toObject(pkg, lm, nil), args, flags)
  2168  }
  2169  
  2170  // UnaryOp:
  2171  //   - cb.UnaryOp(op token.Token)
  2172  //   - cb.UnaryOp(op token.Token, twoValue bool)
  2173  //   - cb.UnaryOp(op token.Token, twoValue bool, src ast.Node)
  2174  func (p *CodeBuilder) UnaryOp(op token.Token, params ...interface{}) *CodeBuilder {
  2175  	var src ast.Node
  2176  	var flags InstrFlags
  2177  	switch len(params) {
  2178  	case 2:
  2179  		src, _ = params[1].(ast.Node)
  2180  		fallthrough
  2181  	case 1:
  2182  		if params[0].(bool) {
  2183  			flags = InstrFlagTwoValue
  2184  		}
  2185  	}
  2186  	if debugInstr {
  2187  		log.Println("UnaryOp", op, "flags:", flags)
  2188  	}
  2189  	ret, err := doUnaryOp(p, op, p.stk.GetArgs(1), flags)
  2190  	if err != nil {
  2191  		panic(err)
  2192  	}
  2193  	ret.Src = src
  2194  	p.stk.Ret(1, ret)
  2195  	return p
  2196  }
  2197  
  2198  // BinaryOp func
  2199  func (p *CodeBuilder) BinaryOp(op token.Token, src ...ast.Node) *CodeBuilder {
  2200  	const (
  2201  		errNotFound = syscall.ENOENT
  2202  	)
  2203  	if debugInstr {
  2204  		log.Println("BinaryOp", xtoken.String(op))
  2205  	}
  2206  	pkg := p.pkg
  2207  	name := goxPrefix + binaryOps[op]
  2208  	args := p.stk.GetArgs(2)
  2209  
  2210  	var ret *internal.Elem
  2211  	var err error = errNotFound
  2212  	isUserDef := false
  2213  	arg0 := args[0].Type
  2214  	named0, ok0 := checkNamed(arg0)
  2215  	if ok0 {
  2216  		if fn, e := pkg.MethodToFunc(arg0, name, src...); e == nil {
  2217  			ret, err = matchFuncCall(pkg, fn, args, instrFlagBinaryOp)
  2218  			isUserDef = true
  2219  		}
  2220  	}
  2221  	if err != nil {
  2222  		arg1 := args[1].Type
  2223  		if named1, ok1 := checkNamed(arg1); ok1 && named0 != named1 {
  2224  			if fn, e := pkg.MethodToFunc(arg1, name, src...); e == nil {
  2225  				ret, err = matchFuncCall(pkg, fn, args, instrFlagBinaryOp)
  2226  				isUserDef = true
  2227  			}
  2228  		}
  2229  	}
  2230  	if err != nil && !isUserDef {
  2231  		if op == token.QUO {
  2232  			checkDivisionByZero(p, args[0], args[1])
  2233  		}
  2234  		if op == token.EQL || op == token.NEQ {
  2235  			if !ComparableTo(pkg, args[0], args[1]) {
  2236  				err = errors.New("mismatched types")
  2237  			} else {
  2238  				ret, err = &internal.Elem{
  2239  					Val: &ast.BinaryExpr{
  2240  						X: checkParenExpr(args[0].Val), Op: op,
  2241  						Y: checkParenExpr(args[1].Val),
  2242  					},
  2243  					Type: types.Typ[types.UntypedBool],
  2244  					CVal: binaryOp(p, op, args),
  2245  				}, nil
  2246  			}
  2247  		} else if lm := pkg.builtin.TryRef(name); lm != nil {
  2248  			ret, err = matchFuncCall(pkg, toObject(pkg, lm, nil), args, 0)
  2249  		} else {
  2250  			err = errNotFound
  2251  		}
  2252  	}
  2253  
  2254  	expr := getSrc(src)
  2255  	if err != nil {
  2256  		opstr := xtoken.String(op)
  2257  		src, pos := p.loadExpr(expr)
  2258  		if src == "" {
  2259  			src = opstr
  2260  		}
  2261  		if err != errNotFound {
  2262  			p.panicCodeErrorf(
  2263  				pos, "invalid operation: %s (mismatched types %v and %v)", src, arg0, args[1].Type)
  2264  		} else {
  2265  			arg0Src, _ := p.loadExpr(args[0].Src)
  2266  			p.panicCodeErrorf(
  2267  				pos, "invalid operation: operator %s not defined on %s (%v)", opstr, arg0Src, arg0)
  2268  		}
  2269  	}
  2270  	ret.Src = expr
  2271  	p.stk.Ret(2, ret)
  2272  	return p
  2273  }
  2274  
  2275  func checkNamed(typ types.Type) (ret *types.Named, ok bool) {
  2276  	if t, ok := typ.(*types.Pointer); ok {
  2277  		typ = t.Elem()
  2278  	}
  2279  	ret, ok = typ.(*types.Named)
  2280  	return
  2281  }
  2282  
  2283  var (
  2284  	unaryOps = [...]string{
  2285  		token.SUB:   "Neg",
  2286  		token.ADD:   "Dup",
  2287  		token.XOR:   "Not",
  2288  		token.NOT:   "LNot",
  2289  		token.ARROW: "Recv",
  2290  		token.AND:   "Addr",
  2291  	}
  2292  	binaryOps = [...]string{
  2293  		token.ADD: "Add", // +
  2294  		token.SUB: "Sub", // -
  2295  		token.MUL: "Mul", // *
  2296  		token.QUO: "Quo", // /
  2297  		token.REM: "Rem", // %
  2298  
  2299  		token.AND:     "And",    // &
  2300  		token.OR:      "Or",     // |
  2301  		token.XOR:     "Xor",    // ^
  2302  		token.AND_NOT: "AndNot", // &^
  2303  		token.SHL:     "Lsh",    // <<
  2304  		token.SHR:     "Rsh",    // >>
  2305  
  2306  		token.LAND: "LAnd", // &&
  2307  		token.LOR:  "LOr",  // ||
  2308  
  2309  		token.LSS: "LT",
  2310  		token.LEQ: "LE",
  2311  		token.GTR: "GT",
  2312  		token.GEQ: "GE",
  2313  		token.EQL: "EQ",
  2314  		token.NEQ: "NE",
  2315  
  2316  		xtoken.SRARROW:   "PointTo", // ->
  2317  		xtoken.BIDIARROW: "PointBi", // <>
  2318  	}
  2319  )
  2320  
  2321  // CompareNil func
  2322  func (p *CodeBuilder) CompareNil(op token.Token, src ...ast.Node) *CodeBuilder {
  2323  	return p.Val(nil).BinaryOp(op)
  2324  }
  2325  
  2326  // Send func
  2327  func (p *CodeBuilder) Send() *CodeBuilder {
  2328  	if debugInstr {
  2329  		log.Println("Send")
  2330  	}
  2331  	val := p.stk.Pop()
  2332  	ch := p.stk.Pop()
  2333  	// TODO: check types
  2334  	p.emitStmt(&ast.SendStmt{Chan: ch.Val, Value: val.Val})
  2335  	return p
  2336  }
  2337  
  2338  // Defer func
  2339  func (p *CodeBuilder) Defer() *CodeBuilder {
  2340  	if debugInstr {
  2341  		log.Println("Defer")
  2342  	}
  2343  	arg := p.stk.Pop()
  2344  	call, ok := arg.Val.(*ast.CallExpr)
  2345  	if !ok {
  2346  		panic("TODO: please use defer callExpr()")
  2347  	}
  2348  	p.emitStmt(&ast.DeferStmt{Call: call})
  2349  	return p
  2350  }
  2351  
  2352  // Go func
  2353  func (p *CodeBuilder) Go() *CodeBuilder {
  2354  	if debugInstr {
  2355  		log.Println("Go")
  2356  	}
  2357  	arg := p.stk.Pop()
  2358  	call, ok := arg.Val.(*ast.CallExpr)
  2359  	if !ok {
  2360  		panic("TODO: please use go callExpr()")
  2361  	}
  2362  	p.emitStmt(&ast.GoStmt{Call: call})
  2363  	return p
  2364  }
  2365  
  2366  // Block starts a block statement.
  2367  func (p *CodeBuilder) Block(src ...ast.Node) *CodeBuilder {
  2368  	if debugInstr {
  2369  		log.Println("Block")
  2370  	}
  2371  	stmt := &blockStmt{}
  2372  	p.startBlockStmt(stmt, src, "block statement", &stmt.old)
  2373  	return p
  2374  }
  2375  
  2376  // VBlock starts a vblock statement.
  2377  func (p *CodeBuilder) VBlock() *CodeBuilder {
  2378  	if debugInstr {
  2379  		log.Println("VBlock")
  2380  	}
  2381  	stmt := &vblockStmt{}
  2382  	p.startVBlockStmt(stmt, "vblock statement", &stmt.old)
  2383  	return p
  2384  }
  2385  
  2386  // InVBlock checks if current statement is in vblock or not.
  2387  func (p *CodeBuilder) InVBlock() bool {
  2388  	_, ok := p.current.codeBlock.(*vblockStmt)
  2389  	return ok
  2390  }
  2391  
  2392  // Block starts a if statement.
  2393  func (p *CodeBuilder) If(src ...ast.Node) *CodeBuilder {
  2394  	if debugInstr {
  2395  		log.Println("If")
  2396  	}
  2397  	stmt := &ifStmt{}
  2398  	p.startBlockStmt(stmt, src, "if statement", &stmt.old)
  2399  	return p
  2400  }
  2401  
  2402  // Then starts body of a if/switch/for/case statement.
  2403  func (p *CodeBuilder) Then(src ...ast.Node) *CodeBuilder {
  2404  	if debugInstr {
  2405  		log.Println("Then")
  2406  	}
  2407  	if flow, ok := p.current.codeBlock.(controlFlow); ok {
  2408  		flow.Then(p, src...)
  2409  		return p
  2410  	}
  2411  	panic("use if..then or switch..then or for..then please")
  2412  }
  2413  
  2414  // Else starts else body of a if..else statement.
  2415  func (p *CodeBuilder) Else(src ...ast.Node) *CodeBuilder {
  2416  	if debugInstr {
  2417  		log.Println("Else")
  2418  	}
  2419  	if flow, ok := p.current.codeBlock.(*ifStmt); ok {
  2420  		flow.Else(p, src...)
  2421  		return p
  2422  	}
  2423  	panic("use if..else please")
  2424  }
  2425  
  2426  // TypeSwitch starts a type switch statement.
  2427  //
  2428  // <pre>
  2429  // typeSwitch(name) init; expr typeAssertThen
  2430  // type1, type2, ... typeN typeCase(N)
  2431  //
  2432  //	...
  2433  //	end
  2434  //
  2435  // type1, type2, ... typeM typeCase(M)
  2436  //
  2437  //	...
  2438  //	end
  2439  //
  2440  // end
  2441  // </pre>
  2442  func (p *CodeBuilder) TypeSwitch(name string, src ...ast.Node) *CodeBuilder {
  2443  	if debugInstr {
  2444  		log.Println("TypeSwitch")
  2445  	}
  2446  	stmt := &typeSwitchStmt{name: name}
  2447  	p.startBlockStmt(stmt, src, "type switch statement", &stmt.old)
  2448  	return p
  2449  }
  2450  
  2451  // TypeAssert func
  2452  func (p *CodeBuilder) TypeAssert(typ types.Type, twoValue bool, src ...ast.Node) *CodeBuilder {
  2453  	if debugInstr {
  2454  		log.Println("TypeAssert", typ, twoValue)
  2455  	}
  2456  	arg := p.stk.Get(-1)
  2457  	xType, ok := p.checkInterface(arg.Type)
  2458  	if !ok {
  2459  		text, pos := p.loadExpr(getSrc(src))
  2460  		p.panicCodeErrorf(
  2461  			pos, "invalid type assertion: %s (non-interface type %v on left)", text, arg.Type)
  2462  	}
  2463  	if missing := p.missingMethod(typ, xType); missing != "" {
  2464  		pos := getSrcPos(getSrc(src))
  2465  		p.panicCodeErrorf(
  2466  			pos, "impossible type assertion:\n\t%v does not implement %v (missing %s method)",
  2467  			typ, arg.Type, missing)
  2468  	}
  2469  	pkg := p.pkg
  2470  	ret := &ast.TypeAssertExpr{X: arg.Val, Type: toType(pkg, typ)}
  2471  	if twoValue {
  2472  		tyRet := types.NewTuple(
  2473  			pkg.NewParam(token.NoPos, "", typ),
  2474  			pkg.NewParam(token.NoPos, "", types.Typ[types.Bool]))
  2475  		p.stk.Ret(1, &internal.Elem{Type: tyRet, Val: ret})
  2476  	} else {
  2477  		p.stk.Ret(1, &internal.Elem{Type: typ, Val: ret})
  2478  	}
  2479  	return p
  2480  }
  2481  
  2482  func (p *CodeBuilder) missingMethod(T types.Type, V *types.Interface) (missing string) {
  2483  	p.ensureLoaded(T)
  2484  	if m, _ := types.MissingMethod(T, V, false); m != nil {
  2485  		missing = m.Name()
  2486  	}
  2487  	return
  2488  }
  2489  
  2490  func (p *CodeBuilder) checkInterface(typ types.Type) (*types.Interface, bool) {
  2491  retry:
  2492  	switch t := typ.(type) {
  2493  	case *types.Interface:
  2494  		return t, true
  2495  	case *types.Named:
  2496  		typ = p.getUnderlying(t)
  2497  		goto retry
  2498  	}
  2499  	return nil, false
  2500  }
  2501  
  2502  // TypeAssertThen starts body of a type switch statement.
  2503  func (p *CodeBuilder) TypeAssertThen() *CodeBuilder {
  2504  	if debugInstr {
  2505  		log.Println("TypeAssertThen")
  2506  	}
  2507  	if flow, ok := p.current.codeBlock.(*typeSwitchStmt); ok {
  2508  		flow.TypeAssertThen(p)
  2509  		return p
  2510  	}
  2511  	panic("use typeSwitch..typeAssertThen please")
  2512  }
  2513  
  2514  // TypeCase starts case body of a type switch statement.
  2515  func (p *CodeBuilder) TypeCase(src ...ast.Node) *CodeBuilder {
  2516  	if debugInstr {
  2517  		log.Println("TypeCase")
  2518  	}
  2519  	if flow, ok := p.current.codeBlock.(*typeSwitchStmt); ok {
  2520  		flow.TypeCase(p, src...)
  2521  		return p
  2522  	}
  2523  	panic("use switch x.(type) .. case please")
  2524  }
  2525  
  2526  // TypeDefaultThen starts default clause of a type switch statement.
  2527  func (p *CodeBuilder) TypeDefaultThen(src ...ast.Node) *CodeBuilder {
  2528  	return p.TypeCase(src...).Then(src...)
  2529  }
  2530  
  2531  // Select starts a select statement.
  2532  func (p *CodeBuilder) Select(src ...ast.Node) *CodeBuilder {
  2533  	if debugInstr {
  2534  		log.Println("Select")
  2535  	}
  2536  	stmt := &selectStmt{}
  2537  	p.startBlockStmt(stmt, src, "select statement", &stmt.old)
  2538  	return p
  2539  }
  2540  
  2541  // CommCase starts case clause of a select statement.
  2542  func (p *CodeBuilder) CommCase(src ...ast.Node) *CodeBuilder {
  2543  	if debugInstr {
  2544  		log.Println("CommCase")
  2545  	}
  2546  	if flow, ok := p.current.codeBlock.(*selectStmt); ok {
  2547  		flow.CommCase(p, src...)
  2548  		return p
  2549  	}
  2550  	panic("use select..case please")
  2551  }
  2552  
  2553  // CommDefaultThen starts default clause of a select statement.
  2554  func (p *CodeBuilder) CommDefaultThen(src ...ast.Node) *CodeBuilder {
  2555  	return p.CommCase(src...).Then(src...)
  2556  }
  2557  
  2558  // Switch starts a switch statement.
  2559  func (p *CodeBuilder) Switch(src ...ast.Node) *CodeBuilder {
  2560  	if debugInstr {
  2561  		log.Println("Switch")
  2562  	}
  2563  	stmt := &switchStmt{}
  2564  	p.startBlockStmt(stmt, src, "switch statement", &stmt.old)
  2565  	return p
  2566  }
  2567  
  2568  // Case starts case clause of a switch statement.
  2569  func (p *CodeBuilder) Case(src ...ast.Node) *CodeBuilder {
  2570  	if debugInstr {
  2571  		log.Println("Case")
  2572  	}
  2573  	if flow, ok := p.current.codeBlock.(*switchStmt); ok {
  2574  		flow.Case(p, src...)
  2575  		return p
  2576  	}
  2577  	panic("use switch..case please")
  2578  }
  2579  
  2580  // DefaultThen starts default clause of a switch statement.
  2581  func (p *CodeBuilder) DefaultThen(src ...ast.Node) *CodeBuilder {
  2582  	return p.Case(src...).Then(src...)
  2583  }
  2584  
  2585  func (p *CodeBuilder) NewLabel(pos token.Pos, name string) *Label {
  2586  	if p.current.fn == nil {
  2587  		panic(p.newCodeError(pos, "syntax error: non-declaration statement outside function body"))
  2588  	}
  2589  	if old, ok := p.current.labels[name]; ok {
  2590  		oldPos := p.fset.Position(old.Pos())
  2591  		p.handleCodeErrorf(pos, "label %s already defined at %v", name, oldPos)
  2592  		return nil
  2593  	}
  2594  	if p.current.labels == nil {
  2595  		p.current.labels = make(map[string]*Label)
  2596  	}
  2597  	l := &Label{Label: *types.NewLabel(pos, p.pkg.Types, name)}
  2598  	p.current.labels[name] = l
  2599  	return l
  2600  }
  2601  
  2602  // LookupLabel func
  2603  func (p *CodeBuilder) LookupLabel(name string) (l *Label, ok bool) {
  2604  	l, ok = p.current.labels[name]
  2605  	return
  2606  }
  2607  
  2608  // Label func
  2609  func (p *CodeBuilder) Label(l *Label) *CodeBuilder {
  2610  	name := l.Name()
  2611  	if debugInstr {
  2612  		log.Println("Label", name)
  2613  	}
  2614  	if p.current.label != nil {
  2615  		p.current.label.Stmt = &ast.EmptyStmt{}
  2616  		p.current.stmts = append(p.current.stmts, p.current.label)
  2617  	}
  2618  	p.current.label = &ast.LabeledStmt{Label: ident(name)}
  2619  	return p
  2620  }
  2621  
  2622  // Goto func
  2623  func (p *CodeBuilder) Goto(l *Label) *CodeBuilder {
  2624  	name := l.Name()
  2625  	if debugInstr {
  2626  		log.Println("Goto", name)
  2627  	}
  2628  	l.used = true
  2629  	p.current.flows |= flowFlagGoto
  2630  	p.emitStmt(&ast.BranchStmt{Tok: token.GOTO, Label: ident(name)})
  2631  	return p
  2632  }
  2633  
  2634  func (p *CodeBuilder) labelFlow(flow int, l *Label) (string, *ast.Ident) {
  2635  	if l != nil {
  2636  		l.used = true
  2637  		p.current.flows |= (flow | flowFlagWithLabel)
  2638  		return l.Name(), ident(l.Name())
  2639  	}
  2640  	p.current.flows |= flow
  2641  	return "", nil
  2642  }
  2643  
  2644  // Break func
  2645  func (p *CodeBuilder) Break(l *Label) *CodeBuilder {
  2646  	name, label := p.labelFlow(flowFlagBreak, l)
  2647  	if debugInstr {
  2648  		log.Println("Break", name)
  2649  	}
  2650  	p.emitStmt(&ast.BranchStmt{Tok: token.BREAK, Label: label})
  2651  	return p
  2652  }
  2653  
  2654  // Continue func
  2655  func (p *CodeBuilder) Continue(l *Label) *CodeBuilder {
  2656  	name, label := p.labelFlow(flowFlagContinue, l)
  2657  	if debugInstr {
  2658  		log.Println("Continue", name)
  2659  	}
  2660  	p.emitStmt(&ast.BranchStmt{Tok: token.CONTINUE, Label: label})
  2661  	return p
  2662  }
  2663  
  2664  // Fallthrough func
  2665  func (p *CodeBuilder) Fallthrough() *CodeBuilder {
  2666  	if debugInstr {
  2667  		log.Println("Fallthrough")
  2668  	}
  2669  	if flow, ok := p.current.codeBlock.(*caseStmt); ok {
  2670  		flow.Fallthrough(p)
  2671  		return p
  2672  	}
  2673  	panic("please use fallthrough in case statement")
  2674  }
  2675  
  2676  // For func
  2677  func (p *CodeBuilder) For(src ...ast.Node) *CodeBuilder {
  2678  	if debugInstr {
  2679  		log.Println("For")
  2680  	}
  2681  	stmt := &forStmt{}
  2682  	p.startBlockStmt(stmt, src, "for statement", &stmt.old)
  2683  	return p
  2684  }
  2685  
  2686  // Post func
  2687  func (p *CodeBuilder) Post() *CodeBuilder {
  2688  	if debugInstr {
  2689  		log.Println("Post")
  2690  	}
  2691  	if flow, ok := p.current.codeBlock.(*forStmt); ok {
  2692  		flow.Post(p)
  2693  		return p
  2694  	}
  2695  	panic("please use Post() in for statement")
  2696  }
  2697  
  2698  // ForRange func
  2699  func (p *CodeBuilder) ForRange(names ...string) *CodeBuilder {
  2700  	return p.ForRangeEx(names)
  2701  }
  2702  
  2703  // ForRangeEx func
  2704  func (p *CodeBuilder) ForRangeEx(names []string, src ...ast.Node) *CodeBuilder {
  2705  	if debugInstr {
  2706  		log.Println("ForRange", names)
  2707  	}
  2708  	stmt := &forRangeStmt{names: names}
  2709  	p.startBlockStmt(stmt, src, "for range statement", &stmt.old)
  2710  	return p
  2711  }
  2712  
  2713  // RangeAssignThen func
  2714  func (p *CodeBuilder) RangeAssignThen(pos token.Pos) *CodeBuilder {
  2715  	if debugInstr {
  2716  		log.Println("RangeAssignThen")
  2717  	}
  2718  	if flow, ok := p.current.codeBlock.(*forRangeStmt); ok {
  2719  		flow.RangeAssignThen(p, pos)
  2720  		return p
  2721  	}
  2722  	panic("please use RangeAssignThen() in for range statement")
  2723  }
  2724  
  2725  // ResetStmt resets the statement state of CodeBuilder.
  2726  func (p *CodeBuilder) ResetStmt() {
  2727  	if debugInstr {
  2728  		log.Println("ResetStmt")
  2729  	}
  2730  	p.stk.SetLen(p.current.base)
  2731  }
  2732  
  2733  // EndStmt func
  2734  func (p *CodeBuilder) EndStmt() *CodeBuilder {
  2735  	n := p.stk.Len() - p.current.base
  2736  	if n > 0 {
  2737  		if n != 1 {
  2738  			panic("syntax error: unexpected newline, expecting := or = or comma")
  2739  		}
  2740  		if e := p.stk.Pop(); p.noSkipConst || e.CVal == nil { // skip constant
  2741  			p.emitStmt(&ast.ExprStmt{X: e.Val})
  2742  		}
  2743  	}
  2744  	return p
  2745  }
  2746  
  2747  // End func
  2748  func (p *CodeBuilder) End(src ...ast.Node) *CodeBuilder {
  2749  	if debugInstr {
  2750  		typ := reflect.TypeOf(p.current.codeBlock)
  2751  		if typ.Kind() == reflect.Ptr {
  2752  			typ = typ.Elem()
  2753  		}
  2754  		name := strings.TrimSuffix(strings.Title(typ.Name()), "Stmt")
  2755  		log.Println("End //", name)
  2756  		if p.stk.Len() > p.current.base {
  2757  			panic("forget to call EndStmt()?")
  2758  		}
  2759  	}
  2760  	p.current.End(p, getSrc(src))
  2761  	return p
  2762  }
  2763  
  2764  func (p *CodeBuilder) SetBodyHandler(handle func(body *ast.BlockStmt, kind int)) *CodeBuilder {
  2765  	if ini, ok := p.current.codeBlock.(interface {
  2766  		SetBodyHandler(func(body *ast.BlockStmt, kind int))
  2767  	}); ok {
  2768  		ini.SetBodyHandler(handle)
  2769  	}
  2770  	return p
  2771  }
  2772  
  2773  // ResetInit resets the variable init state of CodeBuilder.
  2774  func (p *CodeBuilder) ResetInit() {
  2775  	if debugInstr {
  2776  		log.Println("ResetInit")
  2777  	}
  2778  	p.valDecl = p.valDecl.resetInit(p)
  2779  }
  2780  
  2781  // EndInit func
  2782  func (p *CodeBuilder) EndInit(n int) *CodeBuilder {
  2783  	if debugInstr {
  2784  		log.Println("EndInit", n)
  2785  	}
  2786  	p.valDecl = p.valDecl.endInit(p, n)
  2787  	return p
  2788  }
  2789  
  2790  // Debug func
  2791  func (p *CodeBuilder) Debug(dbg func(cb *CodeBuilder)) *CodeBuilder {
  2792  	dbg(p)
  2793  	return p
  2794  }
  2795  
  2796  // Get func
  2797  func (p *CodeBuilder) Get(idx int) *Element {
  2798  	return p.stk.Get(idx)
  2799  }
  2800  
  2801  // ----------------------------------------------------------------------------
  2802  
  2803  type InternalStack = internal.Stack
  2804  
  2805  // InternalStack: don't call it (only for internal use)
  2806  func (p *CodeBuilder) InternalStack() *InternalStack {
  2807  	return &p.stk
  2808  }
  2809  
  2810  // ----------------------------------------------------------------------------