OSDN Git Service

bc4a112c98f3d95a41068f8e58ecc72fa8d9772d
[pf3gnuchains/gcc-fork.git] / libgo / go / exp / gotype / gotype.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package main
6
7 import (
8         "errors"
9         "exp/types"
10         "flag"
11         "fmt"
12         "go/ast"
13         "go/parser"
14         "go/scanner"
15         "go/token"
16         "io/ioutil"
17         "os"
18         "path/filepath"
19         "strings"
20 )
21
22 var (
23         // main operation modes
24         pkgName   = flag.String("p", "", "process only those files in package pkgName")
25         recursive = flag.Bool("r", false, "recursively process subdirectories")
26         verbose   = flag.Bool("v", false, "verbose mode")
27         allErrors = flag.Bool("e", false, "print all (including spurious) errors")
28
29         // debugging support
30         printTrace = flag.Bool("trace", false, "print parse trace")
31         printAST   = flag.Bool("ast", false, "print AST")
32 )
33
34 var exitCode = 0
35
36 func usage() {
37         fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
38         flag.PrintDefaults()
39         os.Exit(2)
40 }
41
42 func report(err error) {
43         scanner.PrintError(os.Stderr, err)
44         exitCode = 2
45 }
46
47 // parse returns the AST for the Go source src.
48 // The filename is for error reporting only.
49 // The result is nil if there were errors or if
50 // the file does not belong to the -p package.
51 func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
52         if *verbose {
53                 fmt.Println(filename)
54         }
55
56         // ignore files with different package name
57         if *pkgName != "" {
58                 file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
59                 if err != nil {
60                         report(err)
61                         return nil
62                 }
63                 if file.Name.Name != *pkgName {
64                         if *verbose {
65                                 fmt.Printf("\tignored (package %s)\n", file.Name.Name)
66                         }
67                         return nil
68                 }
69         }
70
71         // parse entire file
72         mode := parser.DeclarationErrors
73         if *allErrors {
74                 mode |= parser.SpuriousErrors
75         }
76         if *printTrace {
77                 mode |= parser.Trace
78         }
79         file, err := parser.ParseFile(fset, filename, src, mode)
80         if err != nil {
81                 report(err)
82                 return nil
83         }
84         if *printAST {
85                 ast.Print(fset, file)
86         }
87
88         return file
89 }
90
91 func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
92         files = make(map[string]*ast.File)
93         src, err := ioutil.ReadAll(os.Stdin)
94         if err != nil {
95                 report(err)
96                 return
97         }
98         const filename = "<standard input>"
99         if file := parse(fset, filename, src); file != nil {
100                 files[filename] = file
101         }
102         return
103 }
104
105 func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
106         files = make(map[string]*ast.File)
107         for _, filename := range filenames {
108                 src, err := ioutil.ReadFile(filename)
109                 if err != nil {
110                         report(err)
111                         continue
112                 }
113                 if file := parse(fset, filename, src); file != nil {
114                         if files[filename] != nil {
115                                 report(errors.New(fmt.Sprintf("%q: duplicate file", filename)))
116                                 continue
117                         }
118                         files[filename] = file
119                 }
120         }
121         return
122 }
123
124 func isGoFilename(filename string) bool {
125         // ignore non-Go files
126         return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
127 }
128
129 func processDirectory(dirname string) {
130         f, err := os.Open(dirname)
131         if err != nil {
132                 report(err)
133                 return
134         }
135         filenames, err := f.Readdirnames(-1)
136         f.Close()
137         if err != nil {
138                 report(err)
139                 // continue since filenames may not be empty
140         }
141         for i, filename := range filenames {
142                 filenames[i] = filepath.Join(dirname, filename)
143         }
144         processFiles(filenames, false)
145 }
146
147 func processFiles(filenames []string, allFiles bool) {
148         i := 0
149         for _, filename := range filenames {
150                 switch info, err := os.Stat(filename); {
151                 case err != nil:
152                         report(err)
153                 case info.IsRegular():
154                         if allFiles || isGoFilename(info.Name) {
155                                 filenames[i] = filename
156                                 i++
157                         }
158                 case info.IsDirectory():
159                         if allFiles || *recursive {
160                                 processDirectory(filename)
161                         }
162                 }
163         }
164         fset := token.NewFileSet()
165         processPackage(fset, parseFiles(fset, filenames[0:i]))
166 }
167
168 func processPackage(fset *token.FileSet, files map[string]*ast.File) {
169         // make a package (resolve all identifiers)
170         pkg, err := ast.NewPackage(fset, files, types.GcImporter, types.Universe)
171         if err != nil {
172                 report(err)
173                 return
174         }
175         _, err = types.Check(fset, pkg)
176         if err != nil {
177                 report(err)
178         }
179 }
180
181 func main() {
182         flag.Usage = usage
183         flag.Parse()
184
185         if flag.NArg() == 0 {
186                 fset := token.NewFileSet()
187                 processPackage(fset, parseStdin(fset))
188         } else {
189                 processFiles(flag.Args(), true)
190         }
191
192         os.Exit(exitCode)
193 }