1
0
mirror of https://github.com/golang/go synced 2024-11-26 05:07:59 -07:00

[dev.typeparams] cmd/compile/internal/syntax: implement parsing of type parameters

Port from dev.go2go prototype branch. The compiler doesn't yet set the
syntax.AllowGenerics mode, so parsing of generic code remains disabled.

Known issue: The doc strings documenting the specific syntax accepted
by parser methods are not all up-to-date.

Change-Id: I13d134289fd9330fd0ed7f97c997cca6f23466fd
Reviewed-on: https://go-review.googlesource.com/c/go/+/261658
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Robert Griesemer 2020-10-12 14:07:31 -07:00
parent 617b633917
commit b627988b0c
2 changed files with 447 additions and 207 deletions

View File

@ -459,20 +459,21 @@ func isEmptyFuncDecl(dcl Decl) bool {
// Declarations
// list parses a possibly empty, sep-separated list, optionally
// followed by sep and enclosed by ( and ) or { and }. open is
// one of _Lparen, or _Lbrace, sep is one of _Comma or _Semi,
// and close is expected to be the (closing) opposite of open.
// followed sep, and closed by close. sep must be one of _Comma
// or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack.
// For each list element, f is called. After f returns true, no
// more list elements are accepted. list returns the position
// of the closing token.
//
// list = "(" { f sep } ")" |
// "{" { f sep } "}" . // sep is optional before ")" or "}"
// list = { f sep } ")" |
// { f sep } "}" . // "," or ";" is optional before ")", "}" or "]"
//
func (p *parser) list(open, sep, close token, f func() bool) Pos {
p.want(open)
func (p *parser) list(sep, close token, f func() bool) Pos {
if debug && (sep != _Comma && sep != _Semi || close != _Rparen && close != _Rbrace && close != _Rbrack) {
panic("invalid sep or close argument for list")
}
var done bool
done := false
for p.tok != _EOF && p.tok != close && !done {
done = f()
// sep is optional before close
@ -496,7 +497,8 @@ func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
if p.tok == _Lparen {
g := new(Group)
p.clearPragma()
p.list(_Lparen, _Semi, _Rparen, func() bool {
p.next() // must consume "(" after calling clearPragma!
p.list(_Semi, _Rparen, func() bool {
list = append(list, f(g))
return false
})
@ -566,7 +568,7 @@ func (p *parser) constDecl(group *Group) Decl {
return d
}
// TypeSpec = identifier [ "=" ] Type .
// TypeSpec = identifier [ TypeParams ] [ "=" ] Type .
func (p *parser) typeDecl(group *Group) Decl {
if trace {
defer p.trace("typeDecl")()
@ -578,8 +580,42 @@ func (p *parser) typeDecl(group *Group) Decl {
d.Pragma = p.takePragma()
d.Name = p.name()
d.Alias = p.gotAssign()
d.Type = p.typeOrNil()
if p.tok == _Lbrack {
// array/slice or generic type
pos := p.pos()
p.next()
switch p.tok {
case _Rbrack:
p.next()
d.Type = p.sliceType(pos)
case _Name:
// array or generic type
p.xnest++
x := p.expr()
p.xnest--
if name0, ok := x.(*Name); p.mode&AllowGenerics != 0 && ok && p.tok != _Rbrack {
// generic type
d.TParamList = p.paramList(name0, _Rbrack)
pos := p.pos()
if p.gotAssign() {
p.syntaxErrorAt(pos, "generic type cannot be alias")
}
d.Type = p.typeOrNil()
} else {
// x is the array length expression
if debug && x == nil {
panic("internal error: nil expression")
}
d.Type = p.arrayType(pos, x)
}
default:
d.Type = p.arrayType(pos, nil)
}
} else {
d.Alias = p.gotAssign()
d.Type = p.typeOrNil()
}
if d.Type == nil {
d.Type = p.badExpr()
p.syntaxError("in type declaration")
@ -613,7 +649,7 @@ func (p *parser) varDecl(group *Group) Decl {
return d
}
// FunctionDecl = "func" FunctionName ( Function | Signature ) .
// FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) .
// FunctionName = identifier .
// Function = Signature FunctionBody .
// MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
@ -627,8 +663,8 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
f.pos = p.pos()
f.Pragma = p.takePragma()
if p.tok == _Lparen {
rcvr := p.paramList()
if p.got(_Lparen) {
rcvr := p.paramList(nil, _Rparen)
switch len(rcvr) {
case 0:
p.error("method has no receiver")
@ -647,6 +683,14 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
}
f.Name = p.name()
if p.mode&AllowGenerics != 0 && p.got(_Lbrack) {
if p.tok == _Rbrack {
p.syntaxError("empty type parameter list")
p.next()
} else {
f.TParamList = p.paramList(nil, _Rbrack)
}
}
f.Type = p.funcType()
if p.tok == _Lbrace {
f.Body = p.funcBody()
@ -850,13 +894,7 @@ func (p *parser) operand(keep_parens bool) Expr {
// Optimization: Record presence of ()'s only where needed
// for error reporting. Don't bother in other cases; it is
// just a waste of memory and time.
// Parentheses are not permitted on lhs of := .
// switch x.Op {
// case ONAME, ONONAME, OPACK, OTYPE, OLITERAL, OTYPESW:
// keep_parens = true
// }
//
// Parentheses are not permitted around T in a composite
// literal T{}. If the next token is a {, assume x is a
// composite literal type T (it may not be, { could be
@ -879,19 +917,19 @@ func (p *parser) operand(keep_parens bool) Expr {
case _Func:
pos := p.pos()
p.next()
t := p.funcType()
ftyp := p.funcType()
if p.tok == _Lbrace {
p.xnest++
f := new(FuncLit)
f.pos = pos
f.Type = t
f.Type = ftyp
f.Body = p.funcBody()
p.xnest--
return f
}
return t
return ftyp
case _Lbrack, _Chan, _Map, _Struct, _Interface:
return p.type_() // othertype
@ -971,6 +1009,14 @@ loop:
case _Lbrack:
p.next()
if p.tok == _Rbrack {
// invalid empty instance, slice or index expression; accept but complain
p.syntaxError("expecting operand")
p.next()
break
}
p.xnest++
var i Expr
@ -986,6 +1032,20 @@ loop:
p.xnest--
break
}
if p.mode&AllowGenerics != 0 && p.tok == _Comma {
// x[i, ... (instantiated type)
// TODO(gri) Suggestion by mdempsky@: Use IndexExpr + ExprList for this case.
// Then we can get rid of CallExpr.Brackets.
t := new(CallExpr)
t.pos = pos
t.Fun = x
t.ArgList, _ = p.argList(i, _Rbrack)
t.Brackets = true
x = t
p.xnest--
break
}
}
// x[i:...
@ -1022,8 +1082,9 @@ loop:
case _Lparen:
t := new(CallExpr)
t.pos = pos
p.next()
t.Fun = x
t.ArgList, t.HasDots = p.argList()
t.ArgList, t.HasDots = p.argList(nil, _Rparen)
x = t
case _Lbrace:
@ -1032,10 +1093,20 @@ loop:
t := unparen(x)
// determine if '{' belongs to a composite literal or a block statement
complit_ok := false
switch t.(type) {
switch t := t.(type) {
case *Name, *SelectorExpr:
if p.xnest >= 0 {
// x is considered a composite literal type
// x is possibly a composite literal type
complit_ok = true
}
case *CallExpr:
if t.Brackets && p.xnest >= 0 {
// x is possibly a composite literal type
complit_ok = true
}
case *IndexExpr:
if p.xnest >= 0 {
// x is possibly a composite literal type
complit_ok = true
}
case *ArrayType, *SliceType, *StructType, *MapType:
@ -1085,7 +1156,8 @@ func (p *parser) complitexpr() *CompositeLit {
x.pos = p.pos()
p.xnest++
x.Rbrace = p.list(_Lbrace, _Comma, _Rbrace, func() bool {
p.want(_Lbrace)
x.Rbrace = p.list(_Comma, _Rbrace, func() bool {
// value
e := p.bare_complitexpr()
if p.tok == _Colon {
@ -1170,26 +1242,10 @@ func (p *parser) typeOrNil() Expr {
// '[' oexpr ']' ntype
// '[' _DotDotDot ']' ntype
p.next()
p.xnest++
if p.got(_Rbrack) {
// []T
p.xnest--
t := new(SliceType)
t.pos = pos
t.Elem = p.type_()
return t
return p.sliceType(pos)
}
// [n]T
t := new(ArrayType)
t.pos = pos
if !p.got(_DotDotDot) {
t.Len = p.expr()
}
p.want(_Rbrack)
p.xnest--
t.Elem = p.type_()
return t
return p.arrayType(pos, nil)
case _Chan:
// _Chan non_recvchantype
@ -1221,7 +1277,7 @@ func (p *parser) typeOrNil() Expr {
return p.interfaceType()
case _Name:
return p.dotname(p.name())
return p.qualifiedName(nil)
case _Lparen:
p.next()
@ -1233,6 +1289,27 @@ func (p *parser) typeOrNil() Expr {
return nil
}
func (p *parser) typeInstance(typ Expr) Expr {
if trace {
defer p.trace("typeInstance")()
}
pos := p.pos()
p.want(_Lbrack)
if p.tok == _Rbrack {
p.error("expecting type")
p.next()
return typ
}
call := new(CallExpr)
call.pos = pos
call.Fun = typ
call.ArgList, _ = p.argList(nil, _Rbrack)
call.Brackets = true
return call
}
func (p *parser) funcType() *FuncType {
if trace {
defer p.trace("funcType")()
@ -1240,12 +1317,41 @@ func (p *parser) funcType() *FuncType {
typ := new(FuncType)
typ.pos = p.pos()
typ.ParamList = p.paramList()
p.want(_Lparen)
typ.ParamList = p.paramList(nil, _Rparen)
typ.ResultList = p.funcResult()
return typ
}
// "[" has already been consumed, and pos is its position.
// If len != nil it is the already consumed array length.
func (p *parser) arrayType(pos Pos, len Expr) Expr {
if trace {
defer p.trace("arrayType")()
}
if len == nil && !p.got(_DotDotDot) {
p.xnest++
len = p.expr()
p.xnest--
}
p.want(_Rbrack)
t := new(ArrayType)
t.pos = pos
t.Len = len
t.Elem = p.type_()
return t
}
// "[" and "]" have already been consumed, and pos is the position of "[".
func (p *parser) sliceType(pos Pos) Expr {
t := new(SliceType)
t.pos = pos
t.Elem = p.type_()
return t
}
func (p *parser) chanElem() Expr {
if trace {
defer p.trace("chanElem")()
@ -1261,22 +1367,6 @@ func (p *parser) chanElem() Expr {
return typ
}
func (p *parser) dotname(name *Name) Expr {
if trace {
defer p.trace("dotname")()
}
if p.tok == _Dot {
s := new(SelectorExpr)
s.pos = p.pos()
p.next()
s.X = name
s.Sel = p.name()
return s
}
return name
}
// StructType = "struct" "{" { FieldDecl ";" } "}" .
func (p *parser) structType() *StructType {
if trace {
@ -1287,7 +1377,8 @@ func (p *parser) structType() *StructType {
typ.pos = p.pos()
p.want(_Struct)
p.list(_Lbrace, _Semi, _Rbrace, func() bool {
p.want(_Lbrace)
p.list(_Semi, _Rbrace, func() bool {
p.fieldDecl(typ)
return false
})
@ -1305,9 +1396,56 @@ func (p *parser) interfaceType() *InterfaceType {
typ.pos = p.pos()
p.want(_Interface)
p.list(_Lbrace, _Semi, _Rbrace, func() bool {
if m := p.methodDecl(); m != nil {
typ.MethodList = append(typ.MethodList, m)
p.want(_Lbrace)
p.list(_Semi, _Rbrace, func() bool {
switch p.tok {
case _Name:
typ.MethodList = append(typ.MethodList, p.methodDecl())
case _Lparen:
p.syntaxError("cannot parenthesize embedded type")
f := new(Field)
f.pos = p.pos()
p.next()
f.Type = p.qualifiedName(nil)
p.want(_Rparen)
typ.MethodList = append(typ.MethodList, f)
case _Type:
if p.mode&AllowGenerics != 0 {
// TODO(gri) factor this better
type_ := new(Name)
type_.pos = p.pos()
type_.Value = "type" // cannot have a method named "type"
p.next()
if p.tok != _Semi && p.tok != _Rbrace {
f := new(Field)
f.pos = p.pos()
f.Name = type_
f.Type = p.type_()
typ.MethodList = append(typ.MethodList, f)
for p.got(_Comma) {
f := new(Field)
f.pos = p.pos()
f.Name = type_
f.Type = p.type_()
typ.MethodList = append(typ.MethodList, f)
}
} else {
p.syntaxError("expecting type")
}
break
}
fallthrough
default:
if p.mode&AllowGenerics != 0 {
p.syntaxError("expecting method, interface name, or type list")
p.advance(_Semi, _Rbrace, _Type)
} else {
p.syntaxError("expecting method or interface name")
p.advance(_Semi, _Rbrace)
}
}
return false
})
@ -1321,8 +1459,8 @@ func (p *parser) funcResult() []*Field {
defer p.trace("funcResult")()
}
if p.tok == _Lparen {
return p.paramList()
if p.got(_Lparen) {
return p.paramList(nil, _Rparen)
}
pos := p.pos()
@ -1368,59 +1506,71 @@ func (p *parser) fieldDecl(styp *StructType) {
case _Name:
name := p.name()
if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
// embed oliteral
// embedded type
typ := p.qualifiedName(name)
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
return
break
}
// new_name_list ntype oliteral
// name1, name2, ... Type [ tag ]
names := p.nameList(name)
typ := p.type_()
var typ Expr
// Careful dance: We don't know if we have an embedded instantiated
// type T[P1, P2, ...] or a field T of array/slice type [P]E or []E.
if p.mode&AllowGenerics != 0 && len(names) == 1 && p.tok == _Lbrack {
typ = p.arrayOrTArgs()
if typ, ok := typ.(*CallExpr); ok {
// embedded type T[P1, P2, ...]
typ.Fun = name // name == names[0]
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
break
}
} else {
// T P
typ = p.type_()
}
tag := p.oliteral()
for _, name := range names {
p.addField(styp, name.Pos(), name, typ, tag)
}
case _Lparen:
p.next()
if p.tok == _Star {
// '(' '*' embed ')' oliteral
pos := p.pos()
p.next()
typ := newIndirect(pos, p.qualifiedName(nil))
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
p.syntaxError("cannot parenthesize embedded type")
} else {
// '(' embed ')' oliteral
typ := p.qualifiedName(nil)
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
p.syntaxError("cannot parenthesize embedded type")
}
case _Star:
p.next()
if p.got(_Lparen) {
// '*' '(' embed ')' oliteral
typ := newIndirect(pos, p.qualifiedName(nil))
p.want(_Rparen)
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
var typ Expr
if p.tok == _Lparen {
// *(T)
p.syntaxError("cannot parenthesize embedded type")
p.next()
typ = p.qualifiedName(nil)
p.got(_Rparen) // no need to complain if missing
} else {
// '*' embed oliteral
typ := newIndirect(pos, p.qualifiedName(nil))
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
// *T
typ = p.qualifiedName(nil)
}
tag := p.oliteral()
p.addField(styp, pos, nil, newIndirect(pos, typ), tag)
case _Lparen:
p.syntaxError("cannot parenthesize embedded type")
p.next()
var typ Expr
if p.tok == _Star {
// (*T)
pos := p.pos()
p.next()
typ = newIndirect(pos, p.qualifiedName(nil))
} else {
// (T)
typ = p.qualifiedName(nil)
}
p.got(_Rparen) // no need to complain if missing
tag := p.oliteral()
p.addField(styp, pos, nil, typ, tag)
default:
p.syntaxError("expecting field name or embedded type")
@ -1428,6 +1578,39 @@ func (p *parser) fieldDecl(styp *StructType) {
}
}
func (p *parser) arrayOrTArgs() Expr {
if trace {
defer p.trace("arrayOrTArgs")()
}
pos := p.pos()
p.want(_Lbrack)
if p.got(_Rbrack) {
return p.sliceType(pos)
}
// x [P]E or x[P]
args, _ := p.argList(nil, _Rbrack)
if len(args) == 1 {
if elem := p.typeOrNil(); elem != nil {
// x [P]E
t := new(ArrayType)
t.pos = pos
t.Len = args[0]
t.Elem = elem
return t
}
}
// x[P], x[P1, P2], ...
t := new(CallExpr)
t.pos = pos
// t.Fun will be filled in by caller
t.ArgList = args
t.Brackets = true
return t
}
func (p *parser) oliteral() *BasicLit {
if p.tok == _Literal {
b := new(BasicLit)
@ -1449,51 +1632,93 @@ func (p *parser) methodDecl() *Field {
defer p.trace("methodDecl")()
}
f := new(Field)
f.pos = p.pos()
name := p.name()
// accept potential name list but complain
// TODO(gri) We probably don't need this special check anymore.
// Nobody writes this kind of code. It's from ancient
// Go beginnings.
hasNameList := false
for p.got(_Comma) {
p.name()
hasNameList = true
}
if hasNameList {
p.syntaxError("name list not allowed in interface type")
// already progressed, no need to advance
}
switch p.tok {
case _Name:
name := p.name()
// accept potential name list but complain
hasNameList := false
for p.got(_Comma) {
p.name()
hasNameList = true
}
if hasNameList {
p.syntaxError("name list not allowed in interface type")
// already progressed, no need to advance
}
f := new(Field)
f.pos = name.Pos()
if p.tok != _Lparen {
// packname
f.Type = p.qualifiedName(name)
return f
}
case _Lparen:
// method
f.Name = name
f.Type = p.funcType()
return f
case _Lparen:
p.syntaxError("cannot parenthesize embedded type")
f := new(Field)
f.pos = p.pos()
p.next()
f.Type = p.qualifiedName(nil)
p.want(_Rparen)
return f
case _Lbrack:
if p.mode&AllowGenerics != 0 {
// Careful dance: We don't know if we have a generic method m[T C](x T)
// or an embedded instantiated type T[P1, P2] (we accept generic methods
// for generality and robustness of parsing).
pos := p.pos()
p.next()
// empty type parameter or argument lists are not permitted
if p.tok == _Rbrack {
// name[]
pos := p.pos()
p.next()
if p.tok == _Lparen {
// name[](
p.errorAt(pos, "empty type parameter list")
f.Name = name
f.Type = p.funcType()
} else {
p.errorAt(pos, "empty type argument list")
f.Type = name
}
break
}
// A type argument list looks like a parameter list with only
// types. Parse a parameter list and decide afterwards.
list := p.paramList(nil, _Rbrack)
if len(list) > 0 && list[0].Name != nil {
// generic method
f.Name = name
f.Type = p.funcType()
// TODO(gri) Record list as type parameter list with f.Type
// if we want to type-check the generic method.
// For now, report an error so this is not a silent event.
p.errorAt(pos, "interface method cannot have type parameters")
break
}
// embedded instantiated type
call := new(CallExpr)
call.pos = pos
call.Fun = name
call.Brackets = true
call.ArgList = make([]Expr, len(list))
for i := range list {
call.ArgList[i] = list[i].Type
}
f.Type = call
break
}
fallthrough
default:
p.syntaxError("expecting method or interface name")
p.advance(_Semi, _Rbrace)
return nil
// embedded type
f.Type = p.qualifiedName(name)
}
return f
}
// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
func (p *parser) paramDeclOrNil() *Field {
func (p *parser) paramDeclOrNil(name *Name) *Field {
if trace {
defer p.trace("paramDecl")()
}
@ -1501,73 +1726,67 @@ func (p *parser) paramDeclOrNil() *Field {
f := new(Field)
f.pos = p.pos()
switch p.tok {
case _Name:
f.Name = p.name()
switch p.tok {
case _Name, _Star, _Arrow, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
// sym name_or_type
f.Type = p.type_()
case _DotDotDot:
// sym dotdotdot
f.Type = p.dotsType()
case _Dot:
// name_or_type
// from dotname
f.Type = p.dotname(f.Name)
f.Name = nil
if p.tok == _Name || name != nil {
if name == nil {
name = p.name()
}
case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
// name_or_type
f.Type = p.type_()
if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
f.Type = p.arrayOrTArgs()
if typ, ok := f.Type.(*CallExpr); ok {
typ.Fun = name
} else {
f.Name = name
}
return f
}
case _DotDotDot:
// dotdotdot
f.Type = p.dotsType()
if p.tok == _Dot {
// name_or_type
f.Type = p.qualifiedName(name)
return f
}
default:
p.syntaxError("expecting )")
p.advance(_Comma, _Rparen)
return nil
f.Name = name
}
return f
}
// ...Type
func (p *parser) dotsType() *DotsType {
if trace {
defer p.trace("dotsType")()
if p.tok == _DotDotDot {
t := new(DotsType)
t.pos = p.pos()
p.next()
t.Elem = p.typeOrNil()
if t.Elem == nil {
t.Elem = p.badExpr()
p.syntaxError("final argument in variadic function missing type")
}
f.Type = t
return f
}
t := new(DotsType)
t.pos = p.pos()
p.want(_DotDotDot)
t.Elem = p.typeOrNil()
if t.Elem == nil {
t.Elem = p.badExpr()
p.syntaxError("final argument in variadic function missing type")
f.Type = p.typeOrNil()
if f.Name != nil || f.Type != nil {
return f
}
return t
p.syntaxError("expecting )")
p.advance(_Comma, _Rparen)
return nil
}
// Parameters = "(" [ ParameterList [ "," ] ] ")" .
// ParameterList = ParameterDecl { "," ParameterDecl } .
func (p *parser) paramList() (list []*Field) {
// "(" or "[" has already been consumed.
// If name != nil, it is the first name after "(" or "[".
func (p *parser) paramList(name *Name, close token) (list []*Field) {
if trace {
defer p.trace("paramList")()
}
pos := p.pos()
var named int // number of parameters that have an explicit name and type
p.list(_Lparen, _Comma, _Rparen, func() bool {
if par := p.paramDeclOrNil(); par != nil {
var named int // number of parameters that have an explicit name and type/bound
p.list(_Comma, close, func() bool {
par := p.paramDeclOrNil(name)
name = nil // 1st name was consumed if present
if par != nil {
if debug && par.Name == nil && par.Type == nil {
panic("parameter without name or type")
}
@ -1589,30 +1808,30 @@ func (p *parser) paramList() (list []*Field) {
}
}
} else if named != len(list) {
// some named => all must be named
ok := true
// some named => all must have names and types
var pos Pos // error position (or unknown)
var typ Expr
for i := len(list) - 1; i >= 0; i-- {
if par := list[i]; par.Type != nil {
typ = par.Type
if par.Name == nil {
ok = false
pos = typ.Pos()
n := p.newName("_")
n.pos = typ.Pos() // correct position
n.pos = pos // correct position
par.Name = n
}
} else if typ != nil {
par.Type = typ
} else {
// par.Type == nil && typ == nil => we only have a par.Name
ok = false
pos = par.Name.Pos()
t := p.badExpr()
t.pos = par.Name.Pos() // correct position
t.pos = pos // correct position
par.Type = t
}
}
if !ok {
p.syntaxErrorAt(pos, "mixed named and unnamed function parameters")
if pos.IsKnown() {
p.syntaxErrorAt(pos, "mixed named and unnamed parameters")
}
}
@ -2209,15 +2428,21 @@ func (p *parser) stmtList() (l []Stmt) {
}
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
func (p *parser) argList() (list []Expr, hasDots bool) {
func (p *parser) argList(arg Expr, close token) (list []Expr, hasDots bool) {
if trace {
defer p.trace("argList")()
}
p.xnest++
p.list(_Lparen, _Comma, _Rparen, func() bool {
list = append(list, p.expr())
hasDots = p.got(_DotDotDot)
p.list(_Comma, close, func() bool {
if arg == nil {
arg = p.expr()
}
list = append(list, arg)
arg = nil
if close == _Rparen {
hasDots = p.got(_DotDotDot)
}
return hasDots
})
p.xnest--
@ -2275,18 +2500,32 @@ func (p *parser) qualifiedName(name *Name) Expr {
defer p.trace("qualifiedName")()
}
var x Expr
switch {
case name != nil:
// name is provided
x = name
case p.tok == _Name:
name = p.name()
x = p.name()
default:
name = p.newName("_")
x = p.newName("_")
p.syntaxError("expecting name")
p.advance(_Dot, _Semi, _Rbrace)
}
return p.dotname(name)
if p.tok == _Dot {
s := new(SelectorExpr)
s.pos = p.pos()
p.next()
s.X = x
s.Sel = p.name()
x = s
}
if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
x = p.typeInstance(x)
}
return x
}
// ExpressionList = Expression { "," Expression } .

View File

@ -16,6 +16,7 @@ type Mode uint
// Modes supported by the parser.
const (
CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
AllowGenerics
)
// Error describes a syntax error. Error implements the error interface.