github.com/bakjos/protoreflect@v1.9.2/desc/protoparse/ast/options.go (about) 1 package ast 2 3 import "fmt" 4 5 // OptionDeclNode is a placeholder interface for AST nodes that represent 6 // options. This allows NoSourceNode to be used in place of *OptionNode 7 // for some usages. 8 type OptionDeclNode interface { 9 Node 10 GetName() Node 11 GetValue() ValueNode 12 } 13 14 var _ OptionDeclNode = (*OptionNode)(nil) 15 var _ OptionDeclNode = NoSourceNode{} 16 17 // OptionNode represents the declaration of a single option for an element. 18 // It is used both for normal option declarations (start with "option" keyword 19 // and end with semicolon) and for compact options found in fields, enum values, 20 // and extension ranges. Example: 21 // 22 // option (custom.option) = "foo"; 23 type OptionNode struct { 24 compositeNode 25 Keyword *KeywordNode // absent for compact options 26 Name *OptionNameNode 27 Equals *RuneNode 28 Val ValueNode 29 Semicolon *RuneNode // absent for compact options 30 } 31 32 func (e *OptionNode) fileElement() {} 33 func (e *OptionNode) msgElement() {} 34 func (e *OptionNode) oneOfElement() {} 35 func (e *OptionNode) enumElement() {} 36 func (e *OptionNode) serviceElement() {} 37 func (e *OptionNode) methodElement() {} 38 39 // NewOptionNode creates a new *OptionNode for a full option declaration (as 40 // used in files, messages, oneofs, enums, services, and methods). All arguments 41 // must be non-nil. (Also see NewCompactOptionNode.) 42 // - keyword: The token corresponding to the "option" keyword. 43 // - name: The token corresponding to the name of the option. 44 // - equals: The token corresponding to the "=" rune after the name. 45 // - val: The token corresponding to the option value. 46 // - semicolon: The token corresponding to the ";" rune that ends the declaration. 47 func NewOptionNode(keyword *KeywordNode, name *OptionNameNode, equals *RuneNode, val ValueNode, semicolon *RuneNode) *OptionNode { 48 if keyword == nil { 49 panic("keyword is nil") 50 } 51 if name == nil { 52 panic("name is nil") 53 } 54 if equals == nil { 55 panic("equals is nil") 56 } 57 if val == nil { 58 panic("val is nil") 59 } 60 if semicolon == nil { 61 panic("semicolon is nil") 62 } 63 children := []Node{keyword, name, equals, val, semicolon} 64 return &OptionNode{ 65 compositeNode: compositeNode{ 66 children: children, 67 }, 68 Keyword: keyword, 69 Name: name, 70 Equals: equals, 71 Val: val, 72 Semicolon: semicolon, 73 } 74 } 75 76 // NewCompactOptionNode creates a new *OptionNode for a full compact declaration 77 // (as used in fields, enum values, and extension ranges). All arguments must be 78 // non-nil. 79 // - name: The token corresponding to the name of the option. 80 // - equals: The token corresponding to the "=" rune after the name. 81 // - val: The token corresponding to the option value. 82 func NewCompactOptionNode(name *OptionNameNode, equals *RuneNode, val ValueNode) *OptionNode { 83 if name == nil { 84 panic("name is nil") 85 } 86 if equals == nil { 87 panic("equals is nil") 88 } 89 if val == nil { 90 panic("val is nil") 91 } 92 children := []Node{name, equals, val} 93 return &OptionNode{ 94 compositeNode: compositeNode{ 95 children: children, 96 }, 97 Name: name, 98 Equals: equals, 99 Val: val, 100 } 101 } 102 103 func (n *OptionNode) GetName() Node { 104 return n.Name 105 } 106 107 func (n *OptionNode) GetValue() ValueNode { 108 return n.Val 109 } 110 111 // OptionNameNode represents an option name or even a traversal through message 112 // types to name a nested option field. Example: 113 // 114 // (foo.bar).baz.(bob) 115 type OptionNameNode struct { 116 compositeNode 117 Parts []*FieldReferenceNode 118 // Dots represent the separating '.' characters between name parts. The 119 // length of this slice must be exactly len(Parts)-1, each item in Parts 120 // having a corresponding item in this slice *except the last* (since a 121 // trailing dot is not allowed). 122 // 123 // These do *not* include dots that are inside of an extension name. For 124 // example: (foo.bar).baz.(bob) has three parts: 125 // 1. (foo.bar) - an extension name 126 // 2. baz - a regular field in foo.bar 127 // 3. (bob) - an extension field in baz 128 // Note that the dot in foo.bar will thus not be present in Dots but is 129 // instead in Parts[0]. 130 Dots []*RuneNode 131 } 132 133 // NewOptionNameNode creates a new *OptionNameNode. The dots arg must have a 134 // length that is one less than the length of parts. The parts arg must not be 135 // empty. 136 func NewOptionNameNode(parts []*FieldReferenceNode, dots []*RuneNode) *OptionNameNode { 137 if len(parts) == 0 { 138 panic("must have at least one part") 139 } 140 if len(dots) != len(parts)-1 { 141 panic(fmt.Sprintf("%d parts requires %d dots, not %d", len(parts), len(parts)-1, len(dots))) 142 } 143 children := make([]Node, 0, len(parts)*2-1) 144 for i, part := range parts { 145 if part == nil { 146 panic(fmt.Sprintf("parts[%d] is nil", i)) 147 } 148 if i > 0 { 149 if dots[i-1] == nil { 150 panic(fmt.Sprintf("dots[%d] is nil", i-1)) 151 } 152 children = append(children, dots[i-1]) 153 } 154 children = append(children, part) 155 } 156 return &OptionNameNode{ 157 compositeNode: compositeNode{ 158 children: children, 159 }, 160 Parts: parts, 161 Dots: dots, 162 } 163 } 164 165 // FieldReferenceNode is a reference to a field name. It can indicate a regular 166 // field (simple unqualified name) or an extension field (possibly-qualified 167 // name that is enclosed either in brackets or parentheses). 168 // 169 // This is used in options to indicate the names of custom options (which are 170 // actually extensions), in which case the name is enclosed in parentheses "(" 171 // and ")". It is also used in message literals to set extension fields, in 172 // which case the name is enclosed in square brackets "[" and "]". 173 // 174 // Example: 175 // (foo.bar) 176 type FieldReferenceNode struct { 177 compositeNode 178 Open *RuneNode // only present for extension names 179 Name IdentValueNode 180 Close *RuneNode // only present for extension names 181 } 182 183 // NewFieldReferenceNode creates a new *FieldReferenceNode for a regular field. 184 // The name arg must not be nil. 185 func NewFieldReferenceNode(name *IdentNode) *FieldReferenceNode { 186 if name == nil { 187 panic("name is nil") 188 } 189 children := []Node{name} 190 return &FieldReferenceNode{ 191 compositeNode: compositeNode{ 192 children: children, 193 }, 194 Name: name, 195 } 196 } 197 198 // NewExtensionFieldReferenceNode creates a new *FieldReferenceNode for an 199 // extension field. All args must be non-nil. The openSym and closeSym runes 200 // should be "(" and ")" or "[" and "]". 201 func NewExtensionFieldReferenceNode(openSym *RuneNode, name IdentValueNode, closeSym *RuneNode) *FieldReferenceNode { 202 if name == nil { 203 panic("name is nil") 204 } 205 if openSym == nil { 206 panic("openSym is nil") 207 } 208 if closeSym == nil { 209 panic("closeSym is nil") 210 } 211 children := []Node{openSym, name, closeSym} 212 return &FieldReferenceNode{ 213 compositeNode: compositeNode{ 214 children: children, 215 }, 216 Open: openSym, 217 Name: name, 218 Close: closeSym, 219 } 220 } 221 222 // IsExtension reports if this is an extension name or not (e.g. enclosed in 223 // punctuation, such as parentheses or brackets). 224 func (a *FieldReferenceNode) IsExtension() bool { 225 return a.Open != nil 226 } 227 228 func (a *FieldReferenceNode) Value() string { 229 if a.Open != nil { 230 return string(a.Open.Rune) + string(a.Name.AsIdentifier()) + string(a.Close.Rune) 231 } else { 232 return string(a.Name.AsIdentifier()) 233 } 234 } 235 236 // CompactOptionsNode represents a compact options declaration, as used with 237 // fields, enum values, and extension ranges. Example: 238 // 239 // [deprecated = true, json_name = "foo_bar"] 240 type CompactOptionsNode struct { 241 compositeNode 242 OpenBracket *RuneNode 243 Options []*OptionNode 244 // Commas represent the separating ',' characters between options. The 245 // length of this slice must be exactly len(Options)-1, with each item 246 // in Options having a corresponding item in this slice *except the last* 247 // (since a trailing comma is not allowed). 248 Commas []*RuneNode 249 CloseBracket *RuneNode 250 } 251 252 // NewCompactOptionsNode creates a *CompactOptionsNode. All args must be 253 // non-nil. The commas arg must have a length that is one less than the 254 // length of opts. The opts arg must not be empty. 255 func NewCompactOptionsNode(openBracket *RuneNode, opts []*OptionNode, commas []*RuneNode, closeBracket *RuneNode) *CompactOptionsNode { 256 if openBracket == nil { 257 panic("openBracket is nil") 258 } 259 if closeBracket == nil { 260 panic("closeBracket is nil") 261 } 262 if len(opts) == 0 { 263 panic("must have at least one part") 264 } 265 if len(commas) != len(opts)-1 { 266 panic(fmt.Sprintf("%d opts requires %d commas, not %d", len(opts), len(opts)-1, len(commas))) 267 } 268 children := make([]Node, 0, len(opts)*2+1) 269 children = append(children, openBracket) 270 for i, opt := range opts { 271 if i > 0 { 272 if commas[i-1] == nil { 273 panic(fmt.Sprintf("commas[%d] is nil", i-1)) 274 } 275 children = append(children, commas[i-1]) 276 } 277 if opt == nil { 278 panic(fmt.Sprintf("opts[%d] is nil", i)) 279 } 280 children = append(children, opt) 281 } 282 children = append(children, closeBracket) 283 284 return &CompactOptionsNode{ 285 compositeNode: compositeNode{ 286 children: children, 287 }, 288 OpenBracket: openBracket, 289 Options: opts, 290 Commas: commas, 291 CloseBracket: closeBracket, 292 } 293 } 294 295 func (e *CompactOptionsNode) GetElements() []*OptionNode { 296 if e == nil { 297 return nil 298 } 299 return e.Options 300 }