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 | 94 +++++++++++++++++++++++--------------------- src/lib/go/parser.go | 84 ++++++++++++++++++--------------------- 2 files changed, 89 insertions(+), 89 deletions(-) diff --git a/src/lib/go/ast.go b/src/lib/go/ast.go index 79a5d7d849..79e14484b5 100644 --- a/src/lib/go/ast.go +++ b/src/lib/go/ast.go @@ -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); } // ---------------------------------------------------------------------------- diff --git a/src/lib/go/parser.go b/src/lib/go/parser.go index 6083ce32b4..39aeb5c159 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}; -} - - -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(); } -- 2.48.1