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() {}