1
0
mirror of https://github.com/golang/go synced 2024-11-22 03:54:39 -07:00

Simplified parser interface.

R=rsc, r
CC=golang-dev, rog
https://golang.org/cl/183116
This commit is contained in:
Robert Griesemer 2010-01-04 17:26:01 -08:00
parent a0ee18bdd5
commit 50442290bb
4 changed files with 39 additions and 54 deletions

View File

@ -59,7 +59,7 @@ type FuncType struct {
func openProg(name string, p *Prog) { func openProg(name string, p *Prog) {
var err os.Error var err os.Error
p.AST, err = parser.ParsePkgFile("", name, parser.ParseComments) p.AST, err = parser.ParseFile(name, nil, parser.ParseComments)
if err != nil { if err != nil {
if list, ok := err.(scanner.ErrorList); ok { if list, ok := err.(scanner.ErrorList); ok {
// If err is a scanner.ErrorList, its String will print just // If err is a scanner.ErrorList, its String will print just

View File

@ -1021,10 +1021,18 @@ func (h *httpHandler) getPageInfo(path string) PageInfo {
} }
// get package AST // get package AST
pkg, err := parser.ParsePackage(dirname, filter, parser.ParseComments) pkgs, err := parser.ParseDir(dirname, filter, parser.ParseComments)
if err != nil { if err != nil {
// TODO: parse errors should be shown instead of an empty directory // TODO: errors should be shown instead of an empty directory
log.Stderrf("parser.parsePackage: %s", err) log.Stderrf("parser.parseDir: %s", err)
}
if len(pkgs) != 1 {
// TODO: should handle multiple packages
log.Stderrf("parser.parseDir: found %d packages", len(pkgs))
}
var pkg *ast.Package
for _, pkg = range pkgs {
break // take the first package found
} }
// compute package documentation // compute package documentation

View File

@ -8,7 +8,6 @@ package parser
import ( import (
"bytes" "bytes"
"fmt"
"go/ast" "go/ast"
"go/scanner" "go/scanner"
"io" "io"
@ -132,41 +131,16 @@ func ParseFile(filename string, src interface{}, mode uint) (*ast.File, os.Error
} }
// ParsePkgFile parses the file specified by filename and returns the // ParseDir calls ParseFile for the files in the directory specified by path and
// corresponding AST. If the file cannot be read, has syntax errors, or // returns a map of package name -> package AST with all the packages found. If
// does not belong to the package (i.e., pkgname != "" and the package // filter != nil, only the files with os.Dir entries passing through the filter
// name in the file doesn't match pkkname), an error is returned. // are considered. The mode bits are passed to ParseFile unchanged.
// //
func ParsePkgFile(pkgname, filename string, mode uint) (*ast.File, os.Error) { // If the directory couldn't be read, a nil map and the respective error are
src, err := ioutil.ReadFile(filename) // returned. If a parse error occured, a non-nil but incomplete map and the
if err != nil { // error are returned.
return nil, err
}
if pkgname != "" {
prog, err := ParseFile(filename, src, PackageClauseOnly)
if err != nil {
return nil, err
}
if prog.Name.Value != pkgname {
return nil, os.NewError(fmt.Sprintf("multiple packages found: %s, %s", prog.Name.Value, pkgname))
}
if mode == PackageClauseOnly {
return prog, nil
}
}
return ParseFile(filename, src, mode)
}
// ParsePackage parses all files in the directory specified by path and
// returns an AST representing the package found. The set of files may be
// restricted by providing a non-nil filter function; only the files with
// os.Dir entries passing through the filter are considered.
// If ParsePackage does not find exactly one package, it returns an error.
// //
func ParsePackage(path string, filter func(*os.Dir) bool, mode uint) (*ast.Package, os.Error) { func ParseDir(path string, filter func(*os.Dir) bool, mode uint) (map[string]*ast.Package, os.Error) {
fd, err := os.Open(path, os.O_RDONLY, 0) fd, err := os.Open(path, os.O_RDONLY, 0)
if err != nil { if err != nil {
return nil, err return nil, err
@ -178,25 +152,23 @@ func ParsePackage(path string, filter func(*os.Dir) bool, mode uint) (*ast.Packa
return nil, err return nil, err
} }
name := "" pkgs := make(map[string]*ast.Package)
files := make(map[string]*ast.File)
for i := 0; i < len(list); i++ { for i := 0; i < len(list); i++ {
entry := &list[i] entry := &list[i]
if filter == nil || filter(entry) { if filter == nil || filter(entry) {
src, err := ParsePkgFile(name, pathutil.Join(path, entry.Name), mode) src, err := ParseFile(pathutil.Join(path, entry.Name), nil, mode)
if err != nil { if err != nil {
return nil, err return pkgs, err
} }
files[entry.Name] = src name := src.Name.Value
if name == "" { pkg, found := pkgs[name]
name = src.Name.Value if !found {
pkg = &ast.Package{name, path, make(map[string]*ast.File)}
pkgs[name] = pkg
} }
pkg.Files[entry.Name] = src
} }
} }
if len(files) == 0 { return pkgs, nil
return nil, os.NewError(path + ": no package found")
}
return &ast.Package{name, path, files}, nil
} }

View File

@ -78,12 +78,17 @@ func dirFilter(d *os.Dir) bool { return nameFilter(d.Name) }
func TestParse4(t *testing.T) { func TestParse4(t *testing.T) {
path := "." path := "."
pkg, err := ParsePackage(path, dirFilter, 0) pkgs, err := ParseDir(path, dirFilter, 0)
if err != nil { if err != nil {
t.Fatalf("ParsePackage(%s): %v", path, err) t.Fatalf("ParseDir(%s): %v", path, err)
} }
if pkg.Name != "parser" { if len(pkgs) != 1 {
t.Errorf("incorrect package name: %s", pkg.Name) t.Errorf("incorrect number of packages: %d", len(pkgs))
}
pkg, found := pkgs["parser"]
if pkg == nil || !found {
t.Errorf(`package "parser" not found`)
return
} }
for filename, _ := range pkg.Files { for filename, _ := range pkg.Files {
if !nameFilter(filename) { if !nameFilter(filename) {