github.com/jhump/protoreflect@v1.16.0/desc/protoparse/ast/print.go (about)

     1  package ast
     2  
     3  import "io"
     4  
     5  // Print prints the given AST node to the given output. This operation
     6  // basically walks the AST and, for each TerminalNode, prints the node's
     7  // leading comments, leading whitespace, the node's raw text, and then
     8  // any trailing comments. If the given node is a *FileNode, it will then
     9  // also print the file's FinalComments and FinalWhitespace.
    10  func Print(w io.Writer, node Node) error {
    11  	sw, ok := w.(stringWriter)
    12  	if !ok {
    13  		sw = &strWriter{w}
    14  	}
    15  	var err error
    16  	Walk(node, func(n Node) (bool, VisitFunc) {
    17  		if err != nil {
    18  			return false, nil
    19  		}
    20  		token, ok := n.(TerminalNode)
    21  		if !ok {
    22  			return true, nil
    23  		}
    24  
    25  		err = printComments(sw, token.LeadingComments())
    26  		if err != nil {
    27  			return false, nil
    28  		}
    29  
    30  		_, err = sw.WriteString(token.LeadingWhitespace())
    31  		if err != nil {
    32  			return false, nil
    33  		}
    34  
    35  		_, err = sw.WriteString(token.RawText())
    36  		if err != nil {
    37  			return false, nil
    38  		}
    39  
    40  		err = printComments(sw, token.TrailingComments())
    41  		return false, nil
    42  	})
    43  	if err != nil {
    44  		return err
    45  	}
    46  
    47  	if file, ok := node.(*FileNode); ok {
    48  		err = printComments(sw, file.FinalComments)
    49  		if err != nil {
    50  			return err
    51  		}
    52  		_, err = sw.WriteString(file.FinalWhitespace)
    53  		return err
    54  	}
    55  
    56  	return nil
    57  }
    58  
    59  func printComments(sw stringWriter, comments []Comment) error {
    60  	for _, comment := range comments {
    61  		if _, err := sw.WriteString(comment.LeadingWhitespace); err != nil {
    62  			return err
    63  		}
    64  		if _, err := sw.WriteString(comment.Text); err != nil {
    65  			return err
    66  		}
    67  	}
    68  	return nil
    69  }
    70  
    71  // many io.Writer impls also provide a string-based method
    72  type stringWriter interface {
    73  	WriteString(s string) (n int, err error)
    74  }
    75  
    76  // adapter, in case the given writer does NOT provide a string-based method
    77  type strWriter struct {
    78  	io.Writer
    79  }
    80  
    81  func (s *strWriter) WriteString(str string) (int, error) {
    82  	if str == "" {
    83  		return 0, nil
    84  	}
    85  	return s.Write([]byte(str))
    86  }