github.com/jhump/protocompile@v0.0.0-20221021153901-4f6f732835e8/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() Token
    10  	End() Token
    11  }
    12  
    13  // TerminalNode represents a leaf in the AST. These represent
    14  // the tokens/lexemes in the protobuf language. Comments and
    15  // whitespace are accumulated by the lexer and associated with
    16  // the following lexed token.
    17  type TerminalNode interface {
    18  	Node
    19  	Token() Token
    20  }
    21  
    22  var _ TerminalNode = (*StringLiteralNode)(nil)
    23  var _ TerminalNode = (*UintLiteralNode)(nil)
    24  var _ TerminalNode = (*FloatLiteralNode)(nil)
    25  var _ TerminalNode = (*IdentNode)(nil)
    26  var _ TerminalNode = (*BoolLiteralNode)(nil)
    27  var _ TerminalNode = (*SpecialFloatLiteralNode)(nil)
    28  var _ TerminalNode = (*KeywordNode)(nil)
    29  var _ TerminalNode = (*RuneNode)(nil)
    30  
    31  // CompositeNode represents any non-terminal node in the tree. These
    32  // are interior or root nodes and have child nodes.
    33  type CompositeNode interface {
    34  	Node
    35  	// All AST nodes that are immediate children of this one.
    36  	Children() []Node
    37  }
    38  
    39  // terminalNode contains book-keeping shared by all TerminalNode
    40  // implementations. It is embedded in all such node types in this
    41  // package. It provides the implementation of the TerminalNode
    42  // interface.
    43  type terminalNode Token
    44  
    45  func (n terminalNode) Start() Token {
    46  	return Token(n)
    47  }
    48  
    49  func (n terminalNode) End() Token {
    50  	return Token(n)
    51  }
    52  
    53  func (n terminalNode) Token() Token {
    54  	return Token(n)
    55  }
    56  
    57  // compositeNode contains book-keeping shared by all CompositeNode
    58  // implementations. It is embedded in all such node types in this
    59  // package. It provides the implementation of the CompositeNode
    60  // interface.
    61  type compositeNode struct {
    62  	children []Node
    63  }
    64  
    65  func (n *compositeNode) Children() []Node {
    66  	return n.children
    67  }
    68  
    69  func (n *compositeNode) Start() Token {
    70  	return n.children[0].Start()
    71  }
    72  
    73  func (n *compositeNode) End() Token {
    74  	return n.children[len(n.children)-1].End()
    75  }
    76  
    77  // RuneNode represents a single rune in protobuf source. Runes
    78  // are typically collected into tokens, but some runes stand on
    79  // their own, such as punctuation/symbols like commas, semicolons,
    80  // equals signs, open and close symbols (braces, brackets, angles,
    81  // and parentheses), and periods/dots.
    82  // TODO: make this more compact; if runes don't have attributed comments
    83  //  then we don't need a Token to represent them and only need an offset
    84  //  into the file's contents
    85  type RuneNode struct {
    86  	terminalNode
    87  	Rune rune
    88  }
    89  
    90  // NewRuneNode creates a new *RuneNode with the given properties.
    91  func NewRuneNode(r rune, tok Token) *RuneNode {
    92  	return &RuneNode{
    93  		terminalNode: tok.asTerminalNode(),
    94  		Rune:         r,
    95  	}
    96  }
    97  
    98  // EmptyDeclNode represents an empty declaration in protobuf source.
    99  // These amount to extra semicolons, with no actual content preceding
   100  // the semicolon.
   101  type EmptyDeclNode struct {
   102  	compositeNode
   103  	Semicolon *RuneNode
   104  }
   105  
   106  // NewEmptyDeclNode creates a new *EmptyDeclNode. The one argument must
   107  // be non-nil.
   108  func NewEmptyDeclNode(semicolon *RuneNode) *EmptyDeclNode {
   109  	if semicolon == nil {
   110  		panic("semicolon is nil")
   111  	}
   112  	return &EmptyDeclNode{
   113  		compositeNode: compositeNode{
   114  			children: []Node{semicolon},
   115  		},
   116  		Semicolon: semicolon,
   117  	}
   118  }
   119  
   120  func (e *EmptyDeclNode) fileElement()    {}
   121  func (e *EmptyDeclNode) msgElement()     {}
   122  func (e *EmptyDeclNode) extendElement()  {}
   123  func (e *EmptyDeclNode) oneOfElement()   {}
   124  func (e *EmptyDeclNode) enumElement()    {}
   125  func (e *EmptyDeclNode) serviceElement() {}
   126  func (e *EmptyDeclNode) methodElement()  {}