github.com/jhump/protoreflect@v1.16.0/desc/protoparse/ast/ranges.go (about) 1 package ast 2 3 import "fmt" 4 5 // ExtensionRangeNode represents an extension range declaration in an extendable 6 // message. Example: 7 // 8 // extensions 100 to max; 9 type ExtensionRangeNode struct { 10 compositeNode 11 Keyword *KeywordNode 12 Ranges []*RangeNode 13 // Commas represent the separating ',' characters between ranges. The 14 // length of this slice must be exactly len(Ranges)-1, each item in Ranges 15 // having a corresponding item in this slice *except the last* (since a 16 // trailing comma is not allowed). 17 Commas []*RuneNode 18 Options *CompactOptionsNode 19 Semicolon *RuneNode 20 } 21 22 func (e *ExtensionRangeNode) msgElement() {} 23 24 // NewExtensionRangeNode creates a new *ExtensionRangeNode. All args must be 25 // non-nil except opts, which may be nil. 26 // - keyword: The token corresponding to the "extends" keyword. 27 // - ranges: One or more range expressions. 28 // - commas: Tokens that represent the "," runes that delimit the range expressions. 29 // The length of commas must be one less than the length of ranges. 30 // - opts: The node corresponding to options that apply to each of the ranges. 31 // - semicolon The token corresponding to the ";" rune that ends the declaration. 32 func NewExtensionRangeNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, opts *CompactOptionsNode, semicolon *RuneNode) *ExtensionRangeNode { 33 if keyword == nil { 34 panic("keyword is nil") 35 } 36 if semicolon == nil { 37 panic("semicolon is nil") 38 } 39 if len(ranges) == 0 { 40 panic("must have at least one range") 41 } 42 if len(commas) != len(ranges)-1 { 43 panic(fmt.Sprintf("%d ranges requires %d commas, not %d", len(ranges), len(ranges)-1, len(commas))) 44 } 45 numChildren := len(ranges)*2 + 1 46 if opts != nil { 47 numChildren++ 48 } 49 children := make([]Node, 0, numChildren) 50 children = append(children, keyword) 51 for i, rng := range ranges { 52 if i > 0 { 53 if commas[i-1] == nil { 54 panic(fmt.Sprintf("commas[%d] is nil", i-1)) 55 } 56 children = append(children, commas[i-1]) 57 } 58 if rng == nil { 59 panic(fmt.Sprintf("ranges[%d] is nil", i)) 60 } 61 children = append(children, rng) 62 } 63 if opts != nil { 64 children = append(children, opts) 65 } 66 children = append(children, semicolon) 67 return &ExtensionRangeNode{ 68 compositeNode: compositeNode{ 69 children: children, 70 }, 71 Keyword: keyword, 72 Ranges: ranges, 73 Commas: commas, 74 Options: opts, 75 Semicolon: semicolon, 76 } 77 } 78 79 // RangeDeclNode is a placeholder interface for AST nodes that represent 80 // numeric values. This allows NoSourceNode to be used in place of *RangeNode 81 // for some usages. 82 type RangeDeclNode interface { 83 Node 84 RangeStart() Node 85 RangeEnd() Node 86 } 87 88 var _ RangeDeclNode = (*RangeNode)(nil) 89 var _ RangeDeclNode = NoSourceNode{} 90 91 // RangeNode represents a range expression, used in both extension ranges and 92 // reserved ranges. Example: 93 // 94 // 1000 to max 95 type RangeNode struct { 96 compositeNode 97 StartVal IntValueNode 98 // if To is non-nil, then exactly one of EndVal or Max must also be non-nil 99 To *KeywordNode 100 // EndVal and Max are mutually exclusive 101 EndVal IntValueNode 102 Max *KeywordNode 103 } 104 105 // NewRangeNode creates a new *RangeNode. The start argument must be non-nil. 106 // The to argument represents the "to" keyword. If present (i.e. if it is non-nil), 107 // then so must be exactly one of end or max. If max is non-nil, it indicates a 108 // "100 to max" style range. But if end is non-nil, the end of the range is a 109 // literal, such as "100 to 200". 110 func NewRangeNode(start IntValueNode, to *KeywordNode, end IntValueNode, max *KeywordNode) *RangeNode { 111 if start == nil { 112 panic("start is nil") 113 } 114 numChildren := 1 115 if to != nil { 116 if end == nil && max == nil { 117 panic("to is not nil, but end and max both are") 118 } 119 if end != nil && max != nil { 120 panic("end and max cannot be both non-nil") 121 } 122 numChildren = 3 123 } else { 124 if end != nil { 125 panic("to is nil, but end is not") 126 } 127 if max != nil { 128 panic("to is nil, but max is not") 129 } 130 } 131 children := make([]Node, 0, numChildren) 132 children = append(children, start) 133 if to != nil { 134 children = append(children, to) 135 if end != nil { 136 children = append(children, end) 137 } else { 138 children = append(children, max) 139 } 140 } 141 return &RangeNode{ 142 compositeNode: compositeNode{ 143 children: children, 144 }, 145 StartVal: start, 146 To: to, 147 EndVal: end, 148 Max: max, 149 } 150 } 151 152 func (n *RangeNode) RangeStart() Node { 153 return n.StartVal 154 } 155 156 func (n *RangeNode) RangeEnd() Node { 157 if n.Max != nil { 158 return n.Max 159 } 160 if n.EndVal != nil { 161 return n.EndVal 162 } 163 return n.StartVal 164 } 165 166 func (n *RangeNode) StartValue() interface{} { 167 return n.StartVal.Value() 168 } 169 170 func (n *RangeNode) StartValueAsInt32(min, max int32) (int32, bool) { 171 return AsInt32(n.StartVal, min, max) 172 } 173 174 func (n *RangeNode) EndValue() interface{} { 175 if n.EndVal == nil { 176 return nil 177 } 178 return n.EndVal.Value() 179 } 180 181 func (n *RangeNode) EndValueAsInt32(min, max int32) (int32, bool) { 182 if n.Max != nil { 183 return max, true 184 } 185 if n.EndVal == nil { 186 return n.StartValueAsInt32(min, max) 187 } 188 return AsInt32(n.EndVal, min, max) 189 } 190 191 // ReservedNode represents reserved declaration, which can be used to reserve 192 // either names or numbers. Examples: 193 // 194 // reserved 1, 10-12, 15; 195 // reserved "foo", "bar", "baz"; 196 type ReservedNode struct { 197 compositeNode 198 Keyword *KeywordNode 199 // If non-empty, this node represents reserved ranges and Names will be empty. 200 Ranges []*RangeNode 201 // If non-empty, this node represents reserved names and Ranges will be empty. 202 Names []StringValueNode 203 // Commas represent the separating ',' characters between options. The 204 // length of this slice must be exactly len(Ranges)-1 or len(Names)-1, depending 205 // on whether this node represents reserved ranges or reserved names. Each item 206 // in Ranges or Names has a corresponding item in this slice *except the last* 207 // (since a trailing comma is not allowed). 208 Commas []*RuneNode 209 Semicolon *RuneNode 210 } 211 212 func (*ReservedNode) msgElement() {} 213 func (*ReservedNode) enumElement() {} 214 215 // NewReservedRangesNode creates a new *ReservedNode that represents reserved 216 // numeric ranges. All args must be non-nil. 217 // - keyword: The token corresponding to the "reserved" keyword. 218 // - ranges: One or more range expressions. 219 // - commas: Tokens that represent the "," runes that delimit the range expressions. 220 // The length of commas must be one less than the length of ranges. 221 // - semicolon The token corresponding to the ";" rune that ends the declaration. 222 func NewReservedRangesNode(keyword *KeywordNode, ranges []*RangeNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode { 223 if keyword == nil { 224 panic("keyword is nil") 225 } 226 if semicolon == nil { 227 panic("semicolon is nil") 228 } 229 if len(ranges) == 0 { 230 panic("must have at least one range") 231 } 232 if len(commas) != len(ranges)-1 { 233 panic(fmt.Sprintf("%d ranges requires %d commas, not %d", len(ranges), len(ranges)-1, len(commas))) 234 } 235 children := make([]Node, 0, len(ranges)*2+1) 236 children = append(children, keyword) 237 for i, rng := range ranges { 238 if i > 0 { 239 if commas[i-1] == nil { 240 panic(fmt.Sprintf("commas[%d] is nil", i-1)) 241 } 242 children = append(children, commas[i-1]) 243 } 244 if rng == nil { 245 panic(fmt.Sprintf("ranges[%d] is nil", i)) 246 } 247 children = append(children, rng) 248 } 249 children = append(children, semicolon) 250 return &ReservedNode{ 251 compositeNode: compositeNode{ 252 children: children, 253 }, 254 Keyword: keyword, 255 Ranges: ranges, 256 Commas: commas, 257 Semicolon: semicolon, 258 } 259 } 260 261 // NewReservedNamesNode creates a new *ReservedNode that represents reserved 262 // names. All args must be non-nil. 263 // - keyword: The token corresponding to the "reserved" keyword. 264 // - names: One or more names. 265 // - commas: Tokens that represent the "," runes that delimit the names. 266 // The length of commas must be one less than the length of names. 267 // - semicolon The token corresponding to the ";" rune that ends the declaration. 268 func NewReservedNamesNode(keyword *KeywordNode, names []StringValueNode, commas []*RuneNode, semicolon *RuneNode) *ReservedNode { 269 if keyword == nil { 270 panic("keyword is nil") 271 } 272 if semicolon == nil { 273 panic("semicolon is nil") 274 } 275 if len(names) == 0 { 276 panic("must have at least one name") 277 } 278 if len(commas) != len(names)-1 { 279 panic(fmt.Sprintf("%d names requires %d commas, not %d", len(names), len(names)-1, len(commas))) 280 } 281 children := make([]Node, 0, len(names)*2+1) 282 children = append(children, keyword) 283 for i, name := range names { 284 if i > 0 { 285 if commas[i-1] == nil { 286 panic(fmt.Sprintf("commas[%d] is nil", i-1)) 287 } 288 children = append(children, commas[i-1]) 289 } 290 if name == nil { 291 panic(fmt.Sprintf("names[%d] is nil", i)) 292 } 293 children = append(children, name) 294 } 295 children = append(children, semicolon) 296 return &ReservedNode{ 297 compositeNode: compositeNode{ 298 children: children, 299 }, 300 Keyword: keyword, 301 Names: names, 302 Commas: commas, 303 Semicolon: semicolon, 304 } 305 }