Copyright 2018 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.
Module file printer.

package modfile

import (
	
	
	
)
Format returns a go.mod file as a byte slice, formatted in standard style.
func ( *FileSyntax) []byte {
	 := &printer{}
	.file()
	return .Bytes()
}
A printer collects the state during printing of a file or expression.
type printer struct {
	bytes.Buffer           // output buffer
	comment      []Comment // pending end-of-line comments
	margin       int       // left margin (indent), a number of tabs
}
printf prints to the buffer.
func ( *printer) ( string,  ...interface{}) {
	fmt.Fprintf(, , ...)
}
indent returns the position on the current line, in bytes, 0-indexed.
func ( *printer) () int {
	 := .Bytes()
	 := 0
	for  < len() && [len()-1-] != '\n' {
		++
	}
	return 
}
newline ends the current line, flushing end-of-line comments.
func ( *printer) () {
	if len(.comment) > 0 {
		.printf(" ")
		for ,  := range .comment {
			if  > 0 {
				.trim()
				.printf("\n")
				for  := 0;  < .margin; ++ {
					.printf("\t")
				}
			}
			.printf("%s", strings.TrimSpace(.Token))
		}
		.comment = .comment[:0]
	}

	.trim()
	.printf("\n")
	for  := 0;  < .margin; ++ {
		.printf("\t")
	}
}
trim removes trailing spaces and tabs from the current line.
Remove trailing spaces and tabs from line we're about to end.
	 := .Bytes()
	 := len()
	for  > 0 && ([-1] == '\t' || [-1] == ' ') {
		--
	}
	.Truncate()
}
file formats the given file into the print buffer.
func ( *printer) ( *FileSyntax) {
	for ,  := range .Before {
		.printf("%s", strings.TrimSpace(.Token))
		.newline()
	}

	for ,  := range .Stmt {
		switch x := .(type) {
comments already handled
			.expr()

		default:
			.expr()
			.newline()
		}

		for ,  := range .Comment().After {
			.printf("%s", strings.TrimSpace(.Token))
			.newline()
		}

		if +1 < len(.Stmt) {
			.newline()
		}
	}
}

Emit line-comments preceding this expression.
Want to print a line comment. Line comments must be at the current margin.
		.trim()
There's other text on the line. Start a new line.
			.printf("\n")
Re-indent to margin.
		for  := 0;  < .margin; ++ {
			.printf("\t")
		}
		for ,  := range  {
			.printf("%s", strings.TrimSpace(.Token))
			.newline()
		}
	}

	switch x := .(type) {
	default:
		panic(fmt.Errorf("printer: unexpected type %T", ))

done

	case *LParen:
		.printf("(")
	case *RParen:
		.printf(")")

	case *Line:
		.tokens(.Token)

	case *LineBlock:
		.tokens(.Token)
		.printf(" ")
		.(&.LParen)
		.margin++
		for ,  := range .Line {
			.newline()
			.()
		}
		.margin--
		.newline()
		.(&.RParen)
	}
Queue end-of-line comments for printing when we reach the end of the line.
	.comment = append(.comment, .Comment().Suffix...)
}

func ( *printer) ( []string) {
	 := ""
	for ,  := range  {
		if  == "," ||  == ")" ||  == "]" ||  == "}" {
			 = ""
		}
		.printf("%s%s", , )
		 = " "
		if  == "(" ||  == "[" ||  == "{" {
			 = ""
		}
	}