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

     1  package ast
     2  
     3  // Node is the interface implemented by all nodes in the AST. It
     4  // provides information about the span of this AST node in terms
     5  // of location in the source file. It also provides information
     6  // about all prior comments (attached as leading comments) and
     7  // optional subsequent comments (attached as trailing comments).
     8  type Node interface {
     9  	Start() *SourcePos
    10  	End() *SourcePos
    11  	LeadingComments() []Comment
    12  	TrailingComments() []Comment
    13  }
    14  
    15  // TerminalNode represents a leaf in the AST. These represent
    16  // the tokens/lexemes in the protobuf language. Comments and
    17  // whitespace are accumulated by the lexer and associated with
    18  // the following lexed token.
    19  type TerminalNode interface {
    20  	Node
    21  	// PopLeadingComment removes the first leading comment from this
    22  	// token and returns it. If the node has no leading comments then
    23  	// this method will panic.
    24  	PopLeadingComment() Comment
    25  	// PushTrailingComment appends the given comment to the token's
    26  	// trailing comments.
    27  	PushTrailingComment(Comment)
    28  	// LeadingWhitespace returns any whitespace between the prior comment
    29  	// (last leading comment), if any, or prior lexed token and this token.
    30  	LeadingWhitespace() string
    31  	// RawText returns the raw text of the token as read from the source.
    32  	RawText() string
    33  }
    34  
    35  var _ TerminalNode = (*StringLiteralNode)(nil)
    36  var _ TerminalNode = (*UintLiteralNode)(nil)
    37  var _ TerminalNode = (*FloatLiteralNode)(nil)
    38  var _ TerminalNode = (*IdentNode)(nil)
    39  var _ TerminalNode = (*BoolLiteralNode)(nil)
    40  var _ TerminalNode = (*SpecialFloatLiteralNode)(nil)
    41  var _ TerminalNode = (*KeywordNode)(nil)
    42  var _ TerminalNode = (*RuneNode)(nil)
    43  
    44  // TokenInfo represents state accumulated by the lexer to associated with a
    45  // token (aka terminal node).
    46  type TokenInfo struct {
    47  	// The location of the token in the source file.
    48  	PosRange
    49  	// The raw text of the token.
    50  	RawText string
    51  	// Any comments encountered preceding this token.
    52  	LeadingComments []Comment
    53  	// Any leading whitespace immediately preceding this token.
    54  	LeadingWhitespace string
    55  	// Any trailing comments following this token. This is usually
    56  	// empty as tokens are created by the lexer immediately and
    57  	// trailing comments are accounted for afterwards, added using
    58  	// the node's PushTrailingComment method.
    59  	TrailingComments []Comment
    60  }
    61  
    62  func (t *TokenInfo) asTerminalNode() terminalNode {
    63  	return terminalNode{
    64  		posRange:          t.PosRange,
    65  		leadingComments:   t.LeadingComments,
    66  		leadingWhitespace: t.LeadingWhitespace,
    67  		trailingComments:  t.TrailingComments,
    68  		raw:               t.RawText,
    69  	}
    70  }
    71  
    72  // CompositeNode represents any non-terminal node in the tree. These
    73  // are interior or root nodes and have child nodes.
    74  type CompositeNode interface {
    75  	Node
    76  	// All AST nodes that are immediate children of this one.
    77  	Children() []Node
    78  }
    79  
    80  // terminalNode contains book-keeping shared by all TerminalNode
    81  // implementations. It is embedded in all such node types in this
    82  // package. It provides the implementation of the TerminalNode
    83  // interface.
    84  type terminalNode struct {
    85  	posRange          PosRange
    86  	leadingComments   []Comment
    87  	leadingWhitespace string
    88  	trailingComments  []Comment
    89  	raw               string
    90  }
    91  
    92  func (n *terminalNode) Start() *SourcePos {
    93  	return &n.posRange.Start
    94  }
    95  
    96  func (n *terminalNode) End() *SourcePos {
    97  	return &n.posRange.End
    98  }
    99  
   100  func (n *terminalNode) LeadingComments() []Comment {
   101  	return n.leadingComments
   102  }
   103  
   104  func (n *terminalNode) TrailingComments() []Comment {
   105  	return n.trailingComments
   106  }
   107  
   108  func (n *terminalNode) PopLeadingComment() Comment {
   109  	c := n.leadingComments[0]
   110  	n.leadingComments = n.leadingComments[1:]
   111  	return c
   112  }
   113  
   114  func (n *terminalNode) PushTrailingComment(c Comment) {
   115  	n.trailingComments = append(n.trailingComments, c)
   116  }
   117  
   118  func (n *terminalNode) LeadingWhitespace() string {
   119  	return n.leadingWhitespace
   120  }
   121  
   122  func (n *terminalNode) RawText() string {
   123  	return n.raw
   124  }
   125  
   126  // compositeNode contains book-keeping shared by all CompositeNode
   127  // implementations. It is embedded in all such node types in this
   128  // package. It provides the implementation of the CompositeNode
   129  // interface.
   130  type compositeNode struct {
   131  	children []Node
   132  }
   133  
   134  func (n *compositeNode) Children() []Node {
   135  	return n.children
   136  }
   137  
   138  func (n *compositeNode) Start() *SourcePos {
   139  	return n.children[0].Start()
   140  }
   141  
   142  func (n *compositeNode) End() *SourcePos {
   143  	return n.children[len(n.children)-1].End()
   144  }
   145  
   146  func (n *compositeNode) LeadingComments() []Comment {
   147  	return n.children[0].LeadingComments()
   148  }
   149  
   150  func (n *compositeNode) TrailingComments() []Comment {
   151  	return n.children[len(n.children)-1].TrailingComments()
   152  }
   153  
   154  // RuneNode represents a single rune in protobuf source. Runes
   155  // are typically collected into tokens, but some runes stand on
   156  // their own, such as punctuation/symbols like commas, semicolons,
   157  // equals signs, open and close symbols (braces, brackets, angles,
   158  // and parentheses), and periods/dots.
   159  type RuneNode struct {
   160  	terminalNode
   161  	Rune rune
   162  }
   163  
   164  // NewRuneNode creates a new *RuneNode with the given properties.
   165  func NewRuneNode(r rune, info TokenInfo) *RuneNode {
   166  	return &RuneNode{
   167  		terminalNode: info.asTerminalNode(),
   168  		Rune:         r,
   169  	}
   170  }
   171  
   172  // EmptyDeclNode represents an empty declaration in protobuf source.
   173  // These amount to extra semicolons, with no actual content preceding
   174  // the semicolon.
   175  type EmptyDeclNode struct {
   176  	compositeNode
   177  	Semicolon *RuneNode
   178  }
   179  
   180  // NewEmptyDeclNode creates a new *EmptyDeclNode. The one argument must
   181  // be non-nil.
   182  func NewEmptyDeclNode(semicolon *RuneNode) *EmptyDeclNode {
   183  	if semicolon == nil {
   184  		panic("semicolon is nil")
   185  	}
   186  	return &EmptyDeclNode{
   187  		compositeNode: compositeNode{
   188  			children: []Node{semicolon},
   189  		},
   190  		Semicolon: semicolon,
   191  	}
   192  }
   193  
   194  func (e *EmptyDeclNode) fileElement()    {}
   195  func (e *EmptyDeclNode) msgElement()     {}
   196  func (e *EmptyDeclNode) extendElement()  {}
   197  func (e *EmptyDeclNode) oneOfElement()   {}
   198  func (e *EmptyDeclNode) enumElement()    {}
   199  func (e *EmptyDeclNode) serviceElement() {}
   200  func (e *EmptyDeclNode) methodElement()  {}