From 32db3f2756324616b7c856ac9501deccc2491239 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 15 Sep 2016 17:40:26 -0700 Subject: [PATCH] cmd/compile/internal/syntax: support for alias declarations Permits parsing of alias declarations with -newparser const/type/var/func T => p.T but the compiler will reject it with an error. For now this also accepts type T = p.T so we can experiment with a type-alias only scenario. - renamed _Arrow token to _Larrow (<-) - introduced _Rarrow token (=>) - introduced AliasDecl node - extended scanner to accept _Rarrow - extended parser and printer to handle alias declarations Change-Id: I0170d10a87df8255db9186d466b6fd405228c38e Reviewed-on: https://go-review.googlesource.com/29355 Run-TryBot: Robert Griesemer Reviewed-by: Matthew Dempsky TryBot-Result: Gobot Gobot --- src/cmd/compile/internal/gc/noder.go | 7 ++ src/cmd/compile/internal/syntax/nodes.go | 32 ++++++ src/cmd/compile/internal/syntax/parser.go | 100 ++++++++++++------ src/cmd/compile/internal/syntax/printer.go | 20 +++- src/cmd/compile/internal/syntax/scanner.go | 9 +- .../compile/internal/syntax/scanner_test.go | 3 +- src/cmd/compile/internal/syntax/tokens.go | 12 ++- 7 files changed, 144 insertions(+), 39 deletions(-) diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go index 13429ba816..4d97b48bce 100644 --- a/src/cmd/compile/internal/gc/noder.go +++ b/src/cmd/compile/internal/gc/noder.go @@ -60,6 +60,9 @@ func (p *noder) decls(decls []syntax.Decl) (l []*Node) { case *syntax.ImportDecl: p.importDecl(decl) + case *syntax.AliasDecl: + yyerror("alias declarations not yet implemented") + case *syntax.VarDecl: l = append(l, p.varDecl(decl)...) @@ -87,6 +90,10 @@ func (p *noder) decls(decls []syntax.Decl) (l []*Node) { lastConstGroup = decl.Group case *syntax.TypeDecl: + if decl.Alias { + yyerror("alias declarations not yet implemented") + break + } l = append(l, p.typeDecl(decl)) case *syntax.FuncDecl: diff --git a/src/cmd/compile/internal/syntax/nodes.go b/src/cmd/compile/internal/syntax/nodes.go index 280a2e8f69..9555a4b9a8 100644 --- a/src/cmd/compile/internal/syntax/nodes.go +++ b/src/cmd/compile/internal/syntax/nodes.go @@ -25,14 +25,21 @@ func (n *node) Line() uint32 { return n.line } +// TODO(gri) clean up init/initFrom once we have a good file pos story func (n *node) init(p *parser) { n.pos = uint32(p.pos) n.line = uint32(p.line) } +func (n *node) initFrom(a *node) { + n.pos = a.pos + n.line = a.line +} + // ---------------------------------------------------------------------------- // Files +// package PkgName; DeclList[0], DeclList[1], ... type File struct { PkgName *Name DeclList []Decl @@ -49,6 +56,8 @@ type ( aDecl() } + // Path + // LocalPkgName Path ImportDecl struct { LocalPkgName *Name // including "."; nil means no rename present Path *BasicLit @@ -56,6 +65,18 @@ type ( decl } + // Name => Orig + AliasDecl struct { + Tok token // Const, Type, Var, or Func + Name *Name + Orig Expr + Group *Group // nil means not part of a group + decl + } + + // NameList + // NameList = Values + // NameList Type = Values ConstDecl struct { NameList []*Name Type Expr // nil means no type @@ -64,13 +85,18 @@ type ( decl } + // Name Type TypeDecl struct { Name *Name Type Expr + Alias bool Group *Group // nil means not part of a group decl } + // NameList Type + // NameList Type = Values + // NameList = Values VarDecl struct { NameList []*Name Type Expr // nil means no type @@ -79,6 +105,10 @@ type ( decl } + // func Name Type { Body } + // func Name Type + // func Receiver Name Type { Body } + // func Receiver Name Type FuncDecl struct { Attr map[string]bool // go:attr map Recv *Field // nil means regular function @@ -418,6 +448,8 @@ func (simpleStmt) aSimpleStmt() {} // ---------------------------------------------------------------------------- // Comments +// TODO(gri) Consider renaming to CommentPos, CommentPlacement, etc. +// Kind = Above doesn't make much sense. type CommentKind uint const ( diff --git a/src/cmd/compile/internal/syntax/parser.go b/src/cmd/compile/internal/syntax/parser.go index 369f3ffccd..6cf899dd91 100644 --- a/src/cmd/compile/internal/syntax/parser.go +++ b/src/cmd/compile/internal/syntax/parser.go @@ -315,16 +315,37 @@ func (p *parser) importDecl(group *Group) Decl { return d } -// ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] . +// AliasSpec = identifier "=>" [ PackageName "." ] identifier . +func (p *parser) aliasDecl(tok token, name *Name, group *Group) Decl { + // no tracing since this is already called from a const/type/var/funcDecl + + d := new(AliasDecl) + d.initFrom(&name.node) + + p.want(_Rarrow) + d.Tok = tok + d.Name = name + d.Orig = p.dotname(p.name()) + d.Group = group + + return d +} + +// ConstSpec = IdentifierList [ [ Type ] "=" ExpressionList ] | AliasSpec . func (p *parser) constDecl(group *Group) Decl { if trace { defer p.trace("constDecl")() } + name := p.name() + if p.tok == _Rarrow { + return p.aliasDecl(Const, name, group) + } + d := new(ConstDecl) - d.init(p) + d.initFrom(&name.node) - d.NameList = p.nameList(p.name()) + d.NameList = p.nameList(name) if p.tok != _EOF && p.tok != _Semi && p.tok != _Rparen { d.Type = p.tryType() if p.got(_Assign) { @@ -336,16 +357,24 @@ func (p *parser) constDecl(group *Group) Decl { return d } -// TypeSpec = identifier Type . +// TypeSpec = identifier Type | AliasSpec . func (p *parser) typeDecl(group *Group) Decl { if trace { defer p.trace("typeDecl")() } + name := p.name() + if p.tok == _Rarrow { + return p.aliasDecl(Type, name, group) + } + d := new(TypeDecl) - d.init(p) + d.initFrom(&name.node) - d.Name = p.name() + d.Name = name + // accept "type T = p.T" for now so we can experiment + // with a type-alias only approach as well + d.Alias = p.got(_Assign) d.Type = p.tryType() if d.Type == nil { p.syntax_error("in type declaration") @@ -356,16 +385,21 @@ func (p *parser) typeDecl(group *Group) Decl { return d } -// VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) . +// VarSpec = IdentifierList ( Type [ "=" ExpressionList ] | "=" ExpressionList ) | AliasSpec . func (p *parser) varDecl(group *Group) Decl { if trace { defer p.trace("varDecl")() } + name := p.name() + if p.tok == _Rarrow { + return p.aliasDecl(Var, name, group) + } + d := new(VarDecl) - d.init(p) + d.initFrom(&name.node) - d.NameList = p.nameList(p.name()) + d.NameList = p.nameList(name) if p.got(_Assign) { d.Values = p.exprList() } else { @@ -382,31 +416,28 @@ func (p *parser) varDecl(group *Group) Decl { return d } -// FunctionDecl = "func" FunctionName ( Function | Signature ) . +var badRecv = new(Field) // to signal invalid receiver in funcDecl + +// FunctionDecl = "func" FunctionName ( Function | Signature ) | "func" AliasSpec . // FunctionName = identifier . // Function = Signature FunctionBody . // MethodDecl = "func" Receiver MethodName ( Function | Signature ) . // Receiver = Parameters . -func (p *parser) funcDecl() *FuncDecl { +func (p *parser) funcDecl() Decl { if trace { defer p.trace("funcDecl")() } - f := new(FuncDecl) - f.init(p) - - badRecv := false + var recv *Field if p.tok == _Lparen { - rcvr := p.paramList() - switch len(rcvr) { + recv = badRecv + switch list := p.paramList(); len(list) { case 0: p.error("method has no receiver") - badRecv = true case 1: - f.Recv = rcvr[0] + recv = list[0] default: p.error("method has multiple receivers") - badRecv = true } } @@ -416,6 +447,11 @@ func (p *parser) funcDecl() *FuncDecl { return nil } + name := p.name() + if recv == nil && p.tok == _Rarrow { + return p.aliasDecl(Func, name, nil) + } + // TODO(gri) check for regular functions only // if name.Sym.Name == "init" { // name = renameinit() @@ -430,7 +466,11 @@ func (p *parser) funcDecl() *FuncDecl { // } // } - f.Name = p.name() + f := new(FuncDecl) + f.initFrom(&name.node) // TODO(gri) is this the correct position for methods? + + f.Recv = recv + f.Name = name f.Type = p.funcType() if gcCompat { f.node = f.Type.node @@ -445,7 +485,7 @@ func (p *parser) funcDecl() *FuncDecl { // p.error("can only use //go:noescape with external func implementations") // } - if badRecv { + if recv == badRecv { return nil // TODO(gri) better solution } return f @@ -514,7 +554,7 @@ func (p *parser) unaryExpr() Expr { return x } - case _Arrow: + case _Larrow: // receive op (<-x) or receive-only channel (<-chan E) p.next() @@ -928,7 +968,7 @@ func (p *parser) tryType() Expr { p.next() return indirect(p.type_()) - case _Arrow: + case _Larrow: // recvchantype p.next() p.want(_Chan) @@ -974,7 +1014,7 @@ func (p *parser) tryType() Expr { p.next() t := new(ChanType) t.init(p) - if p.got(_Arrow) { + if p.got(_Larrow) { t.Dir = SendOnly } t.Elem = p.chanElem() @@ -1317,7 +1357,7 @@ func (p *parser) paramDecl() *Field { case _Name: f.Name = p.name() switch p.tok { - case _Name, _Star, _Arrow, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen: + case _Name, _Star, _Larrow, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen: // sym name_or_type f.Type = p.type_() @@ -1332,7 +1372,7 @@ func (p *parser) paramDecl() *Field { f.Name = nil } - case _Arrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen: + case _Larrow, _Star, _Func, _Lbrack, _Chan, _Map, _Struct, _Interface, _Lparen: // name_or_type f.Type = p.type_() @@ -1466,7 +1506,7 @@ func (p *parser) simpleStmt(lhs Expr, rangeOk bool) SimpleStmt { p.next() return p.newAssignStmt(op, lhs, ImplicitOne) - case _Arrow: + case _Larrow: // lhs <- rhs p.next() s := new(SendStmt) @@ -1819,7 +1859,7 @@ func (p *parser) commClause() *CommClause { p.next() lhs := p.exprList() - if _, ok := lhs.(*ListExpr); !ok && p.tok == _Arrow { + if _, ok := lhs.(*ListExpr); !ok && p.tok == _Larrow { // lhs <- x } else { // lhs @@ -1899,7 +1939,7 @@ func (p *parser) stmt() Stmt { case _Literal, _Func, _Lparen, // operands _Lbrack, _Struct, _Map, _Chan, _Interface, // composite types - _Arrow: // receive operator + _Larrow: // receive operator return p.simpleStmt(nil, false) case _For: diff --git a/src/cmd/compile/internal/syntax/printer.go b/src/cmd/compile/internal/syntax/printer.go index 0cacf1e5d4..de2afe0499 100644 --- a/src/cmd/compile/internal/syntax/printer.go +++ b/src/cmd/compile/internal/syntax/printer.go @@ -473,11 +473,11 @@ func (p *printer) printRawNode(n Node) { case *ChanType: if n.Dir == RecvOnly { - p.print(_Arrow) + p.print(_Larrow) } p.print(_Chan) if n.Dir == SendOnly { - p.print(_Arrow) + p.print(_Larrow) } p.print(blank, n.Elem) @@ -495,7 +495,7 @@ func (p *printer) printRawNode(n Node) { p.print(n.X) case *SendStmt: - p.print(n.Chan, blank, _Arrow, blank, n.Value) + p.print(n.Chan, blank, _Larrow, blank, n.Value) case *AssignStmt: p.print(n.Lhs) @@ -603,6 +603,12 @@ func (p *printer) printRawNode(n Node) { } p.print(n.Path) + case *AliasDecl: + if n.Group == nil { + p.print(n.Tok, blank) + } + p.print(n.Name, blank, _Rarrow, blank, n.Orig) + case *ConstDecl: if n.Group == nil { p.print(_Const, blank) @@ -619,7 +625,11 @@ func (p *printer) printRawNode(n Node) { if n.Group == nil { p.print(_Type, blank) } - p.print(n.Name, blank, n.Type) + p.print(n.Name, blank) + if n.Alias { + p.print(_Assign, blank) + } + p.print(n.Type) case *VarDecl: if n.Group == nil { @@ -757,6 +767,8 @@ func groupFor(d Decl) (token, *Group) { switch d := d.(type) { case *ImportDecl: return _Import, d.Group + case *AliasDecl: + return d.Tok, d.Group case *ConstDecl: return _Const, d.Group case *TypeDecl: diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go index b84fcc5fd1..bd38943c30 100644 --- a/src/cmd/compile/internal/syntax/scanner.go +++ b/src/cmd/compile/internal/syntax/scanner.go @@ -229,7 +229,7 @@ redo: goto assignop } if c == '-' { - s.tok = _Arrow + s.tok = _Larrow break } s.ungetr() @@ -253,11 +253,16 @@ redo: s.tok = _Operator case '=': - if s.getr() == '=' { + c = s.getr() + if c == '=' { s.op, s.prec = Eql, precCmp s.tok = _Operator break } + if c == '>' { + s.tok = _Rarrow + break + } s.ungetr() s.tok = _Assign diff --git a/src/cmd/compile/internal/syntax/scanner_test.go b/src/cmd/compile/internal/syntax/scanner_test.go index 38a7e0da4c..0e0ff1b172 100644 --- a/src/cmd/compile/internal/syntax/scanner_test.go +++ b/src/cmd/compile/internal/syntax/scanner_test.go @@ -210,7 +210,8 @@ var sampleTokens = [...]struct { {_IncOp, "--", Sub, precAdd}, {_Assign, "=", 0, 0}, {_Define, ":=", 0, 0}, - {_Arrow, "<-", 0, 0}, + {_Larrow, "<-", 0, 0}, + {_Rarrow, "=>", 0, 0}, // delimiters {_Lparen, "(", 0, 0}, diff --git a/src/cmd/compile/internal/syntax/tokens.go b/src/cmd/compile/internal/syntax/tokens.go index bd0118a141..4a02c0ce3b 100644 --- a/src/cmd/compile/internal/syntax/tokens.go +++ b/src/cmd/compile/internal/syntax/tokens.go @@ -22,7 +22,8 @@ const ( _IncOp _Assign _Define - _Arrow + _Larrow + _Rarrow _Star // delimitors @@ -69,6 +70,12 @@ const ( ) const ( + // for AliasDecl + Const = _Const + Type = _Type + Var = _Var + Func = _Func + // for BranchStmt Break = _Break Continue = _Continue @@ -94,7 +101,8 @@ var tokstrings = [...]string{ _IncOp: "opop", _Assign: "=", _Define: ":=", - _Arrow: "<-", + _Larrow: "<-", + _Rarrow: "=>", _Star: "*", // delimitors -- 2.48.1