// constant, type, or variable declaration.
//
type (
- // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec.
+ // The Spec type stands for any of *ImportSpec, *AliasSpec, *ValueSpec, or *TypeSpec.
Spec interface {
Node
specNode()
EndPos token.Pos // end of spec (overrides Path.Pos if nonzero)
}
+ // An AliasSpec node represents a constant, type, variable, or function alias.
+ AliasSpec struct {
+ Doc *CommentGroup // associated documentation; or nil
+ Name *Ident // alias name
+ Orig Expr // original (possibly qualified) name
+ Comment *CommentGroup // line comments; or nil
+ }
+
// A ValueSpec node represents a constant or variable declaration
// (ConstSpec or VarSpec production).
//
}
return s.Path.Pos()
}
+func (s *AliasSpec) Pos() token.Pos { return s.Name.Pos() }
func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() }
func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() }
}
return s.Path.End()
}
-
+func (s *AliasSpec) End() token.Pos { return s.Orig.End() }
func (s *ValueSpec) End() token.Pos {
if n := len(s.Values); n > 0 {
return s.Values[n-1].End()
// assigned to a Spec.
//
func (*ImportSpec) specNode() {}
+func (*AliasSpec) specNode() {}
func (*ValueSpec) specNode() {}
func (*TypeSpec) specNode() {}
}
// A GenDecl node (generic declaration node) represents an import,
- // constant, type or variable declaration. A valid Lparen position
- // (Lparen.Line > 0) indicates a parenthesized declaration.
+ // constant, type, or variable declaration, or a function alias
+ // declaration. A valid Lparen position (Lparen.Line > 0) indicates
+ // a parenthesized declaration.
//
// Relationship between Tok value and Specs element type:
//
// token.IMPORT *ImportSpec
- // token.CONST *ValueSpec
- // token.TYPE *TypeSpec
- // token.VAR *ValueSpec
+ // token.CONST *ValueSpec or *AliasSpec
+ // token.TYPE *TypeSpec or *AliasSpec
+ // token.VAR *ValueSpec or *AliasSpec
+ // token.FUNC *AliasSpec
//
GenDecl struct {
Doc *CommentGroup // associated documentation; or nil
TokPos token.Pos // position of Tok
- Tok token.Token // IMPORT, CONST, TYPE, VAR
+ Tok token.Token // IMPORT, CONST, TYPE, VAR, FUNC (alias decl only)
Lparen token.Pos // position of '(', if any
Specs []Spec
Rparen token.Pos // position of ')', if any
return &ast.Ident{NamePos: pos, Name: name}
}
-func (p *parser) parseIdentList() (list []*ast.Ident) {
+func (p *parser) parseIdentList(first *ast.Ident) []*ast.Ident {
if p.trace {
defer un(trace(p, "IdentList"))
}
- list = append(list, p.parseIdent())
+ list := []*ast.Ident{first}
for p.tok == token.COMMA {
p.next()
list = append(list, p.parseIdent())
}
- return
+ return list
}
// ----------------------------------------------------------------------------
// don't resolve ident yet - it may be a parameter or field name
if p.tok == token.PERIOD {
- // ident is a package name
+ // ident must be a package name
p.next()
p.resolve(ident)
- sel := p.parseIdent()
- return &ast.SelectorExpr{X: ident, Sel: sel}
+ return &ast.SelectorExpr{X: ident, Sel: p.parseIdent()}
}
return ident
}
p.next()
for p.tok != token.RPAREN && p.tok != token.EOF {
- idents := p.parseIdentList()
+ idents := p.parseIdentList(p.parseIdent())
typ := p.parseVarType(ellipsisOk)
field := &ast.Field{Names: idents, Type: typ}
params = append(params, field)
return &ast.BadExpr{From: pos, To: p.pos}
}
-func (p *parser) parseSelector(x ast.Expr) ast.Expr {
- if p.trace {
- defer un(trace(p, "Selector"))
- }
-
- sel := p.parseIdent()
-
- return &ast.SelectorExpr{X: x, Sel: sel}
-}
-
func (p *parser) parseTypeAssertion(x ast.Expr) ast.Expr {
if p.trace {
defer un(trace(p, "TypeAssertion"))
}
switch p.tok {
case token.IDENT:
- x = p.parseSelector(p.checkExprOrType(x))
+ x = &ast.SelectorExpr{X: p.checkExprOrType(x), Sel: p.parseIdent()}
case token.LPAREN:
x = p.parseTypeAssertion(p.checkExpr(x))
default:
return spec
}
+// AliasSpec = identifier "=>" [ PackageName "." ] identifier .
+func (p *parser) parseAliasSpec(doc *ast.CommentGroup, kind ast.ObjKind, ident *ast.Ident) ast.Spec {
+ // no tracing since this is already called from a parse(Value/Type)Spec or parseFuncDecl
+
+ // lhs identifier and "=>" have been consumed already
+
+ var orig ast.Expr = p.parseIdent()
+ if p.tok == token.PERIOD {
+ // orig must be a package name
+ p.next()
+ p.resolve(orig)
+ orig = &ast.SelectorExpr{X: orig, Sel: p.parseIdent()}
+ }
+
+ p.expectSemi() // call before accessing p.linecomment
+
+ spec := &ast.AliasSpec{
+ Doc: doc,
+ Name: ident,
+ Orig: orig,
+ Comment: p.lineComment,
+ }
+ p.declare(spec, nil, p.topScope, kind, ident)
+
+ return spec
+}
+
func (p *parser) parseValueSpec(doc *ast.CommentGroup, keyword token.Token, iota int) ast.Spec {
if p.trace {
defer un(trace(p, keyword.String()+"Spec"))
}
+ kind := ast.Con
+ if keyword == token.VAR {
+ kind = ast.Var
+ }
+
pos := p.pos
- idents := p.parseIdentList()
+ ident := p.parseIdent()
+ if p.tok == token.ALIAS {
+ p.next()
+ return p.parseAliasSpec(doc, kind, ident)
+ }
+
+ idents := p.parseIdentList(ident)
typ := p.tryType()
var values []ast.Expr
// always permit optional initialization for more tolerant parsing
Values: values,
Comment: p.lineComment,
}
- kind := ast.Con
- if keyword == token.VAR {
- kind = ast.Var
- }
p.declare(spec, iota, p.topScope, kind, idents...)
return spec
}
ident := p.parseIdent()
+ // permit both: type T => p.T and: type T = p.T for now
+ if p.tok == token.ALIAS || p.tok == token.ASSIGN {
+ p.next()
+ return p.parseAliasSpec(doc, ast.Typ, ident)
+ }
// Go spec: The scope of a type identifier declared inside a function begins
// at the identifier in the TypeSpec and ends at the end of the innermost
}
}
-func (p *parser) parseFuncDecl() *ast.FuncDecl {
+func (p *parser) parseFuncDecl() ast.Decl {
if p.trace {
defer un(trace(p, "FunctionDecl"))
}
}
ident := p.parseIdent()
+ if recv == nil && p.tok == token.ALIAS {
+ p.next()
+ return &ast.GenDecl{
+ Doc: doc,
+ TokPos: pos,
+ Tok: token.FUNC,
+ Specs: []ast.Spec{p.parseAliasSpec(nil, ast.Fun, ident)},
+ }
+ }
params, results := p.parseSignature(scope)