func (p *parser) fnArgs(c *ast.CallExpr) { for { if tok := p.peek(); tok.Type == scan.Rparen { break } c.Args = append(c.Args, p.asgmnt()) if tok := p.peek(); tok.Type == scan.Comma { p.next() if tok := p.peek(); tok.Type == scan.Rparen { p.errorf(tok.Span().Start, "trailing ',' in function call") } } else { break } } c.Rparen = p.expect(scan.Rparen) }
// call type checks a call expression. func (c *checker) call(x *operand, e *ast.CallExpr) exprType { // if there is no forward declaration of the function // it is assumed to be variadic and returns an int ident, ok := e.Fun.(*ast.Ident) if ok { var y operand c.ident(&y, ident, true) if y.mode == invalid { pos := e.Span().Start result := NewVar(pos, 0, ident.Name, Typ[Int], nil) sig := NewSignature(nil, result, true) fun := NewFunc(pos, GlobalStatic, ident.Name, sig) fwrd := NewFwrd(ident.Name, fun) c.declare(Fwd, c.scope, ident, fwrd, scan.NoPos) } } c.expr(x, e.Fun) invalidArgs := false var y operand for _, arg := range e.Args { c.expr(&y, arg) if isRecord(y.typ) { c.errorf(arg.Span().Start, "struct/union passing by value is not supported") invalidArgs = true } } if invalidArgs { goto Error } switch x.mode { case invalid: x.expr = e return statement default: sig, _ := x.typ.Underlying().(*Signature) if sig == nil { c.errorf(e.Span().Start, "cannot call a non-function %v", x) goto Error } params := sig.Params() numParams := 0 if params != nil { numParams = params.Len() } if !sig.Variadic() && len(e.Args) != numParams { c.errorf(e.Lparen.Span().Start, "expected %d arguments, but function call passed %d arguments", numParams, len(e.Args)) goto Error } if sig.Variadic() && numParams != 0 && len(e.Args) < numParams { c.errorf(e.Lparen.Span().Start, "expected at least %d arguments for variadic function, but function call passed %d arguments", numParams, len(e.Args)) } // don't need to check the individual arguments, because we don't support passing records, so everything else // is a pointer or integer and pointers can be passed to integer and vice versa x.typ = sig.Result().Type().Underlying() if x.typ == Typ[Void] { x.mode = novalue } return statement } Error: x.mode = invalid x.expr = e return statement }