Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(894)

Side by Side Diff: src/pkg/go/doc/example.go

Issue 6524047: code review 6524047: go/doc: strip example output comment from synthesized m... (Closed)
Patch Set: diff -r 838111caecdd https://go.googlecode.com/hg Created 11 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2011 The Go Authors. All rights reserved. 1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // Extract example functions from file ASTs. 5 // Extract example functions from file ASTs.
6 6
7 package doc 7 package doc
8 8
9 import ( 9 import (
10 "go/ast" 10 "go/ast"
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
54 var doc string 54 var doc string
55 if f.Doc != nil { 55 if f.Doc != nil {
56 doc = f.Doc.Text() 56 doc = f.Doc.Text()
57 } 57 }
58 flist = append(flist, &Example{ 58 flist = append(flist, &Example{
59 Name: name[len("Example"):], 59 Name: name[len("Example"):],
60 Doc: doc, 60 Doc: doc,
61 Code: f.Body, 61 Code: f.Body,
62 Play: playExample(file, f.Body), 62 Play: playExample(file, f.Body),
63 Comments: file.Comments, 63 Comments: file.Comments,
64 » » » » Output: exampleOutput(f, file.Comments), 64 » » » » Output: exampleOutput(f.Body, file.Comments),
65 }) 65 })
66 } 66 }
67 if !hasTests && numDecl > 1 && len(flist) == 1 { 67 if !hasTests && numDecl > 1 && len(flist) == 1 {
68 // If this file only has one example function, some 68 // If this file only has one example function, some
69 // other top-level declarations, and no tests or 69 // other top-level declarations, and no tests or
70 // benchmarks, use the whole file as the example. 70 // benchmarks, use the whole file as the example.
71 flist[0].Code = file 71 flist[0].Code = file
72 } 72 }
73 list = append(list, flist...) 73 list = append(list, flist...)
74 } 74 }
75 sort.Sort(exampleByName(list)) 75 sort.Sort(exampleByName(list))
76 return list 76 return list
77 } 77 }
78 78
79 var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`) 79 var outputPrefix = regexp.MustCompile(`(?i)^[[:space:]]*output:`)
80 80
81 func exampleOutput(fun *ast.FuncDecl, comments []*ast.CommentGroup) string { 81 func exampleOutput(b *ast.BlockStmt, comments []*ast.CommentGroup) string {
82 // find the last comment in the function 82 // find the last comment in the function
83 var last *ast.CommentGroup 83 var last *ast.CommentGroup
84 for _, cg := range comments { 84 for _, cg := range comments {
85 » » if cg.Pos() < fun.Pos() { 85 » » if cg.Pos() < b.Pos() {
86 continue 86 continue
87 } 87 }
88 » » if cg.End() > fun.End() { 88 » » if cg.End() > b.End() {
89 break 89 break
90 } 90 }
91 last = cg 91 last = cg
92 } 92 }
93 if last != nil { 93 if last != nil {
94 // test that it begins with the correct prefix 94 // test that it begins with the correct prefix
95 text := last.Text() 95 text := last.Text()
96 if loc := outputPrefix.FindStringIndex(text); loc != nil { 96 if loc := outputPrefix.FindStringIndex(text); loc != nil {
97 » » » return strings.TrimSpace(text[loc[1]:]) 97 » » » return strings.TrimSpace(last.Text()[loc[1]:])
gri 2012/09/28 18:03:38 Why is text here not ok? it there's a reason, it n
adg 2012/10/01 22:35:49 This was an accident of some experimentation I did
98 } 98 }
99 } 99 }
100 return "" // no suitable comment found 100 return "" // no suitable comment found
101 } 101 }
102 102
103 // isTest tells whether name looks like a test, example, or benchmark. 103 // isTest tells whether name looks like a test, example, or benchmark.
104 // It is a Test (say) if there is a character after Test that is not a 104 // It is a Test (say) if there is a character after Test that is not a
105 // lower-case letter. (We don't want Testiness.) 105 // lower-case letter. (We don't want Testiness.)
106 func isTest(name, prefix string) bool { 106 func isTest(name, prefix string) bool {
107 if !strings.HasPrefix(name, prefix) { 107 if !strings.HasPrefix(name, prefix) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
156 n = s.Name.Name 156 n = s.Name.Name
157 } 157 }
158 for _, id := range unresolved { 158 for _, id := range unresolved {
159 if n == id.Name { 159 if n == id.Name {
160 imports[n] = p 160 imports[n] = p
161 break 161 break
162 } 162 }
163 } 163 }
164 } 164 }
165 165
166 // TODO(adg): look for other unresolved identifiers and, if found, give up.
167
168 // Synthesize new imports. 166 // Synthesize new imports.
169 importDecl := &ast.GenDecl{ 167 importDecl := &ast.GenDecl{
170 Tok: token.IMPORT, 168 Tok: token.IMPORT,
171 Lparen: 1, // Need non-zero Lparen and Rparen so that printer 169 Lparen: 1, // Need non-zero Lparen and Rparen so that printer
172 Rparen: 1, // treats this as a factored import. 170 Rparen: 1, // treats this as a factored import.
173 } 171 }
174 for n, p := range imports { 172 for n, p := range imports {
175 s := &ast.ImportSpec{Path: &ast.BasicLit{Value: strconv.Quote(p) }} 173 s := &ast.ImportSpec{Path: &ast.BasicLit{Value: strconv.Quote(p) }}
176 if path.Base(p) != n { 174 if path.Base(p) != n {
177 s.Name = ast.NewIdent(n) 175 s.Name = ast.NewIdent(n)
178 } 176 }
179 importDecl.Specs = append(importDecl.Specs, s) 177 importDecl.Specs = append(importDecl.Specs, s)
180 } 178 }
181 179
182 » // Synthesize main function. 180 » // TODO(adg): look for other unresolved identifiers and, if found, give up.
183 » funcDecl := &ast.FuncDecl{
184 » » Name: ast.NewIdent("main"),
185 » » Type: &ast.FuncType{},
186 » » Body: body,
187 » }
188 181
189 // Filter out comments that are outside the function body. 182 // Filter out comments that are outside the function body.
190 var comments []*ast.CommentGroup 183 var comments []*ast.CommentGroup
191 for _, c := range file.Comments { 184 for _, c := range file.Comments {
192 if c.Pos() < body.Pos() || c.Pos() >= body.End() { 185 if c.Pos() < body.Pos() || c.Pos() >= body.End() {
193 continue 186 continue
194 } 187 }
195 comments = append(comments, c) 188 comments = append(comments, c)
196 } 189 }
197 190
191 // Strip "Output:" commment and adjust body end position.
192 if len(comments) > 0 {
193 last := comments[len(comments)-1]
194 if outputPrefix.MatchString(last.Text()) {
195 comments = comments[:len(comments)-1]
196 // Copy body, as the original may be used elsewhere.
197 body = &ast.BlockStmt{
198 Lbrace: body.Pos(),
199 List: body.List,
200 Rbrace: last.Pos(),
201 }
202 }
203 }
204
205 // Synthesize main function.
206 funcDecl := &ast.FuncDecl{
207 Name: ast.NewIdent("main"),
208 Type: &ast.FuncType{},
209 Body: body,
210 }
211
198 // Synthesize file. 212 // Synthesize file.
199 f := &ast.File{ 213 f := &ast.File{
200 Name: ast.NewIdent("main"), 214 Name: ast.NewIdent("main"),
201 Decls: []ast.Decl{importDecl, funcDecl}, 215 Decls: []ast.Decl{importDecl, funcDecl},
202 Comments: comments, 216 Comments: comments,
203 } 217 }
204 218
205 // TODO(adg): look for resolved identifiers declared outside function sc ope 219 // TODO(adg): look for resolved identifiers declared outside function sc ope
206 // and include their declarations in the new file. 220 // and include their declarations in the new file.
207 221
208 return f 222 return f
209 } 223 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b