From 3ba69bf08b507eb8fa9c889b230d3de1ba8fc1a6 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Thu, 2 Apr 2009 10:15:58 -0700 Subject: [PATCH] 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 --- src/lib/go/ast.go | 112 +++++++++++++++++++++++-------------------- src/lib/go/parser.go | 84 +++++++++++++++----------------- 2 files changed, 98 insertions(+), 98 deletions(-) diff --git a/src/lib/go/ast.go b/src/lib/go/ast.go index 79a5d7d8491..79e14484b59 100644 --- a/src/lib/go/ast.go +++ b/src/lib/go/ast.go @@ -654,6 +654,38 @@ func (s *RangeStmt) Visit(v StmtVisitor) { v.DoRangeStmt(s); } // ---------------------------------------------------------------------------- // Declarations +// A Spec node represents a single (non-parenthesized) import, +// constant, type, or variable declaration. +// +type ( + // The Spec type stands for any of *ImportSpec, *ValueSpec, and *TypeSpec. + Spec interface {}; + + // An ImportSpec node represents a single package import. + ImportSpec struct { + Doc Comments; // associated documentation; or nil + Name *Ident; // local package name (including "."); or nil + Path []*StringLit; // package path + }; + + // A ValueSpec node represents a constant or variable declaration + // (ConstSpec or VarSpec production). + ValueSpec struct { + Doc Comments; // associated documentation; or nil + Names []*Ident; + Type Expr; // value type; or nil + Values []Expr; + }; + + // A TypeSpec node represents a type declaration (TypeSpec production). + TypeSpec struct { + Doc Comments; // associated documentation; or nil + Name *Ident; // type name + Type Expr; + }; +) + + // A declaration is represented by one of the following declaration nodes. // type ( @@ -665,51 +697,33 @@ type ( token.Position; // beginning position of bad declaration }; - ImportDecl struct { - Doc Comments; // associated documentation; or nil - token.Position; // position of "import" keyword - Name *Ident; // local package name or nil - Path []*StringLit; // package path - }; - - ConstDecl struct { - Doc Comments; // associated documentation; or nil - token.Position; // position of "const" keyword - Names []*Ident; - Type Expr; // constant type or nil - Values []Expr; - }; - - TypeDecl struct { - Doc Comments; // associated documentation; or nil - token.Position; // position of "type" keyword - Name *Ident; - Type Expr; - }; - - VarDecl struct { - Doc Comments; // associated documentation; or nil - token.Position; // position of "var" keyword - Names []*Ident; - Type Expr; // variable type or nil - Values []Expr; - }; - - FuncDecl struct { - Doc Comments; // associated documentation; or nil - 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 { + // 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 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 ')' + 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) + Name *Ident; // function/method name + Type *FuncType; // position of Func keyword, parameters and results + 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); } // ---------------------------------------------------------------------------- diff --git a/src/lib/go/parser.go b/src/lib/go/parser.go index 6083ce32b4f..39aeb5c1594 100644 --- a/src/lib/go/parser.go +++ b/src/lib/go/parser.go @@ -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}; + 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 { - 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(); }