mirror of
https://github.com/golang/go
synced 2024-11-20 04:54:44 -07:00
- ast.FilterExports: strips all non-exported nodes from an AST
- use FilterExports instead of the various predicates in printer.go and doc.go which simplifies a lot of code and makes it easier to deal with complex cases R=rsc DELTA=445 (197 added, 190 deleted, 58 changed) OCL=31110 CL=31196
This commit is contained in:
parent
cd4aab62e3
commit
deb954772d
@ -198,9 +198,13 @@ func parse(path string, mode uint) (*ast.Program, *parseErrors) {
|
||||
// Templates
|
||||
|
||||
// Return text for an AST node.
|
||||
func nodeText(node interface{}, mode uint) []byte {
|
||||
func nodeText(node interface{}) []byte {
|
||||
var buf bytes.Buffer;
|
||||
tw := makeTabwriter(&buf);
|
||||
mode := uint(0);
|
||||
if _, isProgram := node.(*ast.Program); isProgram {
|
||||
mode = printer.DocComments;
|
||||
}
|
||||
printer.Fprint(tw, node, mode);
|
||||
tw.Flush();
|
||||
return buf.Data();
|
||||
@ -219,9 +223,9 @@ func toText(x interface{}) []byte {
|
||||
case String:
|
||||
return strings.Bytes(v.String());
|
||||
case ast.Decl:
|
||||
return nodeText(v, printer.ExportsOnly);
|
||||
return nodeText(v);
|
||||
case ast.Expr:
|
||||
return nodeText(v, printer.ExportsOnly);
|
||||
return nodeText(v);
|
||||
}
|
||||
var buf bytes.Buffer;
|
||||
fmt.Fprint(&buf, x);
|
||||
@ -331,7 +335,7 @@ func serveGoSource(c *http.Conn, name string) {
|
||||
|
||||
var buf bytes.Buffer;
|
||||
fmt.Fprintln(&buf, "<pre>");
|
||||
template.HtmlEscape(&buf, nodeText(prog, printer.DocComments));
|
||||
template.HtmlEscape(&buf, nodeText(prog));
|
||||
fmt.Fprintln(&buf, "</pre>");
|
||||
|
||||
servePage(c, name + " - Go source", buf.Data());
|
||||
@ -491,6 +495,7 @@ func (p *pakDesc) Doc() (*doc.PackageDoc, *parseErrors) {
|
||||
r.Init(prog.Name.Value, p.importpath);
|
||||
}
|
||||
i++;
|
||||
ast.FilterExports(prog); // we only care about exports
|
||||
r.AddProgram(prog);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,7 @@ package main
|
||||
import (
|
||||
"flag";
|
||||
"fmt";
|
||||
"go/ast";
|
||||
"go/parser";
|
||||
"go/printer";
|
||||
"io";
|
||||
@ -48,9 +49,6 @@ func parserMode() uint {
|
||||
|
||||
func printerMode() uint {
|
||||
mode := uint(0);
|
||||
if *exports {
|
||||
mode |= printer.ExportsOnly;
|
||||
}
|
||||
if *optcommas {
|
||||
mode |= printer.OptCommas;
|
||||
}
|
||||
@ -100,6 +98,9 @@ func main() {
|
||||
}
|
||||
|
||||
if !*silent {
|
||||
if *exports {
|
||||
ast.FilterExports(prog); // ignore result
|
||||
}
|
||||
w := makeTabwriter(os.Stdout);
|
||||
printer.Fprint(w, prog, printerMode());
|
||||
w.Flush();
|
||||
|
@ -2,8 +2,9 @@
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
|
||||
|
||||
# DO NOT EDIT. Automatically generated by gobuild.
|
||||
# gobuild -m >Makefile
|
||||
# gobuild -m ast.go filter.go >Makefile
|
||||
|
||||
D=/go/
|
||||
|
||||
@ -20,7 +21,7 @@ test: packages
|
||||
|
||||
coverage: packages
|
||||
gotest
|
||||
6cov -g `pwd` | grep -v '_test\.go:'
|
||||
6cov -g $$(pwd) | grep -v '_test\.go:'
|
||||
|
||||
%.$O: %.go
|
||||
$(GC) -I_obj $*.go
|
||||
@ -34,14 +35,21 @@ coverage: packages
|
||||
O1=\
|
||||
ast.$O\
|
||||
|
||||
O2=\
|
||||
filter.$O\
|
||||
|
||||
phases: a1
|
||||
|
||||
phases: a1 a2
|
||||
_obj$D/ast.a: phases
|
||||
|
||||
a1: $(O1)
|
||||
$(AR) grc _obj$D/ast.a ast.$O
|
||||
rm -f $(O1)
|
||||
|
||||
a2: $(O2)
|
||||
$(AR) grc _obj$D/ast.a filter.$O
|
||||
rm -f $(O2)
|
||||
|
||||
|
||||
newpkg: clean
|
||||
mkdir -p _obj$D
|
||||
@ -49,6 +57,7 @@ newpkg: clean
|
||||
|
||||
$(O1): newpkg
|
||||
$(O2): a1
|
||||
$(O3): a2
|
||||
|
||||
nuke: clean
|
||||
rm -f $(GOROOT)/pkg/$(GOOS)_$(GOARCH)$D/ast.a
|
||||
|
134
src/pkg/go/ast/filter.go
Normal file
134
src/pkg/go/ast/filter.go
Normal file
@ -0,0 +1,134 @@
|
||||
// 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 ast
|
||||
|
||||
import "go/ast"
|
||||
|
||||
|
||||
func filterIdentList(list []*Ident) []*Ident {
|
||||
j := 0;
|
||||
for _, x := range list {
|
||||
if x.IsExported() {
|
||||
list[j] = x;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return list[0 : j];
|
||||
}
|
||||
|
||||
|
||||
func filterType(typ Expr)
|
||||
|
||||
func filterFieldList(list []*Field) []*Field {
|
||||
j := 0;
|
||||
for _, f := range list {
|
||||
exported := false;
|
||||
if len(f.Names) == 0 {
|
||||
// anonymous field
|
||||
// TODO(gri) check if the type is exported for anonymous field
|
||||
exported = true;
|
||||
} else {
|
||||
f.Names = filterIdentList(f.Names);
|
||||
exported = len(f.Names) > 0;
|
||||
}
|
||||
if exported {
|
||||
filterType(f.Type);
|
||||
list[j] = f;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return list[0 : j];
|
||||
}
|
||||
|
||||
|
||||
func filterType(typ Expr) {
|
||||
switch t := typ.(type) {
|
||||
case *ArrayType:
|
||||
filterType(t.Elt);
|
||||
case *StructType:
|
||||
t.Fields = filterFieldList(t.Fields);
|
||||
case *FuncType:
|
||||
t.Params = filterFieldList(t.Params);
|
||||
t.Results = filterFieldList(t.Results);
|
||||
case *InterfaceType:
|
||||
t.Methods = filterFieldList(t.Methods);
|
||||
case *MapType:
|
||||
filterType(t.Key);
|
||||
filterType(t.Value);
|
||||
case *ChanType:
|
||||
filterType(t.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func filterSpec(spec Spec) bool {
|
||||
switch s := spec.(type) {
|
||||
case *ValueSpec:
|
||||
s.Names = filterIdentList(s.Names);
|
||||
if len(s.Names) > 0 {
|
||||
filterType(s.Type);
|
||||
return true;
|
||||
}
|
||||
case *TypeSpec:
|
||||
// TODO(gri) consider stripping forward declarations
|
||||
// of structs, interfaces, functions, and methods
|
||||
if s.Name.IsExported() {
|
||||
filterType(s.Type);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
func filterSpecList(list []Spec) []Spec {
|
||||
j := 0;
|
||||
for _, s := range list {
|
||||
if filterSpec(s) {
|
||||
list[j] = s;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return list[0 : j];
|
||||
}
|
||||
|
||||
|
||||
func filterDecl(decl Decl) bool {
|
||||
switch d := decl.(type) {
|
||||
case *GenDecl:
|
||||
d.Specs = filterSpecList(d.Specs);
|
||||
return len(d.Specs) > 0;
|
||||
case *FuncDecl:
|
||||
// TODO consider removing function declaration altogether if
|
||||
// forward declaration (i.e., if d.Body == nil) because
|
||||
// in that case the actual declaration will come later.
|
||||
d.Body = nil; // strip body
|
||||
return d.Name.IsExported();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// FilterExports trims an AST in place such that only exported nodes remain:
|
||||
// all top-level identififiers 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.
|
||||
//
|
||||
// FilterExports returns true if there is an exported declaration; it returns
|
||||
// false otherwise.
|
||||
//
|
||||
func FilterExports(prog *Program) bool {
|
||||
j := 0;
|
||||
for _, d := range prog.Decls {
|
||||
if filterDecl(d) {
|
||||
prog.Decls[j] = d;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
prog.Decls = prog.Decls[0 : j];
|
||||
prog.Comments = nil; // remove unassociated comments
|
||||
return j > 0;
|
||||
}
|
@ -17,28 +17,6 @@ import (
|
||||
)
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Elementary support
|
||||
|
||||
func hasExportedNames(names []*ast.Ident) bool {
|
||||
for i, name := range names {
|
||||
if name.IsExported() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
type typeDoc struct {
|
||||
@ -149,33 +127,25 @@ func (doc *DocReader) addDecl(decl ast.Decl) {
|
||||
// ignore
|
||||
case token.CONST:
|
||||
// constants are always handled as a group
|
||||
if hasExportedSpecs(d.Specs) {
|
||||
doc.consts.Push(d);
|
||||
}
|
||||
doc.consts.Push(d);
|
||||
case token.TYPE:
|
||||
// types are handled individually
|
||||
var noPos token.Position;
|
||||
for i, spec := range d.Specs {
|
||||
// make a (fake) GenDecl node for this TypeSpec
|
||||
// (we need to do this here - as opposed to just
|
||||
// for printing - so we don't lose the GenDecl
|
||||
// documentation)
|
||||
s := spec.(*ast.TypeSpec);
|
||||
if s.Name.IsExported() {
|
||||
// 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});
|
||||
}
|
||||
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(d);
|
||||
}
|
||||
doc.vars.Push(d);
|
||||
}
|
||||
}
|
||||
case *ast.FuncDecl:
|
||||
if d.Name.IsExported() {
|
||||
doc.addFunc(d);
|
||||
}
|
||||
doc.addFunc(d);
|
||||
}
|
||||
}
|
||||
|
||||
@ -194,7 +164,7 @@ func (doc *DocReader) AddProgram(prog *ast.Program) {
|
||||
doc.doc = prog.Doc
|
||||
}
|
||||
|
||||
// add all exported declarations
|
||||
// add all declarations
|
||||
for i, decl := range prog.Decls {
|
||||
doc.addDecl(decl);
|
||||
}
|
||||
|
@ -20,8 +20,7 @@ import (
|
||||
// to Fprint via the mode parameter.
|
||||
//
|
||||
const (
|
||||
ExportsOnly uint = 1 << iota; // print exported code only
|
||||
DocComments; // print documentation comments
|
||||
DocComments uint = 1 << iota; // print documentation comments
|
||||
OptCommas; // print optional commas
|
||||
OptSemis; // print optional semicolons
|
||||
)
|
||||
@ -181,97 +180,13 @@ func (p *printer) print(args ...) {
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Predicates
|
||||
// Printing of common AST nodes.
|
||||
|
||||
func (p *printer) optSemis() bool {
|
||||
return p.mode & OptSemis != 0;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) exportsOnly() bool {
|
||||
return p.mode & ExportsOnly != 0;
|
||||
}
|
||||
|
||||
|
||||
// The isVisibleX predicates return true if X should produce any output
|
||||
// given the printing mode and depending on whether X contains exported
|
||||
// names.
|
||||
|
||||
func (p *printer) isVisibleIdent(x *ast.Ident) bool {
|
||||
// identifiers in local scopes (p.level > 0) are always visible
|
||||
// if the surrounding code is printed in the first place
|
||||
return !p.exportsOnly() || x.IsExported() || p.level > 0;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) isVisibleIdentList(list []*ast.Ident) bool {
|
||||
for _, x := range list {
|
||||
if p.isVisibleIdent(x) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) isVisibleFieldList(list []*ast.Field) bool {
|
||||
for _, f := range list {
|
||||
if len(f.Names) == 0 {
|
||||
// anonymous field
|
||||
// TODO should only return true if the anonymous field
|
||||
// type is visible (for now be conservative and
|
||||
// print it so that the generated code is valid)
|
||||
return true;
|
||||
}
|
||||
if p.isVisibleIdentList(f.Names) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) isVisibleSpec(spec ast.Spec) bool {
|
||||
switch s := spec.(type) {
|
||||
case *ast.ImportSpec:
|
||||
return !p.exportsOnly();
|
||||
case *ast.ValueSpec:
|
||||
return p.isVisibleIdentList(s.Names);
|
||||
case *ast.TypeSpec:
|
||||
return p.isVisibleIdent(s.Name);
|
||||
}
|
||||
panic("unreachable");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) isVisibleSpecList(list []ast.Spec) bool {
|
||||
for _, s := range list {
|
||||
if p.isVisibleSpec(s) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
func (p *printer) isVisibleDecl(decl ast.Decl) bool {
|
||||
switch d := decl.(type) {
|
||||
case *ast.BadDecl:
|
||||
return false;
|
||||
case *ast.GenDecl:
|
||||
return p.isVisibleSpecList(d.Specs);
|
||||
case *ast.FuncDecl:
|
||||
return p.isVisibleIdent(d.Name);
|
||||
}
|
||||
panic("unreachable");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Printing of common AST nodes.
|
||||
|
||||
func (p *printer) comment(c *ast.Comment) {
|
||||
if c != nil {
|
||||
text := c.Text;
|
||||
@ -297,15 +212,11 @@ func (p *printer) doc(d ast.Comments) {
|
||||
func (p *printer) expr(x ast.Expr) bool
|
||||
|
||||
func (p *printer) identList(list []*ast.Ident) {
|
||||
needsComma := false;
|
||||
for i, x := range list {
|
||||
if p.isVisibleIdent(x) {
|
||||
if needsComma {
|
||||
p.print(token.COMMA, blank);
|
||||
}
|
||||
p.expr(x);
|
||||
needsComma = true;
|
||||
if i > 0 {
|
||||
p.print(token.COMMA, blank);
|
||||
}
|
||||
p.expr(x);
|
||||
}
|
||||
}
|
||||
|
||||
@ -362,83 +273,73 @@ func (p *printer) signature(params, result []*ast.Field) {
|
||||
|
||||
// Returns true if the field list ends in a closing brace.
|
||||
func (p *printer) fieldList(lbrace token.Position, list []*ast.Field, rbrace token.Position, isInterface bool) bool {
|
||||
hasBody := p.isVisibleFieldList(list);
|
||||
if !lbrace.IsValid() || p.exportsOnly() && !hasBody {
|
||||
// forward declaration without {}'s or no visible exported fields
|
||||
// (in all other cases, the {}'s must be printed even if there are
|
||||
// no fields, otherwise the type is incorrect)
|
||||
if !lbrace.IsValid() {
|
||||
// forward declaration without {}'s
|
||||
return false; // no {}'s
|
||||
}
|
||||
|
||||
p.print(blank, lbrace, token.LBRACE);
|
||||
if len(list) == 0 {
|
||||
p.print(blank, lbrace, token.LBRACE, rbrace, token.RBRACE);
|
||||
return true; // empty list with {}'s
|
||||
}
|
||||
|
||||
if hasBody {
|
||||
p.print(+1, newline);
|
||||
p.print(blank, lbrace, token.LBRACE, +1, newline);
|
||||
|
||||
var needsSemi bool;
|
||||
var lastWasAnon bool; // true if the previous line was an anonymous field
|
||||
var lastComment *ast.Comment; // the comment from the previous line
|
||||
for _, f := range list {
|
||||
hasNames := p.isVisibleIdentList(f.Names);
|
||||
isAnon := len(f.Names) == 0;
|
||||
|
||||
if hasNames || isAnon {
|
||||
// at least one visible identifier or anonymous field
|
||||
// TODO this is conservative - see isVisibleFieldList
|
||||
if needsSemi {
|
||||
p.print(token.SEMICOLON);
|
||||
p.comment(lastComment);
|
||||
if lastWasAnon == isAnon {
|
||||
// previous and current line have same structure;
|
||||
// continue with existing columns
|
||||
p.print(newline);
|
||||
} else {
|
||||
// previous and current line have different structure;
|
||||
// flush tabwriter and start new columns (the "type
|
||||
// column" on a line with named fields may line up
|
||||
// with the "trailing comment column" on a line with
|
||||
// an anonymous field, leading to bad alignment)
|
||||
p.print(formfeed);
|
||||
}
|
||||
}
|
||||
|
||||
p.doc(f.Doc);
|
||||
if hasNames {
|
||||
p.identList(f.Names);
|
||||
p.print(tab);
|
||||
}
|
||||
|
||||
if isInterface {
|
||||
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
|
||||
// methods
|
||||
p.signature(ftyp.Params, ftyp.Results);
|
||||
} else {
|
||||
// embedded interface
|
||||
p.expr(f.Type);
|
||||
}
|
||||
} else {
|
||||
p.expr(f.Type);
|
||||
if f.Tag != nil && !p.exportsOnly() {
|
||||
p.print(tab);
|
||||
p.expr(&ast.StringList{f.Tag});
|
||||
}
|
||||
}
|
||||
|
||||
needsSemi = true;
|
||||
lastWasAnon = isAnon;
|
||||
lastComment = f.Comment;
|
||||
var lastWasAnon bool; // true if the previous line was an anonymous field
|
||||
var lastComment *ast.Comment; // the comment from the previous line
|
||||
for i, f := range list {
|
||||
// at least one visible identifier or anonymous field
|
||||
isAnon := len(f.Names) == 0;
|
||||
if i > 0 {
|
||||
p.print(token.SEMICOLON);
|
||||
p.comment(lastComment);
|
||||
if lastWasAnon == isAnon {
|
||||
// previous and current line have same structure;
|
||||
// continue with existing columns
|
||||
p.print(newline);
|
||||
} else {
|
||||
// previous and current line have different structure;
|
||||
// flush tabwriter and start new columns (the "type
|
||||
// column" on a line with named fields may line up
|
||||
// with the "trailing comment column" on a line with
|
||||
// an anonymous field, leading to bad alignment)
|
||||
p.print(formfeed);
|
||||
}
|
||||
}
|
||||
|
||||
if p.optSemis() {
|
||||
p.print(token.SEMICOLON);
|
||||
p.doc(f.Doc);
|
||||
if !isAnon {
|
||||
p.identList(f.Names);
|
||||
p.print(tab);
|
||||
}
|
||||
|
||||
p.comment(lastComment);
|
||||
p.print(-1, newline);
|
||||
if isInterface {
|
||||
if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
|
||||
// methods
|
||||
p.signature(ftyp.Params, ftyp.Results);
|
||||
} else {
|
||||
// embedded interface
|
||||
p.expr(f.Type);
|
||||
}
|
||||
} else {
|
||||
p.expr(f.Type);
|
||||
if f.Tag != nil {
|
||||
p.print(tab);
|
||||
p.expr(&ast.StringList{f.Tag});
|
||||
}
|
||||
}
|
||||
|
||||
lastWasAnon = isAnon;
|
||||
lastComment = f.Comment;
|
||||
}
|
||||
|
||||
p.print(rbrace, token.RBRACE);
|
||||
if p.optSemis() {
|
||||
p.print(token.SEMICOLON);
|
||||
}
|
||||
p.comment(lastComment);
|
||||
|
||||
p.print(-1, newline, rbrace, token.RBRACE);
|
||||
|
||||
return true; // field list with {}'s
|
||||
}
|
||||
|
||||
@ -905,25 +806,17 @@ func (p *printer) decl(decl ast.Decl) (optSemi bool) {
|
||||
|
||||
if d.Lparen.IsValid() {
|
||||
// group of parenthesized declarations
|
||||
p.print(d.Lparen, token.LPAREN);
|
||||
if p.isVisibleSpecList(d.Specs) {
|
||||
p.print(+1, newline);
|
||||
semi := false;
|
||||
for _, s := range d.Specs {
|
||||
if p.isVisibleSpec(s) {
|
||||
if semi {
|
||||
p.print(token.SEMICOLON, newline);
|
||||
}
|
||||
p.spec(s);
|
||||
semi = true;
|
||||
}
|
||||
p.print(d.Lparen, token.LPAREN, +1, newline);
|
||||
for i, s := range d.Specs {
|
||||
if i > 0 {
|
||||
p.print(token.SEMICOLON, newline);
|
||||
}
|
||||
if p.optSemis() {
|
||||
p.print(token.SEMICOLON);
|
||||
}
|
||||
p.print(-1, newline);
|
||||
p.spec(s);
|
||||
}
|
||||
p.print(d.Rparen, token.RPAREN);
|
||||
if p.optSemis() {
|
||||
p.print(token.SEMICOLON);
|
||||
}
|
||||
p.print(-1, newline, d.Rparen, token.RPAREN);
|
||||
optSemi = true;
|
||||
|
||||
} else {
|
||||
@ -946,7 +839,7 @@ func (p *printer) decl(decl ast.Decl) (optSemi bool) {
|
||||
}
|
||||
p.expr(d.Name);
|
||||
p.signature(d.Type.Params, d.Type.Results);
|
||||
if !p.exportsOnly() && d.Body != nil {
|
||||
if d.Body != nil {
|
||||
p.print(blank);
|
||||
p.level++; // adjust nesting level for function body
|
||||
p.stmt(d.Body);
|
||||
@ -965,23 +858,19 @@ func (p *printer) decl(decl ast.Decl) (optSemi bool) {
|
||||
// Programs
|
||||
|
||||
func (p *printer) program(prog *ast.Program) {
|
||||
// set unassociated comments if all code is printed
|
||||
if !p.exportsOnly() {
|
||||
// TODO enable this once comments are properly interspersed
|
||||
//p.setComments(prog.Comments);
|
||||
}
|
||||
// set unassociated comments
|
||||
// TODO enable this once comments are properly interspersed
|
||||
// p.setComments(prog.Comments);
|
||||
|
||||
p.doc(prog.Doc);
|
||||
p.print(prog.Pos(), token.PACKAGE, blank);
|
||||
p.expr(prog.Name);
|
||||
|
||||
for _, d := range prog.Decls {
|
||||
if p.isVisibleDecl(d) {
|
||||
p.print(newline, newline);
|
||||
p.decl(d);
|
||||
if p.optSemis() {
|
||||
p.print(token.SEMICOLON);
|
||||
}
|
||||
p.print(newline, newline);
|
||||
p.decl(d);
|
||||
if p.optSemis() {
|
||||
p.print(token.SEMICOLON);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user