diff options
| author | Robert Griesemer <gri@golang.org> | 2021-04-05 19:10:22 -0700 |
|---|---|---|
| committer | Robert Griesemer <gri@golang.org> | 2021-04-10 19:02:03 +0000 |
| commit | 4638545d85d7e10e49132ee94ff9a6778db1c893 (patch) | |
| tree | 2d62f3b4aa751124ca5c6fa2ed0a3516159d04a7 /src/cmd/compile/internal/syntax/parser.go | |
| parent | 1129a60f1c1e64147ca1133857c4571ce9b87a35 (diff) | |
| download | go-4638545d85d7e10e49132ee94ff9a6778db1c893.tar.xz | |
cmd/compile/internal/syntax: accept "~" and "|" interface elements
Type lists continue to be accepted as before.
While at it, print missing filenames in error tests
(which uses an ad-hoc position representation).
Change-Id: I933b3acbc9cf1985ad8f70f6b206e3a1dbd64d1e
Reviewed-on: https://go-review.googlesource.com/c/go/+/307371
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Diffstat (limited to 'src/cmd/compile/internal/syntax/parser.go')
| -rw-r--r-- | src/cmd/compile/internal/syntax/parser.go | 92 |
1 files changed, 78 insertions, 14 deletions
diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index c4ccbb82cb..026297432d 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -735,9 +735,9 @@ func (p *parser) binaryExpr(prec int) Expr { t := new(Operation) t.pos = p.pos() t.Op = p.op - t.X = x tprec := p.prec p.next() + t.X = x t.Y = p.binaryExpr(tprec) x = t } @@ -1381,7 +1381,9 @@ func (p *parser) structType() *StructType { return typ } -// InterfaceType = "interface" "{" { MethodSpec ";" } "}" . +// InterfaceType = "interface" "{" { ( MethodDecl | EmbeddedElem | TypeList ) ";" } "}" . +// TypeList = "type" Type { "," Type } . +// TODO(gri) remove TypeList syntax if we accept #45346 func (p *parser) interfaceType() *InterfaceType { if trace { defer p.trace("interfaceType")() @@ -1395,9 +1397,15 @@ func (p *parser) interfaceType() *InterfaceType { p.list(_Semi, _Rbrace, func() bool { switch p.tok { case _Name: - typ.MethodList = append(typ.MethodList, p.methodDecl()) + f := p.methodDecl() + if f.Name == nil && p.mode&AllowGenerics != 0 { + f = p.embeddedElem(f) + } + typ.MethodList = append(typ.MethodList, f) + return false case _Lparen: + // TODO(gri) Need to decide how to adjust this restriction. p.syntaxError("cannot parenthesize embedded type") f := new(Field) f.pos = p.pos() @@ -1405,10 +1413,17 @@ func (p *parser) interfaceType() *InterfaceType { f.Type = p.qualifiedName(nil) p.want(_Rparen) typ.MethodList = append(typ.MethodList, f) + return false + + case _Operator: + if p.op == Tilde && p.mode&AllowGenerics != 0 { + typ.MethodList = append(typ.MethodList, p.embeddedElem(nil)) + return false + } case _Type: + // TODO(gri) remove TypeList syntax if we accept #45346 if p.mode&AllowGenerics != 0 { - // TODO(gri) factor this better type_ := NewName(p.pos(), "type") // cannot have a method named "type" p.next() if p.tok != _Semi && p.tok != _Rbrace { @@ -1427,19 +1442,18 @@ func (p *parser) interfaceType() *InterfaceType { } else { p.syntaxError("expecting type") } - break + return false } - 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) - } + if p.mode&AllowGenerics != 0 { + p.syntaxError("expecting method, type list, or embedded element") + p.advance(_Semi, _Rbrace, _Type) // TODO(gri) remove _Type if we don't accept it anymore + return false } + + p.syntaxError("expecting method or interface name") + p.advance(_Semi, _Rbrace) return false }) @@ -1732,6 +1746,56 @@ func (p *parser) methodDecl() *Field { return f } +// EmbeddedElem = MethodSpec | EmbeddedTerm { "|" EmbeddedTerm } . +func (p *parser) embeddedElem(f *Field) *Field { + if trace { + defer p.trace("embeddedElem")() + } + + if f == nil { + f = new(Field) + f.pos = p.pos() + f.Type = p.embeddedTerm() + } + + for p.tok == _Operator && p.op == Or { + t := new(Operation) + t.pos = p.pos() + t.Op = Or + p.next() + t.X = f.Type + t.Y = p.embeddedTerm() + f.Type = t + } + + return f +} + +// EmbeddedTerm = [ "~" ] Type . +func (p *parser) embeddedTerm() Expr { + if trace { + defer p.trace("embeddedTerm")() + } + + if p.tok == _Operator && p.op == Tilde { + t := new(Operation) + t.pos = p.pos() + t.Op = Tilde + p.next() + t.X = p.type_() + return t + } + + t := p.typeOrNil() + if t == nil { + t = p.badExpr() + p.syntaxError("expecting ~ term or type") + p.advance(_Operator, _Semi, _Rparen, _Rbrack, _Rbrace) + } + + return t +} + // ParameterDecl = [ IdentifierList ] [ "..." ] Type . func (p *parser) paramDeclOrNil(name *Name) *Field { if trace { |
