| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | // Copyright 2009 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 docPrinter | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"ast"; | 
					
						
							| 
									
										
										
										
											2009-04-02 18:25:18 -07:00
										 |  |  | 	"fmt"; | 
					
						
							|  |  |  | 	"io"; | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	"token"; | 
					
						
							| 
									
										
										
										
											2009-04-02 18:25:18 -07:00
										 |  |  | 	"unicode"; | 
					
						
							|  |  |  | 	"utf8"; | 
					
						
							|  |  |  | 	"vector"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	"astprinter"; | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ---------------------------------------------------------------------------- | 
					
						
							|  |  |  | // Elementary support | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TODO this should be an AST method | 
					
						
							|  |  |  | func isExported(name *ast.Ident) bool { | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 	ch, len := utf8.DecodeRuneInString(name.Value, 0); | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	return unicode.IsUpper(ch); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func hasExportedNames(names []*ast.Ident) bool { | 
					
						
							|  |  |  | 	for i, name := range names { | 
					
						
							|  |  |  | 		if isExported(name) { | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | func hasExportedSpecs(specs []ast.Spec) bool { | 
					
						
							|  |  |  | 	for i, s := range specs { | 
					
						
							|  |  |  | 		// only called for []astSpec lists of *ast.ValueSpec | 
					
						
							|  |  |  | 		return hasExportedNames(s.(*ast.ValueSpec).Names); | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | // ---------------------------------------------------------------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | type valueDoc struct { | 
					
						
							|  |  |  | 	decl *ast.GenDecl;  // len(decl.Specs) >= 1, and the element type is *ast.ValueSpec | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type funcDoc struct { | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	decl *ast.FuncDecl; | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type typeDoc struct { | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	decl *ast.GenDecl;  // len(decl.Specs) == 1, and the element type is *ast.TypeSpec | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 	factories map[string] *funcDoc; | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	methods map[string] *funcDoc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type PackageDoc struct { | 
					
						
							|  |  |  | 	name string;  // package name | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	doc ast.Comments;  // package documentation, if any | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	consts *vector.Vector;  // list of *valueDoc | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	types map[string] *typeDoc; | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	vars *vector.Vector;  // list of *valueDoc | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	funcs map[string] *funcDoc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 18:25:18 -07:00
										 |  |  | func (doc *PackageDoc) PackageName() string { | 
					
						
							|  |  |  | 	return doc.name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | // PackageDoc initializes a document to collect package documentation. | 
					
						
							|  |  |  | // The package name is provided as initial argument. Use AddPackage to | 
					
						
							|  |  |  | // add the AST for each source file belonging to the same package. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | func (doc *PackageDoc) Init(name string) { | 
					
						
							|  |  |  | 	doc.name = name; | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	doc.consts = vector.New(0); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	doc.types = make(map[string] *typeDoc); | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	doc.vars = vector.New(0); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	doc.funcs = make(map[string] *funcDoc); | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | func baseTypeName(typ ast.Expr) string { | 
					
						
							|  |  |  | 	switch t := typ.(type) { | 
					
						
							|  |  |  | 	case *ast.Ident: | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 		return string(t.Value); | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 	case *ast.StarExpr: | 
					
						
							|  |  |  | 		return baseTypeName(t.X); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return ""; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (doc *PackageDoc) lookupTypeDoc(typ ast.Expr) *typeDoc { | 
					
						
							|  |  |  | 	tdoc, found := doc.types[baseTypeName(typ)]; | 
					
						
							|  |  |  | 	if found { | 
					
						
							|  |  |  | 		return tdoc; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return nil; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | func (doc *PackageDoc) addType(decl *ast.GenDecl) { | 
					
						
							|  |  |  | 	typ := decl.Specs[0].(*ast.TypeSpec); | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 	name := typ.Name.Value; | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	tdoc := &typeDoc{decl, make(map[string] *funcDoc), make(map[string] *funcDoc)}; | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	doc.types[name] = tdoc; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | func (doc *PackageDoc) addFunc(fun *ast.FuncDecl) { | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 	name := fun.Name.Value; | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 	fdoc := &funcDoc{fun}; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// determine if it should be associated with a type | 
					
						
							|  |  |  | 	var typ *typeDoc; | 
					
						
							|  |  |  | 	if fun.Recv != nil { | 
					
						
							|  |  |  | 		// method | 
					
						
							| 
									
										
										
										
											2009-04-02 22:39:52 -07:00
										 |  |  | 		// (all receiver types must be declared before they are used) | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 		typ = doc.lookupTypeDoc(fun.Recv.Type); | 
					
						
							|  |  |  | 		if typ != nil { | 
					
						
							| 
									
										
										
										
											2009-04-02 22:39:52 -07:00
										 |  |  | 			// type found (i.e., exported) | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 			typ.methods[name] = fdoc; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-04-02 22:39:52 -07:00
										 |  |  | 		// if the type wasn't found, it wasn't exported | 
					
						
							| 
									
										
										
										
											2009-04-03 16:19:22 -07:00
										 |  |  | 		// TODO: a non-exported type may still have exported functions | 
					
						
							|  |  |  | 		//       determine what to do in that case | 
					
						
							|  |  |  | 		return; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-02 22:39:52 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-03 16:19:22 -07:00
										 |  |  | 	// perhaps a factory function | 
					
						
							|  |  |  | 	// determine result type, if any | 
					
						
							|  |  |  | 	if len(fun.Type.Results) >= 1 { | 
					
						
							|  |  |  | 		res := fun.Type.Results[0]; | 
					
						
							|  |  |  | 		if len(res.Names) <= 1 { | 
					
						
							|  |  |  | 			// exactly one (named or anonymous) result type | 
					
						
							|  |  |  | 			typ = doc.lookupTypeDoc(res.Type); | 
					
						
							|  |  |  | 			if typ != nil { | 
					
						
							|  |  |  | 				typ.factories[name] = fdoc; | 
					
						
							|  |  |  | 				return; | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-03 16:19:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// ordinary function | 
					
						
							|  |  |  | 	doc.funcs[name] = fdoc; | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | func (doc *PackageDoc) addDecl(decl ast.Decl) { | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	switch d := decl.(type) { | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	case *ast.GenDecl: | 
					
						
							|  |  |  | 		if len(d.Specs) > 0 { | 
					
						
							|  |  |  | 			switch d.Tok { | 
					
						
							|  |  |  | 			case token.IMPORT: | 
					
						
							|  |  |  | 				// ignore | 
					
						
							|  |  |  | 			case token.CONST: | 
					
						
							|  |  |  | 				// constants are always handled as a group | 
					
						
							|  |  |  | 				if hasExportedSpecs(d.Specs) { | 
					
						
							|  |  |  | 					doc.consts.Push(&valueDoc{d}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case token.TYPE: | 
					
						
							|  |  |  | 				// types are handled individually | 
					
						
							|  |  |  | 				for i, spec := range d.Specs { | 
					
						
							|  |  |  | 					s := spec.(*ast.TypeSpec); | 
					
						
							|  |  |  | 					if isExported(s.Name) { | 
					
						
							|  |  |  | 						// make a (fake) GenDecl node for this TypeSpec | 
					
						
							|  |  |  | 						// (we need to do this here - as opposed to just | 
					
						
							|  |  |  | 						// for printing - so we don't loose the GenDecl | 
					
						
							|  |  |  | 						// documentation) | 
					
						
							|  |  |  | 						var noPos token.Position; | 
					
						
							|  |  |  | 						doc.addType(&ast.GenDecl{d.Doc, d.Pos(), token.TYPE, noPos, []ast.Spec{s}, noPos}); | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			case token.VAR: | 
					
						
							|  |  |  | 				// variables are always handled as a group | 
					
						
							|  |  |  | 				if hasExportedSpecs(d.Specs) { | 
					
						
							|  |  |  | 					doc.vars.Push(&valueDoc{d}); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	case *ast.FuncDecl: | 
					
						
							|  |  |  | 		if isExported(d.Name) { | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 			doc.addFunc(d); | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | // AddProgram adds the AST of a source file belonging to the same | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | // package. The package names must match. If the source was added | 
					
						
							|  |  |  | // before, AddProgram is a no-op. | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | func (doc *PackageDoc) AddProgram(prog *ast.Program) { | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 	if doc.name != prog.Name.Value { | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 		panic("package names don't match"); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// add package documentation | 
					
						
							|  |  |  | 	// TODO what to do if there are multiple files? | 
					
						
							|  |  |  | 	if prog.Doc != nil { | 
					
						
							|  |  |  | 		doc.doc = prog.Doc | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	// add all exported declarations | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	for i, decl := range prog.Decls { | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 		doc.addDecl(decl); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ---------------------------------------------------------------------------- | 
					
						
							|  |  |  | // Printing | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | func htmlEscape(s []byte) []byte { | 
					
						
							|  |  |  | 	var buf io.ByteBuffer; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	i0 := 0; | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	for i := 0; i < len(s); i++ { | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 		var esc string; | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 		switch s[i] { | 
					
						
							|  |  |  | 		case '<': esc = "<"; | 
					
						
							|  |  |  | 		case '&': esc = "&"; | 
					
						
							|  |  |  | 		default: continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 		fmt.Fprintf(&buf, "%s%s", s[i0 : i], esc); | 
					
						
							|  |  |  | 		i0 := i+1;  // skip escaped char | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// write the rest | 
					
						
							|  |  |  | 	if i0 > 0 { | 
					
						
							|  |  |  | 		buf.Write(s[i0 : len(s)]); | 
					
						
							|  |  |  | 		s = buf.Data(); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Reduce contiguous sequences of '\t' in a string to a single '\t'. | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | // This will produce better results when the string is printed via | 
					
						
							|  |  |  | // a tabwriter. | 
					
						
							|  |  |  | // TODO make this functionality optional. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | func untabify(s []byte) []byte { | 
					
						
							|  |  |  | 	var buf io.ByteBuffer; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	i0 := 0; | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	for i := 0; i < len(s); i++ { | 
					
						
							|  |  |  | 		if s[i] == '\t' { | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 			i++;  // include '\t' | 
					
						
							|  |  |  | 			buf.Write(s[i0 : i]); | 
					
						
							|  |  |  | 			// skip additional tabs | 
					
						
							|  |  |  | 			for i < len(s) && s[i] == '\t' { | 
					
						
							|  |  |  | 				i++; | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 			i0 := i; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			i++; | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// write the rest | 
					
						
							|  |  |  | 	if i0 > 0 { | 
					
						
							|  |  |  | 		buf.Write(s[i0 : len(s)]); | 
					
						
							|  |  |  | 		s = buf.Data(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	return s; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | func stripCommentDelimiters(s []byte) []byte { | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	switch s[1] { | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	case '/': return s[2 : len(s)-1]; | 
					
						
							|  |  |  | 	case '*': return s[2 : len(s)-2]; | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	panic(); | 
					
						
							|  |  |  | 	return nil; | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | const /* formatting mode */ ( | 
					
						
							|  |  |  | 	in_gap = iota; | 
					
						
							|  |  |  | 	in_paragraph; | 
					
						
							|  |  |  | 	in_preformatted; | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func printLine(p *astPrinter.Printer, line []byte, mode int) int { | 
					
						
							| 
									
										
										
										
											2009-04-03 16:19:22 -07:00
										 |  |  | 	// If a line starts with " *" (as a result of a vertical /****/ comment), | 
					
						
							|  |  |  | 	// strip it away. For an example of such a comment, see src/lib/flag.go. | 
					
						
							|  |  |  | 	if len(line) >= 2 && line[0] == ' ' && line[1] == '*' { | 
					
						
							|  |  |  | 		line = line[2 : len(line)]; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// The line is indented if it starts with a tab. | 
					
						
							|  |  |  | 	// In either case strip away a leading space or tab. | 
					
						
							|  |  |  | 	indented := false; | 
					
						
							|  |  |  | 	if len(line) > 0 { | 
					
						
							|  |  |  | 		switch line[0] { | 
					
						
							|  |  |  | 		case '\t': | 
					
						
							|  |  |  | 			indented = true; | 
					
						
							|  |  |  | 			fallthrough; | 
					
						
							|  |  |  | 		case ' ': | 
					
						
							|  |  |  | 			line = line[1 : len(line)]; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	if len(line) == 0 { | 
					
						
							|  |  |  | 		// empty line | 
					
						
							|  |  |  | 		switch mode { | 
					
						
							|  |  |  | 		case in_paragraph: | 
					
						
							|  |  |  | 			p.Printf("</p>\n"); | 
					
						
							|  |  |  | 			mode = in_gap; | 
					
						
							|  |  |  | 		case in_preformatted: | 
					
						
							|  |  |  | 			p.Printf("\n"); | 
					
						
							|  |  |  | 			// remain in preformatted | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// non-empty line | 
					
						
							|  |  |  | 		if indented { | 
					
						
							|  |  |  | 			switch mode { | 
					
						
							|  |  |  | 			case in_gap: | 
					
						
							|  |  |  | 				p.Printf("<pre>\n"); | 
					
						
							|  |  |  | 			case in_paragraph: | 
					
						
							|  |  |  | 				p.Printf("</p>\n"); | 
					
						
							|  |  |  | 				p.Printf("<pre>\n"); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 			mode = in_preformatted; | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 			switch mode { | 
					
						
							|  |  |  | 			case in_gap: | 
					
						
							|  |  |  | 				p.Printf("<p>\n"); | 
					
						
							|  |  |  | 			case in_preformatted: | 
					
						
							|  |  |  | 				p.Printf("</pre>\n"); | 
					
						
							|  |  |  | 				p.Printf("<p>\n"); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 			mode = in_paragraph; | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 		// print line | 
					
						
							|  |  |  | 		p.Printf("%s\n", untabify(htmlEscape(line))); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	return mode; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func closeMode(p *astPrinter.Printer, mode int) { | 
					
						
							|  |  |  | 	switch mode { | 
					
						
							|  |  |  | 	case in_paragraph: | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 		p.Printf("</p>\n"); | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	case in_preformatted: | 
					
						
							|  |  |  | 		p.Printf("</pre>\n"); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func printComments(p *astPrinter.Printer, comment ast.Comments) { | 
					
						
							|  |  |  | 	mode := in_gap; | 
					
						
							|  |  |  | 	for i, c := range comment { | 
					
						
							|  |  |  | 		s := stripCommentDelimiters(c.Text); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// split comment into lines and print the lines | 
					
						
							|  |  |  |  		i0 := 0;  // beginning of current line | 
					
						
							|  |  |  | 		for i := 0; i < len(s); i++ { | 
					
						
							|  |  |  | 			if s[i] == '\n' { | 
					
						
							|  |  |  | 				// reached line end - print current line | 
					
						
							|  |  |  | 				mode = printLine(p, s[i0 : i], mode); | 
					
						
							|  |  |  | 				i0 = i + 1;  // beginning of next line; skip '\n' | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// print last line | 
					
						
							|  |  |  | 		mode = printLine(p, s[i0 : len(s)], mode); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	closeMode(p, mode); | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | func (c *valueDoc) print(p *astPrinter.Printer) { | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	printComments(p, c.decl.Doc); | 
					
						
							|  |  |  | 	p.Printf("<pre>"); | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	p.DoGenDecl(c.decl); | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	p.Printf("</pre>\n"); | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | func (f *funcDoc) print(p *astPrinter.Printer, hsize int) { | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	d := f.decl; | 
					
						
							|  |  |  | 	if d.Recv != nil { | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 		p.Printf("<h%d>func (", hsize); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 		p.Expr(d.Recv.Type); | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 		p.Printf(") %s</h%d>\n", d.Name.Value, hsize); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 		p.Printf("<h%d>func %s</h%d>\n", hsize, d.Name.Value, hsize); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	p.Printf("<p><code>"); | 
					
						
							|  |  |  | 	p.DoFuncDecl(d); | 
					
						
							|  |  |  | 	p.Printf("</code></p>\n"); | 
					
						
							| 
									
										
										
										
											2009-04-01 15:00:22 -07:00
										 |  |  | 	printComments(p, d.Doc); | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | func (t *typeDoc) print(p *astPrinter.Printer) { | 
					
						
							|  |  |  | 	d := t.decl; | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	s := d.Specs[0].(*ast.TypeSpec); | 
					
						
							| 
									
										
										
										
											2009-04-02 15:58:58 -07:00
										 |  |  | 	p.Printf("<h2>type %s</h2>\n", s.Name.Value); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	p.Printf("<p><pre>"); | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	p.DoGenDecl(d); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	p.Printf("</pre></p>\n"); | 
					
						
							| 
									
										
										
										
											2009-04-02 10:16:17 -07:00
										 |  |  | 	printComments(p, s.Doc); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	// print associated methods, if any | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 	for name, m := range t.factories { | 
					
						
							|  |  |  | 		m.print(p, 3); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	for name, m := range t.methods { | 
					
						
							| 
									
										
										
										
											2009-03-31 18:46:21 -07:00
										 |  |  | 		m.print(p, 3); | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | func (doc *PackageDoc) Print(writer io.Write) { | 
					
						
							|  |  |  | 	var p astPrinter.Printer; | 
					
						
							| 
									
										
										
										
											2009-04-03 16:19:22 -07:00
										 |  |  | 	p.Init(writer, nil, nil, true); | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2009-04-02 18:25:18 -07:00
										 |  |  | 	// program header | 
					
						
							|  |  |  | 	fmt.Fprintf(writer, "<h1>package %s</h1>\n", doc.name); | 
					
						
							|  |  |  | 	fmt.Fprintf(writer, "<p><code>import \"%s\"</code></p>\n", doc.name); | 
					
						
							|  |  |  | 	printComments(&p, doc.doc); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// constants | 
					
						
							|  |  |  | 	if doc.consts.Len() > 0 { | 
					
						
							|  |  |  | 		fmt.Fprintln(writer, "<hr />"); | 
					
						
							|  |  |  | 		fmt.Fprintln(writer, "<h2>Constants</h2>"); | 
					
						
							|  |  |  | 		for i := 0; i < doc.consts.Len(); i++ { | 
					
						
							|  |  |  | 			doc.consts.At(i).(*valueDoc).print(&p); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-03-31 16:53:58 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-04-02 18:25:18 -07:00
										 |  |  | 	// variables | 
					
						
							|  |  |  | 	if doc.vars.Len() > 0 { | 
					
						
							|  |  |  | 		fmt.Fprintln(writer, "<hr />"); | 
					
						
							|  |  |  | 		fmt.Fprintln(writer, "<h2>Variables</h2>"); | 
					
						
							|  |  |  | 		for i := 0; i < doc.vars.Len(); i++ { | 
					
						
							|  |  |  | 			doc.vars.At(i).(*valueDoc).print(&p); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// functions | 
					
						
							|  |  |  | 	if len(doc.funcs) > 0 { | 
					
						
							|  |  |  | 		fmt.Fprintln(writer, "<hr />"); | 
					
						
							|  |  |  | 		for name, f := range doc.funcs { | 
					
						
							|  |  |  | 			f.print(&p, 2); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-04-02 21:59:37 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// types | 
					
						
							|  |  |  | 	for name, t := range doc.types { | 
					
						
							|  |  |  | 		fmt.Fprintln(writer, "<hr />"); | 
					
						
							|  |  |  | 		t.print(&p); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2009-03-30 17:13:11 -07:00
										 |  |  | } |