diff options
Diffstat (limited to 'src/pkg/go/ast')
-rw-r--r-- | src/pkg/go/ast/Makefile | 1 | ||||
-rw-r--r-- | src/pkg/go/ast/ast.go | 180 | ||||
-rw-r--r-- | src/pkg/go/ast/filter.go | 109 | ||||
-rw-r--r-- | src/pkg/go/ast/import.go | 134 | ||||
-rw-r--r-- | src/pkg/go/ast/print.go | 36 | ||||
-rw-r--r-- | src/pkg/go/ast/print_test.go | 17 | ||||
-rw-r--r-- | src/pkg/go/ast/resolve.go | 7 | ||||
-rw-r--r-- | src/pkg/go/ast/scope.go | 10 |
8 files changed, 363 insertions, 131 deletions
diff --git a/src/pkg/go/ast/Makefile b/src/pkg/go/ast/Makefile index 40be10208..30c386cd8 100644 --- a/src/pkg/go/ast/Makefile +++ b/src/pkg/go/ast/Makefile @@ -8,6 +8,7 @@ TARG=go/ast GOFILES=\ ast.go\ filter.go\ + import.go\ print.go\ resolve.go\ scope.go\ diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go index 22bd5ee22..7123fe58f 100644 --- a/src/pkg/go/ast/ast.go +++ b/src/pkg/go/ast/ast.go @@ -9,8 +9,9 @@ package ast import ( "go/token" + "strings" "unicode" - "utf8" + "unicode/utf8" ) // ---------------------------------------------------------------------------- @@ -76,6 +77,74 @@ type CommentGroup struct { func (g *CommentGroup) Pos() token.Pos { return g.List[0].Pos() } func (g *CommentGroup) End() token.Pos { return g.List[len(g.List)-1].End() } +func isWhitespace(ch byte) bool { return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r' } + +func stripTrailingWhitespace(s string) string { + i := len(s) + for i > 0 && isWhitespace(s[i-1]) { + i-- + } + return s[0:i] +} + +// Text returns the text of the comment, +// with the comment markers - //, /*, and */ - removed. +func (g *CommentGroup) Text() string { + if g == nil { + return "" + } + comments := make([]string, len(g.List)) + for i, c := range g.List { + comments[i] = string(c.Text) + } + + lines := make([]string, 0, 10) // most comments are less than 10 lines + for _, c := range comments { + // Remove comment markers. + // The parser has given us exactly the comment text. + switch c[1] { + case '/': + //-style comment + c = c[2:] + // Remove leading space after //, if there is one. + // TODO(gri) This appears to be necessary in isolated + // cases (bignum.RatFromString) - why? + if len(c) > 0 && c[0] == ' ' { + c = c[1:] + } + case '*': + /*-style comment */ + c = c[2 : len(c)-2] + } + + // Split on newlines. + cl := strings.Split(c, "\n") + + // Walk lines, stripping trailing white space and adding to list. + for _, l := range cl { + lines = append(lines, stripTrailingWhitespace(l)) + } + } + + // Remove leading blank lines; convert runs of + // interior blank lines to a single blank line. + n := 0 + for _, line := range lines { + if line != "" || n > 0 && lines[n-1] != "" { + lines[n] = line + n++ + } + } + lines = lines[0:n] + + // Add final "" entry to get trailing newline from Join. + if n > 0 && lines[n-1] != "" { + lines = append(lines, "") + } + + return strings.Join(lines, "\n") +} + // ---------------------------------------------------------------------------- // Expressions and types @@ -412,29 +481,29 @@ func (x *ChanType) End() token.Pos { return x.Value.End() } // exprNode() ensures that only expression/type nodes can be // assigned to an ExprNode. // -func (x *BadExpr) exprNode() {} -func (x *Ident) exprNode() {} -func (x *Ellipsis) exprNode() {} -func (x *BasicLit) exprNode() {} -func (x *FuncLit) exprNode() {} -func (x *CompositeLit) exprNode() {} -func (x *ParenExpr) exprNode() {} -func (x *SelectorExpr) exprNode() {} -func (x *IndexExpr) exprNode() {} -func (x *SliceExpr) exprNode() {} -func (x *TypeAssertExpr) exprNode() {} -func (x *CallExpr) exprNode() {} -func (x *StarExpr) exprNode() {} -func (x *UnaryExpr) exprNode() {} -func (x *BinaryExpr) exprNode() {} -func (x *KeyValueExpr) exprNode() {} - -func (x *ArrayType) exprNode() {} -func (x *StructType) exprNode() {} -func (x *FuncType) exprNode() {} -func (x *InterfaceType) exprNode() {} -func (x *MapType) exprNode() {} -func (x *ChanType) exprNode() {} +func (*BadExpr) exprNode() {} +func (*Ident) exprNode() {} +func (*Ellipsis) exprNode() {} +func (*BasicLit) exprNode() {} +func (*FuncLit) exprNode() {} +func (*CompositeLit) exprNode() {} +func (*ParenExpr) exprNode() {} +func (*SelectorExpr) exprNode() {} +func (*IndexExpr) exprNode() {} +func (*SliceExpr) exprNode() {} +func (*TypeAssertExpr) exprNode() {} +func (*CallExpr) exprNode() {} +func (*StarExpr) exprNode() {} +func (*UnaryExpr) exprNode() {} +func (*BinaryExpr) exprNode() {} +func (*KeyValueExpr) exprNode() {} + +func (*ArrayType) exprNode() {} +func (*StructType) exprNode() {} +func (*FuncType) exprNode() {} +func (*InterfaceType) exprNode() {} +func (*MapType) exprNode() {} +func (*ChanType) exprNode() {} // ---------------------------------------------------------------------------- // Convenience functions for Idents @@ -711,27 +780,27 @@ func (s *RangeStmt) End() token.Pos { return s.Body.End() } // stmtNode() ensures that only statement nodes can be // assigned to a StmtNode. // -func (s *BadStmt) stmtNode() {} -func (s *DeclStmt) stmtNode() {} -func (s *EmptyStmt) stmtNode() {} -func (s *LabeledStmt) stmtNode() {} -func (s *ExprStmt) stmtNode() {} -func (s *SendStmt) stmtNode() {} -func (s *IncDecStmt) stmtNode() {} -func (s *AssignStmt) stmtNode() {} -func (s *GoStmt) stmtNode() {} -func (s *DeferStmt) stmtNode() {} -func (s *ReturnStmt) stmtNode() {} -func (s *BranchStmt) stmtNode() {} -func (s *BlockStmt) stmtNode() {} -func (s *IfStmt) stmtNode() {} -func (s *CaseClause) stmtNode() {} -func (s *SwitchStmt) stmtNode() {} -func (s *TypeSwitchStmt) stmtNode() {} -func (s *CommClause) stmtNode() {} -func (s *SelectStmt) stmtNode() {} -func (s *ForStmt) stmtNode() {} -func (s *RangeStmt) stmtNode() {} +func (*BadStmt) stmtNode() {} +func (*DeclStmt) stmtNode() {} +func (*EmptyStmt) stmtNode() {} +func (*LabeledStmt) stmtNode() {} +func (*ExprStmt) stmtNode() {} +func (*SendStmt) stmtNode() {} +func (*IncDecStmt) stmtNode() {} +func (*AssignStmt) stmtNode() {} +func (*GoStmt) stmtNode() {} +func (*DeferStmt) stmtNode() {} +func (*ReturnStmt) stmtNode() {} +func (*BranchStmt) stmtNode() {} +func (*BlockStmt) stmtNode() {} +func (*IfStmt) stmtNode() {} +func (*CaseClause) stmtNode() {} +func (*SwitchStmt) stmtNode() {} +func (*TypeSwitchStmt) stmtNode() {} +func (*CommClause) stmtNode() {} +func (*SelectStmt) stmtNode() {} +func (*ForStmt) stmtNode() {} +func (*RangeStmt) stmtNode() {} // ---------------------------------------------------------------------------- // Declarations @@ -752,6 +821,7 @@ type ( Name *Ident // local package name (including "."); or nil Path *BasicLit // import path Comment *CommentGroup // line comments; or nil + EndPos token.Pos // end of spec (overrides Path.Pos if nonzero) } // A ValueSpec node represents a constant or variable declaration @@ -785,7 +855,13 @@ func (s *ImportSpec) Pos() token.Pos { func (s *ValueSpec) Pos() token.Pos { return s.Names[0].Pos() } func (s *TypeSpec) Pos() token.Pos { return s.Name.Pos() } -func (s *ImportSpec) End() token.Pos { return s.Path.End() } +func (s *ImportSpec) End() token.Pos { + if s.EndPos != 0 { + return s.EndPos + } + return s.Path.End() +} + func (s *ValueSpec) End() token.Pos { if n := len(s.Values); n > 0 { return s.Values[n-1].End() @@ -800,9 +876,9 @@ func (s *TypeSpec) End() token.Pos { return s.Type.End() } // specNode() ensures that only spec nodes can be // assigned to a Spec. // -func (s *ImportSpec) specNode() {} -func (s *ValueSpec) specNode() {} -func (s *TypeSpec) specNode() {} +func (*ImportSpec) specNode() {} +func (*ValueSpec) specNode() {} +func (*TypeSpec) specNode() {} // A declaration is represented by one of the following declaration nodes. // @@ -868,9 +944,9 @@ func (d *FuncDecl) End() token.Pos { // declNode() ensures that only declaration nodes can be // assigned to a DeclNode. // -func (d *BadDecl) declNode() {} -func (d *GenDecl) declNode() {} -func (d *FuncDecl) declNode() {} +func (*BadDecl) declNode() {} +func (*GenDecl) declNode() {} +func (*FuncDecl) declNode() {} // ---------------------------------------------------------------------------- // Files and packages diff --git a/src/pkg/go/ast/filter.go b/src/pkg/go/ast/filter.go index 1bd8990f8..4a89b8909 100644 --- a/src/pkg/go/ast/filter.go +++ b/src/pkg/go/ast/filter.go @@ -4,7 +4,10 @@ package ast -import "go/token" +import ( + "go/token" + "sort" +) // ---------------------------------------------------------------------------- // Export filtering @@ -18,14 +21,13 @@ func exportFilter(name string) bool { // only exported nodes remain: all top-level identifiers which are not exported // and their associated information (such as type, initial value, or function // body) are removed. Non-exported fields and methods of exported types are -// stripped, and the function bodies of exported functions are set to nil. -// The File.Comments list is not changed. +// stripped. The File.Comments list is not changed. // -// FileExports returns true if there are exported declarationa; +// FileExports returns true if there are exported declarations; // it returns false otherwise. // func FileExports(src *File) bool { - return FilterFile(src, exportFilter) + return filterFile(src, exportFilter, true) } // PackageExports trims the AST for a Go package in place such that @@ -36,7 +38,7 @@ func FileExports(src *File) bool { // it returns false otherwise. // func PackageExports(pkg *Package) bool { - return FilterPackage(pkg, exportFilter) + return filterPackage(pkg, exportFilter, true) } // ---------------------------------------------------------------------------- @@ -73,7 +75,7 @@ func fieldName(x Expr) *Ident { return nil } -func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) { +func filterFieldList(fields *FieldList, filter Filter, export bool) (removedFields bool) { if fields == nil { return false } @@ -94,8 +96,8 @@ func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) { keepField = len(f.Names) > 0 } if keepField { - if filter == exportFilter { - filterType(f.Type, filter) + if export { + filterType(f.Type, filter, export) } list[j] = f j++ @@ -108,84 +110,84 @@ func filterFieldList(fields *FieldList, filter Filter) (removedFields bool) { return } -func filterParamList(fields *FieldList, filter Filter) bool { +func filterParamList(fields *FieldList, filter Filter, export bool) bool { if fields == nil { return false } var b bool for _, f := range fields.List { - if filterType(f.Type, filter) { + if filterType(f.Type, filter, export) { b = true } } return b } -func filterType(typ Expr, f Filter) bool { +func filterType(typ Expr, f Filter, export bool) bool { switch t := typ.(type) { case *Ident: return f(t.Name) case *ParenExpr: - return filterType(t.X, f) + return filterType(t.X, f, export) case *ArrayType: - return filterType(t.Elt, f) + return filterType(t.Elt, f, export) case *StructType: - if filterFieldList(t.Fields, f) { + if filterFieldList(t.Fields, f, export) { t.Incomplete = true } return len(t.Fields.List) > 0 case *FuncType: - b1 := filterParamList(t.Params, f) - b2 := filterParamList(t.Results, f) + b1 := filterParamList(t.Params, f, export) + b2 := filterParamList(t.Results, f, export) return b1 || b2 case *InterfaceType: - if filterFieldList(t.Methods, f) { + if filterFieldList(t.Methods, f, export) { t.Incomplete = true } return len(t.Methods.List) > 0 case *MapType: - b1 := filterType(t.Key, f) - b2 := filterType(t.Value, f) + b1 := filterType(t.Key, f, export) + b2 := filterType(t.Value, f, export) return b1 || b2 case *ChanType: - return filterType(t.Value, f) + return filterType(t.Value, f, export) } return false } -func filterSpec(spec Spec, f Filter) bool { +func filterSpec(spec Spec, f Filter, export bool) bool { switch s := spec.(type) { case *ValueSpec: s.Names = filterIdentList(s.Names, f) if len(s.Names) > 0 { - if f == exportFilter { - filterType(s.Type, f) + if export { + filterType(s.Type, f, export) } return true } case *TypeSpec: if f(s.Name.Name) { - if f == exportFilter { - filterType(s.Type, f) + if export { + filterType(s.Type, f, export) } return true } - if f != exportFilter { + if !export { // For general filtering (not just exports), // filter type even if name is not filtered // out. // If the type contains filtered elements, // keep the declaration. - return filterType(s.Type, f) + return filterType(s.Type, f, export) } } return false } -func filterSpecList(list []Spec, f Filter) []Spec { +func filterSpecList(list []Spec, f Filter, export bool) []Spec { j := 0 for _, s := range list { - if filterSpec(s, f) { + if filterSpec(s, f, export) { list[j] = s j++ } @@ -201,14 +203,15 @@ func filterSpecList(list []Spec, f Filter) []Spec { // filtering; it returns false otherwise. // func FilterDecl(decl Decl, f Filter) bool { + return filterDecl(decl, f, false) +} + +func filterDecl(decl Decl, f Filter, export bool) bool { switch d := decl.(type) { case *GenDecl: - d.Specs = filterSpecList(d.Specs, f) + d.Specs = filterSpecList(d.Specs, f, export) return len(d.Specs) > 0 case *FuncDecl: - if f == exportFilter { - d.Body = nil // strip body - } return f(d.Name.Name) } return false @@ -225,9 +228,13 @@ func FilterDecl(decl Decl, f Filter) bool { // left after filtering; it returns false otherwise. // func FilterFile(src *File, f Filter) bool { + return filterFile(src, f, false) +} + +func filterFile(src *File, f Filter, export bool) bool { j := 0 for _, d := range src.Decls { - if FilterDecl(d, f) { + if filterDecl(d, f, export) { src.Decls[j] = d j++ } @@ -248,9 +255,13 @@ func FilterFile(src *File, f Filter) bool { // left after filtering; it returns false otherwise. // func FilterPackage(pkg *Package, f Filter) bool { + return filterPackage(pkg, f, false) +} + +func filterPackage(pkg *Package, f Filter, export bool) bool { hasDecls := false for _, src := range pkg.Files { - if FilterFile(src, f) { + if filterFile(src, f, export) { hasDecls = true } } @@ -283,29 +294,35 @@ var separator = &Comment{noPos, "//"} // func MergePackageFiles(pkg *Package, mode MergeMode) *File { // Count the number of package docs, comments and declarations across - // all package files. + // all package files. Also, compute sorted list of filenames, so that + // subsequent iterations can always iterate in the same order. ndocs := 0 ncomments := 0 ndecls := 0 - for _, f := range pkg.Files { + filenames := make([]string, len(pkg.Files)) + i := 0 + for filename, f := range pkg.Files { + filenames[i] = filename + i++ if f.Doc != nil { ndocs += len(f.Doc.List) + 1 // +1 for separator } ncomments += len(f.Comments) ndecls += len(f.Decls) } + sort.Strings(filenames) // Collect package comments from all package files into a single - // CommentGroup - the collected package documentation. The order - // is unspecified. In general there should be only one file with - // a package comment; but it's better to collect extra comments - // than drop them on the floor. + // CommentGroup - the collected package documentation. In general + // there should be only one file with a package comment; but it's + // better to collect extra comments than drop them on the floor. var doc *CommentGroup var pos token.Pos if ndocs > 0 { list := make([]*Comment, ndocs-1) // -1: no separator before first group i := 0 - for _, f := range pkg.Files { + for _, filename := range filenames { + f := pkg.Files[filename] if f.Doc != nil { if i > 0 { // not the first group - add separator @@ -334,7 +351,8 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File { funcs := make(map[string]int) // map of global function name -> decls index i := 0 // current index n := 0 // number of filtered entries - for _, f := range pkg.Files { + for _, filename := range filenames { + f := pkg.Files[filename] for _, d := range f.Decls { if mode&FilterFuncDuplicates != 0 { // A language entity may be declared multiple @@ -390,7 +408,8 @@ func MergePackageFiles(pkg *Package, mode MergeMode) *File { var imports []*ImportSpec if mode&FilterImportDuplicates != 0 { seen := make(map[string]bool) - for _, f := range pkg.Files { + for _, filename := range filenames { + f := pkg.Files[filename] for _, imp := range f.Imports { if path := imp.Path.Value; !seen[path] { // TODO: consider handling cases where: diff --git a/src/pkg/go/ast/import.go b/src/pkg/go/ast/import.go new file mode 100644 index 000000000..2d4f69aae --- /dev/null +++ b/src/pkg/go/ast/import.go @@ -0,0 +1,134 @@ +// 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 ast + +import ( + "go/token" + "sort" + "strconv" +) + +// SortImports sorts runs of consecutive import lines in import blocks in f. +func SortImports(fset *token.FileSet, f *File) { + for _, d := range f.Decls { + d, ok := d.(*GenDecl) + if !ok || d.Tok != token.IMPORT { + // Not an import declaration, so we're done. + // Imports are always first. + break + } + + if d.Lparen == token.NoPos { + // Not a block: sorted by default. + continue + } + + // Identify and sort runs of specs on successive lines. + i := 0 + for j, s := range d.Specs { + if j > i && fset.Position(s.Pos()).Line > 1+fset.Position(d.Specs[j-1].End()).Line { + // j begins a new run. End this one. + sortSpecs(fset, f, d.Specs[i:j]) + i = j + } + } + sortSpecs(fset, f, d.Specs[i:]) + } +} + +func importPath(s Spec) string { + t, err := strconv.Unquote(s.(*ImportSpec).Path.Value) + if err == nil { + return t + } + return "" +} + +type posSpan struct { + Start token.Pos + End token.Pos +} + +func sortSpecs(fset *token.FileSet, f *File, specs []Spec) { + // Avoid work if already sorted (also catches < 2 entries). + sorted := true + for i, s := range specs { + if i > 0 && importPath(specs[i-1]) > importPath(s) { + sorted = false + break + } + } + if sorted { + return + } + + // Record positions for specs. + pos := make([]posSpan, len(specs)) + for i, s := range specs { + pos[i] = posSpan{s.Pos(), s.End()} + } + + // Identify comments in this range. + // Any comment from pos[0].Start to the final line counts. + lastLine := fset.Position(pos[len(pos)-1].End).Line + cstart := len(f.Comments) + cend := len(f.Comments) + for i, g := range f.Comments { + if g.Pos() < pos[0].Start { + continue + } + if i < cstart { + cstart = i + } + if fset.Position(g.End()).Line > lastLine { + cend = i + break + } + } + comments := f.Comments[cstart:cend] + + // Assign each comment to the import spec preceding it. + importComment := map[*ImportSpec][]*CommentGroup{} + specIndex := 0 + for _, g := range comments { + for specIndex+1 < len(specs) && pos[specIndex+1].Start <= g.Pos() { + specIndex++ + } + s := specs[specIndex].(*ImportSpec) + importComment[s] = append(importComment[s], g) + } + + // Sort the import specs by import path. + // Reassign the import paths to have the same position sequence. + // Reassign each comment to abut the end of its spec. + // Sort the comments by new position. + sort.Sort(byImportPath(specs)) + for i, s := range specs { + s := s.(*ImportSpec) + if s.Name != nil { + s.Name.NamePos = pos[i].Start + } + s.Path.ValuePos = pos[i].Start + s.EndPos = pos[i].End + for _, g := range importComment[s] { + for _, c := range g.List { + c.Slash = pos[i].End + } + } + } + sort.Sort(byCommentPos(comments)) +} + +type byImportPath []Spec // slice of *ImportSpec + +func (x byImportPath) Len() int { return len(x) } +func (x byImportPath) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x byImportPath) Less(i, j int) bool { return importPath(x[i]) < importPath(x[j]) } + +type byCommentPos []*CommentGroup + +func (x byCommentPos) Len() int { return len(x) } +func (x byCommentPos) Swap(i, j int) { x[i], x[j] = x[j], x[i] } +func (x byCommentPos) Less(i, j int) bool { return x[i].Pos() < x[j].Pos() } diff --git a/src/pkg/go/ast/print.go b/src/pkg/go/ast/print.go index 62a30481d..f6c63c0d8 100644 --- a/src/pkg/go/ast/print.go +++ b/src/pkg/go/ast/print.go @@ -36,7 +36,7 @@ func NotNilFilter(_ string, v reflect.Value) bool { // struct fields for which f(fieldname, fieldvalue) is true are // are printed; all others are filtered from the output. // -func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n int, err os.Error) { +func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (err error) { // setup printer p := printer{ output: w, @@ -48,7 +48,6 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i // install error handler defer func() { - n = p.written if e := recover(); e != nil { err = e.(localError).err // re-panics if it's not a localError } @@ -67,24 +66,23 @@ func Fprint(w io.Writer, fset *token.FileSet, x interface{}, f FieldFilter) (n i // Print prints x to standard output, skipping nil fields. // Print(fset, x) is the same as Fprint(os.Stdout, fset, x, NotNilFilter). -func Print(fset *token.FileSet, x interface{}) (int, os.Error) { +func Print(fset *token.FileSet, x interface{}) error { return Fprint(os.Stdout, fset, x, NotNilFilter) } type printer struct { - output io.Writer - fset *token.FileSet - filter FieldFilter - ptrmap map[interface{}]int // *T -> line number - written int // number of bytes written to output - indent int // current indentation level - last byte // the last byte processed by Write - line int // current line number + output io.Writer + fset *token.FileSet + filter FieldFilter + ptrmap map[interface{}]int // *T -> line number + indent int // current indentation level + last byte // the last byte processed by Write + line int // current line number } var indent = []byte(". ") -func (p *printer) Write(data []byte) (n int, err os.Error) { +func (p *printer) Write(data []byte) (n int, err error) { var m int for i, b := range data { // invariant: data[0:n] has been written @@ -114,17 +112,15 @@ func (p *printer) Write(data []byte) (n int, err os.Error) { return } -// localError wraps locally caught os.Errors so we can distinguish +// localError wraps locally caught errors so we can distinguish // them from genuine panics which we don't want to return as errors. type localError struct { - err os.Error + err error } // printf is a convenience wrapper that takes care of print errors. func (p *printer) printf(format string, args ...interface{}) { - n, err := fmt.Fprintf(p, format, args...) - p.written += n - if err != nil { + if _, err := fmt.Fprintf(p, format, args...); err != nil { panic(localError{err}) } } @@ -149,7 +145,7 @@ func (p *printer) print(x reflect.Value) { p.print(x.Elem()) case reflect.Map: - p.printf("%s (len = %d) {\n", x.Type().String(), x.Len()) + p.printf("%s (len = %d) {\n", x.Type(), x.Len()) p.indent++ for _, key := range x.MapKeys() { p.print(key) @@ -178,7 +174,7 @@ func (p *printer) print(x reflect.Value) { p.printf("%#q", s) return } - p.printf("%s (len = %d) {\n", x.Type().String(), x.Len()) + p.printf("%s (len = %d) {\n", x.Type(), x.Len()) p.indent++ for i, n := 0, x.Len(); i < n; i++ { p.printf("%d: ", i) @@ -189,7 +185,7 @@ func (p *printer) print(x reflect.Value) { p.printf("}") case reflect.Struct: - p.printf("%s {\n", x.Type().String()) + p.printf("%s {\n", x.Type()) p.indent++ t := x.Type() for i, n := 0, t.NumField(); i < n; i++ { diff --git a/src/pkg/go/ast/print_test.go b/src/pkg/go/ast/print_test.go index f4e8f7a78..71c028e75 100644 --- a/src/pkg/go/ast/print_test.go +++ b/src/pkg/go/ast/print_test.go @@ -23,11 +23,10 @@ var tests = []struct { {"foobar", "0 \"foobar\""}, // maps - {map[string]int{"a": 1, "b": 2}, - `0 map[string] int (len = 2) { + {map[string]int{"a": 1}, + `0 map[string]int (len = 1) { 1 . "a": 1 - 2 . "b": 2 - 3 }`}, + 2 }`}, // pointers {new(int), "0 *0"}, @@ -41,10 +40,10 @@ var tests = []struct { 4 }`}, // structs - {struct{ x, y int }{42, 991}, - `0 struct { x int; y int } { - 1 . x: 42 - 2 . y: 991 + {struct{ X, Y int }{42, 991}, + `0 struct { X int; Y int } { + 1 . X: 42 + 2 . Y: 991 3 }`}, } @@ -67,7 +66,7 @@ func TestPrint(t *testing.T) { var buf bytes.Buffer for _, test := range tests { buf.Reset() - if _, err := Fprint(&buf, nil, test.x, nil); err != nil { + if err := Fprint(&buf, nil, test.x, nil); err != nil { t.Errorf("Fprint failed: %s", err) } if s, ts := trim(buf.String()), trim(test.s); s != ts { diff --git a/src/pkg/go/ast/resolve.go b/src/pkg/go/ast/resolve.go index 3927a799e..c7c8e7c10 100644 --- a/src/pkg/go/ast/resolve.go +++ b/src/pkg/go/ast/resolve.go @@ -10,7 +10,6 @@ import ( "fmt" "go/scanner" "go/token" - "os" "strconv" ) @@ -61,7 +60,7 @@ func resolve(scope *Scope, ident *Ident) bool { // Importer should load the package data for the given path into // a new *Object (pkg), record pkg in the imports map, and then // return pkg. -type Importer func(imports map[string]*Object, path string) (pkg *Object, err os.Error) +type Importer func(imports map[string]*Object, path string) (pkg *Object, err error) // NewPackage creates a new Package node from a set of File nodes. It resolves // unresolved identifiers across files and updates each file's Unresolved list @@ -72,7 +71,7 @@ type Importer func(imports map[string]*Object, path string) (pkg *Object, err os // different package names are reported and then ignored. // The result is a package node and a scanner.ErrorList if there were errors. // -func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, os.Error) { +func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, universe *Scope) (*Package, error) { var p pkgBuilder p.fset = fset @@ -114,7 +113,7 @@ func NewPackage(fset *token.FileSet, files map[string]*File, importer Importer, importErrors = true continue } - path, _ := strconv.Unquote(string(spec.Path.Value)) + path, _ := strconv.Unquote(spec.Path.Value) pkg, err := importer(imports, path) if err != nil { p.errorf(spec.Path.Pos(), "could not import %s (%s)", path, err) diff --git a/src/pkg/go/ast/scope.go b/src/pkg/go/ast/scope.go index 92e366980..11e6b13f1 100644 --- a/src/pkg/go/ast/scope.go +++ b/src/pkg/go/ast/scope.go @@ -80,7 +80,7 @@ func (s *Scope) String() string { type Object struct { Kind ObjKind Name string // declared name - Decl interface{} // corresponding Field, XxxSpec, FuncDecl, or LabeledStmt; or nil + Decl interface{} // corresponding Field, XxxSpec, FuncDecl, LabeledStmt, AssignStmt, Scope; or nil Data interface{} // object-specific data; or nil Type interface{} // place holder for type information; may be nil } @@ -125,6 +125,14 @@ func (obj *Object) Pos() token.Pos { if d.Label.Name == name { return d.Label.Pos() } + case *AssignStmt: + for _, x := range d.Lhs { + if ident, isIdent := x.(*Ident); isIdent && ident.Name == name { + return ident.Pos() + } + } + case *Scope: + // predeclared object - nothing to do for now } return token.NoPos } |