Commit 3ba69bf0 authored by Robert Griesemer's avatar Robert Griesemer

Some AST tuning:

- have explicit XSpec nodes for declarations
- have a general GenDecl node instead of DeclList

R=rsc
DELTA=164  (52 added, 52 deleted, 60 changed)
OCL=27005
CL=27027
parent c4ad4f9f
...@@ -654,62 +654,76 @@ func (s *RangeStmt) Visit(v StmtVisitor) { v.DoRangeStmt(s); } ...@@ -654,62 +654,76 @@ func (s *RangeStmt) Visit(v StmtVisitor) { v.DoRangeStmt(s); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Declarations // 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 ( type (
// A BadDecl node is a placeholder for declarations containing // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec.
// syntax errors for which no correct declaration nodes can be Spec interface {};
// created.
//
BadDecl struct {
token.Position; // beginning position of bad declaration
};
ImportDecl struct { // An ImportSpec node represents a single package import.
ImportSpec struct {
Doc Comments; // associated documentation; or nil Doc Comments; // associated documentation; or nil
token.Position; // position of "import" keyword Name *Ident; // local package name (including "."); or nil
Name *Ident; // local package name or nil
Path []*StringLit; // package path 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 Doc Comments; // associated documentation; or nil
token.Position; // position of "const" keyword
Names []*Ident; Names []*Ident;
Type Expr; // constant type or nil Type Expr; // value type; or nil
Values []Expr; Values []Expr;
}; };
TypeDecl struct { // A TypeSpec node represents a type declaration (TypeSpec production).
TypeSpec struct {
Doc Comments; // associated documentation; or nil Doc Comments; // associated documentation; or nil
token.Position; // position of "type" keyword Name *Ident; // type name
Name *Ident;
Type Expr; 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 Doc Comments; // associated documentation; or nil
token.Position; // position of "var" keyword token.Position; // position of Tok
Names []*Ident; Tok token.Token; // IMPORT, CONST, TYPE, VAR
Type Expr; // variable type or nil Lparen token.Position; // position of '(', if any
Values []Expr; Specs []Spec;
Rparen token.Position; // position of ')', if any
}; };
// A FuncDecl node represents a function declaration.
FuncDecl struct { FuncDecl struct {
Doc Comments; // associated documentation; or nil 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 Name *Ident; // function/method name
Type *FuncType; // position of Func keyword, parameters and results Type *FuncType; // position of Func keyword, parameters and results
Body *BlockStmt; // function body or nil (forward declaration) 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 ')'
}; };
) )
...@@ -725,24 +739,16 @@ func (d *FuncDecl) Pos() token.Position { return d.Type.Pos(); } ...@@ -725,24 +739,16 @@ func (d *FuncDecl) Pos() token.Position { return d.Type.Pos(); }
// //
type DeclVisitor interface { type DeclVisitor interface {
DoBadDecl(d *BadDecl); DoBadDecl(d *BadDecl);
DoImportDecl(d *ImportDecl); DoGenDecl(d *GenDecl);
DoConstDecl(d *ConstDecl);
DoTypeDecl(d *TypeDecl);
DoVarDecl(d *VarDecl);
DoFuncDecl(d *FuncDecl); DoFuncDecl(d *FuncDecl);
DoDeclList(d *DeclList);
} }
// Visit() implementations for all declaration nodes. // Visit() implementations for all declaration nodes.
// //
func (d *BadDecl) Visit(v DeclVisitor) { v.DoBadDecl(d); } func (d *BadDecl) Visit(v DeclVisitor) { v.DoBadDecl(d); }
func (d *ImportDecl) Visit(v DeclVisitor) { v.DoImportDecl(d); } func (d *GenDecl) Visit(v DeclVisitor) { v.DoGenDecl(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 *FuncDecl) Visit(v DeclVisitor) { v.DoFuncDecl(d); } func (d *FuncDecl) Visit(v DeclVisitor) { v.DoFuncDecl(d); }
func (d *DeclList) Visit(v DeclVisitor) { v.DoDeclList(d); }
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
......
...@@ -1645,14 +1645,16 @@ func (p *parser) parseStatement() ast.Stmt { ...@@ -1645,14 +1645,16 @@ func (p *parser) parseStatement() ast.Stmt {
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Declarations // 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 { if p.trace {
defer un(trace(p, "ImportSpec")); defer un(trace(p, "ImportSpec"));
} }
var ident *ast.Ident; var ident *ast.Ident;
if p.tok == token.PERIOD { if p.tok == token.PERIOD {
p.error(p.pos, `"import ." not yet handled properly`); ident = &ast.Ident{p.pos, []byte{'.'}};
p.next(); p.next();
} else if p.tok == token.IDENT { } else if p.tok == token.IDENT {
ident = p.parseIdent(); ident = p.parseIdent();
...@@ -1665,11 +1667,11 @@ func (p *parser) parseImportSpec(pos token.Position, doc ast.Comments) *ast.Impo ...@@ -1665,11 +1667,11 @@ func (p *parser) parseImportSpec(pos token.Position, doc ast.Comments) *ast.Impo
p.expect(token.STRING); // use expect() error handling 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 { if p.trace {
defer un(trace(p, "ConstSpec")); defer un(trace(p, "ConstSpec"));
} }
...@@ -1682,11 +1684,11 @@ func (p *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.Const ...@@ -1682,11 +1684,11 @@ func (p *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.Const
values = p.parseExpressionList(); 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 { if p.trace {
defer un(trace(p, "TypeSpec")); defer un(trace(p, "TypeSpec"));
} }
...@@ -1694,11 +1696,11 @@ func (p *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDe ...@@ -1694,11 +1696,11 @@ func (p *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDe
ident := p.parseIdent(); ident := p.parseIdent();
typ := p.parseType(); 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 { if p.trace {
defer un(trace(p, "VarSpec")); defer un(trace(p, "VarSpec"));
} }
...@@ -1711,55 +1713,43 @@ func (p *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl ...@@ -1711,55 +1713,43 @@ func (p *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl
values = p.parseExpressionList(); values = p.parseExpressionList();
} }
return &ast.VarDecl{doc, pos, idents, typ, values}; return &ast.ValueSpec{doc, 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;
} }
func (p *parser) parseDecl(keyword int) ast.Decl { func (p *parser) parseGenDecl(keyword token.Token, f parseSpecFunction) *ast.GenDecl {
if p.trace { if p.trace {
defer un(trace(p, "Decl")); defer un(trace(p, keyword.String() + "Decl"));
} }
doc := p.getDoc(); doc := p.getDoc();
pos := p.expect(keyword); pos := p.expect(keyword);
var lparen, rparen token.Position;
list := vector.New(0);
if p.tok == token.LPAREN { if p.tok == token.LPAREN {
lparen := p.pos; lparen = p.pos;
p.next(); p.next();
list := vector.New(0);
for p.tok != token.RPAREN && p.tok != token.EOF { 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 { if p.tok == token.SEMICOLON {
p.next(); p.next();
} else { } else {
break; break;
} }
} }
rparen := p.expect(token.RPAREN); rparen = p.expect(token.RPAREN);
p.opt_semi = true; p.opt_semi = true;
} else {
// convert vector list.Push(f(p, doc));
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};
} }
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};
} }
...@@ -1820,17 +1810,21 @@ func (p *parser) parseDeclaration() ast.Decl { ...@@ -1820,17 +1810,21 @@ func (p *parser) parseDeclaration() ast.Decl {
defer un(trace(p, "Declaration")); defer un(trace(p, "Declaration"));
} }
var f parseSpecFunction;
switch p.tok { switch p.tok {
case token.CONST, token.TYPE, token.VAR: case token.CONST: f = parseConstSpec;
return p.parseDecl(p.tok); case token.TYPE: f = parseTypeSpec;
case token.VAR: f = parseVarSpec;
case token.FUNC: case token.FUNC:
return p.parseFunctionDecl(); return p.parseFunctionDecl();
default:
pos := p.pos;
p.error_expected(pos, "declaration");
p.next(); // make progress
return &ast.BadDecl{pos};
} }
pos := p.pos; return p.parseGenDecl(p.tok, f);
p.error_expected(pos, "declaration");
p.next(); // make progress
return &ast.BadDecl{pos};
} }
...@@ -1869,7 +1863,7 @@ func (p *parser) parsePackage() *ast.Program { ...@@ -1869,7 +1863,7 @@ func (p *parser) parsePackage() *ast.Program {
// import decls // import decls
list := vector.New(0); list := vector.New(0);
for p.tok == token.IMPORT { for p.tok == token.IMPORT {
list.Push(p.parseDecl(token.IMPORT)); list.Push(p.parseGenDecl(token.IMPORT, parseImportSpec));
if p.tok == token.SEMICOLON { if p.tok == token.SEMICOLON {
p.next(); p.next();
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment