github.com/jhump/protocompile@v0.0.0-20221021153901-4f6f732835e8/ast/values.go (about) 1 package ast 2 3 import ( 4 "fmt" 5 "math" 6 "strings" 7 ) 8 9 // ValueNode is an AST node that represents a literal value. 10 // 11 // It also includes references (e.g. IdentifierValueNode), which can be 12 // used as values in some contexts, such as describing the default value 13 // for a field, which can refer to an enum value. 14 // 15 // This also allows NoSourceNode to be used in place of a real value node 16 // for some usages. 17 type ValueNode interface { 18 Node 19 // Value returns a Go representation of the value. For scalars, this 20 // will be a string, int64, uint64, float64, or bool. This could also 21 // be an Identifier (e.g. IdentValueNodes). It can also be a composite 22 // literal: 23 // * For array literals, the type returned will be []ValueNode 24 // * For message literals, the type returned will be []*MessageFieldNode 25 Value() interface{} 26 } 27 28 var _ ValueNode = (*IdentNode)(nil) 29 var _ ValueNode = (*CompoundIdentNode)(nil) 30 var _ ValueNode = (*StringLiteralNode)(nil) 31 var _ ValueNode = (*CompoundStringLiteralNode)(nil) 32 var _ ValueNode = (*UintLiteralNode)(nil) 33 var _ ValueNode = (*PositiveUintLiteralNode)(nil) 34 var _ ValueNode = (*NegativeIntLiteralNode)(nil) 35 var _ ValueNode = (*FloatLiteralNode)(nil) 36 var _ ValueNode = (*SpecialFloatLiteralNode)(nil) 37 var _ ValueNode = (*SignedFloatLiteralNode)(nil) 38 var _ ValueNode = (*BoolLiteralNode)(nil) 39 var _ ValueNode = (*ArrayLiteralNode)(nil) 40 var _ ValueNode = (*MessageLiteralNode)(nil) 41 var _ ValueNode = NoSourceNode{} 42 43 // StringValueNode is an AST node that represents a string literal. 44 // Such a node can be a single literal (*StringLiteralNode) or a 45 // concatenation of multiple literals (*CompoundStringLiteralNode). 46 type StringValueNode interface { 47 ValueNode 48 AsString() string 49 } 50 51 var _ StringValueNode = (*StringLiteralNode)(nil) 52 var _ StringValueNode = (*CompoundStringLiteralNode)(nil) 53 54 // StringLiteralNode represents a simple string literal. Example: 55 // 56 // "proto2" 57 type StringLiteralNode struct { 58 terminalNode 59 // Val is the actual string value that the literal indicates. 60 Val string 61 } 62 63 // NewStringLiteralNode creates a new *StringLiteralNode with the given val. 64 func NewStringLiteralNode(val string, tok Token) *StringLiteralNode { 65 return &StringLiteralNode{ 66 terminalNode: tok.asTerminalNode(), 67 Val: val, 68 } 69 } 70 71 func (n *StringLiteralNode) Value() interface{} { 72 return n.AsString() 73 } 74 75 func (n *StringLiteralNode) AsString() string { 76 return n.Val 77 } 78 79 // CompoundStringLiteralNode represents a compound string literal, which is 80 // the concatenaton of adjacent string literals. Example: 81 // 82 // "this " "is" " all one " "string" 83 type CompoundStringLiteralNode struct { 84 compositeNode 85 Val string 86 } 87 88 // NewCompoundLiteralStringNode creates a new *CompoundStringLiteralNode that 89 // consists of the given string components. The components argument may not be 90 // empty. 91 func NewCompoundLiteralStringNode(components ...*StringLiteralNode) *CompoundStringLiteralNode { 92 if len(components) == 0 { 93 panic("must have at least one component") 94 } 95 children := make([]Node, len(components)) 96 var b strings.Builder 97 for i, comp := range components { 98 children[i] = comp 99 b.WriteString(comp.Val) 100 } 101 return &CompoundStringLiteralNode{ 102 compositeNode: compositeNode{ 103 children: children, 104 }, 105 Val: b.String(), 106 } 107 } 108 109 func (n *CompoundStringLiteralNode) Value() interface{} { 110 return n.AsString() 111 } 112 113 func (n *CompoundStringLiteralNode) AsString() string { 114 return n.Val 115 } 116 117 // IntValueNode is an AST node that represents an integer literal. If 118 // an integer literal is too large for an int64 (or uint64 for 119 // positive literals), it is represented instead by a FloatValueNode. 120 type IntValueNode interface { 121 ValueNode 122 AsInt64() (int64, bool) 123 AsUint64() (uint64, bool) 124 } 125 126 // AsInt32 range checks the given int value and returns its value is 127 // in the range or 0, false if it is outside the range. 128 func AsInt32(n IntValueNode, min, max int32) (int32, bool) { 129 i, ok := n.AsInt64() 130 if !ok { 131 return 0, false 132 } 133 if i < int64(min) || i > int64(max) { 134 return 0, false 135 } 136 return int32(i), true 137 } 138 139 var _ IntValueNode = (*UintLiteralNode)(nil) 140 var _ IntValueNode = (*PositiveUintLiteralNode)(nil) 141 var _ IntValueNode = (*NegativeIntLiteralNode)(nil) 142 143 // UintLiteralNode represents a simple integer literal with no sign character. 144 type UintLiteralNode struct { 145 terminalNode 146 // Val is the numeric value indicated by the literal 147 Val uint64 148 } 149 150 // NewUintLiteralNode creates a new *UintLiteralNode with the given val. 151 func NewUintLiteralNode(val uint64, tok Token) *UintLiteralNode { 152 return &UintLiteralNode{ 153 terminalNode: tok.asTerminalNode(), 154 Val: val, 155 } 156 } 157 158 func (n *UintLiteralNode) Value() interface{} { 159 return n.Val 160 } 161 162 func (n *UintLiteralNode) AsInt64() (int64, bool) { 163 if n.Val > math.MaxInt64 { 164 return 0, false 165 } 166 return int64(n.Val), true 167 } 168 169 func (n *UintLiteralNode) AsUint64() (uint64, bool) { 170 return n.Val, true 171 } 172 173 func (n *UintLiteralNode) AsFloat() float64 { 174 return float64(n.Val) 175 } 176 177 // PositiveUintLiteralNode represents an integer literal with a positive (+) sign. 178 type PositiveUintLiteralNode struct { 179 compositeNode 180 Plus *RuneNode 181 Uint *UintLiteralNode 182 Val uint64 183 } 184 185 // NewPositiveUintLiteralNode creates a new *PositiveUintLiteralNode. Both 186 // arguments must be non-nil. 187 func NewPositiveUintLiteralNode(sign *RuneNode, i *UintLiteralNode) *PositiveUintLiteralNode { 188 if sign == nil { 189 panic("sign is nil") 190 } 191 if i == nil { 192 panic("i is nil") 193 } 194 children := []Node{sign, i} 195 return &PositiveUintLiteralNode{ 196 compositeNode: compositeNode{ 197 children: children, 198 }, 199 Plus: sign, 200 Uint: i, 201 Val: i.Val, 202 } 203 } 204 205 func (n *PositiveUintLiteralNode) Value() interface{} { 206 return n.Val 207 } 208 209 func (n *PositiveUintLiteralNode) AsInt64() (int64, bool) { 210 if n.Val > math.MaxInt64 { 211 return 0, false 212 } 213 return int64(n.Val), true 214 } 215 216 func (n *PositiveUintLiteralNode) AsUint64() (uint64, bool) { 217 return n.Val, true 218 } 219 220 // NegativeIntLiteralNode represents an integer literal with a negative (-) sign. 221 type NegativeIntLiteralNode struct { 222 compositeNode 223 Minus *RuneNode 224 Uint *UintLiteralNode 225 Val int64 226 } 227 228 // NewNegativeIntLiteralNode creates a new *NegativeIntLiteralNode. Both 229 // arguments must be non-nil. 230 func NewNegativeIntLiteralNode(sign *RuneNode, i *UintLiteralNode) *NegativeIntLiteralNode { 231 if sign == nil { 232 panic("sign is nil") 233 } 234 if i == nil { 235 panic("i is nil") 236 } 237 children := []Node{sign, i} 238 return &NegativeIntLiteralNode{ 239 compositeNode: compositeNode{ 240 children: children, 241 }, 242 Minus: sign, 243 Uint: i, 244 Val: -int64(i.Val), 245 } 246 } 247 248 func (n *NegativeIntLiteralNode) Value() interface{} { 249 return n.Val 250 } 251 252 func (n *NegativeIntLiteralNode) AsInt64() (int64, bool) { 253 return n.Val, true 254 } 255 256 func (n *NegativeIntLiteralNode) AsUint64() (uint64, bool) { 257 if n.Val < 0 { 258 return 0, false 259 } 260 return uint64(n.Val), true 261 } 262 263 // FloatValueNode is an AST node that represents a numeric literal with 264 // a floating point, in scientific notation, or too large to fit in an 265 // int64 or uint64. 266 type FloatValueNode interface { 267 ValueNode 268 AsFloat() float64 269 } 270 271 var _ FloatValueNode = (*FloatLiteralNode)(nil) 272 var _ FloatValueNode = (*SpecialFloatLiteralNode)(nil) 273 var _ FloatValueNode = (*UintLiteralNode)(nil) 274 275 // FloatLiteralNode represents a floating point numeric literal. 276 type FloatLiteralNode struct { 277 terminalNode 278 // Val is the numeric value indicated by the literal 279 Val float64 280 } 281 282 // NewFloatLiteralNode creates a new *FloatLiteralNode with the given val. 283 func NewFloatLiteralNode(val float64, tok Token) *FloatLiteralNode { 284 return &FloatLiteralNode{ 285 terminalNode: tok.asTerminalNode(), 286 Val: val, 287 } 288 } 289 290 func (n *FloatLiteralNode) Value() interface{} { 291 return n.AsFloat() 292 } 293 294 func (n *FloatLiteralNode) AsFloat() float64 { 295 return n.Val 296 } 297 298 // SpecialFloatLiteralNode represents a special floating point numeric literal 299 // for "inf" and "nan" values. 300 type SpecialFloatLiteralNode struct { 301 *KeywordNode 302 Val float64 303 } 304 305 // NewSpecialFloatLiteralNode returns a new *SpecialFloatLiteralNode for the 306 // given keyword, which must be "inf" or "nan". 307 func NewSpecialFloatLiteralNode(name *KeywordNode) *SpecialFloatLiteralNode { 308 var f float64 309 if name.Val == "inf" { 310 f = math.Inf(1) 311 } else { 312 f = math.NaN() 313 } 314 return &SpecialFloatLiteralNode{ 315 KeywordNode: name, 316 Val: f, 317 } 318 } 319 320 func (n *SpecialFloatLiteralNode) Value() interface{} { 321 return n.AsFloat() 322 } 323 324 func (n *SpecialFloatLiteralNode) AsFloat() float64 { 325 return n.Val 326 } 327 328 // SignedFloatLiteralNode represents a signed floating point number. 329 type SignedFloatLiteralNode struct { 330 compositeNode 331 Sign *RuneNode 332 Float FloatValueNode 333 Val float64 334 } 335 336 // NewSignedFloatLiteralNode creates a new *SignedFloatLiteralNode. Both 337 // arguments must be non-nil. 338 func NewSignedFloatLiteralNode(sign *RuneNode, f FloatValueNode) *SignedFloatLiteralNode { 339 if sign == nil { 340 panic("sign is nil") 341 } 342 if f == nil { 343 panic("f is nil") 344 } 345 children := []Node{sign, f} 346 val := f.AsFloat() 347 if sign.Rune == '-' { 348 val = -val 349 } 350 return &SignedFloatLiteralNode{ 351 compositeNode: compositeNode{ 352 children: children, 353 }, 354 Sign: sign, 355 Float: f, 356 Val: val, 357 } 358 } 359 360 func (n *SignedFloatLiteralNode) Value() interface{} { 361 return n.Val 362 } 363 364 func (n *SignedFloatLiteralNode) AsFloat() float64 { 365 return n.Val 366 } 367 368 // BoolLiteralNode represents a boolean literal. 369 type BoolLiteralNode struct { 370 *KeywordNode 371 Val bool 372 } 373 374 // NewBoolLiteralNode returns a new *BoolLiteralNode for the given keyword, 375 // which must be "true" or "false". 376 func NewBoolLiteralNode(name *KeywordNode) *BoolLiteralNode { 377 return &BoolLiteralNode{ 378 KeywordNode: name, 379 Val: name.Val == "true", 380 } 381 } 382 383 func (n *BoolLiteralNode) Value() interface{} { 384 return n.Val 385 } 386 387 // ArrayLiteralNode represents an array literal, which is only allowed inside of 388 // a MessageLiteralNode, to indicate values for a repeated field. Example: 389 // 390 // ["foo", "bar", "baz"] 391 type ArrayLiteralNode struct { 392 compositeNode 393 OpenBracket *RuneNode 394 Elements []ValueNode 395 // Commas represent the separating ',' characters between elements. The 396 // length of this slice must be exactly len(Elements)-1, with each item 397 // in Elements having a corresponding item in this slice *except the last* 398 // (since a trailing comma is not allowed). 399 Commas []*RuneNode 400 CloseBracket *RuneNode 401 } 402 403 // NewArrayLiteralNode creates a new *ArrayLiteralNode. The openBracket and 404 // closeBracket args must be non-nil and represent the "[" and "]" runes that 405 // surround the array values. The given commas arg must have a length that is 406 // one less than the length of the vals arg. However, vals may be empty, in 407 // which case commas must also be empty. 408 func NewArrayLiteralNode(openBracket *RuneNode, vals []ValueNode, commas []*RuneNode, closeBracket *RuneNode) *ArrayLiteralNode { 409 if openBracket == nil { 410 panic("openBracket is nil") 411 } 412 if closeBracket == nil { 413 panic("closeBracket is nil") 414 } 415 if len(vals) == 0 && len(commas) != 0 { 416 panic("vals is empty but commas is not") 417 } 418 if len(vals) > 0 && len(commas) != len(vals)-1 { 419 panic(fmt.Sprintf("%d vals requires %d commas, not %d", len(vals), len(vals)-1, len(commas))) 420 } 421 children := make([]Node, 0, len(vals)*2+1) 422 children = append(children, openBracket) 423 for i, val := range vals { 424 if i > 0 { 425 if commas[i-1] == nil { 426 panic(fmt.Sprintf("commas[%d] is nil", i-1)) 427 } 428 children = append(children, commas[i-1]) 429 } 430 if val == nil { 431 panic(fmt.Sprintf("vals[%d] is nil", i)) 432 } 433 children = append(children, val) 434 } 435 children = append(children, closeBracket) 436 437 return &ArrayLiteralNode{ 438 compositeNode: compositeNode{ 439 children: children, 440 }, 441 OpenBracket: openBracket, 442 Elements: vals, 443 Commas: commas, 444 CloseBracket: closeBracket, 445 } 446 } 447 448 func (n *ArrayLiteralNode) Value() interface{} { 449 return n.Elements 450 } 451 452 // MessageLiteralNode represents a message literal, which is compatible with the 453 // protobuf text format and can be used for custom options with message types. 454 // Example: 455 // 456 // { foo:1 foo:2 foo:3 bar:<name:"abc" id:123> } 457 type MessageLiteralNode struct { 458 compositeNode 459 Open *RuneNode // should be '{' or '<' 460 Elements []*MessageFieldNode 461 // Separator characters between elements, which can be either ',' 462 // or ';' if present. This slice must be exactly len(Elements) in 463 // length, with each item in Elements having one corresponding item 464 // in Seps. Separators in message literals are optional, so a given 465 // item in this slice may be nil to indicate absence of a separator. 466 Seps []*RuneNode 467 Close *RuneNode // should be '}' or '>', depending on Open 468 } 469 470 // NewMessageLiteralNode creates a new *MessageLiteralNode. The openSym and 471 // closeSym runes must not be nil and should be "{" and "}" or "<" and ">". 472 // 473 // Unlike separators (dots and commas) used for other AST nodes that represent 474 // a list of elements, the seps arg must be the SAME length as vals, and it may 475 // contain nil values to indicate absence of a separator (in fact, it could be 476 // all nils). 477 func NewMessageLiteralNode(openSym *RuneNode, vals []*MessageFieldNode, seps []*RuneNode, closeSym *RuneNode) *MessageLiteralNode { 478 if openSym == nil { 479 panic("openSym is nil") 480 } 481 if closeSym == nil { 482 panic("closeSym is nil") 483 } 484 if len(seps) != len(vals) { 485 panic(fmt.Sprintf("%d vals requires %d commas, not %d", len(vals), len(vals), len(seps))) 486 } 487 numChildren := len(vals) + 2 488 for _, sep := range seps { 489 if sep != nil { 490 numChildren++ 491 } 492 } 493 children := make([]Node, 0, numChildren) 494 children = append(children, openSym) 495 for i, val := range vals { 496 if val == nil { 497 panic(fmt.Sprintf("vals[%d] is nil", i)) 498 } 499 children = append(children, val) 500 if seps[i] != nil { 501 children = append(children, seps[i]) 502 } 503 } 504 children = append(children, closeSym) 505 506 return &MessageLiteralNode{ 507 compositeNode: compositeNode{ 508 children: children, 509 }, 510 Open: openSym, 511 Elements: vals, 512 Seps: seps, 513 Close: closeSym, 514 } 515 } 516 517 func (n *MessageLiteralNode) Value() interface{} { 518 return n.Elements 519 } 520 521 // MessageFieldNode represents a single field (name and value) inside of a 522 // message literal. Example: 523 // 524 // foo:"bar" 525 type MessageFieldNode struct { 526 compositeNode 527 Name *FieldReferenceNode 528 // Sep represents the ':' separator between the name and value. If 529 // the value is a message literal (and thus starts with '<' or '{'), 530 // then the separator is optional, and thus may be nil. 531 Sep *RuneNode 532 Val ValueNode 533 } 534 535 // NewMessageFieldNode creates a new *MessageFieldNode. All args except sep 536 // must be non-nil. 537 func NewMessageFieldNode(name *FieldReferenceNode, sep *RuneNode, val ValueNode) *MessageFieldNode { 538 if name == nil { 539 panic("name is nil") 540 } 541 if val == nil { 542 panic("val is nil") 543 } 544 numChildren := 2 545 if sep != nil { 546 numChildren++ 547 } 548 children := make([]Node, 0, numChildren) 549 children = append(children, name) 550 if sep != nil { 551 children = append(children, sep) 552 } 553 children = append(children, val) 554 555 return &MessageFieldNode{ 556 compositeNode: compositeNode{ 557 children: children, 558 }, 559 Name: name, 560 Sep: sep, 561 Val: val, 562 } 563 }