...

Source file src/pkg/cmd/go/internal/modfile/print.go

     1	// Copyright 2018 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	// Module file printer.
     6	
     7	package modfile
     8	
     9	import (
    10		"bytes"
    11		"fmt"
    12		"strings"
    13	)
    14	
    15	func Format(f *FileSyntax) []byte {
    16		pr := &printer{}
    17		pr.file(f)
    18		return pr.Bytes()
    19	}
    20	
    21	// A printer collects the state during printing of a file or expression.
    22	type printer struct {
    23		bytes.Buffer           // output buffer
    24		comment      []Comment // pending end-of-line comments
    25		margin       int       // left margin (indent), a number of tabs
    26	}
    27	
    28	// printf prints to the buffer.
    29	func (p *printer) printf(format string, args ...interface{}) {
    30		fmt.Fprintf(p, format, args...)
    31	}
    32	
    33	// indent returns the position on the current line, in bytes, 0-indexed.
    34	func (p *printer) indent() int {
    35		b := p.Bytes()
    36		n := 0
    37		for n < len(b) && b[len(b)-1-n] != '\n' {
    38			n++
    39		}
    40		return n
    41	}
    42	
    43	// newline ends the current line, flushing end-of-line comments.
    44	func (p *printer) newline() {
    45		if len(p.comment) > 0 {
    46			p.printf(" ")
    47			for i, com := range p.comment {
    48				if i > 0 {
    49					p.trim()
    50					p.printf("\n")
    51					for i := 0; i < p.margin; i++ {
    52						p.printf("\t")
    53					}
    54				}
    55				p.printf("%s", strings.TrimSpace(com.Token))
    56			}
    57			p.comment = p.comment[:0]
    58		}
    59	
    60		p.trim()
    61		p.printf("\n")
    62		for i := 0; i < p.margin; i++ {
    63			p.printf("\t")
    64		}
    65	}
    66	
    67	// trim removes trailing spaces and tabs from the current line.
    68	func (p *printer) trim() {
    69		// Remove trailing spaces and tabs from line we're about to end.
    70		b := p.Bytes()
    71		n := len(b)
    72		for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') {
    73			n--
    74		}
    75		p.Truncate(n)
    76	}
    77	
    78	// file formats the given file into the print buffer.
    79	func (p *printer) file(f *FileSyntax) {
    80		for _, com := range f.Before {
    81			p.printf("%s", strings.TrimSpace(com.Token))
    82			p.newline()
    83		}
    84	
    85		for i, stmt := range f.Stmt {
    86			switch x := stmt.(type) {
    87			case *CommentBlock:
    88				// comments already handled
    89				p.expr(x)
    90	
    91			default:
    92				p.expr(x)
    93				p.newline()
    94			}
    95	
    96			for _, com := range stmt.Comment().After {
    97				p.printf("%s", strings.TrimSpace(com.Token))
    98				p.newline()
    99			}
   100	
   101			if i+1 < len(f.Stmt) {
   102				p.newline()
   103			}
   104		}
   105	}
   106	
   107	func (p *printer) expr(x Expr) {
   108		// Emit line-comments preceding this expression.
   109		if before := x.Comment().Before; len(before) > 0 {
   110			// Want to print a line comment.
   111			// Line comments must be at the current margin.
   112			p.trim()
   113			if p.indent() > 0 {
   114				// There's other text on the line. Start a new line.
   115				p.printf("\n")
   116			}
   117			// Re-indent to margin.
   118			for i := 0; i < p.margin; i++ {
   119				p.printf("\t")
   120			}
   121			for _, com := range before {
   122				p.printf("%s", strings.TrimSpace(com.Token))
   123				p.newline()
   124			}
   125		}
   126	
   127		switch x := x.(type) {
   128		default:
   129			panic(fmt.Errorf("printer: unexpected type %T", x))
   130	
   131		case *CommentBlock:
   132			// done
   133	
   134		case *LParen:
   135			p.printf("(")
   136		case *RParen:
   137			p.printf(")")
   138	
   139		case *Line:
   140			sep := ""
   141			for _, tok := range x.Token {
   142				p.printf("%s%s", sep, tok)
   143				sep = " "
   144			}
   145	
   146		case *LineBlock:
   147			for _, tok := range x.Token {
   148				p.printf("%s ", tok)
   149			}
   150			p.expr(&x.LParen)
   151			p.margin++
   152			for _, l := range x.Line {
   153				p.newline()
   154				p.expr(l)
   155			}
   156			p.margin--
   157			p.newline()
   158			p.expr(&x.RParen)
   159		}
   160	
   161		// Queue end-of-line comments for printing when we
   162		// reach the end of the line.
   163		p.comment = append(p.comment, x.Comment().Suffix...)
   164	}
   165	

View as plain text