Source File
printer.go
Belonging Package
go/printer
package printer
import (
)
const (
maxNewlines = 2 // max. number of newlines between source text
debug = false // enable for debugging
infinity = 1 << 30
)
type whiteSpace byte
const (
ignore = whiteSpace(0)
blank = whiteSpace(' ')
vtab = whiteSpace('\v')
newline = whiteSpace('\n')
formfeed = whiteSpace('\f')
indent = whiteSpace('>')
unindent = whiteSpace('<')
)
type pmode int
const (
noExtraBlank pmode = 1 << iota // disables extra blank after /*-style comment
noExtraLinebreak // disables extra line break after /*-style comment
)
type commentInfo struct {
cindex int // current comment index
comment *ast.CommentGroup // = printer.comments[cindex]; or nil
commentOffset int // = printer.posFor(printer.comments[cindex].List[0].Pos()).Offset; or infinity
commentNewline bool // true if the comment group contains newlines
}
output []byte // raw printer result
indent int // current indentation
level int // level == 0: outside composite literal; level > 0: inside composite literal
mode pmode // current printer mode
endAlignment bool // if set, terminate alignment immediately
impliedSemi bool // if set, a linebreak implies a semicolon
lastTok token.Token // last token printed (token.ILLEGAL if it's whitespace)
prevOpen token.Token // previous non-brace "open" token (, [, or token.ILLEGAL
wsbuf []whiteSpace // delayed white space
comments []*ast.CommentGroup // may be nil
useNodeComments bool // if not set, ignore lead and line comments of nodes
cachedPos token.Pos
cachedLine int // line corresponding to cachedPos
}
func ( *printer) ( *Config, *token.FileSet, map[ast.Node]int) {
.Config = *
.fset =
.pos = token.Position{Line: 1, Column: 1}
.out = token.Position{Line: 1, Column: 1}
.wsbuf = make([]whiteSpace, 0, 16) // whitespace sequences are short
.nodeSizes =
.cachedPos = -1
}
func ( *printer) ( ...interface{}) {
if debug {
fmt.Print(.pos.String() + ": ")
fmt.Println(...)
panic("go/printer")
}
}
return true
}
if := .Text; len() >= 2 && ([1] == '/' || strings.Contains(, "\n")) {
return true
}
}
_ =
return false
}
func ( *printer) () {
for .cindex < len(.comments) {
:= .comments[.cindex]
.cindex++
if := .List; len() > 0 {
.comment =
.commentOffset = .posFor([0].Pos()).Offset
.commentNewline = .commentsHaveNewline()
return
.commentOffset = infinity
}
func ( *printer) ( token.Position) bool {
return .commentOffset < .Offset && (!.impliedSemi || !.commentNewline)
}
defer func( commentInfo) {
.commentInfo =
}(.commentInfo)
:= 0
for .commentBefore() {
for , := range .comment.List {
+= len(.Text)
}
.nextComment()
}
return
}
return .fset.PositionFor(, false /* absolute position */)
}
func ( *printer) ( token.Pos) int {
if != .cachedPos {
.cachedPos =
.cachedLine = .fset.PositionFor(, false /* absolute position */).Line
}
return .cachedLine
}
switch {
case '\t', '\v':
= ' '
case '\n', '\f':
= '\f'
.endAlignment = false
}
}
.writeIndent()
}
for := 0; < ; ++ {
.output = append(.output, )
}
.pos =
}
:= 0
var int // index of last newline; valid if nlines > 0
++
return
}
.writeByte('\f', maxNewlines)
return
}
:= false
:= 0
for , := range .wsbuf {
switch {
= true
continue
continue
}
=
break
}
.writeWhitespace()
if ! {
:= byte('\t')
= ' '
}
.writeByte(, 1)
}
continue
if .indent == 0 && {
++
}
if ! {
:= [len()-1]
= commonPrefix(, )
}
:= false
if > 0 && [-1] == ' ' {
-- // remove trailing blank from prefix so stars remain aligned
}
= [0:]
= true
:= [0]
= [2:]
[0], [1] = ' ', ' '
= [0:]
= strings.TrimSuffix(, string())
}
}
if {
= " */" // add blank to align final star
}
[len()-1] = +
= commonPrefix(, )
}
if [1] == '/' {
.writeString(, trimRight(), true)
return
}
if .IsValid() && .Column == 1 && .indent > 0 {
for , := range [1:] {
[1+] = " " +
}
}
stripCommonPrefix()
func ( *printer) ( token.Position, token.Token) (, bool) {
var *ast.Comment
for .commentBefore() {
for , := range .comment.List {
.writeCommentPrefix(.posFor(.Pos()), , , )
.writeComment()
=
}
.nextComment()
}
:= false
if .mode&noExtraBlank == 0 &&
.Text[1] == '*' && .lineFor(.Pos()) == .Line &&
!= token.COMMA &&
( != token.RPAREN || .prevOpen == token.LPAREN) &&
( != token.RBRACK || .prevOpen == token.LBRACK) {
if .containsLinebreak() && .mode&noExtraLinebreak == 0 && .level == 0 {
= true
} else {
.writeByte(' ', 1)
}
if .Text[1] == '/' ||
== token.EOF ||
== token.RBRACE && .mode&noExtraLinebreak == 0 {
= true
}
return .writeCommentSuffix()
}
.internalError("intersperseComments called without pending comments")
return
}
for := 0; < ; ++ {
switch := .wsbuf[]; {
func ( int) int {
if > maxNewlines {
= maxNewlines
}
return
}
func ( token.Token, byte) ( bool) {
switch {
case token.INT:
= == '.' // 1.
case token.ADD:
= == '+' // ++
case token.SUB:
= == '-' // --
case token.QUO:
= == '*' // /*
case token.LSS:
= == '-' || == '<' // <- or <<
case token.AND:
= == '&' || == '^' // && or &^
}
return
}
func ( *printer) ( ...interface{}) {
switch .lastTok {
.mode ^=
continue
case whiteSpace:
.writeWhitespace()
= 0
}
.wsbuf = .wsbuf[0 : +1]
.wsbuf[] =
if !.impliedSemi {
if && == maxNewlines {
= maxNewlines - 1
}
if > 0 {
:= byte('\n')
if {
= '\f' // use formfeed since we dropped one before
}
.writeByte(, )
= false
}
}
if .linePtr != nil {
*.linePtr = .out.Line
.linePtr = nil
}
.writeString(, , )
.impliedSemi =
}
}
, = .intersperseComments(, )
.writeWhitespace(len(.wsbuf))
}
return
}
func ( ast.Node) *ast.CommentGroup {
switch n := .(type) {
case *ast.Field:
return .Doc
case *ast.ImportSpec:
return .Doc
case *ast.ValueSpec:
return .Doc
case *ast.TypeSpec:
return .Doc
case *ast.GenDecl:
return .Doc
case *ast.FuncDecl:
return .Doc
case *ast.File:
return .Doc
}
return nil
}
func ( ast.Node) *ast.CommentGroup {
switch n := .(type) {
case *ast.Field:
return .Comment
case *ast.ImportSpec:
return .Comment
case *ast.ValueSpec:
return .Comment
case *ast.TypeSpec:
return .Comment
case *ast.GenDecl:
if len(.Specs) > 0 {
return (.Specs[len(.Specs)-1])
}
case *ast.File:
if len(.Comments) > 0 {
return .Comments[len(.Comments)-1]
}
}
return nil
}
var []*ast.CommentGroup
if , := .(*CommentedNode); {
= .Node
= .Comments
}
.useNodeComments = .comments == nil
.nextComment()
:= 0
var byte
for , = range {
if == '\v' {
= '\t' // convert to htab
}
switch .state {
case inSpace:
switch {
case '\t', ' ':
.space = append(.space, )
case '\n', '\f':
.resetSpace() // discard trailing space
_, = .output.Write(aNewline)
case tabwriter.Escape:
_, = .output.Write(.space)
.state = inEscape
= + 1 // +1: skip tabwriter.Escape
default:
_, = .output.Write(.space)
.state = inText
=
}
case inEscape:
if == tabwriter.Escape {
_, = .output.Write([:])
.resetSpace()
}
case inText:
switch {
case '\t', ' ':
_, = .output.Write([:])
.resetSpace()
.space = append(.space, )
case '\n', '\f':
_, = .output.Write([:])
.resetSpace()
if == nil {
_, = .output.Write(aNewline)
}
case tabwriter.Escape:
_, = .output.Write([:])
.state = inEscape
= + 1 // +1: skip tabwriter.Escape
}
default:
panic("unreachable")
}
if != nil {
return
}
}
= len()
switch .state {
case inEscape, inText:
_, = .output.Write([:])
.resetSpace()
}
return
}
normalizeNumbers Mode = 1 << 30
)
type CommentedNode struct {
Node interface{} // *ast.File, or ast.Expr, ast.Decl, ast.Spec, or ast.Stmt
Comments []*ast.CommentGroup
}
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |