return n
}
-// check that the list of declarations is either all anonymous or all named
-func findtype(s []*Node) *Node {
- for _, n := range s {
- if n.Op == OKEY {
- return n.Right
- }
- }
- return nil
-}
-
-func checkarglist(all []*Node, input int) []*Node {
- named := false
- for _, n := range all {
- if n.Op == OKEY {
- named = true
- break
- }
- }
-
- if named {
- ok := true
- for _, n := range all {
- if n.Op != OKEY && n.Sym == nil {
- Yyerror("mixed named and unnamed function parameters")
- ok = false
- break
- }
- }
-
- if ok && len(all) > 0 && all[len(all)-1].Op != OKEY {
- Yyerror("final function parameter must have type")
- }
- }
-
- var nextt *Node
- for i, n := range all {
- // can cache result from findtype to avoid
- // quadratic behavior here, but unlikely to matter.
-
- var t *Node
- if named {
- if n.Op == OKEY {
- t = n.Right
- n = n.Left
- nextt = nil
- } else {
- if nextt == nil {
- nextt = findtype(all[i:])
- }
- t = nextt
- }
- } else {
- t = n
- n = nil
- }
-
- // during import l->n->op is OKEY, but l->n->left->sym == S
- // means it was a '?', not that it was
- // a lone type This doesn't matter for the exported
- // declarations, which are parsed by rules that don't
- // use checkargs, but can happen for func literals in
- // the inline bodies.
- // TODO(rsc) this can go when typefmt case TFIELD in exportmode fmt.go prints _ instead of ?
- if importpkg != nil && n.Sym == nil {
- n = nil
- }
-
- if n != nil && n.Sym == nil {
- t = n
- n = nil
- }
-
- if n != nil {
- n = newname(n.Sym)
- }
- n = Nod(ODCLFIELD, n, t)
- if n.Right != nil && n.Right.Op == ODDD {
- if input == 0 {
- Yyerror("cannot use ... in output argument list")
- } else if i+1 < len(all) {
- Yyerror("can only use ... as final argument in list")
- }
- n.Right.Op = OTARRAY
- n.Right.Right = n.Right.Left
- n.Right.Left = nil
- n.Isddd = true
- if n.Left != nil {
- n.Left.Isddd = true
- }
- }
-
- all[i] = n
- }
-
- return all
-}
-
func fakethis() *Node {
n := Nod(ODCLFIELD, nil, typenod(Ptrto(typ(TSTRUCT))))
return n
}
}
+// param parses and returns a function parameter list entry which may be
+// a parameter name and type pair (name, typ), a single type (nil, typ),
+// or a single name (name, nil). In the last case, the name may still be
+// a type name. The result is (nil, nil) in case of a syntax error.
+//
// [ParameterName] Type
-func (p *parser) par_type() *Node {
+func (p *parser) param() (name *Sym, typ *Node) {
if trace && Debug['x'] != 0 {
- defer p.trace("par_type")()
+ defer p.trace("param")()
}
switch p.tok {
case LNAME, '@', '?':
- name := p.sym()
+ name = p.sym() // nil if p.tok == '?' (importing only)
switch p.tok {
case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', LNAME, '@', '?', '(':
// sym name_or_type
- typ := p.ntype()
- nn := Nod(ONONAME, nil, nil)
- nn.Sym = name
- return Nod(OKEY, nn, typ)
+ typ = p.ntype()
case LDDD:
// sym dotdotdot
- typ := p.dotdotdot()
- nn := Nod(ONONAME, nil, nil)
- nn.Sym = name
- return Nod(OKEY, nn, typ)
+ typ = p.dotdotdot()
default:
// name_or_type
- name := mkname(name)
- // from dotname
if p.got('.') {
- return p.new_dotname(name)
+ // a qualified name cannot be a parameter name
+ typ = p.new_dotname(mkname(name))
+ name = nil
}
- return name
}
case LDDD:
// dotdotdot
- return p.dotdotdot()
+ typ = p.dotdotdot()
case LCOMM, LFUNC, '[', LCHAN, LMAP, LSTRUCT, LINTERFACE, '*', '(':
// name_or_type
- return p.ntype()
+ typ = p.ntype()
default:
p.syntax_error("expecting )")
p.advance(',', ')')
- return nil
}
+
+ return
}
// Parameters = "(" [ ParameterList [ "," ] ] ")" .
defer p.trace("param_list")()
}
+ type param struct {
+ name *Sym
+ typ *Node
+ }
+ var params []param
+ var named int // number of parameters that have a name and type
+
p.want('(')
- var l []*Node
for p.tok != EOF && p.tok != ')' {
- l = append(l, p.par_type())
+ name, typ := p.param()
+ params = append(params, param{name, typ})
+ if name != nil && typ != nil {
+ named++
+ }
if !p.ocomma(')') {
break
}
}
p.want(')')
+ // 0 <= named <= len(params)
- // TODO(gri) remove this with next commit
- input := 0
- if dddOk {
- input = 1
+ // There are 3 cases:
+ //
+ // 1) named == 0:
+ // No parameter list entry has both a name and a type; i.e. there are only
+ // unnamed parameters. Any name must be a type name; they are "converted"
+ // to types when creating the final parameter list.
+ // In case of a syntax error, there is neither a name nor a type.
+ // Nil checks take care of this.
+ //
+ // 2) named == len(names):
+ // All parameter list entries have both a name and a type.
+ //
+ // 3) Otherwise:
+ if named != 0 && named != len(params) {
+ // Some parameter list entries have both a name and a type:
+ // Distribute types backwards and check that there are no
+ // mixed named and unnamed parameters.
+ var T *Node // type T in a parameter sequence: a, b, c T
+ for i := len(params) - 1; i >= 0; i-- {
+ p := ¶ms[i]
+ if t := p.typ; t != nil {
+ // explicit type: use type for earlier parameters
+ T = t
+ // an explicitly typed entry must have a name
+ // TODO(gri) remove extra importpkg == nil check below
+ // after switch to binary eport format
+ // Exported inlined function bodies containing function
+ // literals may print parameter names as '?' resulting
+ // in nil *Sym and thus nil names. Don't report an error
+ // in this case.
+ if p.name == nil && importpkg == nil {
+ T = nil // error
+ }
+ } else {
+ // no explicit type: use type of next parameter
+ p.typ = T
+ }
+ if T == nil {
+ Yyerror("mixed named and unnamed function parameters")
+ break
+ }
+ }
+ // Unless there was an error, now all parameter entries have a type.
}
- return checkarglist(l, input)
+
+ // create final parameter list
+ list := make([]*Node, len(params))
+ for i, p := range params {
+ // create dcl node
+ var name, typ *Node
+ if p.typ != nil {
+ typ = p.typ
+ if p.name != nil {
+ // name must be a parameter name
+ name = newname(p.name)
+ }
+ } else if p.name != nil {
+ // p.name must be a type name (or nil in case of syntax error)
+ typ = mkname(p.name)
+ }
+ n := Nod(ODCLFIELD, name, typ)
+
+ // rewrite ...T parameter
+ if typ != nil && typ.Op == ODDD {
+ if !dddOk {
+ Yyerror("cannot use ... in receiver or result parameter list")
+ } else if i+1 < len(params) {
+ Yyerror("can only use ... with final parameter in list")
+ }
+ typ.Op = OTARRAY
+ typ.Right = typ.Left
+ typ.Left = nil
+ n.Isddd = true
+ if n.Left != nil {
+ n.Left.Isddd = true
+ }
+ }
+
+ list[i] = n
+ }
+
+ return list
}
var missing_stmt = Nod(OXXX, nil, nil)