1package toml 2 3import ( 4 "fmt" 5 "strings" 6 "unicode/utf8" 7) 8 9type itemType int 10 11const ( 12 itemError itemType = iota 13 itemNIL // used in the parser to indicate no type 14 itemEOF 15 itemText 16 itemString 17 itemRawString 18 itemMultilineString 19 itemRawMultilineString 20 itemBool 21 itemInteger 22 itemFloat 23 itemDatetime 24 itemArray // the start of an array 25 itemArrayEnd 26 itemTableStart 27 itemTableEnd 28 itemArrayTableStart 29 itemArrayTableEnd 30 itemKeyStart 31 itemCommentStart 32) 33 34const ( 35 eof = 0 36 tableStart = '[' 37 tableEnd = ']' 38 arrayTableStart = '[' 39 arrayTableEnd = ']' 40 tableSep = '.' 41 keySep = '=' 42 arrayStart = '[' 43 arrayEnd = ']' 44 arrayValTerm = ',' 45 commentStart = '#' 46 stringStart = '"' 47 stringEnd = '"' 48 rawStringStart = '\'' 49 rawStringEnd = '\'' 50) 51 52type stateFn func(lx *lexer) stateFn 53 54type lexer struct { 55 input string 56 start int 57 pos int 58 width int 59 line int 60 state stateFn 61 items chan item 62 63 // A stack of state functions used to maintain context. 64 // The idea is to reuse parts of the state machine in various places. 65 // For example, values can appear at the top level or within arbitrarily 66 // nested arrays. The last state on the stack is used after a value has 67 // been lexed. Similarly for comments. 68 stack []stateFn 69} 70 71type item struct { 72 typ itemType 73 val string 74 line int 75} 76 77func (lx *lexer) nextItem() item { 78 for { 79 select { 80 case item := <-lx.items: 81 return item 82 default: 83 lx.state = lx.state(lx) 84 } 85 } 86} 87 88func lex(input string) *lexer { 89 lx := &lexer{ 90 input: input + "\n", 91 state: lexTop, 92 line: 1, 93 items: make(chan item, 10), 94 stack: make([]stateFn, 0, 10), 95 } 96 return lx 97} 98 99func (lx *lexer) push(state stateFn) { 100 lx.stack = append(lx.stack, state) 101} 102 103func (lx *lexer) pop() stateFn { 104 if len(lx.stack) == 0 { 105 return lx.errorf("BUG in lexer: no states to pop.") 106 } 107 last := lx.stack[len(lx.stack)-1] 108 lx.stack = lx.stack[0 : len(lx.stack)-1] 109 return last 110} 111 112func (lx *lexer) current() string { 113 return lx.input[lx.start:lx.pos] 114} 115 116func (lx *lexer) emit(typ itemType) { 117 lx.items <- item{typ, lx.current(), lx.line} 118 lx.start = lx.pos 119} 120 121func (lx *lexer) emitTrim(typ itemType) { 122 lx.items <- item{typ, strings.TrimSpace(lx.current()), lx.line} 123 lx.start = lx.pos 124} 125 126func (lx *lexer) next() (r rune) { 127 if lx.pos >= len(lx.input) { 128 lx.width = 0 129 return eof 130 } 131 132 if lx.input[lx.pos] == '\n' { 133 lx.line++ 134 } 135 r, lx.width = utf8.DecodeRuneInString(lx.input[lx.pos:]) 136 lx.pos += lx.width 137 return r 138} 139 140// ignore skips over the pending input before this point. 141func (lx *lexer) ignore() { 142 lx.start = lx.pos 143} 144 145// backup steps back one rune. Can be called only once per call of next. 146func (lx *lexer) backup() { 147 lx.pos -= lx.width 148 if lx.pos < len(lx.input) && lx.input[lx.pos] == '\n' { 149 lx.line-- 150 } 151} 152 153// accept consumes the next rune if it's equal to `valid`. 154func (lx *lexer) accept(valid rune) bool { 155 if lx.next() == valid { 156 return true 157 } 158 lx.backup() 159 return false 160} 161 162// peek returns but does not consume the next rune in the input. 163func (lx *lexer) peek() rune { 164 r := lx.next() 165 lx.backup() 166 return r 167} 168 169// errorf stops all lexing by emitting an error and returning `nil`. 170// Note that any value that is a character is escaped if it's a special 171// character (new lines, tabs, etc.). 172func (lx *lexer) errorf(format string, values ...interface{}) stateFn { 173 lx.items <- item{ 174 itemError, 175 fmt.Sprintf(format, values...), 176 lx.line, 177 } 178 return nil 179} 180 181// lexTop consumes elements at the top level of TOML data. 182func lexTop(lx *lexer) stateFn { 183 r := lx.next() 184 if isWhitespace(r) || isNL(r) { 185 return lexSkip(lx, lexTop) 186 } 187 188 switch r { 189 case commentStart: 190 lx.push(lexTop) 191 return lexCommentStart 192 case tableStart: 193 return lexTableStart 194 case eof: 195 if lx.pos > lx.start { 196 return lx.errorf("Unexpected EOF.") 197 } 198 lx.emit(itemEOF) 199 return nil 200 } 201 202 // At this point, the only valid item can be a key, so we back up 203 // and let the key lexer do the rest. 204 lx.backup() 205 lx.push(lexTopEnd) 206 return lexKeyStart 207} 208 209// lexTopEnd is entered whenever a top-level item has been consumed. (A value 210// or a table.) It must see only whitespace, and will turn back to lexTop 211// upon a new line. If it sees EOF, it will quit the lexer successfully. 212func lexTopEnd(lx *lexer) stateFn { 213 r := lx.next() 214 switch { 215 case r == commentStart: 216 // a comment will read to a new line for us. 217 lx.push(lexTop) 218 return lexCommentStart 219 case isWhitespace(r): 220 return lexTopEnd 221 case isNL(r): 222 lx.ignore() 223 return lexTop 224 case r == eof: 225 lx.ignore() 226 return lexTop 227 } 228 return lx.errorf("Expected a top-level item to end with a new line, "+ 229 "comment or EOF, but got %q instead.", r) 230} 231 232// lexTable lexes the beginning of a table. Namely, it makes sure that 233// it starts with a character other than '.' and ']'. 234// It assumes that '[' has already been consumed. 235// It also handles the case that this is an item in an array of tables. 236// e.g., '[[name]]'. 237func lexTableStart(lx *lexer) stateFn { 238 if lx.peek() == arrayTableStart { 239 lx.next() 240 lx.emit(itemArrayTableStart) 241 lx.push(lexArrayTableEnd) 242 } else { 243 lx.emit(itemTableStart) 244 lx.push(lexTableEnd) 245 } 246 return lexTableNameStart 247} 248 249func lexTableEnd(lx *lexer) stateFn { 250 lx.emit(itemTableEnd) 251 return lexTopEnd 252} 253 254func lexArrayTableEnd(lx *lexer) stateFn { 255 if r := lx.next(); r != arrayTableEnd { 256 return lx.errorf("Expected end of table array name delimiter %q, "+ 257 "but got %q instead.", arrayTableEnd, r) 258 } 259 lx.emit(itemArrayTableEnd) 260 return lexTopEnd 261} 262 263func lexTableNameStart(lx *lexer) stateFn { 264 switch r := lx.peek(); { 265 case r == tableEnd || r == eof: 266 return lx.errorf("Unexpected end of table name. (Table names cannot " + 267 "be empty.)") 268 case r == tableSep: 269 return lx.errorf("Unexpected table separator. (Table names cannot " + 270 "be empty.)") 271 case r == stringStart || r == rawStringStart: 272 lx.ignore() 273 lx.push(lexTableNameEnd) 274 return lexValue // reuse string lexing 275 case isWhitespace(r): 276 return lexTableNameStart 277 default: 278 return lexBareTableName 279 } 280} 281 282// lexTableName lexes the name of a table. It assumes that at least one 283// valid character for the table has already been read. 284func lexBareTableName(lx *lexer) stateFn { 285 switch r := lx.next(); { 286 case isBareKeyChar(r): 287 return lexBareTableName 288 case r == tableSep || r == tableEnd: 289 lx.backup() 290 lx.emitTrim(itemText) 291 return lexTableNameEnd 292 default: 293 return lx.errorf("Bare keys cannot contain %q.", r) 294 } 295} 296 297// lexTableNameEnd reads the end of a piece of a table name, optionally 298// consuming whitespace. 299func lexTableNameEnd(lx *lexer) stateFn { 300 switch r := lx.next(); { 301 case isWhitespace(r): 302 return lexTableNameEnd 303 case r == tableSep: 304 lx.ignore() 305 return lexTableNameStart 306 case r == tableEnd: 307 return lx.pop() 308 default: 309 return lx.errorf("Expected '.' or ']' to end table name, but got %q "+ 310 "instead.", r) 311 } 312} 313 314// lexKeyStart consumes a key name up until the first non-whitespace character. 315// lexKeyStart will ignore whitespace. 316func lexKeyStart(lx *lexer) stateFn { 317 r := lx.peek() 318 switch { 319 case r == keySep: 320 return lx.errorf("Unexpected key separator %q.", keySep) 321 case isWhitespace(r) || isNL(r): 322 lx.next() 323 return lexSkip(lx, lexKeyStart) 324 case r == stringStart || r == rawStringStart: 325 lx.ignore() 326 lx.emit(itemKeyStart) 327 lx.push(lexKeyEnd) 328 return lexValue // reuse string lexing 329 default: 330 lx.ignore() 331 lx.emit(itemKeyStart) 332 return lexBareKey 333 } 334} 335 336// lexBareKey consumes the text of a bare key. Assumes that the first character 337// (which is not whitespace) has not yet been consumed. 338func lexBareKey(lx *lexer) stateFn { 339 switch r := lx.next(); { 340 case isBareKeyChar(r): 341 return lexBareKey 342 case isWhitespace(r): 343 lx.emitTrim(itemText) 344 return lexKeyEnd 345 case r == keySep: 346 lx.backup() 347 lx.emitTrim(itemText) 348 return lexKeyEnd 349 default: 350 return lx.errorf("Bare keys cannot contain %q.", r) 351 } 352} 353 354// lexKeyEnd consumes the end of a key and trims whitespace (up to the key 355// separator). 356func lexKeyEnd(lx *lexer) stateFn { 357 switch r := lx.next(); { 358 case r == keySep: 359 return lexSkip(lx, lexValue) 360 case isWhitespace(r): 361 return lexSkip(lx, lexKeyEnd) 362 default: 363 return lx.errorf("Expected key separator %q, but got %q instead.", 364 keySep, r) 365 } 366} 367 368// lexValue starts the consumption of a value anywhere a value is expected. 369// lexValue will ignore whitespace. 370// After a value is lexed, the last state on the next is popped and returned. 371func lexValue(lx *lexer) stateFn { 372 // We allow whitespace to precede a value, but NOT new lines. 373 // In array syntax, the array states are responsible for ignoring new 374 // lines. 375 r := lx.next() 376 if isWhitespace(r) { 377 return lexSkip(lx, lexValue) 378 } 379 380 switch { 381 case r == arrayStart: 382 lx.ignore() 383 lx.emit(itemArray) 384 return lexArrayValue 385 case r == stringStart: 386 if lx.accept(stringStart) { 387 if lx.accept(stringStart) { 388 lx.ignore() // Ignore """ 389 return lexMultilineString 390 } 391 lx.backup() 392 } 393 lx.ignore() // ignore the '"' 394 return lexString 395 case r == rawStringStart: 396 if lx.accept(rawStringStart) { 397 if lx.accept(rawStringStart) { 398 lx.ignore() // Ignore """ 399 return lexMultilineRawString 400 } 401 lx.backup() 402 } 403 lx.ignore() // ignore the "'" 404 return lexRawString 405 case r == 't': 406 return lexTrue 407 case r == 'f': 408 return lexFalse 409 case r == '-': 410 return lexNumberStart 411 case isDigit(r): 412 lx.backup() // avoid an extra state and use the same as above 413 return lexNumberOrDateStart 414 case r == '.': // special error case, be kind to users 415 return lx.errorf("Floats must start with a digit, not '.'.") 416 } 417 return lx.errorf("Expected value but found %q instead.", r) 418} 419 420// lexArrayValue consumes one value in an array. It assumes that '[' or ',' 421// have already been consumed. All whitespace and new lines are ignored. 422func lexArrayValue(lx *lexer) stateFn { 423 r := lx.next() 424 switch { 425 case isWhitespace(r) || isNL(r): 426 return lexSkip(lx, lexArrayValue) 427 case r == commentStart: 428 lx.push(lexArrayValue) 429 return lexCommentStart 430 case r == arrayValTerm: 431 return lx.errorf("Unexpected array value terminator %q.", 432 arrayValTerm) 433 case r == arrayEnd: 434 return lexArrayEnd 435 } 436 437 lx.backup() 438 lx.push(lexArrayValueEnd) 439 return lexValue 440} 441 442// lexArrayValueEnd consumes the cruft between values of an array. Namely, 443// it ignores whitespace and expects either a ',' or a ']'. 444func lexArrayValueEnd(lx *lexer) stateFn { 445 r := lx.next() 446 switch { 447 case isWhitespace(r) || isNL(r): 448 return lexSkip(lx, lexArrayValueEnd) 449 case r == commentStart: 450 lx.push(lexArrayValueEnd) 451 return lexCommentStart 452 case r == arrayValTerm: 453 lx.ignore() 454 return lexArrayValue // move on to the next value 455 case r == arrayEnd: 456 return lexArrayEnd 457 } 458 return lx.errorf("Expected an array value terminator %q or an array "+ 459 "terminator %q, but got %q instead.", arrayValTerm, arrayEnd, r) 460} 461 462// lexArrayEnd finishes the lexing of an array. It assumes that a ']' has 463// just been consumed. 464func lexArrayEnd(lx *lexer) stateFn { 465 lx.ignore() 466 lx.emit(itemArrayEnd) 467 return lx.pop() 468} 469 470// lexString consumes the inner contents of a string. It assumes that the 471// beginning '"' has already been consumed and ignored. 472func lexString(lx *lexer) stateFn { 473 r := lx.next() 474 switch { 475 case isNL(r): 476 return lx.errorf("Strings cannot contain new lines.") 477 case r == '\\': 478 lx.push(lexString) 479 return lexStringEscape 480 case r == stringEnd: 481 lx.backup() 482 lx.emit(itemString) 483 lx.next() 484 lx.ignore() 485 return lx.pop() 486 } 487 return lexString 488} 489 490// lexMultilineString consumes the inner contents of a string. It assumes that 491// the beginning '"""' has already been consumed and ignored. 492func lexMultilineString(lx *lexer) stateFn { 493 r := lx.next() 494 switch { 495 case r == '\\': 496 return lexMultilineStringEscape 497 case r == stringEnd: 498 if lx.accept(stringEnd) { 499 if lx.accept(stringEnd) { 500 lx.backup() 501 lx.backup() 502 lx.backup() 503 lx.emit(itemMultilineString) 504 lx.next() 505 lx.next() 506 lx.next() 507 lx.ignore() 508 return lx.pop() 509 } 510 lx.backup() 511 } 512 } 513 return lexMultilineString 514} 515 516// lexRawString consumes a raw string. Nothing can be escaped in such a string. 517// It assumes that the beginning "'" has already been consumed and ignored. 518func lexRawString(lx *lexer) stateFn { 519 r := lx.next() 520 switch { 521 case isNL(r): 522 return lx.errorf("Strings cannot contain new lines.") 523 case r == rawStringEnd: 524 lx.backup() 525 lx.emit(itemRawString) 526 lx.next() 527 lx.ignore() 528 return lx.pop() 529 } 530 return lexRawString 531} 532 533// lexMultilineRawString consumes a raw string. Nothing can be escaped in such 534// a string. It assumes that the beginning "'" has already been consumed and 535// ignored. 536func lexMultilineRawString(lx *lexer) stateFn { 537 r := lx.next() 538 switch { 539 case r == rawStringEnd: 540 if lx.accept(rawStringEnd) { 541 if lx.accept(rawStringEnd) { 542 lx.backup() 543 lx.backup() 544 lx.backup() 545 lx.emit(itemRawMultilineString) 546 lx.next() 547 lx.next() 548 lx.next() 549 lx.ignore() 550 return lx.pop() 551 } 552 lx.backup() 553 } 554 } 555 return lexMultilineRawString 556} 557 558// lexMultilineStringEscape consumes an escaped character. It assumes that the 559// preceding '\\' has already been consumed. 560func lexMultilineStringEscape(lx *lexer) stateFn { 561 // Handle the special case first: 562 if isNL(lx.next()) { 563 lx.next() 564 return lexMultilineString 565 } else { 566 lx.backup() 567 lx.push(lexMultilineString) 568 return lexStringEscape(lx) 569 } 570} 571 572func lexStringEscape(lx *lexer) stateFn { 573 r := lx.next() 574 switch r { 575 case 'b': 576 fallthrough 577 case 't': 578 fallthrough 579 case 'n': 580 fallthrough 581 case 'f': 582 fallthrough 583 case 'r': 584 fallthrough 585 case '"': 586 fallthrough 587 case '\\': 588 return lx.pop() 589 case 'u': 590 return lexShortUnicodeEscape 591 case 'U': 592 return lexLongUnicodeEscape 593 } 594 return lx.errorf("Invalid escape character %q. Only the following "+ 595 "escape characters are allowed: "+ 596 "\\b, \\t, \\n, \\f, \\r, \\\", \\/, \\\\, "+ 597 "\\uXXXX and \\UXXXXXXXX.", r) 598} 599 600func lexShortUnicodeEscape(lx *lexer) stateFn { 601 var r rune 602 for i := 0; i < 4; i++ { 603 r = lx.next() 604 if !isHexadecimal(r) { 605 return lx.errorf("Expected four hexadecimal digits after '\\u', "+ 606 "but got '%s' instead.", lx.current()) 607 } 608 } 609 return lx.pop() 610} 611 612func lexLongUnicodeEscape(lx *lexer) stateFn { 613 var r rune 614 for i := 0; i < 8; i++ { 615 r = lx.next() 616 if !isHexadecimal(r) { 617 return lx.errorf("Expected eight hexadecimal digits after '\\U', "+ 618 "but got '%s' instead.", lx.current()) 619 } 620 } 621 return lx.pop() 622} 623 624// lexNumberOrDateStart consumes either a (positive) integer, float or 625// datetime. It assumes that NO negative sign has been consumed. 626func lexNumberOrDateStart(lx *lexer) stateFn { 627 r := lx.next() 628 if !isDigit(r) { 629 if r == '.' { 630 return lx.errorf("Floats must start with a digit, not '.'.") 631 } else { 632 return lx.errorf("Expected a digit but got %q.", r) 633 } 634 } 635 return lexNumberOrDate 636} 637 638// lexNumberOrDate consumes either a (positive) integer, float or datetime. 639func lexNumberOrDate(lx *lexer) stateFn { 640 r := lx.next() 641 switch { 642 case r == '-': 643 if lx.pos-lx.start != 5 { 644 return lx.errorf("All ISO8601 dates must be in full Zulu form.") 645 } 646 return lexDateAfterYear 647 case isDigit(r): 648 return lexNumberOrDate 649 case r == '.': 650 return lexFloatStart 651 } 652 653 lx.backup() 654 lx.emit(itemInteger) 655 return lx.pop() 656} 657 658// lexDateAfterYear consumes a full Zulu Datetime in ISO8601 format. 659// It assumes that "YYYY-" has already been consumed. 660func lexDateAfterYear(lx *lexer) stateFn { 661 formats := []rune{ 662 // digits are '0'. 663 // everything else is direct equality. 664 '0', '0', '-', '0', '0', 665 'T', 666 '0', '0', ':', '0', '0', ':', '0', '0', 667 'Z', 668 } 669 for _, f := range formats { 670 r := lx.next() 671 if f == '0' { 672 if !isDigit(r) { 673 return lx.errorf("Expected digit in ISO8601 datetime, "+ 674 "but found %q instead.", r) 675 } 676 } else if f != r { 677 return lx.errorf("Expected %q in ISO8601 datetime, "+ 678 "but found %q instead.", f, r) 679 } 680 } 681 lx.emit(itemDatetime) 682 return lx.pop() 683} 684 685// lexNumberStart consumes either an integer or a float. It assumes that 686// a negative sign has already been read, but that *no* digits have been 687// consumed. lexNumberStart will move to the appropriate integer or float 688// states. 689func lexNumberStart(lx *lexer) stateFn { 690 // we MUST see a digit. Even floats have to start with a digit. 691 r := lx.next() 692 if !isDigit(r) { 693 if r == '.' { 694 return lx.errorf("Floats must start with a digit, not '.'.") 695 } else { 696 return lx.errorf("Expected a digit but got %q.", r) 697 } 698 } 699 return lexNumber 700} 701 702// lexNumber consumes an integer or a float after seeing the first digit. 703func lexNumber(lx *lexer) stateFn { 704 r := lx.next() 705 switch { 706 case isDigit(r): 707 return lexNumber 708 case r == '.': 709 return lexFloatStart 710 } 711 712 lx.backup() 713 lx.emit(itemInteger) 714 return lx.pop() 715} 716 717// lexFloatStart starts the consumption of digits of a float after a '.'. 718// Namely, at least one digit is required. 719func lexFloatStart(lx *lexer) stateFn { 720 r := lx.next() 721 if !isDigit(r) { 722 return lx.errorf("Floats must have a digit after the '.', but got "+ 723 "%q instead.", r) 724 } 725 return lexFloat 726} 727 728// lexFloat consumes the digits of a float after a '.'. 729// Assumes that one digit has been consumed after a '.' already. 730func lexFloat(lx *lexer) stateFn { 731 r := lx.next() 732 if isDigit(r) { 733 return lexFloat 734 } 735 736 lx.backup() 737 lx.emit(itemFloat) 738 return lx.pop() 739} 740 741// lexConst consumes the s[1:] in s. It assumes that s[0] has already been 742// consumed. 743func lexConst(lx *lexer, s string) stateFn { 744 for i := range s[1:] { 745 if r := lx.next(); r != rune(s[i+1]) { 746 return lx.errorf("Expected %q, but found %q instead.", s[:i+1], 747 s[:i]+string(r)) 748 } 749 } 750 return nil 751} 752 753// lexTrue consumes the "rue" in "true". It assumes that 't' has already 754// been consumed. 755func lexTrue(lx *lexer) stateFn { 756 if fn := lexConst(lx, "true"); fn != nil { 757 return fn 758 } 759 lx.emit(itemBool) 760 return lx.pop() 761} 762 763// lexFalse consumes the "alse" in "false". It assumes that 'f' has already 764// been consumed. 765func lexFalse(lx *lexer) stateFn { 766 if fn := lexConst(lx, "false"); fn != nil { 767 return fn 768 } 769 lx.emit(itemBool) 770 return lx.pop() 771} 772 773// lexCommentStart begins the lexing of a comment. It will emit 774// itemCommentStart and consume no characters, passing control to lexComment. 775func lexCommentStart(lx *lexer) stateFn { 776 lx.ignore() 777 lx.emit(itemCommentStart) 778 return lexComment 779} 780 781// lexComment lexes an entire comment. It assumes that '#' has been consumed. 782// It will consume *up to* the first new line character, and pass control 783// back to the last state on the stack. 784func lexComment(lx *lexer) stateFn { 785 r := lx.peek() 786 if isNL(r) || r == eof { 787 lx.emit(itemText) 788 return lx.pop() 789 } 790 lx.next() 791 return lexComment 792} 793 794// lexSkip ignores all slurped input and moves on to the next state. 795func lexSkip(lx *lexer, nextState stateFn) stateFn { 796 return func(lx *lexer) stateFn { 797 lx.ignore() 798 return nextState 799 } 800} 801 802// isWhitespace returns true if `r` is a whitespace character according 803// to the spec. 804func isWhitespace(r rune) bool { 805 return r == '\t' || r == ' ' 806} 807 808func isNL(r rune) bool { 809 return r == '\n' || r == '\r' 810} 811 812func isDigit(r rune) bool { 813 return r >= '0' && r <= '9' 814} 815 816func isHexadecimal(r rune) bool { 817 return (r >= '0' && r <= '9') || 818 (r >= 'a' && r <= 'f') || 819 (r >= 'A' && r <= 'F') 820} 821 822func isBareKeyChar(r rune) bool { 823 return (r >= 'A' && r <= 'Z') || 824 (r >= 'a' && r <= 'z') || 825 (r >= '0' && r <= '9') || 826 r == '_' || 827 r == '-' 828} 829 830func (itype itemType) String() string { 831 switch itype { 832 case itemError: 833 return "Error" 834 case itemNIL: 835 return "NIL" 836 case itemEOF: 837 return "EOF" 838 case itemText: 839 return "Text" 840 case itemString: 841 return "String" 842 case itemRawString: 843 return "String" 844 case itemMultilineString: 845 return "String" 846 case itemRawMultilineString: 847 return "String" 848 case itemBool: 849 return "Bool" 850 case itemInteger: 851 return "Integer" 852 case itemFloat: 853 return "Float" 854 case itemDatetime: 855 return "DateTime" 856 case itemTableStart: 857 return "TableStart" 858 case itemTableEnd: 859 return "TableEnd" 860 case itemKeyStart: 861 return "KeyStart" 862 case itemArray: 863 return "Array" 864 case itemArrayEnd: 865 return "ArrayEnd" 866 case itemCommentStart: 867 return "CommentStart" 868 } 869 panic(fmt.Sprintf("BUG: Unknown type '%d'.", int(itype))) 870} 871 872func (item item) String() string { 873 return fmt.Sprintf("(%s, %s)", item.typ.String(), item.val) 874} 875