aboutsummaryrefslogtreecommitdiff
path: root/src/go/parser/parser.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/go/parser/parser.go')
-rw-r--r--src/go/parser/parser.go115
1 files changed, 101 insertions, 14 deletions
diff --git a/src/go/parser/parser.go b/src/go/parser/parser.go
index f10c8650af..bdc2ad308c 100644
--- a/src/go/parser/parser.go
+++ b/src/go/parser/parser.go
@@ -77,7 +77,7 @@ func (p *parser) init(fset *token.FileSet, filename string, src []byte, mode Mod
}
func (p *parser) parseTypeParams() bool {
- return typeparams.Enabled && p.mode&typeparams.DisallowParsing == 0
+ return p.mode&typeparams.DisallowParsing == 0
}
// ----------------------------------------------------------------------------
@@ -600,7 +600,7 @@ func (p *parser) parseArrayFieldOrTypeInstance(x *ast.Ident) (*ast.Ident, ast.Ex
}
// x[P], x[P1, P2], ...
- return nil, &ast.IndexExpr{X: x, Lbrack: lbrack, Index: typeparams.PackExpr(args), Rbrack: rbrack}
+ return nil, typeparams.PackIndexExpr(x, lbrack, args, rbrack)
}
func (p *parser) parseFieldDecl() *ast.Field {
@@ -980,6 +980,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
list := []ast.Expr{x}
if p.atComma("type argument list", token.RBRACK) {
p.exprLev++
+ p.next()
for p.tok != token.RBRACK && p.tok != token.EOF {
list = append(list, p.parseType())
if !p.atComma("type argument list", token.RBRACK) {
@@ -990,7 +991,7 @@ func (p *parser) parseMethodSpec() *ast.Field {
p.exprLev--
}
rbrack := p.expectClosing(token.RBRACK, "type argument list")
- typ = &ast.IndexExpr{X: ident, Lbrack: lbrack, Index: typeparams.PackExpr(list), Rbrack: rbrack}
+ typ = typeparams.PackIndexExpr(ident, lbrack, list, rbrack)
}
case p.tok == token.LPAREN:
// ordinary method
@@ -1011,11 +1012,56 @@ func (p *parser) parseMethodSpec() *ast.Field {
typ = p.parseTypeInstance(typ)
}
}
- p.expectSemi() // call before accessing p.linecomment
- spec := &ast.Field{Doc: doc, Names: idents, Type: typ, Comment: p.lineComment}
+ // Comment is added at the callsite: the field below may joined with
+ // additional type specs using '|'.
+ // TODO(rfindley) this should be refactored.
+ // TODO(rfindley) add more tests for comment handling.
+ return &ast.Field{Doc: doc, Names: idents, Type: typ}
+}
- return spec
+func (p *parser) embeddedElem(f *ast.Field) *ast.Field {
+ if p.trace {
+ defer un(trace(p, "EmbeddedElem"))
+ }
+ if f == nil {
+ f = new(ast.Field)
+ f.Type = p.embeddedTerm()
+ }
+ for p.tok == token.OR {
+ t := new(ast.BinaryExpr)
+ t.OpPos = p.pos
+ t.Op = token.OR
+ p.next()
+ t.X = f.Type
+ t.Y = p.embeddedTerm()
+ f.Type = t
+ }
+ return f
+}
+
+func (p *parser) embeddedTerm() ast.Expr {
+ if p.trace {
+ defer un(trace(p, "EmbeddedTerm"))
+ }
+ if p.tok == token.TILDE {
+ t := new(ast.UnaryExpr)
+ t.OpPos = p.pos
+ t.Op = token.TILDE
+ p.next()
+ t.X = p.parseType()
+ return t
+ }
+
+ t := p.tryIdentOrType()
+ if t == nil {
+ pos := p.pos
+ p.errorExpected(pos, "~ term or type")
+ p.advance(exprEnd)
+ return &ast.BadExpr{From: pos, To: p.pos}
+ }
+
+ return t
}
func (p *parser) parseInterfaceType() *ast.InterfaceType {
@@ -1025,11 +1071,28 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
pos := p.expect(token.INTERFACE)
lbrace := p.expect(token.LBRACE)
+
var list []*ast.Field
- for p.tok == token.IDENT || p.parseTypeParams() && p.tok == token.TYPE {
- if p.tok == token.IDENT {
- list = append(list, p.parseMethodSpec())
- } else {
+
+parseElements:
+ for {
+ switch {
+ case p.tok == token.IDENT:
+ f := p.parseMethodSpec()
+ if f.Names == nil && p.parseTypeParams() {
+ f = p.embeddedElem(f)
+ }
+ p.expectSemi()
+ f.Comment = p.lineComment
+ list = append(list, f)
+ case p.tok == token.TILDE && p.parseTypeParams():
+ f := p.embeddedElem(nil)
+ p.expectSemi()
+ f.Comment = p.lineComment
+ list = append(list, f)
+ case p.tok == token.TYPE && p.parseTypeParams():
+ // TODO(rfindley): remove TypeList syntax and refactor the clauses above.
+
// all types in a type list share the same field name "type"
// (since type is a keyword, a Go program cannot have that field name)
name := []*ast.Ident{{NamePos: p.pos, Name: "type"}}
@@ -1039,8 +1102,22 @@ func (p *parser) parseInterfaceType() *ast.InterfaceType {
list = append(list, &ast.Field{Names: name, Type: typ})
}
p.expectSemi()
+ case p.parseTypeParams():
+ if t := p.tryIdentOrType(); t != nil {
+ f := new(ast.Field)
+ f.Type = t
+ f = p.embeddedElem(f)
+ p.expectSemi()
+ f.Comment = p.lineComment
+ list = append(list, f)
+ } else {
+ break parseElements
+ }
+ default:
+ break parseElements
}
}
+
// TODO(rfindley): the error produced here could be improved, since we could
// accept a identifier, 'type', or a '}' at this point.
rbrace := p.expect(token.RBRACE)
@@ -1101,7 +1178,6 @@ func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr {
}
opening := p.expect(token.LBRACK)
-
p.exprLev++
var list []ast.Expr
for p.tok != token.RBRACK && p.tok != token.EOF {
@@ -1115,7 +1191,17 @@ func (p *parser) parseTypeInstance(typ ast.Expr) ast.Expr {
closing := p.expectClosing(token.RBRACK, "type argument list")
- return &ast.IndexExpr{X: typ, Lbrack: opening, Index: typeparams.PackExpr(list), Rbrack: closing}
+ if len(list) == 0 {
+ p.errorExpected(closing, "type argument list")
+ return &ast.IndexExpr{
+ X: typ,
+ Lbrack: opening,
+ Index: &ast.BadExpr{From: opening + 1, To: closing},
+ Rbrack: closing,
+ }
+ }
+
+ return typeparams.PackIndexExpr(typ, opening, list, closing)
}
func (p *parser) tryIdentOrType() ast.Expr {
@@ -1378,7 +1464,7 @@ func (p *parser) parseIndexOrSliceOrInstance(x ast.Expr) ast.Expr {
}
// instance expression
- return &ast.IndexExpr{X: x, Lbrack: lbrack, Index: typeparams.PackExpr(args), Rbrack: rbrack}
+ return typeparams.PackIndexExpr(x, lbrack, args, rbrack)
}
func (p *parser) parseCallOrConversion(fun ast.Expr) *ast.CallExpr {
@@ -1480,6 +1566,7 @@ func (p *parser) checkExpr(x ast.Expr) ast.Expr {
panic("unreachable")
case *ast.SelectorExpr:
case *ast.IndexExpr:
+ case *ast.MultiIndexExpr:
case *ast.SliceExpr:
case *ast.TypeAssertExpr:
// If t.Type == nil we have a type assertion of the form
@@ -1569,7 +1656,7 @@ func (p *parser) parsePrimaryExpr() (x ast.Expr) {
return
}
// x is possibly a composite literal type
- case *ast.IndexExpr:
+ case *ast.IndexExpr, *ast.MultiIndexExpr:
if p.exprLev < 0 {
return
}