Source file src/pkg/go/printer/nodes.go
     1	
     2	
     3	
     4	
     5	
     6	
     7	
     8	
     9	package printer
    10	
    11	import (
    12		"bytes"
    13		"go/ast"
    14		"go/token"
    15		"math"
    16		"strconv"
    17		"strings"
    18		"unicode"
    19		"unicode/utf8"
    20	)
    21	
    22	
    23	
    24	
    25	
    26	
    27	
    28	
    29	
    30	
    31	
    32	
    33	
    34	
    35	
    36	
    37	
    38	
    39	
    40	
    41	
    42	
    43	
    44	
    45	
    46	
    47	
    48	func (p *printer) linebreak(line, min int, ws whiteSpace, newSection bool) (nbreaks int) {
    49		n := nlimit(line - p.pos.Line)
    50		if n < min {
    51			n = min
    52		}
    53		if n > 0 {
    54			p.print(ws)
    55			if newSection {
    56				p.print(formfeed)
    57				n--
    58				nbreaks = 2
    59			}
    60			nbreaks += n
    61			for ; n > 0; n-- {
    62				p.print(newline)
    63			}
    64		}
    65		return
    66	}
    67	
    68	
    69	
    70	
    71	
    72	func (p *printer) setComment(g *ast.CommentGroup) {
    73		if g == nil || !p.useNodeComments {
    74			return
    75		}
    76		if p.comments == nil {
    77			
    78			p.comments = make([]*ast.CommentGroup, 1)
    79		} else if p.cindex < len(p.comments) {
    80			
    81			
    82			
    83			p.flush(p.posFor(g.List[0].Pos()), token.ILLEGAL)
    84			p.comments = p.comments[0:1]
    85			
    86			p.internalError("setComment found pending comments")
    87		}
    88		p.comments[0] = g
    89		p.cindex = 0
    90		
    91		
    92		
    93		
    94		if p.commentOffset == infinity {
    95			p.nextComment() 
    96		}
    97	}
    98	
    99	type exprListMode uint
   100	
   101	const (
   102		commaTerm exprListMode = 1 << iota 
   103		noIndent                           
   104	)
   105	
   106	
   107	
   108	func (p *printer) identList(list []*ast.Ident, indent bool) {
   109		
   110		xlist := make([]ast.Expr, len(list))
   111		for i, x := range list {
   112			xlist[i] = x
   113		}
   114		var mode exprListMode
   115		if !indent {
   116			mode = noIndent
   117		}
   118		p.exprList(token.NoPos, xlist, 1, mode, token.NoPos, false)
   119	}
   120	
   121	const filteredMsg = "contains filtered or unexported fields"
   122	
   123	
   124	
   125	
   126	
   127	
   128	
   129	
   130	func (p *printer) exprList(prev0 token.Pos, list []ast.Expr, depth int, mode exprListMode, next0 token.Pos, isIncomplete bool) {
   131		if len(list) == 0 {
   132			if isIncomplete {
   133				prev := p.posFor(prev0)
   134				next := p.posFor(next0)
   135				if prev.IsValid() && prev.Line == next.Line {
   136					p.print("/* " + filteredMsg + " */")
   137				} else {
   138					p.print(newline)
   139					p.print(indent, "// "+filteredMsg, unindent, newline)
   140				}
   141			}
   142			return
   143		}
   144	
   145		prev := p.posFor(prev0)
   146		next := p.posFor(next0)
   147		line := p.lineFor(list[0].Pos())
   148		endLine := p.lineFor(list[len(list)-1].End())
   149	
   150		if prev.IsValid() && prev.Line == line && line == endLine {
   151			
   152			for i, x := range list {
   153				if i > 0 {
   154					
   155					
   156					p.print(x.Pos(), token.COMMA, blank)
   157				}
   158				p.expr0(x, depth)
   159			}
   160			if isIncomplete {
   161				p.print(token.COMMA, blank, "/* "+filteredMsg+" */")
   162			}
   163			return
   164		}
   165	
   166		
   167		
   168	
   169		
   170		
   171		ws := ignore
   172		if mode&noIndent == 0 {
   173			ws = indent
   174		}
   175	
   176		
   177		
   178		prevBreak := -1 
   179		if prev.IsValid() && prev.Line < line && p.linebreak(line, 0, ws, true) > 0 {
   180			ws = ignore
   181			prevBreak = 0
   182		}
   183	
   184		
   185		size := 0
   186	
   187		
   188		
   189		
   190		
   191		lnsum := 0.0
   192		count := 0
   193	
   194		
   195		prevLine := prev.Line
   196		for i, x := range list {
   197			line = p.lineFor(x.Pos())
   198	
   199			
   200			
   201			
   202			
   203			
   204			useFF := true
   205	
   206			
   207			
   208			
   209			
   210			prevSize := size
   211			const infinity = 1e6 
   212			size = p.nodeSize(x, infinity)
   213			pair, isPair := x.(*ast.KeyValueExpr)
   214			if size <= infinity && prev.IsValid() && next.IsValid() {
   215				
   216				if isPair {
   217					size = p.nodeSize(pair.Key, infinity) 
   218				}
   219			} else {
   220				
   221				size = 0
   222			}
   223	
   224			
   225			
   226			
   227			
   228			
   229			if prevSize > 0 && size > 0 {
   230				const smallSize = 40
   231				if count == 0 || prevSize <= smallSize && size <= smallSize {
   232					useFF = false
   233				} else {
   234					const r = 2.5                               
   235					geomean := math.Exp(lnsum / float64(count)) 
   236					ratio := float64(size) / geomean
   237					useFF = r*ratio <= 1 || r <= ratio
   238				}
   239			}
   240	
   241			needsLinebreak := 0 < prevLine && prevLine < line
   242			if i > 0 {
   243				
   244				
   245				
   246				if !needsLinebreak {
   247					p.print(x.Pos())
   248				}
   249				p.print(token.COMMA)
   250				needsBlank := true
   251				if needsLinebreak {
   252					
   253					
   254					
   255					nbreaks := p.linebreak(line, 0, ws, useFF || prevBreak+1 < i)
   256					if nbreaks > 0 {
   257						ws = ignore
   258						prevBreak = i
   259						needsBlank = false 
   260					}
   261					
   262					
   263					
   264					
   265					if nbreaks > 1 {
   266						lnsum = 0
   267						count = 0
   268					}
   269				}
   270				if needsBlank {
   271					p.print(blank)
   272				}
   273			}
   274	
   275			if len(list) > 1 && isPair && size > 0 && needsLinebreak {
   276				
   277				
   278				
   279				
   280				
   281				p.expr(pair.Key)
   282				p.print(pair.Colon, token.COLON, vtab)
   283				p.expr(pair.Value)
   284			} else {
   285				p.expr0(x, depth)
   286			}
   287	
   288			if size > 0 {
   289				lnsum += math.Log(float64(size))
   290				count++
   291			}
   292	
   293			prevLine = line
   294		}
   295	
   296		if mode&commaTerm != 0 && next.IsValid() && p.pos.Line < next.Line {
   297			
   298			p.print(token.COMMA)
   299			if isIncomplete {
   300				p.print(newline)
   301				p.print("// " + filteredMsg)
   302			}
   303			if ws == ignore && mode&noIndent == 0 {
   304				
   305				p.print(unindent)
   306			}
   307			p.print(formfeed) 
   308			return
   309		}
   310	
   311		if isIncomplete {
   312			p.print(token.COMMA, newline)
   313			p.print("// "+filteredMsg, newline)
   314		}
   315	
   316		if ws == ignore && mode&noIndent == 0 {
   317			
   318			p.print(unindent)
   319		}
   320	}
   321	
   322	func (p *printer) parameters(fields *ast.FieldList) {
   323		p.print(fields.Opening, token.LPAREN)
   324		if len(fields.List) > 0 {
   325			prevLine := p.lineFor(fields.Opening)
   326			ws := indent
   327			for i, par := range fields.List {
   328				
   329				
   330				
   331				var parLineBeg int
   332				if len(par.Names) > 0 {
   333					parLineBeg = p.lineFor(par.Names[0].Pos())
   334				} else {
   335					parLineBeg = p.lineFor(par.Type.Pos())
   336				}
   337				var parLineEnd = p.lineFor(par.Type.End())
   338				
   339				needsLinebreak := 0 < prevLine && prevLine < parLineBeg
   340				if i > 0 {
   341					
   342					
   343					
   344					if !needsLinebreak {
   345						p.print(par.Pos())
   346					}
   347					p.print(token.COMMA)
   348				}
   349				
   350				if needsLinebreak && p.linebreak(parLineBeg, 0, ws, true) > 0 {
   351					
   352					ws = ignore
   353				} else if i > 0 {
   354					p.print(blank)
   355				}
   356				
   357				if len(par.Names) > 0 {
   358					
   359					
   360					
   361					
   362					
   363					
   364					p.identList(par.Names, ws == indent)
   365					p.print(blank)
   366				}
   367				
   368				p.expr(stripParensAlways(par.Type))
   369				prevLine = parLineEnd
   370			}
   371			
   372			
   373			if closing := p.lineFor(fields.Closing); 0 < prevLine && prevLine < closing {
   374				p.print(token.COMMA)
   375				p.linebreak(closing, 0, ignore, true)
   376			}
   377			
   378			if ws == ignore {
   379				p.print(unindent)
   380			}
   381		}
   382		p.print(fields.Closing, token.RPAREN)
   383	}
   384	
   385	func (p *printer) signature(params, result *ast.FieldList) {
   386		if params != nil {
   387			p.parameters(params)
   388		} else {
   389			p.print(token.LPAREN, token.RPAREN)
   390		}
   391		n := result.NumFields()
   392		if n > 0 {
   393			
   394			p.print(blank)
   395			if n == 1 && result.List[0].Names == nil {
   396				
   397				p.expr(stripParensAlways(result.List[0].Type))
   398				return
   399			}
   400			p.parameters(result)
   401		}
   402	}
   403	
   404	func identListSize(list []*ast.Ident, maxSize int) (size int) {
   405		for i, x := range list {
   406			if i > 0 {
   407				size += len(", ")
   408			}
   409			size += utf8.RuneCountInString(x.Name)
   410			if size >= maxSize {
   411				break
   412			}
   413		}
   414		return
   415	}
   416	
   417	func (p *printer) isOneLineFieldList(list []*ast.Field) bool {
   418		if len(list) != 1 {
   419			return false 
   420		}
   421		f := list[0]
   422		if f.Tag != nil || f.Comment != nil {
   423			return false 
   424		}
   425		
   426		const maxSize = 30 
   427		namesSize := identListSize(f.Names, maxSize)
   428		if namesSize > 0 {
   429			namesSize = 1 
   430		}
   431		typeSize := p.nodeSize(f.Type, maxSize)
   432		return namesSize+typeSize <= maxSize
   433	}
   434	
   435	func (p *printer) setLineComment(text string) {
   436		p.setComment(&ast.CommentGroup{List: []*ast.Comment{{Slash: token.NoPos, Text: text}}})
   437	}
   438	
   439	func (p *printer) fieldList(fields *ast.FieldList, isStruct, isIncomplete bool) {
   440		lbrace := fields.Opening
   441		list := fields.List
   442		rbrace := fields.Closing
   443		hasComments := isIncomplete || p.commentBefore(p.posFor(rbrace))
   444		srcIsOneLine := lbrace.IsValid() && rbrace.IsValid() && p.lineFor(lbrace) == p.lineFor(rbrace)
   445	
   446		if !hasComments && srcIsOneLine {
   447			
   448			if len(list) == 0 {
   449				
   450				p.print(lbrace, token.LBRACE, rbrace, token.RBRACE)
   451				return
   452			} else if p.isOneLineFieldList(list) {
   453				
   454				
   455				p.print(lbrace, token.LBRACE, blank)
   456				f := list[0]
   457				if isStruct {
   458					for i, x := range f.Names {
   459						if i > 0 {
   460							
   461							p.print(token.COMMA, blank)
   462						}
   463						p.expr(x)
   464					}
   465					if len(f.Names) > 0 {
   466						p.print(blank)
   467					}
   468					p.expr(f.Type)
   469				} else { 
   470					if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
   471						
   472						p.expr(f.Names[0])
   473						p.signature(ftyp.Params, ftyp.Results)
   474					} else {
   475						
   476						p.expr(f.Type)
   477					}
   478				}
   479				p.print(blank, rbrace, token.RBRACE)
   480				return
   481			}
   482		}
   483		
   484	
   485		p.print(blank, lbrace, token.LBRACE, indent)
   486		if hasComments || len(list) > 0 {
   487			p.print(formfeed)
   488		}
   489	
   490		if isStruct {
   491	
   492			sep := vtab
   493			if len(list) == 1 {
   494				sep = blank
   495			}
   496			var line int
   497			for i, f := range list {
   498				if i > 0 {
   499					p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
   500				}
   501				extraTabs := 0
   502				p.setComment(f.Doc)
   503				p.recordLine(&line)
   504				if len(f.Names) > 0 {
   505					
   506					p.identList(f.Names, false)
   507					p.print(sep)
   508					p.expr(f.Type)
   509					extraTabs = 1
   510				} else {
   511					
   512					p.expr(f.Type)
   513					extraTabs = 2
   514				}
   515				if f.Tag != nil {
   516					if len(f.Names) > 0 && sep == vtab {
   517						p.print(sep)
   518					}
   519					p.print(sep)
   520					p.expr(f.Tag)
   521					extraTabs = 0
   522				}
   523				if f.Comment != nil {
   524					for ; extraTabs > 0; extraTabs-- {
   525						p.print(sep)
   526					}
   527					p.setComment(f.Comment)
   528				}
   529			}
   530			if isIncomplete {
   531				if len(list) > 0 {
   532					p.print(formfeed)
   533				}
   534				p.flush(p.posFor(rbrace), token.RBRACE) 
   535				p.setLineComment("// " + filteredMsg)
   536			}
   537	
   538		} else { 
   539	
   540			var line int
   541			for i, f := range list {
   542				if i > 0 {
   543					p.linebreak(p.lineFor(f.Pos()), 1, ignore, p.linesFrom(line) > 0)
   544				}
   545				p.setComment(f.Doc)
   546				p.recordLine(&line)
   547				if ftyp, isFtyp := f.Type.(*ast.FuncType); isFtyp {
   548					
   549					p.expr(f.Names[0])
   550					p.signature(ftyp.Params, ftyp.Results)
   551				} else {
   552					
   553					p.expr(f.Type)
   554				}
   555				p.setComment(f.Comment)
   556			}
   557			if isIncomplete {
   558				if len(list) > 0 {
   559					p.print(formfeed)
   560				}
   561				p.flush(p.posFor(rbrace), token.RBRACE) 
   562				p.setLineComment("// contains filtered or unexported methods")
   563			}
   564	
   565		}
   566		p.print(unindent, formfeed, rbrace, token.RBRACE)
   567	}
   568	
   569	
   570	
   571	
   572	func walkBinary(e *ast.BinaryExpr) (has4, has5 bool, maxProblem int) {
   573		switch e.Op.Precedence() {
   574		case 4:
   575			has4 = true
   576		case 5:
   577			has5 = true
   578		}
   579	
   580		switch l := e.X.(type) {
   581		case *ast.BinaryExpr:
   582			if l.Op.Precedence() < e.Op.Precedence() {
   583				
   584				
   585				break
   586			}
   587			h4, h5, mp := walkBinary(l)
   588			has4 = has4 || h4
   589			has5 = has5 || h5
   590			if maxProblem < mp {
   591				maxProblem = mp
   592			}
   593		}
   594	
   595		switch r := e.Y.(type) {
   596		case *ast.BinaryExpr:
   597			if r.Op.Precedence() <= e.Op.Precedence() {
   598				
   599				
   600				break
   601			}
   602			h4, h5, mp := walkBinary(r)
   603			has4 = has4 || h4
   604			has5 = has5 || h5
   605			if maxProblem < mp {
   606				maxProblem = mp
   607			}
   608	
   609		case *ast.StarExpr:
   610			if e.Op == token.QUO { 
   611				maxProblem = 5
   612			}
   613	
   614		case *ast.UnaryExpr:
   615			switch e.Op.String() + r.Op.String() {
   616			case "/*", "&&", "&^":
   617				maxProblem = 5
   618			case "++", "--":
   619				if maxProblem < 4 {
   620					maxProblem = 4
   621				}
   622			}
   623		}
   624		return
   625	}
   626	
   627	func cutoff(e *ast.BinaryExpr, depth int) int {
   628		has4, has5, maxProblem := walkBinary(e)
   629		if maxProblem > 0 {
   630			return maxProblem + 1
   631		}
   632		if has4 && has5 {
   633			if depth == 1 {
   634				return 5
   635			}
   636			return 4
   637		}
   638		if depth == 1 {
   639			return 6
   640		}
   641		return 4
   642	}
   643	
   644	func diffPrec(expr ast.Expr, prec int) int {
   645		x, ok := expr.(*ast.BinaryExpr)
   646		if !ok || prec != x.Op.Precedence() {
   647			return 1
   648		}
   649		return 0
   650	}
   651	
   652	func reduceDepth(depth int) int {
   653		depth--
   654		if depth < 1 {
   655			depth = 1
   656		}
   657		return depth
   658	}
   659	
   660	
   661	
   662	
   663	
   664	
   665	
   666	
   667	
   668	
   669	
   670	
   671	
   672	
   673	
   674	
   675	
   676	
   677	
   678	
   679	
   680	
   681	
   682	
   683	
   684	
   685	
   686	
   687	
   688	
   689	
   690	
   691	
   692	
   693	
   694	
   695	
   696	func (p *printer) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
   697		prec := x.Op.Precedence()
   698		if prec < prec1 {
   699			
   700			
   701			
   702			p.print(token.LPAREN)
   703			p.expr0(x, reduceDepth(depth)) 
   704			p.print(token.RPAREN)
   705			return
   706		}
   707	
   708		printBlank := prec < cutoff
   709	
   710		ws := indent
   711		p.expr1(x.X, prec, depth+diffPrec(x.X, prec))
   712		if printBlank {
   713			p.print(blank)
   714		}
   715		xline := p.pos.Line 
   716		yline := p.lineFor(x.Y.Pos())
   717		p.print(x.OpPos, x.Op)
   718		if xline != yline && xline > 0 && yline > 0 {
   719			
   720			
   721			if p.linebreak(yline, 1, ws, true) > 0 {
   722				ws = ignore
   723				printBlank = false 
   724			}
   725		}
   726		if printBlank {
   727			p.print(blank)
   728		}
   729		p.expr1(x.Y, prec+1, depth+1)
   730		if ws == ignore {
   731			p.print(unindent)
   732		}
   733	}
   734	
   735	func isBinary(expr ast.Expr) bool {
   736		_, ok := expr.(*ast.BinaryExpr)
   737		return ok
   738	}
   739	
   740	func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
   741		p.print(expr.Pos())
   742	
   743		switch x := expr.(type) {
   744		case *ast.BadExpr:
   745			p.print("BadExpr")
   746	
   747		case *ast.Ident:
   748			p.print(x)
   749	
   750		case *ast.BinaryExpr:
   751			if depth < 1 {
   752				p.internalError("depth < 1:", depth)
   753				depth = 1
   754			}
   755			p.binaryExpr(x, prec1, cutoff(x, depth), depth)
   756	
   757		case *ast.KeyValueExpr:
   758			p.expr(x.Key)
   759			p.print(x.Colon, token.COLON, blank)
   760			p.expr(x.Value)
   761	
   762		case *ast.StarExpr:
   763			const prec = token.UnaryPrec
   764			if prec < prec1 {
   765				
   766				p.print(token.LPAREN)
   767				p.print(token.MUL)
   768				p.expr(x.X)
   769				p.print(token.RPAREN)
   770			} else {
   771				
   772				p.print(token.MUL)
   773				p.expr(x.X)
   774			}
   775	
   776		case *ast.UnaryExpr:
   777			const prec = token.UnaryPrec
   778			if prec < prec1 {
   779				
   780				p.print(token.LPAREN)
   781				p.expr(x)
   782				p.print(token.RPAREN)
   783			} else {
   784				
   785				p.print(x.Op)
   786				if x.Op == token.RANGE {
   787					
   788					p.print(blank)
   789				}
   790				p.expr1(x.X, prec, depth)
   791			}
   792	
   793		case *ast.BasicLit:
   794			p.print(x)
   795	
   796		case *ast.FuncLit:
   797			p.expr(x.Type)
   798			p.funcBody(p.distanceFrom(x.Type.Pos()), blank, x.Body)
   799	
   800		case *ast.ParenExpr:
   801			if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
   802				
   803				
   804				p.expr0(x.X, depth)
   805			} else {
   806				p.print(token.LPAREN)
   807				p.expr0(x.X, reduceDepth(depth)) 
   808				p.print(x.Rparen, token.RPAREN)
   809			}
   810	
   811		case *ast.SelectorExpr:
   812			p.selectorExpr(x, depth, false)
   813	
   814		case *ast.TypeAssertExpr:
   815			p.expr1(x.X, token.HighestPrec, depth)
   816			p.print(token.PERIOD, x.Lparen, token.LPAREN)
   817			if x.Type != nil {
   818				p.expr(x.Type)
   819			} else {
   820				p.print(token.TYPE)
   821			}
   822			p.print(x.Rparen, token.RPAREN)
   823	
   824		case *ast.IndexExpr:
   825			
   826			p.expr1(x.X, token.HighestPrec, 1)
   827			p.print(x.Lbrack, token.LBRACK)
   828			p.expr0(x.Index, depth+1)
   829			p.print(x.Rbrack, token.RBRACK)
   830	
   831		case *ast.SliceExpr:
   832			
   833			p.expr1(x.X, token.HighestPrec, 1)
   834			p.print(x.Lbrack, token.LBRACK)
   835			indices := []ast.Expr{x.Low, x.High}
   836			if x.Max != nil {
   837				indices = append(indices, x.Max)
   838			}
   839			
   840			var needsBlanks bool
   841			if depth <= 1 {
   842				var indexCount int
   843				var hasBinaries bool
   844				for _, x := range indices {
   845					if x != nil {
   846						indexCount++
   847						if isBinary(x) {
   848							hasBinaries = true
   849						}
   850					}
   851				}
   852				if indexCount > 1 && hasBinaries {
   853					needsBlanks = true
   854				}
   855			}
   856			for i, x := range indices {
   857				if i > 0 {
   858					if indices[i-1] != nil && needsBlanks {
   859						p.print(blank)
   860					}
   861					p.print(token.COLON)
   862					if x != nil && needsBlanks {
   863						p.print(blank)
   864					}
   865				}
   866				if x != nil {
   867					p.expr0(x, depth+1)
   868				}
   869			}
   870			p.print(x.Rbrack, token.RBRACK)
   871	
   872		case *ast.CallExpr:
   873			if len(x.Args) > 1 {
   874				depth++
   875			}
   876			var wasIndented bool
   877			if _, ok := x.Fun.(*ast.FuncType); ok {
   878				
   879				p.print(token.LPAREN)
   880				wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
   881				p.print(token.RPAREN)
   882			} else {
   883				wasIndented = p.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
   884			}
   885			p.print(x.Lparen, token.LPAREN)
   886			if x.Ellipsis.IsValid() {
   887				p.exprList(x.Lparen, x.Args, depth, 0, x.Ellipsis, false)
   888				p.print(x.Ellipsis, token.ELLIPSIS)
   889				if x.Rparen.IsValid() && p.lineFor(x.Ellipsis) < p.lineFor(x.Rparen) {
   890					p.print(token.COMMA, formfeed)
   891				}
   892			} else {
   893				p.exprList(x.Lparen, x.Args, depth, commaTerm, x.Rparen, false)
   894			}
   895			p.print(x.Rparen, token.RPAREN)
   896			if wasIndented {
   897				p.print(unindent)
   898			}
   899	
   900		case *ast.CompositeLit:
   901			
   902			if x.Type != nil {
   903				p.expr1(x.Type, token.HighestPrec, depth)
   904			}
   905			p.level++
   906			p.print(x.Lbrace, token.LBRACE)
   907			p.exprList(x.Lbrace, x.Elts, 1, commaTerm, x.Rbrace, x.Incomplete)
   908			
   909			
   910			
   911			mode := noExtraLinebreak
   912			
   913			
   914			if len(x.Elts) > 0 {
   915				mode |= noExtraBlank
   916			}
   917			
   918			
   919			p.print(indent, unindent, mode, x.Rbrace, token.RBRACE, mode)
   920			p.level--
   921	
   922		case *ast.Ellipsis:
   923			p.print(token.ELLIPSIS)
   924			if x.Elt != nil {
   925				p.expr(x.Elt)
   926			}
   927	
   928		case *ast.ArrayType:
   929			p.print(token.LBRACK)
   930			if x.Len != nil {
   931				p.expr(x.Len)
   932			}
   933			p.print(token.RBRACK)
   934			p.expr(x.Elt)
   935	
   936		case *ast.StructType:
   937			p.print(token.STRUCT)
   938			p.fieldList(x.Fields, true, x.Incomplete)
   939	
   940		case *ast.FuncType:
   941			p.print(token.FUNC)
   942			p.signature(x.Params, x.Results)
   943	
   944		case *ast.InterfaceType:
   945			p.print(token.INTERFACE)
   946			p.fieldList(x.Methods, false, x.Incomplete)
   947	
   948		case *ast.MapType:
   949			p.print(token.MAP, token.LBRACK)
   950			p.expr(x.Key)
   951			p.print(token.RBRACK)
   952			p.expr(x.Value)
   953	
   954		case *ast.ChanType:
   955			switch x.Dir {
   956			case ast.SEND | ast.RECV:
   957				p.print(token.CHAN)
   958			case ast.RECV:
   959				p.print(token.ARROW, token.CHAN) 
   960			case ast.SEND:
   961				p.print(token.CHAN, x.Arrow, token.ARROW)
   962			}
   963			p.print(blank)
   964			p.expr(x.Value)
   965	
   966		default:
   967			panic("unreachable")
   968		}
   969	}
   970	
   971	func (p *printer) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool {
   972		if x, ok := expr.(*ast.SelectorExpr); ok {
   973			return p.selectorExpr(x, depth, true)
   974		}
   975		p.expr1(expr, prec1, depth)
   976		return false
   977	}
   978	
   979	
   980	
   981	func (p *printer) selectorExpr(x *ast.SelectorExpr, depth int, isMethod bool) bool {
   982		p.expr1(x.X, token.HighestPrec, depth)
   983		p.print(token.PERIOD)
   984		if line := p.lineFor(x.Sel.Pos()); p.pos.IsValid() && p.pos.Line < line {
   985			p.print(indent, newline, x.Sel.Pos(), x.Sel)
   986			if !isMethod {
   987				p.print(unindent)
   988			}
   989			return true
   990		}
   991		p.print(x.Sel.Pos(), x.Sel)
   992		return false
   993	}
   994	
   995	func (p *printer) expr0(x ast.Expr, depth int) {
   996		p.expr1(x, token.LowestPrec, depth)
   997	}
   998	
   999	func (p *printer) expr(x ast.Expr) {
  1000		const depth = 1
  1001		p.expr1(x, token.LowestPrec, depth)
  1002	}
  1003	
  1004	
  1005	
  1006	
  1007	
  1008	
  1009	
  1010	func (p *printer) stmtList(list []ast.Stmt, nindent int, nextIsRBrace bool) {
  1011		if nindent > 0 {
  1012			p.print(indent)
  1013		}
  1014		var line int
  1015		i := 0
  1016		for _, s := range list {
  1017			
  1018			if _, isEmpty := s.(*ast.EmptyStmt); !isEmpty {
  1019				
  1020				
  1021				if len(p.output) > 0 {
  1022					
  1023					
  1024					p.linebreak(p.lineFor(s.Pos()), 1, ignore, i == 0 || nindent == 0 || p.linesFrom(line) > 0)
  1025				}
  1026				p.recordLine(&line)
  1027				p.stmt(s, nextIsRBrace && i == len(list)-1)
  1028				
  1029				
  1030				
  1031				for t := s; ; {
  1032					lt, _ := t.(*ast.LabeledStmt)
  1033					if lt == nil {
  1034						break
  1035					}
  1036					line++
  1037					t = lt.Stmt
  1038				}
  1039				i++
  1040			}
  1041		}
  1042		if nindent > 0 {
  1043			p.print(unindent)
  1044		}
  1045	}
  1046	
  1047	
  1048	func (p *printer) block(b *ast.BlockStmt, nindent int) {
  1049		p.print(b.Lbrace, token.LBRACE)
  1050		p.stmtList(b.List, nindent, true)
  1051		p.linebreak(p.lineFor(b.Rbrace), 1, ignore, true)
  1052		p.print(b.Rbrace, token.RBRACE)
  1053	}
  1054	
  1055	func isTypeName(x ast.Expr) bool {
  1056		switch t := x.(type) {
  1057		case *ast.Ident:
  1058			return true
  1059		case *ast.SelectorExpr:
  1060			return isTypeName(t.X)
  1061		}
  1062		return false
  1063	}
  1064	
  1065	func stripParens(x ast.Expr) ast.Expr {
  1066		if px, strip := x.(*ast.ParenExpr); strip {
  1067			
  1068			
  1069			
  1070			ast.Inspect(px.X, func(node ast.Node) bool {
  1071				switch x := node.(type) {
  1072				case *ast.ParenExpr:
  1073					
  1074					return false
  1075				case *ast.CompositeLit:
  1076					if isTypeName(x.Type) {
  1077						strip = false 
  1078					}
  1079					return false
  1080				}
  1081				
  1082				return true
  1083			})
  1084			if strip {
  1085				return stripParens(px.X)
  1086			}
  1087		}
  1088		return x
  1089	}
  1090	
  1091	func stripParensAlways(x ast.Expr) ast.Expr {
  1092		if x, ok := x.(*ast.ParenExpr); ok {
  1093			return stripParensAlways(x.X)
  1094		}
  1095		return x
  1096	}
  1097	
  1098	func (p *printer) controlClause(isForStmt bool, init ast.Stmt, expr ast.Expr, post ast.Stmt) {
  1099		p.print(blank)
  1100		needsBlank := false
  1101		if init == nil && post == nil {
  1102			
  1103			if expr != nil {
  1104				p.expr(stripParens(expr))
  1105				needsBlank = true
  1106			}
  1107		} else {
  1108			
  1109			
  1110			if init != nil {
  1111				p.stmt(init, false)
  1112			}
  1113			p.print(token.SEMICOLON, blank)
  1114			if expr != nil {
  1115				p.expr(stripParens(expr))
  1116				needsBlank = true
  1117			}
  1118			if isForStmt {
  1119				p.print(token.SEMICOLON, blank)
  1120				needsBlank = false
  1121				if post != nil {
  1122					p.stmt(post, false)
  1123					needsBlank = true
  1124				}
  1125			}
  1126		}
  1127		if needsBlank {
  1128			p.print(blank)
  1129		}
  1130	}
  1131	
  1132	
  1133	
  1134	
  1135	
  1136	func (p *printer) indentList(list []ast.Expr) bool {
  1137		
  1138		
  1139		
  1140		if len(list) >= 2 {
  1141			var b = p.lineFor(list[0].Pos())
  1142			var e = p.lineFor(list[len(list)-1].End())
  1143			if 0 < b && b < e {
  1144				
  1145				n := 0 
  1146				line := b
  1147				for _, x := range list {
  1148					xb := p.lineFor(x.Pos())
  1149					xe := p.lineFor(x.End())
  1150					if line < xb {
  1151						
  1152						
  1153						return true
  1154					}
  1155					if xb < xe {
  1156						
  1157						n++
  1158					}
  1159					line = xe
  1160				}
  1161				return n > 1
  1162			}
  1163		}
  1164		return false
  1165	}
  1166	
  1167	func (p *printer) stmt(stmt ast.Stmt, nextIsRBrace bool) {
  1168		p.print(stmt.Pos())
  1169	
  1170		switch s := stmt.(type) {
  1171		case *ast.BadStmt:
  1172			p.print("BadStmt")
  1173	
  1174		case *ast.DeclStmt:
  1175			p.decl(s.Decl)
  1176	
  1177		case *ast.EmptyStmt:
  1178			
  1179	
  1180		case *ast.LabeledStmt:
  1181			
  1182			
  1183			
  1184			p.print(unindent)
  1185			p.expr(s.Label)
  1186			p.print(s.Colon, token.COLON, indent)
  1187			if e, isEmpty := s.Stmt.(*ast.EmptyStmt); isEmpty {
  1188				if !nextIsRBrace {
  1189					p.print(newline, e.Pos(), token.SEMICOLON)
  1190					break
  1191				}
  1192			} else {
  1193				p.linebreak(p.lineFor(s.Stmt.Pos()), 1, ignore, true)
  1194			}
  1195			p.stmt(s.Stmt, nextIsRBrace)
  1196	
  1197		case *ast.ExprStmt:
  1198			const depth = 1
  1199			p.expr0(s.X, depth)
  1200	
  1201		case *ast.SendStmt:
  1202			const depth = 1
  1203			p.expr0(s.Chan, depth)
  1204			p.print(blank, s.Arrow, token.ARROW, blank)
  1205			p.expr0(s.Value, depth)
  1206	
  1207		case *ast.IncDecStmt:
  1208			const depth = 1
  1209			p.expr0(s.X, depth+1)
  1210			p.print(s.TokPos, s.Tok)
  1211	
  1212		case *ast.AssignStmt:
  1213			var depth = 1
  1214			if len(s.Lhs) > 1 && len(s.Rhs) > 1 {
  1215				depth++
  1216			}
  1217			p.exprList(s.Pos(), s.Lhs, depth, 0, s.TokPos, false)
  1218			p.print(blank, s.TokPos, s.Tok, blank)
  1219			p.exprList(s.TokPos, s.Rhs, depth, 0, token.NoPos, false)
  1220	
  1221		case *ast.GoStmt:
  1222			p.print(token.GO, blank)
  1223			p.expr(s.Call)
  1224	
  1225		case *ast.DeferStmt:
  1226			p.print(token.DEFER, blank)
  1227			p.expr(s.Call)
  1228	
  1229		case *ast.ReturnStmt:
  1230			p.print(token.RETURN)
  1231			if s.Results != nil {
  1232				p.print(blank)
  1233				
  1234				
  1235				
  1236				
  1237				
  1238				if p.indentList(s.Results) {
  1239					p.print(indent)
  1240					p.exprList(s.Pos(), s.Results, 1, noIndent, token.NoPos, false)
  1241					p.print(unindent)
  1242				} else {
  1243					p.exprList(s.Pos(), s.Results, 1, 0, token.NoPos, false)
  1244				}
  1245			}
  1246	
  1247		case *ast.BranchStmt:
  1248			p.print(s.Tok)
  1249			if s.Label != nil {
  1250				p.print(blank)
  1251				p.expr(s.Label)
  1252			}
  1253	
  1254		case *ast.BlockStmt:
  1255			p.block(s, 1)
  1256	
  1257		case *ast.IfStmt:
  1258			p.print(token.IF)
  1259			p.controlClause(false, s.Init, s.Cond, nil)
  1260			p.block(s.Body, 1)
  1261			if s.Else != nil {
  1262				p.print(blank, token.ELSE, blank)
  1263				switch s.Else.(type) {
  1264				case *ast.BlockStmt, *ast.IfStmt:
  1265					p.stmt(s.Else, nextIsRBrace)
  1266				default:
  1267					
  1268					
  1269					
  1270					p.print(token.LBRACE, indent, formfeed)
  1271					p.stmt(s.Else, true)
  1272					p.print(unindent, formfeed, token.RBRACE)
  1273				}
  1274			}
  1275	
  1276		case *ast.CaseClause:
  1277			if s.List != nil {
  1278				p.print(token.CASE, blank)
  1279				p.exprList(s.Pos(), s.List, 1, 0, s.Colon, false)
  1280			} else {
  1281				p.print(token.DEFAULT)
  1282			}
  1283			p.print(s.Colon, token.COLON)
  1284			p.stmtList(s.Body, 1, nextIsRBrace)
  1285	
  1286		case *ast.SwitchStmt:
  1287			p.print(token.SWITCH)
  1288			p.controlClause(false, s.Init, s.Tag, nil)
  1289			p.block(s.Body, 0)
  1290	
  1291		case *ast.TypeSwitchStmt:
  1292			p.print(token.SWITCH)
  1293			if s.Init != nil {
  1294				p.print(blank)
  1295				p.stmt(s.Init, false)
  1296				p.print(token.SEMICOLON)
  1297			}
  1298			p.print(blank)
  1299			p.stmt(s.Assign, false)
  1300			p.print(blank)
  1301			p.block(s.Body, 0)
  1302	
  1303		case *ast.CommClause:
  1304			if s.Comm != nil {
  1305				p.print(token.CASE, blank)
  1306				p.stmt(s.Comm, false)
  1307			} else {
  1308				p.print(token.DEFAULT)
  1309			}
  1310			p.print(s.Colon, token.COLON)
  1311			p.stmtList(s.Body, 1, nextIsRBrace)
  1312	
  1313		case *ast.SelectStmt:
  1314			p.print(token.SELECT, blank)
  1315			body := s.Body
  1316			if len(body.List) == 0 && !p.commentBefore(p.posFor(body.Rbrace)) {
  1317				
  1318				p.print(body.Lbrace, token.LBRACE, body.Rbrace, token.RBRACE)
  1319			} else {
  1320				p.block(body, 0)
  1321			}
  1322	
  1323		case *ast.ForStmt:
  1324			p.print(token.FOR)
  1325			p.controlClause(true, s.Init, s.Cond, s.Post)
  1326			p.block(s.Body, 1)
  1327	
  1328		case *ast.RangeStmt:
  1329			p.print(token.FOR, blank)
  1330			if s.Key != nil {
  1331				p.expr(s.Key)
  1332				if s.Value != nil {
  1333					
  1334					
  1335					p.print(s.Value.Pos(), token.COMMA, blank)
  1336					p.expr(s.Value)
  1337				}
  1338				p.print(blank, s.TokPos, s.Tok, blank)
  1339			}
  1340			p.print(token.RANGE, blank)
  1341			p.expr(stripParens(s.X))
  1342			p.print(blank)
  1343			p.block(s.Body, 1)
  1344	
  1345		default:
  1346			panic("unreachable")
  1347		}
  1348	}
  1349	
  1350	
  1351	
  1352	
  1353	
  1354	
  1355	
  1356	
  1357	
  1358	
  1359	
  1360	
  1361	
  1362	
  1363	
  1364	
  1365	
  1366	
  1367	
  1368	
  1369	
  1370	
  1371	
  1372	
  1373	
  1374	
  1375	
  1376	
  1377	
  1378	func keepTypeColumn(specs []ast.Spec) []bool {
  1379		m := make([]bool, len(specs))
  1380	
  1381		populate := func(i, j int, keepType bool) {
  1382			if keepType {
  1383				for ; i < j; i++ {
  1384					m[i] = true
  1385				}
  1386			}
  1387		}
  1388	
  1389		i0 := -1 
  1390		var keepType bool
  1391		for i, s := range specs {
  1392			t := s.(*ast.ValueSpec)
  1393			if t.Values != nil {
  1394				if i0 < 0 {
  1395					
  1396					i0 = i
  1397					keepType = false
  1398				}
  1399			} else {
  1400				if i0 >= 0 {
  1401					
  1402					populate(i0, i, keepType)
  1403					i0 = -1
  1404				}
  1405			}
  1406			if t.Type != nil {
  1407				keepType = true
  1408			}
  1409		}
  1410		if i0 >= 0 {
  1411			
  1412			populate(i0, len(specs), keepType)
  1413		}
  1414	
  1415		return m
  1416	}
  1417	
  1418	func (p *printer) valueSpec(s *ast.ValueSpec, keepType bool) {
  1419		p.setComment(s.Doc)
  1420		p.identList(s.Names, false) 
  1421		extraTabs := 3
  1422		if s.Type != nil || keepType {
  1423			p.print(vtab)
  1424			extraTabs--
  1425		}
  1426		if s.Type != nil {
  1427			p.expr(s.Type)
  1428		}
  1429		if s.Values != nil {
  1430			p.print(vtab, token.ASSIGN, blank)
  1431			p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
  1432			extraTabs--
  1433		}
  1434		if s.Comment != nil {
  1435			for ; extraTabs > 0; extraTabs-- {
  1436				p.print(vtab)
  1437			}
  1438			p.setComment(s.Comment)
  1439		}
  1440	}
  1441	
  1442	func sanitizeImportPath(lit *ast.BasicLit) *ast.BasicLit {
  1443		
  1444		
  1445		
  1446		
  1447		
  1448		
  1449	
  1450		
  1451		if lit.Kind != token.STRING {
  1452			return lit
  1453		}
  1454		s, err := strconv.Unquote(lit.Value)
  1455		if err != nil {
  1456			return lit
  1457		}
  1458	
  1459		
  1460		
  1461		
  1462		
  1463		
  1464		
  1465		
  1466		
  1467		if s == "" {
  1468			return lit
  1469		}
  1470		const illegalChars = `!"#$%&'()*,:;<=>?[\]^{|}` + "`\uFFFD"
  1471		for _, r := range s {
  1472			if !unicode.IsGraphic(r) || unicode.IsSpace(r) || strings.ContainsRune(illegalChars, r) {
  1473				return lit
  1474			}
  1475		}
  1476	
  1477		
  1478		s = strconv.Quote(s)
  1479		if s == lit.Value {
  1480			return lit 
  1481		}
  1482		return &ast.BasicLit{ValuePos: lit.ValuePos, Kind: token.STRING, Value: s}
  1483	}
  1484	
  1485	
  1486	
  1487	
  1488	
  1489	func (p *printer) spec(spec ast.Spec, n int, doIndent bool) {
  1490		switch s := spec.(type) {
  1491		case *ast.ImportSpec:
  1492			p.setComment(s.Doc)
  1493			if s.Name != nil {
  1494				p.expr(s.Name)
  1495				p.print(blank)
  1496			}
  1497			p.expr(sanitizeImportPath(s.Path))
  1498			p.setComment(s.Comment)
  1499			p.print(s.EndPos)
  1500	
  1501		case *ast.ValueSpec:
  1502			if n != 1 {
  1503				p.internalError("expected n = 1; got", n)
  1504			}
  1505			p.setComment(s.Doc)
  1506			p.identList(s.Names, doIndent) 
  1507			if s.Type != nil {
  1508				p.print(blank)
  1509				p.expr(s.Type)
  1510			}
  1511			if s.Values != nil {
  1512				p.print(blank, token.ASSIGN, blank)
  1513				p.exprList(token.NoPos, s.Values, 1, 0, token.NoPos, false)
  1514			}
  1515			p.setComment(s.Comment)
  1516	
  1517		case *ast.TypeSpec:
  1518			p.setComment(s.Doc)
  1519			p.expr(s.Name)
  1520			if n == 1 {
  1521				p.print(blank)
  1522			} else {
  1523				p.print(vtab)
  1524			}
  1525			if s.Assign.IsValid() {
  1526				p.print(token.ASSIGN, blank)
  1527			}
  1528			p.expr(s.Type)
  1529			p.setComment(s.Comment)
  1530	
  1531		default:
  1532			panic("unreachable")
  1533		}
  1534	}
  1535	
  1536	func (p *printer) genDecl(d *ast.GenDecl) {
  1537		p.setComment(d.Doc)
  1538		p.print(d.Pos(), d.Tok, blank)
  1539	
  1540		if d.Lparen.IsValid() || len(d.Specs) > 1 {
  1541			
  1542			p.print(d.Lparen, token.LPAREN)
  1543			if n := len(d.Specs); n > 0 {
  1544				p.print(indent, formfeed)
  1545				if n > 1 && (d.Tok == token.CONST || d.Tok == token.VAR) {
  1546					
  1547					
  1548					keepType := keepTypeColumn(d.Specs)
  1549					var line int
  1550					for i, s := range d.Specs {
  1551						if i > 0 {
  1552							p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
  1553						}
  1554						p.recordLine(&line)
  1555						p.valueSpec(s.(*ast.ValueSpec), keepType[i])
  1556					}
  1557				} else {
  1558					var line int
  1559					for i, s := range d.Specs {
  1560						if i > 0 {
  1561							p.linebreak(p.lineFor(s.Pos()), 1, ignore, p.linesFrom(line) > 0)
  1562						}
  1563						p.recordLine(&line)
  1564						p.spec(s, n, false)
  1565					}
  1566				}
  1567				p.print(unindent, formfeed)
  1568			}
  1569			p.print(d.Rparen, token.RPAREN)
  1570	
  1571		} else if len(d.Specs) > 0 {
  1572			
  1573			p.spec(d.Specs[0], 1, true)
  1574		}
  1575	}
  1576	
  1577	
  1578	
  1579	
  1580	
  1581	
  1582	func (p *printer) nodeSize(n ast.Node, maxSize int) (size int) {
  1583		
  1584		
  1585		
  1586		
  1587		if size, found := p.nodeSizes[n]; found {
  1588			return size
  1589		}
  1590	
  1591		size = maxSize + 1 
  1592		p.nodeSizes[n] = size
  1593	
  1594		
  1595		
  1596		
  1597		cfg := Config{Mode: RawFormat}
  1598		var buf bytes.Buffer
  1599		if err := cfg.fprint(&buf, p.fset, n, p.nodeSizes); err != nil {
  1600			return
  1601		}
  1602		if buf.Len() <= maxSize {
  1603			for _, ch := range buf.Bytes() {
  1604				if ch < ' ' {
  1605					return
  1606				}
  1607			}
  1608			size = buf.Len() 
  1609			p.nodeSizes[n] = size
  1610		}
  1611		return
  1612	}
  1613	
  1614	
  1615	func (p *printer) numLines(n ast.Node) int {
  1616		if from := n.Pos(); from.IsValid() {
  1617			if to := n.End(); to.IsValid() {
  1618				return p.lineFor(to) - p.lineFor(from) + 1
  1619			}
  1620		}
  1621		return infinity
  1622	}
  1623	
  1624	
  1625	func (p *printer) bodySize(b *ast.BlockStmt, maxSize int) int {
  1626		pos1 := b.Pos()
  1627		pos2 := b.Rbrace
  1628		if pos1.IsValid() && pos2.IsValid() && p.lineFor(pos1) != p.lineFor(pos2) {
  1629			
  1630			return maxSize + 1
  1631		}
  1632		if len(b.List) > 5 {
  1633			
  1634			return maxSize + 1
  1635		}
  1636		
  1637		bodySize := p.commentSizeBefore(p.posFor(pos2))
  1638		for i, s := range b.List {
  1639			if bodySize > maxSize {
  1640				break 
  1641			}
  1642			if i > 0 {
  1643				bodySize += 2 
  1644			}
  1645			bodySize += p.nodeSize(s, maxSize)
  1646		}
  1647		return bodySize
  1648	}
  1649	
  1650	
  1651	
  1652	
  1653	
  1654	
  1655	
  1656	func (p *printer) funcBody(headerSize int, sep whiteSpace, b *ast.BlockStmt) {
  1657		if b == nil {
  1658			return
  1659		}
  1660	
  1661		
  1662		defer func(level int) {
  1663			p.level = level
  1664		}(p.level)
  1665		p.level = 0
  1666	
  1667		const maxSize = 100
  1668		if headerSize+p.bodySize(b, maxSize) <= maxSize {
  1669			p.print(sep, b.Lbrace, token.LBRACE)
  1670			if len(b.List) > 0 {
  1671				p.print(blank)
  1672				for i, s := range b.List {
  1673					if i > 0 {
  1674						p.print(token.SEMICOLON, blank)
  1675					}
  1676					p.stmt(s, i == len(b.List)-1)
  1677				}
  1678				p.print(blank)
  1679			}
  1680			p.print(noExtraLinebreak, b.Rbrace, token.RBRACE, noExtraLinebreak)
  1681			return
  1682		}
  1683	
  1684		if sep != ignore {
  1685			p.print(blank) 
  1686		}
  1687		p.block(b, 1)
  1688	}
  1689	
  1690	
  1691	
  1692	
  1693	func (p *printer) distanceFrom(from token.Pos) int {
  1694		if from.IsValid() && p.pos.IsValid() {
  1695			if f := p.posFor(from); f.Line == p.pos.Line {
  1696				return p.pos.Column - f.Column
  1697			}
  1698		}
  1699		return infinity
  1700	}
  1701	
  1702	func (p *printer) funcDecl(d *ast.FuncDecl) {
  1703		p.setComment(d.Doc)
  1704		p.print(d.Pos(), token.FUNC, blank)
  1705		if d.Recv != nil {
  1706			p.parameters(d.Recv) 
  1707			p.print(blank)
  1708		}
  1709		p.expr(d.Name)
  1710		p.signature(d.Type.Params, d.Type.Results)
  1711		p.funcBody(p.distanceFrom(d.Pos()), vtab, d.Body)
  1712	}
  1713	
  1714	func (p *printer) decl(decl ast.Decl) {
  1715		switch d := decl.(type) {
  1716		case *ast.BadDecl:
  1717			p.print(d.Pos(), "BadDecl")
  1718		case *ast.GenDecl:
  1719			p.genDecl(d)
  1720		case *ast.FuncDecl:
  1721			p.funcDecl(d)
  1722		default:
  1723			panic("unreachable")
  1724		}
  1725	}
  1726	
  1727	
  1728	
  1729	
  1730	func declToken(decl ast.Decl) (tok token.Token) {
  1731		tok = token.ILLEGAL
  1732		switch d := decl.(type) {
  1733		case *ast.GenDecl:
  1734			tok = d.Tok
  1735		case *ast.FuncDecl:
  1736			tok = token.FUNC
  1737		}
  1738		return
  1739	}
  1740	
  1741	func (p *printer) declList(list []ast.Decl) {
  1742		tok := token.ILLEGAL
  1743		for _, d := range list {
  1744			prev := tok
  1745			tok = declToken(d)
  1746			
  1747			
  1748			
  1749			
  1750			
  1751			
  1752			
  1753			if len(p.output) > 0 {
  1754				
  1755				
  1756				min := 1
  1757				if prev != tok || getDoc(d) != nil {
  1758					min = 2
  1759				}
  1760				
  1761				
  1762				p.linebreak(p.lineFor(d.Pos()), min, ignore, tok == token.FUNC && p.numLines(d) > 1)
  1763			}
  1764			p.decl(d)
  1765		}
  1766	}
  1767	
  1768	func (p *printer) file(src *ast.File) {
  1769		p.setComment(src.Doc)
  1770		p.print(src.Pos(), token.PACKAGE, blank)
  1771		p.expr(src.Name)
  1772		p.declList(src.Decls)
  1773		p.print(newline)
  1774	}
  1775	
View as plain text