]> Cypherpunks repositories - gostls13.git/commitdiff
Some AST tuning:
authorRobert Griesemer <gri@golang.org>
Thu, 2 Apr 2009 17:15:58 +0000 (10:15 -0700)
committerRobert Griesemer <gri@golang.org>
Thu, 2 Apr 2009 17:15:58 +0000 (10:15 -0700)
- 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

src/lib/go/ast.go
src/lib/go/parser.go

index 79a5d7d84919e6c392ddd0348ecfaebc9959a146..79e14484b596cd4fec5e305cd1e5dda382c358ea 100644 (file)
@@ -654,62 +654,76 @@ func (s *RangeStmt) Visit(v StmtVisitor) { v.DoRangeStmt(s); }
 // ----------------------------------------------------------------------------
 // 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)
        };
 )
 
@@ -725,24 +739,16 @@ func (d *FuncDecl) Pos() token.Position  { return d.Type.Pos(); }
 //
 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); }
 
 
 // ----------------------------------------------------------------------------
index 6083ce32b4febd124ae07c7642eb6dd298e18d21..39aeb5c1594e7b3955c7b8863cda73dd2c3928fc 100644 (file)
@@ -1645,14 +1645,16 @@ func (p *parser) parseStatement() ast.Stmt {
 // ----------------------------------------------------------------------------
 // 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();
@@ -1665,11 +1667,11 @@ func (p *parser) parseImportSpec(pos token.Position, doc ast.Comments) *ast.Impo
                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"));
        }
@@ -1682,11 +1684,11 @@ func (p *parser) parseConstSpec(pos token.Position, doc ast.Comments) *ast.Const
                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"));
        }
@@ -1694,11 +1696,11 @@ func (p *parser) parseTypeSpec(pos token.Position, doc ast.Comments) *ast.TypeDe
        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"));
        }
@@ -1711,55 +1713,43 @@ func (p *parser) parseVarSpec(pos token.Position, doc ast.Comments) *ast.VarDecl
                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};
 }
 
 
@@ -1820,17 +1810,21 @@ func (p *parser) parseDeclaration() ast.Decl {
                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);
 }
 
 
@@ -1869,7 +1863,7 @@ func (p *parser) parsePackage() *ast.Program {
                // 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();
                        }