From c734b50b11c6d9e46856c51870dc4bee94b8f18c Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Fri, 11 Mar 2011 16:15:33 -0800 Subject: [PATCH] gotype: clean handling of stdin, added tests - removed uses of global variables - minor cleanups R=r CC=golang-dev https://golang.org/cl/4277044 --- src/cmd/gotype/Makefile | 3 + src/cmd/gotype/doc.go | 2 + src/cmd/gotype/gotype.go | 103 ++++++++++++++++++---------------- src/cmd/gotype/gotype_test.go | 29 ++++++++++ src/pkg/Makefile | 1 - 5 files changed, 89 insertions(+), 49 deletions(-) create mode 100644 src/cmd/gotype/gotype_test.go diff --git a/src/cmd/gotype/Makefile b/src/cmd/gotype/Makefile index ac9e3bef44f..929fc52de1e 100644 --- a/src/cmd/gotype/Makefile +++ b/src/cmd/gotype/Makefile @@ -9,3 +9,6 @@ GOFILES=\ gotype.go\ include ../../Make.cmd + +test: + gotest diff --git a/src/cmd/gotype/doc.go b/src/cmd/gotype/doc.go index 1bd4b5f6cf7..ec4eb7c2448 100644 --- a/src/cmd/gotype/doc.go +++ b/src/cmd/gotype/doc.go @@ -55,3 +55,5 @@ To verify the output of a pipe: */ package documentation + +// BUG(gri): At the moment, only single-file scope analysis is performed. diff --git a/src/cmd/gotype/gotype.go b/src/cmd/gotype/gotype.go index 435f1aa941d..0d57c18a65a 100644 --- a/src/cmd/gotype/gotype.go +++ b/src/cmd/gotype/gotype.go @@ -30,11 +30,7 @@ var ( ) -var ( - fset = token.NewFileSet() - exitCode = 0 - parserMode = parser.DeclarationErrors -) +var exitCode = 0 func usage() { @@ -44,35 +40,21 @@ func usage() { } -func processFlags() { - flag.Usage = usage - flag.Parse() - if *printTrace { - parserMode |= parser.Trace - } -} - - func report(err os.Error) { scanner.PrintError(os.Stderr, err) exitCode = 2 } -// parseFile returns the AST for the given file. -// The result -func parseFile(filename string) *ast.File { +// parse returns the AST for the Go source src. +// The filename is for error reporting only. +// The result is nil if there were errors or if +// the file does not belong to the -p package. +func parse(fset *token.FileSet, filename string, src []byte) *ast.File { if *verbose { fmt.Println(filename) } - // get source - src, err := ioutil.ReadFile(filename) - if err != nil { - report(err) - return nil - } - // ignore files with different package name if *pkgName != "" { file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly) @@ -89,7 +71,11 @@ func parseFile(filename string) *ast.File { } // parse entire file - file, err := parser.ParseFile(fset, filename, src, parserMode) + mode := parser.DeclarationErrors + if *printTrace { + mode |= parser.Trace + } + file, err := parser.ParseFile(fset, filename, src, mode) if err != nil { report(err) return nil @@ -102,33 +88,38 @@ func parseFile(filename string) *ast.File { } -// BUG(gri): At the moment, only single-file scope analysis is performed. +func parseStdin(fset *token.FileSet) (files map[string]*ast.File) { + files = make(map[string]*ast.File) + src, err := ioutil.ReadAll(os.Stdin) + if err != nil { + report(err) + return + } + const filename = "" + if file := parse(fset, filename, src); file != nil { + files[filename] = file + } + return +} -func processPackage(filenames []string) { - var files []*ast.File - pkgName := "" + +func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) { + files = make(map[string]*ast.File) for _, filename := range filenames { - file := parseFile(filename) - if file == nil { - continue // ignore file + src, err := ioutil.ReadFile(filename) + if err != nil { + report(err) + continue } - // package names must match - // TODO(gri): this check should be moved into a - // function making the package below - if pkgName == "" { - // first package file - pkgName = file.Name.Name - } else { - if file.Name.Name != pkgName { - report(os.NewError(fmt.Sprintf("file %q is in package %q not %q", filename, file.Name.Name, pkgName))) + if file := parse(fset, filename, src); file != nil { + if files[filename] != nil { + report(os.ErrorString(fmt.Sprintf("%q: duplicate file", filename))) continue } + files[filename] = file } - files = append(files, file) } - - // TODO(gri): make a ast.Package and analyze it - _ = files + return } @@ -174,15 +165,31 @@ func processFiles(filenames []string, allFiles bool) { } } } - processPackage(filenames[0:i]) + processPackage(parseFiles(token.NewFileSet(), filenames[0:i])) +} + + +func processPackage(files map[string]*ast.File) { + // TODO(gri) Enable this code once we have ast.NewPackage. + /* + // make a package (resolve all identifiers) + pkg, err := ast.NewPackage(files) + if err != nil { + report(err) + return + } + // TODO(gri): typecheck package + _ = pkg + */ } func main() { - processFlags() + flag.Usage = usage + flag.Parse() if flag.NArg() == 0 { - processPackage([]string{os.Stdin.Name()}) + processPackage(parseStdin(token.NewFileSet())) } else { processFiles(flag.Args(), true) } diff --git a/src/cmd/gotype/gotype_test.go b/src/cmd/gotype/gotype_test.go new file mode 100644 index 00000000000..ddd958c9aa9 --- /dev/null +++ b/src/cmd/gotype/gotype_test.go @@ -0,0 +1,29 @@ +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "path/filepath" + "runtime" + "testing" +) + + +func testDir(t *testing.T, dir, pkg string) { + *pkgName = pkg + *recursive = false + processDirectory(dir) + if exitCode != 0 { + t.Errorf("processing %d failed: exitCode = %d", dir, exitCode) + } +} + + +func Test(t *testing.T) { + testDir(t, ".", "main") + testDir(t, filepath.Join(runtime.GOROOT(), "src/pkg/go/ast"), "ast") + testDir(t, filepath.Join(runtime.GOROOT(), "src/pkg/go/scanner"), "scanner") + testDir(t, filepath.Join(runtime.GOROOT(), "src/pkg/go/parser"), "parser") +} diff --git a/src/pkg/Makefile b/src/pkg/Makefile index ccba63b6aa8..3edb1e60bd0 100644 --- a/src/pkg/Makefile +++ b/src/pkg/Makefile @@ -192,7 +192,6 @@ NOTEST=\ ../cmd/ebnflint\ ../cmd/godoc\ ../cmd/gofmt\ - ../cmd/gotype\ ../cmd/govet\ ../cmd/goyacc\ ../cmd/hgpatch\