mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00: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:
parent
617b633917
commit
b627988b0c
2 changed files with 447 additions and 207 deletions
|
|
@ -459,20 +459,21 @@ func isEmptyFuncDecl(dcl Decl) bool {
|
||||||
// Declarations
|
// Declarations
|
||||||
|
|
||||||
// list parses a possibly empty, sep-separated list, optionally
|
// list parses a possibly empty, sep-separated list, optionally
|
||||||
// followed by sep and enclosed by ( and ) or { and }. open is
|
// followed sep, and closed by close. sep must be one of _Comma
|
||||||
// one of _Lparen, or _Lbrace, sep is one of _Comma or _Semi,
|
// or _Semi, and close must be one of _Rparen, _Rbrace, or _Rbrack.
|
||||||
// and close is expected to be the (closing) opposite of open.
|
|
||||||
// For each list element, f is called. After f returns true, no
|
// For each list element, f is called. After f returns true, no
|
||||||
// more list elements are accepted. list returns the position
|
// more list elements are accepted. list returns the position
|
||||||
// of the closing token.
|
// of the closing token.
|
||||||
//
|
//
|
||||||
// list = "(" { f sep } ")" |
|
// list = { f sep } ")" |
|
||||||
// "{" { f sep } "}" . // sep is optional before ")" or "}"
|
// { f sep } "}" . // "," or ";" is optional before ")", "}" or "]"
|
||||||
//
|
//
|
||||||
func (p *parser) list(open, sep, close token, f func() bool) Pos {
|
func (p *parser) list(sep, close token, f func() bool) Pos {
|
||||||
p.want(open)
|
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 {
|
for p.tok != _EOF && p.tok != close && !done {
|
||||||
done = f()
|
done = f()
|
||||||
// sep is optional before close
|
// sep is optional before close
|
||||||
|
|
@ -496,7 +497,8 @@ func (p *parser) appendGroup(list []Decl, f func(*Group) Decl) []Decl {
|
||||||
if p.tok == _Lparen {
|
if p.tok == _Lparen {
|
||||||
g := new(Group)
|
g := new(Group)
|
||||||
p.clearPragma()
|
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))
|
list = append(list, f(g))
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
@ -566,7 +568,7 @@ func (p *parser) constDecl(group *Group) Decl {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// TypeSpec = identifier [ "=" ] Type .
|
// TypeSpec = identifier [ TypeParams ] [ "=" ] Type .
|
||||||
func (p *parser) typeDecl(group *Group) Decl {
|
func (p *parser) typeDecl(group *Group) Decl {
|
||||||
if trace {
|
if trace {
|
||||||
defer p.trace("typeDecl")()
|
defer p.trace("typeDecl")()
|
||||||
|
|
@ -578,8 +580,42 @@ func (p *parser) typeDecl(group *Group) Decl {
|
||||||
d.Pragma = p.takePragma()
|
d.Pragma = p.takePragma()
|
||||||
|
|
||||||
d.Name = p.name()
|
d.Name = p.name()
|
||||||
|
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.Alias = p.gotAssign()
|
||||||
d.Type = p.typeOrNil()
|
d.Type = p.typeOrNil()
|
||||||
|
}
|
||||||
|
|
||||||
if d.Type == nil {
|
if d.Type == nil {
|
||||||
d.Type = p.badExpr()
|
d.Type = p.badExpr()
|
||||||
p.syntaxError("in type declaration")
|
p.syntaxError("in type declaration")
|
||||||
|
|
@ -613,7 +649,7 @@ func (p *parser) varDecl(group *Group) Decl {
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
// FunctionDecl = "func" FunctionName ( Function | Signature ) .
|
// FunctionDecl = "func" FunctionName [ TypeParams ] ( Function | Signature ) .
|
||||||
// FunctionName = identifier .
|
// FunctionName = identifier .
|
||||||
// Function = Signature FunctionBody .
|
// Function = Signature FunctionBody .
|
||||||
// MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
|
// MethodDecl = "func" Receiver MethodName ( Function | Signature ) .
|
||||||
|
|
@ -627,8 +663,8 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
|
||||||
f.pos = p.pos()
|
f.pos = p.pos()
|
||||||
f.Pragma = p.takePragma()
|
f.Pragma = p.takePragma()
|
||||||
|
|
||||||
if p.tok == _Lparen {
|
if p.got(_Lparen) {
|
||||||
rcvr := p.paramList()
|
rcvr := p.paramList(nil, _Rparen)
|
||||||
switch len(rcvr) {
|
switch len(rcvr) {
|
||||||
case 0:
|
case 0:
|
||||||
p.error("method has no receiver")
|
p.error("method has no receiver")
|
||||||
|
|
@ -647,6 +683,14 @@ func (p *parser) funcDeclOrNil() *FuncDecl {
|
||||||
}
|
}
|
||||||
|
|
||||||
f.Name = p.name()
|
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()
|
f.Type = p.funcType()
|
||||||
if p.tok == _Lbrace {
|
if p.tok == _Lbrace {
|
||||||
f.Body = p.funcBody()
|
f.Body = p.funcBody()
|
||||||
|
|
@ -850,13 +894,7 @@ func (p *parser) operand(keep_parens bool) Expr {
|
||||||
// Optimization: Record presence of ()'s only where needed
|
// Optimization: Record presence of ()'s only where needed
|
||||||
// for error reporting. Don't bother in other cases; it is
|
// for error reporting. Don't bother in other cases; it is
|
||||||
// just a waste of memory and time.
|
// 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
|
// Parentheses are not permitted around T in a composite
|
||||||
// literal T{}. If the next token is a {, assume x is a
|
// literal T{}. If the next token is a {, assume x is a
|
||||||
// composite literal type T (it may not be, { could be
|
// composite literal type T (it may not be, { could be
|
||||||
|
|
@ -879,19 +917,19 @@ func (p *parser) operand(keep_parens bool) Expr {
|
||||||
case _Func:
|
case _Func:
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
p.next()
|
p.next()
|
||||||
t := p.funcType()
|
ftyp := p.funcType()
|
||||||
if p.tok == _Lbrace {
|
if p.tok == _Lbrace {
|
||||||
p.xnest++
|
p.xnest++
|
||||||
|
|
||||||
f := new(FuncLit)
|
f := new(FuncLit)
|
||||||
f.pos = pos
|
f.pos = pos
|
||||||
f.Type = t
|
f.Type = ftyp
|
||||||
f.Body = p.funcBody()
|
f.Body = p.funcBody()
|
||||||
|
|
||||||
p.xnest--
|
p.xnest--
|
||||||
return f
|
return f
|
||||||
}
|
}
|
||||||
return t
|
return ftyp
|
||||||
|
|
||||||
case _Lbrack, _Chan, _Map, _Struct, _Interface:
|
case _Lbrack, _Chan, _Map, _Struct, _Interface:
|
||||||
return p.type_() // othertype
|
return p.type_() // othertype
|
||||||
|
|
@ -971,6 +1009,14 @@ loop:
|
||||||
|
|
||||||
case _Lbrack:
|
case _Lbrack:
|
||||||
p.next()
|
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++
|
p.xnest++
|
||||||
|
|
||||||
var i Expr
|
var i Expr
|
||||||
|
|
@ -986,6 +1032,20 @@ loop:
|
||||||
p.xnest--
|
p.xnest--
|
||||||
break
|
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:...
|
// x[i:...
|
||||||
|
|
@ -1022,8 +1082,9 @@ loop:
|
||||||
case _Lparen:
|
case _Lparen:
|
||||||
t := new(CallExpr)
|
t := new(CallExpr)
|
||||||
t.pos = pos
|
t.pos = pos
|
||||||
|
p.next()
|
||||||
t.Fun = x
|
t.Fun = x
|
||||||
t.ArgList, t.HasDots = p.argList()
|
t.ArgList, t.HasDots = p.argList(nil, _Rparen)
|
||||||
x = t
|
x = t
|
||||||
|
|
||||||
case _Lbrace:
|
case _Lbrace:
|
||||||
|
|
@ -1032,10 +1093,20 @@ loop:
|
||||||
t := unparen(x)
|
t := unparen(x)
|
||||||
// determine if '{' belongs to a composite literal or a block statement
|
// determine if '{' belongs to a composite literal or a block statement
|
||||||
complit_ok := false
|
complit_ok := false
|
||||||
switch t.(type) {
|
switch t := t.(type) {
|
||||||
case *Name, *SelectorExpr:
|
case *Name, *SelectorExpr:
|
||||||
if p.xnest >= 0 {
|
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
|
complit_ok = true
|
||||||
}
|
}
|
||||||
case *ArrayType, *SliceType, *StructType, *MapType:
|
case *ArrayType, *SliceType, *StructType, *MapType:
|
||||||
|
|
@ -1085,7 +1156,8 @@ func (p *parser) complitexpr() *CompositeLit {
|
||||||
x.pos = p.pos()
|
x.pos = p.pos()
|
||||||
|
|
||||||
p.xnest++
|
p.xnest++
|
||||||
x.Rbrace = p.list(_Lbrace, _Comma, _Rbrace, func() bool {
|
p.want(_Lbrace)
|
||||||
|
x.Rbrace = p.list(_Comma, _Rbrace, func() bool {
|
||||||
// value
|
// value
|
||||||
e := p.bare_complitexpr()
|
e := p.bare_complitexpr()
|
||||||
if p.tok == _Colon {
|
if p.tok == _Colon {
|
||||||
|
|
@ -1170,26 +1242,10 @@ func (p *parser) typeOrNil() Expr {
|
||||||
// '[' oexpr ']' ntype
|
// '[' oexpr ']' ntype
|
||||||
// '[' _DotDotDot ']' ntype
|
// '[' _DotDotDot ']' ntype
|
||||||
p.next()
|
p.next()
|
||||||
p.xnest++
|
|
||||||
if p.got(_Rbrack) {
|
if p.got(_Rbrack) {
|
||||||
// []T
|
return p.sliceType(pos)
|
||||||
p.xnest--
|
|
||||||
t := new(SliceType)
|
|
||||||
t.pos = pos
|
|
||||||
t.Elem = p.type_()
|
|
||||||
return t
|
|
||||||
}
|
}
|
||||||
|
return p.arrayType(pos, nil)
|
||||||
// [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
|
|
||||||
|
|
||||||
case _Chan:
|
case _Chan:
|
||||||
// _Chan non_recvchantype
|
// _Chan non_recvchantype
|
||||||
|
|
@ -1221,7 +1277,7 @@ func (p *parser) typeOrNil() Expr {
|
||||||
return p.interfaceType()
|
return p.interfaceType()
|
||||||
|
|
||||||
case _Name:
|
case _Name:
|
||||||
return p.dotname(p.name())
|
return p.qualifiedName(nil)
|
||||||
|
|
||||||
case _Lparen:
|
case _Lparen:
|
||||||
p.next()
|
p.next()
|
||||||
|
|
@ -1233,6 +1289,27 @@ func (p *parser) typeOrNil() Expr {
|
||||||
return nil
|
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 {
|
func (p *parser) funcType() *FuncType {
|
||||||
if trace {
|
if trace {
|
||||||
defer p.trace("funcType")()
|
defer p.trace("funcType")()
|
||||||
|
|
@ -1240,12 +1317,41 @@ func (p *parser) funcType() *FuncType {
|
||||||
|
|
||||||
typ := new(FuncType)
|
typ := new(FuncType)
|
||||||
typ.pos = p.pos()
|
typ.pos = p.pos()
|
||||||
typ.ParamList = p.paramList()
|
p.want(_Lparen)
|
||||||
|
typ.ParamList = p.paramList(nil, _Rparen)
|
||||||
typ.ResultList = p.funcResult()
|
typ.ResultList = p.funcResult()
|
||||||
|
|
||||||
return typ
|
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 {
|
func (p *parser) chanElem() Expr {
|
||||||
if trace {
|
if trace {
|
||||||
defer p.trace("chanElem")()
|
defer p.trace("chanElem")()
|
||||||
|
|
@ -1261,22 +1367,6 @@ func (p *parser) chanElem() Expr {
|
||||||
return typ
|
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 ";" } "}" .
|
// StructType = "struct" "{" { FieldDecl ";" } "}" .
|
||||||
func (p *parser) structType() *StructType {
|
func (p *parser) structType() *StructType {
|
||||||
if trace {
|
if trace {
|
||||||
|
|
@ -1287,7 +1377,8 @@ func (p *parser) structType() *StructType {
|
||||||
typ.pos = p.pos()
|
typ.pos = p.pos()
|
||||||
|
|
||||||
p.want(_Struct)
|
p.want(_Struct)
|
||||||
p.list(_Lbrace, _Semi, _Rbrace, func() bool {
|
p.want(_Lbrace)
|
||||||
|
p.list(_Semi, _Rbrace, func() bool {
|
||||||
p.fieldDecl(typ)
|
p.fieldDecl(typ)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
@ -1305,9 +1396,56 @@ func (p *parser) interfaceType() *InterfaceType {
|
||||||
typ.pos = p.pos()
|
typ.pos = p.pos()
|
||||||
|
|
||||||
p.want(_Interface)
|
p.want(_Interface)
|
||||||
p.list(_Lbrace, _Semi, _Rbrace, func() bool {
|
p.want(_Lbrace)
|
||||||
if m := p.methodDecl(); m != nil {
|
p.list(_Semi, _Rbrace, func() bool {
|
||||||
typ.MethodList = append(typ.MethodList, m)
|
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
|
return false
|
||||||
})
|
})
|
||||||
|
|
@ -1321,8 +1459,8 @@ func (p *parser) funcResult() []*Field {
|
||||||
defer p.trace("funcResult")()
|
defer p.trace("funcResult")()
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.tok == _Lparen {
|
if p.got(_Lparen) {
|
||||||
return p.paramList()
|
return p.paramList(nil, _Rparen)
|
||||||
}
|
}
|
||||||
|
|
||||||
pos := p.pos()
|
pos := p.pos()
|
||||||
|
|
@ -1368,59 +1506,71 @@ func (p *parser) fieldDecl(styp *StructType) {
|
||||||
case _Name:
|
case _Name:
|
||||||
name := p.name()
|
name := p.name()
|
||||||
if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
|
if p.tok == _Dot || p.tok == _Literal || p.tok == _Semi || p.tok == _Rbrace {
|
||||||
// embed oliteral
|
// embedded type
|
||||||
typ := p.qualifiedName(name)
|
typ := p.qualifiedName(name)
|
||||||
tag := p.oliteral()
|
tag := p.oliteral()
|
||||||
p.addField(styp, pos, nil, typ, tag)
|
p.addField(styp, pos, nil, typ, tag)
|
||||||
return
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
// new_name_list ntype oliteral
|
// name1, name2, ... Type [ tag ]
|
||||||
names := p.nameList(name)
|
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()
|
tag := p.oliteral()
|
||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
p.addField(styp, name.Pos(), name, typ, tag)
|
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:
|
case _Star:
|
||||||
p.next()
|
p.next()
|
||||||
if p.got(_Lparen) {
|
var typ Expr
|
||||||
// '*' '(' embed ')' oliteral
|
if p.tok == _Lparen {
|
||||||
typ := newIndirect(pos, p.qualifiedName(nil))
|
// *(T)
|
||||||
p.want(_Rparen)
|
|
||||||
tag := p.oliteral()
|
|
||||||
p.addField(styp, pos, nil, typ, tag)
|
|
||||||
p.syntaxError("cannot parenthesize embedded type")
|
p.syntaxError("cannot parenthesize embedded type")
|
||||||
|
p.next()
|
||||||
|
typ = p.qualifiedName(nil)
|
||||||
|
p.got(_Rparen) // no need to complain if missing
|
||||||
} else {
|
} else {
|
||||||
// '*' embed oliteral
|
// *T
|
||||||
typ := newIndirect(pos, p.qualifiedName(nil))
|
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()
|
tag := p.oliteral()
|
||||||
p.addField(styp, pos, nil, typ, tag)
|
p.addField(styp, pos, nil, typ, tag)
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p.syntaxError("expecting field name or embedded type")
|
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 {
|
func (p *parser) oliteral() *BasicLit {
|
||||||
if p.tok == _Literal {
|
if p.tok == _Literal {
|
||||||
b := new(BasicLit)
|
b := new(BasicLit)
|
||||||
|
|
@ -1449,11 +1632,14 @@ func (p *parser) methodDecl() *Field {
|
||||||
defer p.trace("methodDecl")()
|
defer p.trace("methodDecl")()
|
||||||
}
|
}
|
||||||
|
|
||||||
switch p.tok {
|
f := new(Field)
|
||||||
case _Name:
|
f.pos = p.pos()
|
||||||
name := p.name()
|
name := p.name()
|
||||||
|
|
||||||
// accept potential name list but complain
|
// 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
|
hasNameList := false
|
||||||
for p.got(_Comma) {
|
for p.got(_Comma) {
|
||||||
p.name()
|
p.name()
|
||||||
|
|
@ -1464,36 +1650,75 @@ func (p *parser) methodDecl() *Field {
|
||||||
// already progressed, no need to advance
|
// already progressed, no need to advance
|
||||||
}
|
}
|
||||||
|
|
||||||
f := new(Field)
|
switch p.tok {
|
||||||
f.pos = name.Pos()
|
case _Lparen:
|
||||||
if p.tok != _Lparen {
|
// method
|
||||||
// packname
|
|
||||||
f.Type = p.qualifiedName(name)
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
|
|
||||||
f.Name = name
|
f.Name = name
|
||||||
f.Type = p.funcType()
|
f.Type = p.funcType()
|
||||||
return f
|
|
||||||
|
|
||||||
case _Lparen:
|
case _Lbrack:
|
||||||
p.syntaxError("cannot parenthesize embedded type")
|
if p.mode&AllowGenerics != 0 {
|
||||||
f := new(Field)
|
// Careful dance: We don't know if we have a generic method m[T C](x T)
|
||||||
f.pos = p.pos()
|
// or an embedded instantiated type T[P1, P2] (we accept generic methods
|
||||||
|
// for generality and robustness of parsing).
|
||||||
|
pos := p.pos()
|
||||||
p.next()
|
p.next()
|
||||||
f.Type = p.qualifiedName(nil)
|
|
||||||
p.want(_Rparen)
|
// empty type parameter or argument lists are not permitted
|
||||||
return f
|
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:
|
default:
|
||||||
p.syntaxError("expecting method or interface name")
|
// embedded type
|
||||||
p.advance(_Semi, _Rbrace)
|
f.Type = p.qualifiedName(name)
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return f
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
|
// ParameterDecl = [ IdentifierList ] [ "..." ] Type .
|
||||||
func (p *parser) paramDeclOrNil() *Field {
|
func (p *parser) paramDeclOrNil(name *Name) *Field {
|
||||||
if trace {
|
if trace {
|
||||||
defer p.trace("paramDecl")()
|
defer p.trace("paramDecl")()
|
||||||
}
|
}
|
||||||
|
|
@ -1501,73 +1726,67 @@ func (p *parser) paramDeclOrNil() *Field {
|
||||||
f := new(Field)
|
f := new(Field)
|
||||||
f.pos = p.pos()
|
f.pos = p.pos()
|
||||||
|
|
||||||
switch p.tok {
|
if p.tok == _Name || name != nil {
|
||||||
case _Name:
|
if name == nil {
|
||||||
f.Name = p.name()
|
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen:
|
if p.mode&AllowGenerics != 0 && p.tok == _Lbrack {
|
||||||
// name_or_type
|
f.Type = p.arrayOrTArgs()
|
||||||
f.Type = p.type_()
|
if typ, ok := f.Type.(*CallExpr); ok {
|
||||||
|
typ.Fun = name
|
||||||
case _DotDotDot:
|
} else {
|
||||||
// dotdotdot
|
f.Name = name
|
||||||
f.Type = p.dotsType()
|
|
||||||
|
|
||||||
default:
|
|
||||||
p.syntaxError("expecting )")
|
|
||||||
p.advance(_Comma, _Rparen)
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return f
|
return f
|
||||||
}
|
|
||||||
|
|
||||||
// ...Type
|
|
||||||
func (p *parser) dotsType() *DotsType {
|
|
||||||
if trace {
|
|
||||||
defer p.trace("dotsType")()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if p.tok == _Dot {
|
||||||
|
// name_or_type
|
||||||
|
f.Type = p.qualifiedName(name)
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
f.Name = name
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.tok == _DotDotDot {
|
||||||
t := new(DotsType)
|
t := new(DotsType)
|
||||||
t.pos = p.pos()
|
t.pos = p.pos()
|
||||||
|
p.next()
|
||||||
p.want(_DotDotDot)
|
|
||||||
t.Elem = p.typeOrNil()
|
t.Elem = p.typeOrNil()
|
||||||
if t.Elem == nil {
|
if t.Elem == nil {
|
||||||
t.Elem = p.badExpr()
|
t.Elem = p.badExpr()
|
||||||
p.syntaxError("final argument in variadic function missing type")
|
p.syntaxError("final argument in variadic function missing type")
|
||||||
}
|
}
|
||||||
|
f.Type = t
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
return t
|
f.Type = p.typeOrNil()
|
||||||
|
if f.Name != nil || f.Type != nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
|
||||||
|
p.syntaxError("expecting )")
|
||||||
|
p.advance(_Comma, _Rparen)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
// Parameters = "(" [ ParameterList [ "," ] ] ")" .
|
||||||
// ParameterList = ParameterDecl { "," ParameterDecl } .
|
// 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 {
|
if trace {
|
||||||
defer p.trace("paramList")()
|
defer p.trace("paramList")()
|
||||||
}
|
}
|
||||||
|
|
||||||
pos := p.pos()
|
var named int // number of parameters that have an explicit name and type/bound
|
||||||
|
p.list(_Comma, close, func() bool {
|
||||||
var named int // number of parameters that have an explicit name and type
|
par := p.paramDeclOrNil(name)
|
||||||
p.list(_Lparen, _Comma, _Rparen, func() bool {
|
name = nil // 1st name was consumed if present
|
||||||
if par := p.paramDeclOrNil(); par != nil {
|
if par != nil {
|
||||||
if debug && par.Name == nil && par.Type == nil {
|
if debug && par.Name == nil && par.Type == nil {
|
||||||
panic("parameter without name or type")
|
panic("parameter without name or type")
|
||||||
}
|
}
|
||||||
|
|
@ -1589,30 +1808,30 @@ func (p *parser) paramList() (list []*Field) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if named != len(list) {
|
} else if named != len(list) {
|
||||||
// some named => all must be named
|
// some named => all must have names and types
|
||||||
ok := true
|
var pos Pos // error position (or unknown)
|
||||||
var typ Expr
|
var typ Expr
|
||||||
for i := len(list) - 1; i >= 0; i-- {
|
for i := len(list) - 1; i >= 0; i-- {
|
||||||
if par := list[i]; par.Type != nil {
|
if par := list[i]; par.Type != nil {
|
||||||
typ = par.Type
|
typ = par.Type
|
||||||
if par.Name == nil {
|
if par.Name == nil {
|
||||||
ok = false
|
pos = typ.Pos()
|
||||||
n := p.newName("_")
|
n := p.newName("_")
|
||||||
n.pos = typ.Pos() // correct position
|
n.pos = pos // correct position
|
||||||
par.Name = n
|
par.Name = n
|
||||||
}
|
}
|
||||||
} else if typ != nil {
|
} else if typ != nil {
|
||||||
par.Type = typ
|
par.Type = typ
|
||||||
} else {
|
} else {
|
||||||
// par.Type == nil && typ == nil => we only have a par.Name
|
// par.Type == nil && typ == nil => we only have a par.Name
|
||||||
ok = false
|
pos = par.Name.Pos()
|
||||||
t := p.badExpr()
|
t := p.badExpr()
|
||||||
t.pos = par.Name.Pos() // correct position
|
t.pos = pos // correct position
|
||||||
par.Type = t
|
par.Type = t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !ok {
|
if pos.IsKnown() {
|
||||||
p.syntaxErrorAt(pos, "mixed named and unnamed function parameters")
|
p.syntaxErrorAt(pos, "mixed named and unnamed parameters")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2209,15 +2428,21 @@ func (p *parser) stmtList() (l []Stmt) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Arguments = "(" [ ( ExpressionList | Type [ "," ExpressionList ] ) [ "..." ] [ "," ] ] ")" .
|
// 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 {
|
if trace {
|
||||||
defer p.trace("argList")()
|
defer p.trace("argList")()
|
||||||
}
|
}
|
||||||
|
|
||||||
p.xnest++
|
p.xnest++
|
||||||
p.list(_Lparen, _Comma, _Rparen, func() bool {
|
p.list(_Comma, close, func() bool {
|
||||||
list = append(list, p.expr())
|
if arg == nil {
|
||||||
|
arg = p.expr()
|
||||||
|
}
|
||||||
|
list = append(list, arg)
|
||||||
|
arg = nil
|
||||||
|
if close == _Rparen {
|
||||||
hasDots = p.got(_DotDotDot)
|
hasDots = p.got(_DotDotDot)
|
||||||
|
}
|
||||||
return hasDots
|
return hasDots
|
||||||
})
|
})
|
||||||
p.xnest--
|
p.xnest--
|
||||||
|
|
@ -2275,18 +2500,32 @@ func (p *parser) qualifiedName(name *Name) Expr {
|
||||||
defer p.trace("qualifiedName")()
|
defer p.trace("qualifiedName")()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var x Expr
|
||||||
switch {
|
switch {
|
||||||
case name != nil:
|
case name != nil:
|
||||||
// name is provided
|
x = name
|
||||||
case p.tok == _Name:
|
case p.tok == _Name:
|
||||||
name = p.name()
|
x = p.name()
|
||||||
default:
|
default:
|
||||||
name = p.newName("_")
|
x = p.newName("_")
|
||||||
p.syntaxError("expecting name")
|
p.syntaxError("expecting name")
|
||||||
p.advance(_Dot, _Semi, _Rbrace)
|
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 } .
|
// ExpressionList = Expression { "," Expression } .
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ type Mode uint
|
||||||
// Modes supported by the parser.
|
// Modes supported by the parser.
|
||||||
const (
|
const (
|
||||||
CheckBranches Mode = 1 << iota // check correct use of labels, break, continue, and goto statements
|
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.
|
// Error describes a syntax error. Error implements the error interface.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue