// ----------------------------------------------------------------------------
// Declarations
-// A declaration is represented by one of the following declaration nodes.
+// A Spec node represents a single (non-parenthesized) import,
+// constant, type, or variable declaration.
//
-type (
- // A BadDecl node is a placeholder for declarations containing
- // syntax errors for which no correct declaration nodes can be
- // created.
- //
- BadDecl struct {
- token.Position; // beginning position of bad declaration
- };
+type (
+ // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec.
+ Spec interface {};
- ImportDecl struct {
+ // An ImportSpec node represents a single package import.
+ ImportSpec struct {
Doc Comments; // associated documentation; or nil
- token.Position; // position of "import" keyword
- Name *Ident; // local package name or nil
+ Name *Ident; // local package name (including "."); or nil
Path []*StringLit; // package path
};
- ConstDecl struct {
+ // A ValueSpec node represents a constant or variable declaration
+ // (ConstSpec or VarSpec production).
+ ValueSpec struct {
Doc Comments; // associated documentation; or nil
- token.Position; // position of "const" keyword
Names []*Ident;
- Type Expr; // constant type or nil
+ Type Expr; // value type; or nil
Values []Expr;
};
- TypeDecl struct {
+ // A TypeSpec node represents a type declaration (TypeSpec production).
+ TypeSpec struct {
Doc Comments; // associated documentation; or nil
- token.Position; // position of "type" keyword
- Name *Ident;
+ Name *Ident; // type name
Type Expr;
};
+)
- VarDecl struct {
+
+// A declaration is represented by one of the following declaration nodes.
+//
+type (
+ // A BadDecl node is a placeholder for declarations containing
+ // syntax errors for which no correct declaration nodes can be
+ // created.
+ //
+ BadDecl struct {
+ token.Position; // beginning position of bad declaration
+ };
+
+ // 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.
+ //
+ // Relationship between Tok value and Specs element type:
+ //
+ // token.IMPORT *ImportSpec
+ // token.CONST *ValueSpec
+ // token.TYPE *TypeSpec
+ // token.VAR *ValueSpec
+ //
+ GenDecl struct {
Doc Comments; // associated documentation; or nil
- token.Position; // position of "var" keyword
- Names []*Ident;
- Type Expr; // variable type or nil
- Values []Expr;
+ token.Position; // position of Tok
+ Tok token.Token; // IMPORT, CONST, TYPE, VAR
+ Lparen token.Position; // position of '(', if any
+ Specs []Spec;
+ Rparen token.Position; // position of ')', if any
};
+ // A FuncDecl node represents a function declaration.
FuncDecl struct {
Doc Comments; // associated documentation; or nil
- Recv *Field; // receiver (methods) or nil (functions)
+ Recv *Field; // receiver (methods); or nil (functions)
Name *Ident; // function/method name
Type *FuncType; // position of Func keyword, parameters and results
- Body *BlockStmt; // function body or nil (forward declaration)
- };
-
- DeclList struct {
- Doc Comments; // associated documentation; or nil
- token.Position; // position of Tok
- Tok token.Token; // IMPORT, CONST, VAR, TYPE
- Lparen token.Position; // position of '('
- List []Decl; // the list of parenthesized declarations
- Rparen token.Position; // position of ')'
+ Body *BlockStmt; // function body; or nil (forward declaration)
};
)
//
type DeclVisitor interface {
DoBadDecl(d *BadDecl);
- DoImportDecl(d *ImportDecl);
- DoConstDecl(d *ConstDecl);
- DoTypeDecl(d *TypeDecl);
- DoVarDecl(d *VarDecl);
+ DoGenDecl(d *GenDecl);
DoFuncDecl(d *FuncDecl);
- DoDeclList(d *DeclList);
}
// Visit() implementations for all declaration nodes.
//
func (d *BadDecl) Visit(v DeclVisitor) { v.DoBadDecl(d); }
-func (d *ImportDecl) Visit(v DeclVisitor) { v.DoImportDecl(d); }
-func (d *ConstDecl) Visit(v DeclVisitor) { v.DoConstDecl(d); }
-func (d *TypeDecl) Visit(v DeclVisitor) { v.DoTypeDecl(d); }
-func (d *VarDecl) Visit(v DeclVisitor) { v.DoVarDecl(d); }
+func (d *GenDecl) Visit(v DeclVisitor) { v.DoGenDecl(d); }
func (d *FuncDecl) Visit(v DeclVisitor) { v.DoFuncDecl(d); }
-func (d *DeclList) Visit(v DeclVisitor) { v.DoDeclList(d); }
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// Declarations
-func (p *parser) parseImportSpec(pos token.Position, doc ast.Comments) *ast.ImportDecl {
+type parseSpecFunction func(p *parser, doc ast.Comments) ast.Spec
+
+func parseImportSpec(p *parser, doc ast.Comments) ast.Spec {
if p.trace {
defer un(trace(p, "ImportSpec"));
}
var ident *ast.Ident;
if p.tok == token.PERIOD {
- p.error(p.pos, `"import ." not yet handled properly`);
+ ident = &ast.Ident{p.pos, []byte{'.'}};
p.next();
} else if p.tok == token.IDENT {
ident = p.parseIdent();
p.expect(token.STRING); // use expect() error handling
}
- return &ast.ImportDecl{doc, pos, ident, path};
+ return &ast.ImportSpec{doc, ident, path};
}
-func (p *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.ConstDecl {
+func parseConstSpec(p *parser, doc ast.Comments) ast.Spec {
if p.trace {
defer un(trace(p, "ConstSpec"));
}
values = p.parseExpressionList();
}
- return &ast.ConstDecl{doc, pos, idents, typ, values};
+ return &ast.ValueSpec{doc, idents, typ, values};
}
-func (p *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDecl {
+func parseTypeSpec(p *parser, doc ast.Comments) ast.Spec {
if p.trace {
defer un(trace(p, "TypeSpec"));
}
ident := p.parseIdent();
typ := p.parseType();
- return &ast.TypeDecl{doc, pos, ident, typ};
+ return &ast.TypeSpec{doc, ident, typ};
}
-func (p *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl {
+func parseVarSpec(p *parser, doc ast.Comments) ast.Spec {
if p.trace {
defer un(trace(p, "VarSpec"));
}
values = p.parseExpressionList();
}
- return &ast.VarDecl{doc, pos, idents, typ, values};
-}
-
-
-func (p *parser) parseSpec(pos token.Position, doc ast.Comments, keyword int) ast.Decl {
- switch keyword {
- case token.IMPORT: return p.parseImportSpec(pos, doc);
- case token.CONST: return p.parseConstSpec(pos, doc);
- case token.TYPE: return p.parseTypeSpec(pos, doc);
- case token.VAR: return p.parseVarSpec(pos, doc);
- }
-
- panic(); // unreachable
- return nil;
+ return &ast.ValueSpec{doc, idents, typ, values};
}
-func (p *parser) parseDecl(keyword int) ast.Decl {
+func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
if p.trace {
- defer un(trace(p, "Decl"));
+ defer un(trace(p, keyword.String() + "Decl"));
}
doc := p.getDoc();
pos := p.expect(keyword);
+ var lparen, rparen token.Position;
+ list := vector.New(0);
if p.tok == token.LPAREN {
- lparen := p.pos;
+ lparen = p.pos;
p.next();
- list := vector.New(0);
for p.tok != token.RPAREN && p.tok != token.EOF {
- list.Push(p.parseSpec(noPos, nil, keyword));
+ doc := p.getDoc();
+ list.Push(f(p, doc));
if p.tok == token.SEMICOLON {
p.next();
} else {
break;
}
}
- rparen := p.expect(token.RPAREN);
+ rparen = p.expect(token.RPAREN);
p.opt_semi = true;
-
- // convert vector
- decls := make([]ast.Decl, list.Len());
- for i := 0; i < list.Len(); i++ {
- decls[i] = list.At(i).(ast.Decl);
- }
-
- return &ast.DeclList{doc, pos, keyword, lparen, decls, rparen};
+ } else {
+ list.Push(f(p, doc));
}
- return p.parseSpec(pos, doc, keyword);
+ // convert vector
+ specs := make([]ast.Spec, list.Len());
+ for i := 0; i < list.Len(); i++ {
+ specs[i] = list.At(i);
+ }
+ return &ast.GenDecl{doc, pos, keyword, lparen, specs, rparen};
}
defer un(trace(p, "Declaration"));
}
+ var f parseSpecFunction;
switch p.tok {
- case token.CONST, token.TYPE, token.VAR:
- return p.parseDecl(p.tok);
+ case token.CONST: f = parseConstSpec;
+ case token.TYPE: f = parseTypeSpec;
+ case token.VAR: f = parseVarSpec;
case token.FUNC:
return p.parseFunctionDecl();
+ default:
+ pos := p.pos;
+ p.error_expected(pos, "declaration");
+ p.next(); // make progress
+ return &ast.BadDecl{pos};
}
-
- pos := p.pos;
- p.error_expected(pos, "declaration");
- p.next(); // make progress
- return &ast.BadDecl{pos};
+
+ return p.parseGenDecl(p.tok, f);
}
// import decls
list := vector.New(0);
for p.tok == token.IMPORT {
- list.Push(p.parseDecl(token.IMPORT));
+ list.Push(p.parseGenDecl(token.IMPORT, parseImportSpec));
if p.tok == token.SEMICOLON {
p.next();
}