func()

in internal/compile/compile.go [1805:1869]


func (fcomp *fcomp) function(f *resolve.Function) {
	// Evaluation of the defaults may fail, so record the position.
	fcomp.setPos(f.Pos)

	// To reduce allocation, we emit a combined tuple
	// for the defaults and the freevars.
	// The function knows where to split it at run time.

	// Generate tuple of parameter defaults. For:
	//  def f(p1, p2=dp2, p3=dp3, *, k1, k2=dk2, k3, **kwargs)
	// the tuple is:
	//  (dp2, dp3, MANDATORY, dk2, MANDATORY).
	ndefaults := 0
	seenStar := false
	for _, param := range f.Params {
		switch param := param.(type) {
		case *syntax.BinaryExpr:
			fcomp.expr(param.Y)
			ndefaults++
		case *syntax.UnaryExpr:
			seenStar = true // * or *args (also **kwargs)
		case *syntax.Ident:
			if seenStar {
				fcomp.emit(MANDATORY)
				ndefaults++
			}
		}
	}

	// Capture the cells of the function's
	// free variables from the lexical environment.
	for _, freevar := range f.FreeVars {
		// Don't call fcomp.lookup because we want
		// the cell itself, not its content.
		switch freevar.Scope {
		case resolve.Free:
			fcomp.emit1(FREE, uint32(freevar.Index))
		case resolve.Cell:
			fcomp.emit1(LOCAL, uint32(freevar.Index))
		}
	}

	fcomp.emit1(MAKETUPLE, uint32(ndefaults+len(f.FreeVars)))

	funcode := fcomp.pcomp.function(f.Name, f.Pos, f.Body, f.Locals, f.FreeVars)

	if debug {
		// TODO(adonovan): do compilations sequentially not as a tree,
		// to make the log easier to read.
		// Simplify by identifying Toplevel and functionIndex 0.
		fmt.Fprintf(os.Stderr, "resuming %s @ %s\n", fcomp.fn.Name, fcomp.pos)
	}

	// def f(a, *, b=1) has only 2 parameters.
	numParams := len(f.Params)
	if f.NumKwonlyParams > 0 && !f.HasVarargs {
		numParams--
	}

	funcode.NumParams = numParams
	funcode.NumKwonlyParams = f.NumKwonlyParams
	funcode.HasVarargs = f.HasVarargs
	funcode.HasKwargs = f.HasKwargs
	fcomp.emit1(MAKEFUNC, fcomp.pcomp.functionIndex(funcode))
}