github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/yaml/token/token.go (about) 1 package token 2 3 import ( 4 "fmt" 5 "strings" 6 ) 7 8 // Character type for character 9 type Character byte 10 11 const ( 12 // SequenceEntryCharacter character for sequence entry 13 SequenceEntryCharacter Character = '-' 14 // MappingKeyCharacter character for mapping key 15 MappingKeyCharacter = '?' 16 // MappingValueCharacter character for mapping value 17 MappingValueCharacter = ':' 18 // CollectEntryCharacter character for collect entry 19 CollectEntryCharacter = ',' 20 // SequenceStartCharacter character for sequence start 21 SequenceStartCharacter = '[' 22 // SequenceEndCharacter character for sequence end 23 SequenceEndCharacter = ']' 24 // MappingStartCharacter character for mapping start 25 MappingStartCharacter = '{' 26 // MappingEndCharacter character for mapping end 27 MappingEndCharacter = '}' 28 // CommentCharacter character for comment 29 CommentCharacter = '#' 30 // AnchorCharacter character for anchor 31 AnchorCharacter = '&' 32 // AliasCharacter character for alias 33 AliasCharacter = '*' 34 // TagCharacter character for tag 35 TagCharacter = '!' 36 // LiteralCharacter character for literal 37 LiteralCharacter = '|' 38 // FoldedCharacter character for folded 39 FoldedCharacter = '>' 40 // SingleQuoteCharacter character for single quote 41 SingleQuoteCharacter = '\'' 42 // DoubleQuoteCharacter character for double quote 43 DoubleQuoteCharacter = '"' 44 // DirectiveCharacter character for directive 45 DirectiveCharacter = '%' 46 // SpaceCharacter character for space 47 SpaceCharacter = ' ' 48 // LineBreakCharacter character for line break 49 LineBreakCharacter = '\n' 50 ) 51 52 // Type type identifier for token 53 type Type int 54 55 const ( 56 // UnknownType reserve for invalid type 57 UnknownType Type = iota 58 // DocumentHeaderType type for DocumentHeader token 59 DocumentHeaderType 60 // DocumentEndType type for DocumentEnd token 61 DocumentEndType 62 // SequenceEntryType type for SequenceEntry token 63 SequenceEntryType 64 // MappingKeyType type for MappingKey token 65 MappingKeyType 66 // MappingValueType type for MappingValue token 67 MappingValueType 68 // MergeKeyType type for MergeKey token 69 MergeKeyType 70 // CollectEntryType type for CollectEntry token 71 CollectEntryType 72 // SequenceStartType type for SequenceStart token 73 SequenceStartType 74 // SequenceEndType type for SequenceEnd token 75 SequenceEndType 76 // MappingStartType type for MappingStart token 77 MappingStartType 78 // MappingEndType type for MappingEnd token 79 MappingEndType 80 // CommentType type for Comment token 81 CommentType 82 // AnchorType type for Anchor token 83 AnchorType 84 // AliasType type for Alias token 85 AliasType 86 // TagType type for Tag token 87 TagType 88 // LiteralType type for Literal token 89 LiteralType 90 // FoldedType type for Folded token 91 FoldedType 92 // SingleQuoteType type for SingleQuote token 93 SingleQuoteType 94 // DoubleQuoteType type for DoubleQuote token 95 DoubleQuoteType 96 // DirectiveType type for Directive token 97 DirectiveType 98 // SpaceType type for Space token 99 SpaceType 100 // NullType type for Null token 101 NullType 102 // InfinityType type for Infinity token 103 InfinityType 104 // NanType type for Nan token 105 NanType 106 // IntegerType type for Integer token 107 IntegerType 108 // BinaryIntegerType type for BinaryInteger token 109 BinaryIntegerType 110 // OctetIntegerType type for OctetInteger token 111 OctetIntegerType 112 // HexIntegerType type for HexInteger token 113 HexIntegerType 114 // FloatType type for Float token 115 FloatType 116 // StringType type for String token 117 StringType 118 // BoolType type for Bool token 119 BoolType 120 ) 121 122 // String type identifier to text 123 func (t Type) String() string { 124 switch t { 125 case UnknownType: 126 return "Unknown" 127 case DocumentHeaderType: 128 return "DocumentHeader" 129 case DocumentEndType: 130 return "DocumentEnd" 131 case SequenceEntryType: 132 return "SequenceEntry" 133 case MappingKeyType: 134 return "MappingKey" 135 case MappingValueType: 136 return "MappingValue" 137 case MergeKeyType: 138 return "MergeKey" 139 case CollectEntryType: 140 return "CollectEntry" 141 case SequenceStartType: 142 return "SequenceStart" 143 case SequenceEndType: 144 return "SequenceEnd" 145 case MappingStartType: 146 return "MappingStart" 147 case MappingEndType: 148 return "MappingEnd" 149 case CommentType: 150 return "Comment" 151 case AnchorType: 152 return "Anchor" 153 case AliasType: 154 return "Alias" 155 case TagType: 156 return "Tag" 157 case LiteralType: 158 return "Literal" 159 case FoldedType: 160 return "Folded" 161 case SingleQuoteType: 162 return "SingleQuote" 163 case DoubleQuoteType: 164 return "DoubleQuote" 165 case DirectiveType: 166 return "Directive" 167 case SpaceType: 168 return "Space" 169 case StringType: 170 return "String" 171 case BoolType: 172 return "Bool" 173 case IntegerType: 174 return "Integer" 175 case BinaryIntegerType: 176 return "BinaryInteger" 177 case OctetIntegerType: 178 return "OctetInteger" 179 case HexIntegerType: 180 return "HexInteger" 181 case FloatType: 182 return "Float" 183 case NullType: 184 return "Null" 185 case InfinityType: 186 return "Infinity" 187 case NanType: 188 return "Nan" 189 } 190 return "" 191 } 192 193 // CharacterType type for character category 194 type CharacterType int 195 196 const ( 197 // CharacterTypeIndicator type of indicator character 198 CharacterTypeIndicator CharacterType = iota 199 // CharacterTypeWhiteSpace type of white space character 200 CharacterTypeWhiteSpace 201 // CharacterTypeMiscellaneous type of miscellaneous character 202 CharacterTypeMiscellaneous 203 // CharacterTypeEscaped type of escaped character 204 CharacterTypeEscaped 205 ) 206 207 // String character type identifier to text 208 func (c CharacterType) String() string { 209 switch c { 210 case CharacterTypeIndicator: 211 return "Indicator" 212 case CharacterTypeWhiteSpace: 213 return "WhiteSpcae" 214 case CharacterTypeMiscellaneous: 215 return "Miscellaneous" 216 case CharacterTypeEscaped: 217 return "Escaped" 218 } 219 return "" 220 } 221 222 // Indicator type for indicator 223 type Indicator int 224 225 const ( 226 // NotIndicator not indicator 227 NotIndicator Indicator = iota 228 // BlockStructureIndicator indicator for block structure ( '-', '?', ':' ) 229 BlockStructureIndicator 230 // FlowCollectionIndicator indicator for flow collection ( '[', ']', '{', '}', ',' ) 231 FlowCollectionIndicator 232 // CommentIndicator indicator for comment ( '#' ) 233 CommentIndicator 234 // NodePropertyIndicator indicator for node property ( '!', '&', '*' ) 235 NodePropertyIndicator 236 // BlockScalarIndicator indicator for block scalar ( '|', '>' ) 237 BlockScalarIndicator 238 // QuotedScalarIndicator indicator for quoted scalar ( ''', '"' ) 239 QuotedScalarIndicator 240 // DirectiveIndicator indicator for directive ( '%' ) 241 DirectiveIndicator 242 // InvalidUseOfReservedIndicator indicator for invalid use of reserved keyword ( '@', '`' ) 243 InvalidUseOfReservedIndicator 244 ) 245 246 // String indicator to text 247 func (i Indicator) String() string { 248 switch i { 249 case NotIndicator: 250 return "NotIndicator" 251 case BlockStructureIndicator: 252 return "BlockStructure" 253 case FlowCollectionIndicator: 254 return "FlowCollection" 255 case CommentIndicator: 256 return "Comment" 257 case NodePropertyIndicator: 258 return "NodeProperty" 259 case BlockScalarIndicator: 260 return "BlockScalar" 261 case QuotedScalarIndicator: 262 return "QuotedScalar" 263 case DirectiveIndicator: 264 return "Directive" 265 case InvalidUseOfReservedIndicator: 266 return "InvalidUseOfReserved" 267 } 268 return "" 269 } 270 271 var ( 272 reservedNullKeywords = []string{ 273 "null", 274 "Null", 275 "NULL", 276 "~", 277 } 278 reservedBoolKeywords = []string{ 279 "true", 280 "True", 281 "TRUE", 282 "false", 283 "False", 284 "FALSE", 285 } 286 reservedInfKeywords = []string{ 287 ".inf", 288 ".Inf", 289 ".INF", 290 "-.inf", 291 "-.Inf", 292 "-.INF", 293 } 294 reservedNanKeywords = []string{ 295 ".nan", 296 ".NaN", 297 ".NAN", 298 } 299 reservedKeywordMap = map[string]func(string, string, *Position) *Token{} 300 ) 301 302 func reservedKeywordToken(typ Type, value, org string, pos *Position) *Token { 303 return &Token{ 304 Type: typ, 305 CharacterType: CharacterTypeMiscellaneous, 306 Indicator: NotIndicator, 307 Value: value, 308 Origin: org, 309 Position: pos, 310 } 311 } 312 313 func init() { 314 for _, keyword := range reservedNullKeywords { 315 reservedKeywordMap[keyword] = func(value, org string, pos *Position) *Token { 316 return reservedKeywordToken(NullType, value, org, pos) 317 } 318 } 319 for _, keyword := range reservedBoolKeywords { 320 reservedKeywordMap[keyword] = func(value, org string, pos *Position) *Token { 321 return reservedKeywordToken(BoolType, value, org, pos) 322 } 323 } 324 for _, keyword := range reservedInfKeywords { 325 reservedKeywordMap[keyword] = func(value, org string, pos *Position) *Token { 326 return reservedKeywordToken(InfinityType, value, org, pos) 327 } 328 } 329 for _, keyword := range reservedNanKeywords { 330 reservedKeywordMap[keyword] = func(value, org string, pos *Position) *Token { 331 return reservedKeywordToken(NanType, value, org, pos) 332 } 333 } 334 } 335 336 // ReservedTagKeyword type of reserved tag keyword 337 type ReservedTagKeyword string 338 339 const ( 340 // IntegerTag `!!int` tag 341 IntegerTag ReservedTagKeyword = "!!int" 342 // FloatTag `!!float` tag 343 FloatTag ReservedTagKeyword = "!!float" 344 // NullTag `!!null` tag 345 NullTag ReservedTagKeyword = "!!null" 346 // SequenceTag `!!seq` tag 347 SequenceTag ReservedTagKeyword = "!!seq" 348 // MappingTag `!!map` tag 349 MappingTag ReservedTagKeyword = "!!map" 350 // StringTag `!!str` tag 351 StringTag ReservedTagKeyword = "!!str" 352 // BinaryTag `!!binary` tag 353 BinaryTag ReservedTagKeyword = "!!binary" 354 // OrderedMapTag `!!omap` tag 355 OrderedMapTag ReservedTagKeyword = "!!omap" 356 // SetTag `!!set` tag 357 SetTag ReservedTagKeyword = "!!set" 358 // TimestampTag `!!timestamp` tag 359 TimestampTag ReservedTagKeyword = "!!timestamp" 360 ) 361 362 // ReservedTagKeywordMap map for reserved tag keywords 363 var ReservedTagKeywordMap = map[ReservedTagKeyword]func(string, string, *Position) *Token{ 364 IntegerTag: func(value, org string, pos *Position) *Token { 365 return &Token{ 366 Type: TagType, 367 CharacterType: CharacterTypeIndicator, 368 Indicator: NodePropertyIndicator, 369 Value: value, 370 Origin: org, 371 Position: pos, 372 } 373 }, 374 FloatTag: func(value, org string, pos *Position) *Token { 375 return &Token{ 376 Type: TagType, 377 CharacterType: CharacterTypeIndicator, 378 Indicator: NodePropertyIndicator, 379 Value: value, 380 Origin: org, 381 Position: pos, 382 } 383 }, 384 NullTag: func(value, org string, pos *Position) *Token { 385 return &Token{ 386 Type: TagType, 387 CharacterType: CharacterTypeIndicator, 388 Indicator: NodePropertyIndicator, 389 Value: value, 390 Origin: org, 391 Position: pos, 392 } 393 }, 394 SequenceTag: func(value, org string, pos *Position) *Token { 395 return &Token{ 396 Type: TagType, 397 CharacterType: CharacterTypeIndicator, 398 Indicator: NodePropertyIndicator, 399 Value: value, 400 Origin: org, 401 Position: pos, 402 } 403 }, 404 MappingTag: func(value, org string, pos *Position) *Token { 405 return &Token{ 406 Type: TagType, 407 CharacterType: CharacterTypeIndicator, 408 Indicator: NodePropertyIndicator, 409 Value: value, 410 Origin: org, 411 Position: pos, 412 } 413 }, 414 StringTag: func(value, org string, pos *Position) *Token { 415 return &Token{ 416 Type: TagType, 417 CharacterType: CharacterTypeIndicator, 418 Indicator: NodePropertyIndicator, 419 Value: value, 420 Origin: org, 421 Position: pos, 422 } 423 }, 424 BinaryTag: func(value, org string, pos *Position) *Token { 425 return &Token{ 426 Type: TagType, 427 CharacterType: CharacterTypeIndicator, 428 Indicator: NodePropertyIndicator, 429 Value: value, 430 Origin: org, 431 Position: pos, 432 } 433 }, 434 OrderedMapTag: func(value, org string, pos *Position) *Token { 435 return &Token{ 436 Type: TagType, 437 CharacterType: CharacterTypeIndicator, 438 Indicator: NodePropertyIndicator, 439 Value: value, 440 Origin: org, 441 Position: pos, 442 } 443 }, 444 SetTag: func(value, org string, pos *Position) *Token { 445 return &Token{ 446 Type: TagType, 447 CharacterType: CharacterTypeIndicator, 448 Indicator: NodePropertyIndicator, 449 Value: value, 450 Origin: org, 451 Position: pos, 452 } 453 }, 454 TimestampTag: func(value, org string, pos *Position) *Token { 455 return &Token{ 456 Type: TagType, 457 CharacterType: CharacterTypeIndicator, 458 Indicator: NodePropertyIndicator, 459 Value: value, 460 Origin: org, 461 Position: pos, 462 } 463 }, 464 } 465 466 type numType int 467 468 const ( 469 numTypeNone numType = iota 470 numTypeBinary 471 numTypeOctet 472 numTypeHex 473 numTypeFloat 474 ) 475 476 type numStat struct { 477 isNum bool 478 typ numType 479 } 480 481 func getNumberStat(str string) *numStat { 482 stat := &numStat{} 483 if str == "" { 484 return stat 485 } 486 if str == "-" || str == "." || str == "+" || str == "_" { 487 return stat 488 } 489 if str[0] == '_' { 490 return stat 491 } 492 dotFound := false 493 isNegative := false 494 isExponent := false 495 if str[0] == '-' { 496 isNegative = true 497 } 498 for idx, c := range str { 499 switch c { 500 case 'x': 501 if (isNegative && idx == 2) || (!isNegative && idx == 1) { 502 continue 503 } 504 case 'o': 505 if (isNegative && idx == 2) || (!isNegative && idx == 1) { 506 continue 507 } 508 case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9': 509 continue 510 case 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F': 511 if (len(str) > 2 && str[0] == '0' && str[1] == 'x') || 512 (len(str) > 3 && isNegative && str[1] == '0' && str[2] == 'x') { 513 // hex number 514 continue 515 } 516 if c == 'b' && ((isNegative && idx == 2) || (!isNegative && idx == 1)) { 517 // binary number 518 continue 519 } 520 if (c == 'e' || c == 'E') && dotFound { 521 // exponent 522 isExponent = true 523 continue 524 } 525 case '.': 526 if dotFound { 527 // multiple dot 528 return stat 529 } 530 dotFound = true 531 continue 532 case '-': 533 if idx == 0 || isExponent { 534 continue 535 } 536 case '+': 537 if idx == 0 || isExponent { 538 continue 539 } 540 case '_': 541 continue 542 } 543 return stat 544 } 545 stat.isNum = true 546 switch { 547 case dotFound: 548 stat.typ = numTypeFloat 549 case strings.HasPrefix(str, "0b") || strings.HasPrefix(str, "-0b"): 550 stat.typ = numTypeBinary 551 case strings.HasPrefix(str, "0x") || strings.HasPrefix(str, "-0x"): 552 stat.typ = numTypeHex 553 case strings.HasPrefix(str, "0o") || strings.HasPrefix(str, "-0o"): 554 stat.typ = numTypeOctet 555 case (len(str) > 1 && str[0] == '0') || (len(str) > 1 && str[0] == '-' && str[1] == '0'): 556 stat.typ = numTypeOctet 557 } 558 return stat 559 } 560 561 func looksLikeTimeValue(value string) bool { 562 for i, c := range value { 563 switch c { 564 case ':', '1', '2', '3', '4', '5', '6', '7', '8', '9': 565 continue 566 case '0': 567 if i == 0 { 568 return false 569 } 570 continue 571 } 572 return false 573 } 574 return true 575 } 576 577 // IsNeedQuoted whether need quote for passed string or not 578 func IsNeedQuoted(value string) bool { 579 if value == "" { 580 return true 581 } 582 if _, exists := reservedKeywordMap[value]; exists { 583 return true 584 } 585 if stat := getNumberStat(value); stat.isNum { 586 return true 587 } 588 first := value[0] 589 switch first { 590 case '*', '&', '[', '{', '}', ']', ',', '!', '|', '>', '%', '\'', '"': 591 return true 592 } 593 last := value[len(value)-1] 594 switch last { 595 case ':': 596 return true 597 } 598 if looksLikeTimeValue(value) { 599 return true 600 } 601 for i, c := range value { 602 switch c { 603 case '#', '\\': 604 return true 605 case ':': 606 if i+1 < len(value) && value[i+1] == ' ' { 607 return true 608 } 609 } 610 } 611 return false 612 } 613 614 // LiteralBlockHeader detect literal block scalar header 615 func LiteralBlockHeader(value string) string { 616 lbc := DetectLineBreakCharacter(value) 617 618 switch { 619 case !strings.Contains(value, lbc): 620 return "" 621 case strings.HasSuffix(value, fmt.Sprintf("%s%s", lbc, lbc)): 622 return "|+" 623 case strings.HasSuffix(value, lbc): 624 return "|" 625 default: 626 return "|-" 627 } 628 } 629 630 // New create reserved keyword token or number token and other string token 631 func New(value string, org string, pos *Position) *Token { 632 fn := reservedKeywordMap[value] 633 if fn != nil { 634 return fn(value, org, pos) 635 } 636 if stat := getNumberStat(value); stat.isNum { 637 tk := &Token{ 638 Type: IntegerType, 639 CharacterType: CharacterTypeMiscellaneous, 640 Indicator: NotIndicator, 641 Value: value, 642 Origin: org, 643 Position: pos, 644 } 645 switch stat.typ { 646 case numTypeFloat: 647 tk.Type = FloatType 648 case numTypeBinary: 649 tk.Type = BinaryIntegerType 650 case numTypeOctet: 651 tk.Type = OctetIntegerType 652 case numTypeHex: 653 tk.Type = HexIntegerType 654 } 655 return tk 656 } 657 return String(value, org, pos) 658 } 659 660 // Position type for position in YAML document 661 type Position struct { 662 Line int 663 Column int 664 Offset int 665 IndentNum int 666 IndentLevel int 667 } 668 669 // String position to text 670 func (p *Position) String() string { 671 return fmt.Sprintf("[level:%d,line:%d,column:%d,offset:%d]", p.IndentLevel, p.Line, p.Column, p.Offset) 672 } 673 674 // Token type for token 675 type Token struct { 676 Type Type 677 CharacterType CharacterType 678 Indicator Indicator 679 Value string 680 Origin string 681 Position *Position 682 Next *Token 683 Prev *Token 684 } 685 686 // PreviousType previous token type 687 func (t *Token) PreviousType() Type { 688 if t.Prev != nil { 689 return t.Prev.Type 690 } 691 return UnknownType 692 } 693 694 // NextType next token type 695 func (t *Token) NextType() Type { 696 if t.Next != nil { 697 return t.Next.Type 698 } 699 return UnknownType 700 } 701 702 // AddColumn append column number to current position of column 703 func (t *Token) AddColumn(col int) { 704 if t == nil { 705 return 706 } 707 t.Position.Column += col 708 } 709 710 // Clone copy token ( preserve Prev/Next reference ) 711 func (t *Token) Clone() *Token { 712 if t == nil { 713 return nil 714 } 715 copied := *t 716 if t.Position != nil { 717 pos := *(t.Position) 718 copied.Position = &pos 719 } 720 return &copied 721 } 722 723 // Tokens type of token collection 724 type Tokens []*Token 725 726 func (t *Tokens) add(tk *Token) { 727 tokens := *t 728 if len(tokens) == 0 { 729 tokens = append(tokens, tk) 730 } else { 731 last := tokens[len(tokens)-1] 732 last.Next = tk 733 tk.Prev = last 734 tokens = append(tokens, tk) 735 } 736 *t = tokens 737 } 738 739 // Add append new some tokens 740 func (t *Tokens) Add(tks ...*Token) { 741 for _, tk := range tks { 742 t.add(tk) 743 } 744 } 745 746 // Dump dump all token structures for debugging 747 func (t Tokens) Dump() { 748 for _, tk := range t { 749 fmt.Printf("- %+v\n", tk) 750 } 751 } 752 753 // String create token for String 754 func String(value string, org string, pos *Position) *Token { 755 return &Token{ 756 Type: StringType, 757 CharacterType: CharacterTypeMiscellaneous, 758 Indicator: NotIndicator, 759 Value: value, 760 Origin: org, 761 Position: pos, 762 } 763 } 764 765 // SequenceEntry create token for SequenceEntry 766 func SequenceEntry(org string, pos *Position) *Token { 767 return &Token{ 768 Type: SequenceEntryType, 769 CharacterType: CharacterTypeIndicator, 770 Indicator: BlockStructureIndicator, 771 Value: string(SequenceEntryCharacter), 772 Origin: org, 773 Position: pos, 774 } 775 } 776 777 // MappingKey create token for MappingKey 778 func MappingKey(pos *Position) *Token { 779 return &Token{ 780 Type: MappingKeyType, 781 CharacterType: CharacterTypeIndicator, 782 Indicator: BlockStructureIndicator, 783 Value: string(MappingKeyCharacter), 784 Origin: string(MappingKeyCharacter), 785 Position: pos, 786 } 787 } 788 789 // MappingValue create token for MappingValue 790 func MappingValue(pos *Position) *Token { 791 return &Token{ 792 Type: MappingValueType, 793 CharacterType: CharacterTypeIndicator, 794 Indicator: BlockStructureIndicator, 795 Value: string(MappingValueCharacter), 796 Origin: string(MappingValueCharacter), 797 Position: pos, 798 } 799 } 800 801 // CollectEntry create token for CollectEntry 802 func CollectEntry(org string, pos *Position) *Token { 803 return &Token{ 804 Type: CollectEntryType, 805 CharacterType: CharacterTypeIndicator, 806 Indicator: FlowCollectionIndicator, 807 Value: string(CollectEntryCharacter), 808 Origin: org, 809 Position: pos, 810 } 811 } 812 813 // SequenceStart create token for SequenceStart 814 func SequenceStart(org string, pos *Position) *Token { 815 return &Token{ 816 Type: SequenceStartType, 817 CharacterType: CharacterTypeIndicator, 818 Indicator: FlowCollectionIndicator, 819 Value: string(SequenceStartCharacter), 820 Origin: org, 821 Position: pos, 822 } 823 } 824 825 // SequenceEnd create token for SequenceEnd 826 func SequenceEnd(org string, pos *Position) *Token { 827 return &Token{ 828 Type: SequenceEndType, 829 CharacterType: CharacterTypeIndicator, 830 Indicator: FlowCollectionIndicator, 831 Value: string(SequenceEndCharacter), 832 Origin: org, 833 Position: pos, 834 } 835 } 836 837 // MappingStart create token for MappingStart 838 func MappingStart(org string, pos *Position) *Token { 839 return &Token{ 840 Type: MappingStartType, 841 CharacterType: CharacterTypeIndicator, 842 Indicator: FlowCollectionIndicator, 843 Value: string(MappingStartCharacter), 844 Origin: org, 845 Position: pos, 846 } 847 } 848 849 // MappingEnd create token for MappingEnd 850 func MappingEnd(org string, pos *Position) *Token { 851 return &Token{ 852 Type: MappingEndType, 853 CharacterType: CharacterTypeIndicator, 854 Indicator: FlowCollectionIndicator, 855 Value: string(MappingEndCharacter), 856 Origin: org, 857 Position: pos, 858 } 859 } 860 861 // Comment create token for Comment 862 func Comment(value string, org string, pos *Position) *Token { 863 return &Token{ 864 Type: CommentType, 865 CharacterType: CharacterTypeIndicator, 866 Indicator: CommentIndicator, 867 Value: value, 868 Origin: org, 869 Position: pos, 870 } 871 } 872 873 // Anchor create token for Anchor 874 func Anchor(org string, pos *Position) *Token { 875 return &Token{ 876 Type: AnchorType, 877 CharacterType: CharacterTypeIndicator, 878 Indicator: NodePropertyIndicator, 879 Value: string(AnchorCharacter), 880 Origin: org, 881 Position: pos, 882 } 883 } 884 885 // Alias create token for Alias 886 func Alias(org string, pos *Position) *Token { 887 return &Token{ 888 Type: AliasType, 889 CharacterType: CharacterTypeIndicator, 890 Indicator: NodePropertyIndicator, 891 Value: string(AliasCharacter), 892 Origin: org, 893 Position: pos, 894 } 895 } 896 897 // Tag create token for Tag 898 func Tag(value string, org string, pos *Position) *Token { 899 fn := ReservedTagKeywordMap[ReservedTagKeyword(value)] 900 if fn != nil { 901 return fn(value, org, pos) 902 } 903 return &Token{ 904 Type: TagType, 905 CharacterType: CharacterTypeIndicator, 906 Indicator: NodePropertyIndicator, 907 Value: value, 908 Origin: org, 909 Position: pos, 910 } 911 } 912 913 // Literal create token for Literal 914 func Literal(value string, org string, pos *Position) *Token { 915 return &Token{ 916 Type: LiteralType, 917 CharacterType: CharacterTypeIndicator, 918 Indicator: BlockScalarIndicator, 919 Value: value, 920 Origin: org, 921 Position: pos, 922 } 923 } 924 925 // Folded create token for Folded 926 func Folded(value string, org string, pos *Position) *Token { 927 return &Token{ 928 Type: FoldedType, 929 CharacterType: CharacterTypeIndicator, 930 Indicator: BlockScalarIndicator, 931 Value: value, 932 Origin: org, 933 Position: pos, 934 } 935 } 936 937 // SingleQuote create token for SingleQuote 938 func SingleQuote(value string, org string, pos *Position) *Token { 939 return &Token{ 940 Type: SingleQuoteType, 941 CharacterType: CharacterTypeIndicator, 942 Indicator: QuotedScalarIndicator, 943 Value: value, 944 Origin: org, 945 Position: pos, 946 } 947 } 948 949 // DoubleQuote create token for DoubleQuote 950 func DoubleQuote(value string, org string, pos *Position) *Token { 951 return &Token{ 952 Type: DoubleQuoteType, 953 CharacterType: CharacterTypeIndicator, 954 Indicator: QuotedScalarIndicator, 955 Value: value, 956 Origin: org, 957 Position: pos, 958 } 959 } 960 961 // Directive create token for Directive 962 func Directive(org string, pos *Position) *Token { 963 return &Token{ 964 Type: DirectiveType, 965 CharacterType: CharacterTypeIndicator, 966 Indicator: DirectiveIndicator, 967 Value: string(DirectiveCharacter), 968 Origin: org, 969 Position: pos, 970 } 971 } 972 973 // Space create token for Space 974 func Space(pos *Position) *Token { 975 return &Token{ 976 Type: SpaceType, 977 CharacterType: CharacterTypeWhiteSpace, 978 Indicator: NotIndicator, 979 Value: string(SpaceCharacter), 980 Origin: string(SpaceCharacter), 981 Position: pos, 982 } 983 } 984 985 // MergeKey create token for MergeKey 986 func MergeKey(org string, pos *Position) *Token { 987 return &Token{ 988 Type: MergeKeyType, 989 CharacterType: CharacterTypeMiscellaneous, 990 Indicator: NotIndicator, 991 Value: "<<", 992 Origin: org, 993 Position: pos, 994 } 995 } 996 997 // DocumentHeader create token for DocumentHeader 998 func DocumentHeader(org string, pos *Position) *Token { 999 return &Token{ 1000 Type: DocumentHeaderType, 1001 CharacterType: CharacterTypeMiscellaneous, 1002 Indicator: NotIndicator, 1003 Value: "---", 1004 Origin: org, 1005 Position: pos, 1006 } 1007 } 1008 1009 // DocumentEnd create token for DocumentEnd 1010 func DocumentEnd(org string, pos *Position) *Token { 1011 return &Token{ 1012 Type: DocumentEndType, 1013 CharacterType: CharacterTypeMiscellaneous, 1014 Indicator: NotIndicator, 1015 Value: "...", 1016 Origin: org, 1017 Position: pos, 1018 } 1019 } 1020 1021 // DetectLineBreakCharacter detect line break character in only one inside scalar content scope. 1022 func DetectLineBreakCharacter(src string) string { 1023 nc := strings.Count(src, "\n") 1024 rc := strings.Count(src, "\r") 1025 rnc := strings.Count(src, "\r\n") 1026 switch { 1027 case nc == rnc && rc == rnc: 1028 return "\r\n" 1029 case rc > nc: 1030 return "\r" 1031 default: 1032 return "\n" 1033 } 1034 }