OSDN Git Service

libgo: Update to weekly.2012-03-27 aka go1 release.
[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         parseComments = flag.Bool("comments", false, "parse comments (ignored if -ast not set)")
31         printTrace    = flag.Bool("trace", false, "print parse trace")
32         printAST      = flag.Bool("ast", false, "print AST")
33 )
34
35 var exitCode = 0
36
37 func usage() {
38         fmt.Fprintf(os.Stderr, "usage: gotype [flags] [path ...]\n")
39         flag.PrintDefaults()
40         os.Exit(2)
41 }
42
43 func report(err error) {
44         scanner.PrintError(os.Stderr, err)
45         exitCode = 2
46 }
47
48 // parse returns the AST for the Go source src.
49 // The filename is for error reporting only.
50 // The result is nil if there were errors or if
51 // the file does not belong to the -p package.
52 func parse(fset *token.FileSet, filename string, src []byte) *ast.File {
53         if *verbose {
54                 fmt.Println(filename)
55         }
56
57         // ignore files with different package name
58         if *pkgName != "" {
59                 file, err := parser.ParseFile(fset, filename, src, parser.PackageClauseOnly)
60                 if err != nil {
61                         report(err)
62                         return nil
63                 }
64                 if file.Name.Name != *pkgName {
65                         if *verbose {
66                                 fmt.Printf("\tignored (package %s)\n", file.Name.Name)
67                         }
68                         return nil
69                 }
70         }
71
72         // parse entire file
73         mode := parser.DeclarationErrors
74         if *allErrors {
75                 mode |= parser.SpuriousErrors
76         }
77         if *parseComments && *printAST {
78                 mode |= parser.ParseComments
79         }
80         if *printTrace {
81                 mode |= parser.Trace
82         }
83         file, err := parser.ParseFile(fset, filename, src, mode)
84         if err != nil {
85                 report(err)
86                 return nil
87         }
88         if *printAST {
89                 ast.Print(fset, file)
90         }
91
92         return file
93 }
94
95 func parseStdin(fset *token.FileSet) (files map[string]*ast.File) {
96         files = make(map[string]*ast.File)
97         src, err := ioutil.ReadAll(os.Stdin)
98         if err != nil {
99                 report(err)
100                 return
101         }
102         const filename = "<standard input>"
103         if file := parse(fset, filename, src); file != nil {
104                 files[filename] = file
105         }
106         return
107 }
108
109 func parseFiles(fset *token.FileSet, filenames []string) (files map[string]*ast.File) {
110         files = make(map[string]*ast.File)
111         for _, filename := range filenames {
112                 src, err := ioutil.ReadFile(filename)
113                 if err != nil {
114                         report(err)
115                         continue
116                 }
117                 if file := parse(fset, filename, src); file != nil {
118                         if files[filename] != nil {
119                                 report(errors.New(fmt.Sprintf("%q: duplicate file", filename)))
120                                 continue
121                         }
122                         files[filename] = file
123                 }
124         }
125         return
126 }
127
128 func isGoFilename(filename string) bool {
129         // ignore non-Go files
130         return !strings.HasPrefix(filename, ".") && strings.HasSuffix(filename, ".go")
131 }
132
133 func processDirectory(dirname string) {
134         f, err := os.Open(dirname)
135         if err != nil {
136                 report(err)
137                 return
138         }
139         filenames, err := f.Readdirnames(-1)
140         f.Close()
141         if err != nil {
142                 report(err)
143                 // continue since filenames may not be empty
144         }
145         for i, filename := range filenames {
146                 filenames[i] = filepath.Join(dirname, filename)
147         }
148         processFiles(filenames, false)
149 }
150
151 func processFiles(filenames []string, allFiles bool) {
152         i := 0
153         for _, filename := range filenames {
154                 switch info, err := os.Stat(filename); {
155                 case err != nil:
156                         report(err)
157                 case info.IsDir():
158                         if allFiles || *recursive {
159                                 processDirectory(filename)
160                         }
161                 default:
162                         if allFiles || isGoFilename(info.Name()) {
163                                 filenames[i] = filename
164                                 i++
165                         }
166                 }
167         }
168         fset := token.NewFileSet()
169         processPackage(fset, parseFiles(fset, filenames[0:i]))
170 }
171
172 func processPackage(fset *token.FileSet, files map[string]*ast.File) {
173         // make a package (resolve all identifiers)
174         pkg, err := ast.NewPackage(fset, files, types.GcImport, types.Universe)
175         if err != nil {
176                 report(err)
177                 return
178         }
179         _, err = types.Check(fset, pkg)
180         if err != nil {
181                 report(err)
182         }
183 }
184
185 func main() {
186         flag.Usage = usage
187         flag.Parse()
188
189         if flag.NArg() == 0 {
190                 fset := token.NewFileSet()
191                 processPackage(fset, parseStdin(fset))
192         } else {
193                 processFiles(flag.Args(), true)
194         }
195
196         os.Exit(exitCode)
197 }