├── .gitignore ├── LICENSE.md ├── README.md ├── decode.go ├── encode.go ├── lex.go └── parse.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files, Static and Dynamic libs (Shared Objects) 2 | *.o 3 | *.a 4 | *.so 5 | 6 | # Folders 7 | _obj 8 | _test 9 | 10 | # Architecture specific extensions/prefixes 11 | *.[568vq] 12 | [568vq].out 13 | 14 | *.cgo1.go 15 | *.cgo2.c 16 | _cgo_defun.c 17 | _cgo_gotypes.go 18 | _cgo_export.* 19 | 20 | _testmain.go 21 | 22 | *.exe 23 | *.test 24 | *.prof 25 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jordan Tucker 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # json5-go 2 | 3 | The official implementation of JSON5 for the Go language 4 | -------------------------------------------------------------------------------- /decode.go: -------------------------------------------------------------------------------- 1 | package json5 2 | 3 | func Unmarshal(data []byte, v interface{}) error { 4 | return nil 5 | } 6 | 7 | type Unmarshaler interface { 8 | UnmarshalJSON5([]byte) error 9 | } 10 | -------------------------------------------------------------------------------- /encode.go: -------------------------------------------------------------------------------- 1 | package json5 2 | 3 | func Marshal(v interface{}) ([]byte, error) { 4 | return nil, nil 5 | } 6 | 7 | type Marshaler interface { 8 | MarshalJSON5([]byte, error) 9 | } 10 | -------------------------------------------------------------------------------- /lex.go: -------------------------------------------------------------------------------- 1 | package json5 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "fmt" 7 | "io" 8 | "math" 9 | "strconv" 10 | "unicode" 11 | ) 12 | 13 | type lexer struct { 14 | reader *reader 15 | } 16 | 17 | func newLexer(rd io.Reader) *lexer { 18 | return &lexer{newReader(rd)} 19 | } 20 | 21 | func (l *lexer) lex() (t token, err error) { 22 | state := stateDefault 23 | sign := 1 24 | var ( 25 | inputBuf, valueBuf string 26 | doubleQuote bool 27 | line, column int 28 | ) 29 | 30 | start: 31 | r, _, err := l.reader.ReadRune() 32 | if err != nil && err != io.EOF { 33 | return 34 | } 35 | 36 | switch state { 37 | case stateDefault: 38 | if err == io.EOF { 39 | return 40 | } 41 | 42 | switch r { 43 | case '\t', '\v', '\f', 0x00A0, 0xFEFF, '\n', '\r', 0x2028, 0x2029: 44 | // Skip whitespace. More whitespace is checked for after this switch. 45 | goto start 46 | 47 | case '/': 48 | state = stateComment 49 | goto start 50 | 51 | case '$', '_': 52 | // $ and _ are valid identifiers. More identifiers are checked for after 53 | // this switch. 54 | state = stateIdentifier 55 | inputBuf += string(r) 56 | valueBuf += string(r) 57 | goto start 58 | 59 | case '\\': 60 | state = stateIdentifierStartEscapeSlash 61 | inputBuf = string(r) 62 | goto start 63 | 64 | case '{', '}', '[', ']', ',', ':': 65 | t = l.newToken(typePunctuator, string(r)) 66 | return 67 | 68 | case '+', '-': 69 | state = stateSign 70 | if r == '-' { 71 | sign = -1 72 | } 73 | 74 | inputBuf += string(r) 75 | valueBuf += string(r) 76 | goto start 77 | 78 | case '0': 79 | state = stateZero 80 | inputBuf += string(r) 81 | valueBuf += string(r) 82 | goto start 83 | 84 | case '1', '2', '3', '4', '5', '6', '7', '8', '9': 85 | state = stateDecimalInteger 86 | inputBuf += string(r) 87 | valueBuf += string(r) 88 | goto start 89 | 90 | case '.': 91 | state = stateDecimalPointLeading 92 | inputBuf += string(r) 93 | valueBuf += string(r) 94 | goto start 95 | 96 | case '"', '\'': 97 | state = stateString 98 | doubleQuote = r == '"' 99 | inputBuf += string(r) 100 | line, column = l.reader.line, l.reader.column 101 | goto start 102 | } 103 | 104 | if unicode.Is(unicode.Zs, r) { 105 | // Skip witespace. 106 | goto start 107 | } 108 | 109 | if unicode.In(r, unicode.L, unicode.Nl) { 110 | state = stateIdentifier 111 | inputBuf += string(r) 112 | valueBuf += string(r) 113 | goto start 114 | } 115 | 116 | err = l.invalidChar(r) 117 | return 118 | 119 | case stateComment: 120 | if err == io.EOF { 121 | err = l.invalidEOF() 122 | return 123 | } 124 | 125 | switch r { 126 | case '*': 127 | state = stateMultiLineComment 128 | goto start 129 | 130 | case '/': 131 | state = stateSingleLineComment 132 | goto start 133 | } 134 | 135 | err = l.invalidChar(r) 136 | return 137 | 138 | case stateMultiLineComment: 139 | if err == io.EOF { 140 | err = l.invalidEOF() 141 | return 142 | } 143 | 144 | if r == '*' { 145 | state = stateMultiLineCommentAsterisk 146 | } 147 | 148 | goto start 149 | 150 | case stateMultiLineCommentAsterisk: 151 | if err == io.EOF { 152 | err = l.invalidEOF() 153 | return 154 | } 155 | 156 | if r == '/' { 157 | state = stateDefault 158 | } else { 159 | state = stateMultiLineComment 160 | } 161 | 162 | goto start 163 | 164 | case stateSingleLineComment: 165 | if err == io.EOF { 166 | return 167 | } 168 | 169 | switch r { 170 | case '\n', '\r', '\u2028', '\u2029': 171 | state = stateDefault 172 | } 173 | 174 | goto start 175 | 176 | case stateIdentifier: 177 | if err != io.EOF { 178 | switch r { 179 | case '$', '_': 180 | inputBuf += string(r) 181 | valueBuf += string(r) 182 | goto start 183 | 184 | case '\\': 185 | state = stateIdentifierEscapeSlash 186 | inputBuf += string(r) 187 | goto start 188 | } 189 | 190 | if isUnicodeIDRune(r) { 191 | inputBuf += string(r) 192 | valueBuf += string(r) 193 | goto start 194 | } 195 | } 196 | 197 | t, err = l.newToken(typeIdentifier, inputBuf), nil 198 | return 199 | 200 | case stateIdentifierStartEscapeSlash, stateIdentifierEscapeSlash: 201 | if err == io.EOF { 202 | err = l.invalidEOF() 203 | return 204 | } 205 | 206 | if r != 'u' { 207 | err = l.invalidChar(r) 208 | return 209 | } 210 | 211 | inputBuf += string(r) 212 | var hexBuf string 213 | for i := 0; i < 4; i++ { 214 | r, _, err = l.reader.ReadRune() 215 | if err != nil { 216 | if err == io.EOF { 217 | err = l.invalidEOF() 218 | } 219 | 220 | return 221 | } 222 | 223 | if !isHexDigit(r) { 224 | err = l.invalidChar(r) 225 | return 226 | } 227 | 228 | inputBuf += string(r) 229 | hexBuf += string(r) 230 | } 231 | 232 | // f will test if the escaped rune is an IdentifierStart or IdentifierPart 233 | // depending on the state. 234 | var f func(rune) bool 235 | if state == stateIdentifierStartEscapeSlash { 236 | f = isUnicodeIDStartRune 237 | } else { 238 | f = isUnicodeIDRune 239 | } 240 | 241 | n, _ := strconv.ParseUint(hexBuf, 16, 16) 242 | u := rune(n) 243 | if u == '$' || u == '_' || f(u) { 244 | state = stateIdentifier 245 | valueBuf += string(u) 246 | goto start 247 | } 248 | 249 | err = l.invalidEscape(u) 250 | return 251 | 252 | case stateSign: 253 | if err == io.EOF { 254 | err = l.invalidEOF() 255 | return 256 | } 257 | 258 | switch r { 259 | case '0': 260 | state = stateZero 261 | inputBuf += string(r) 262 | valueBuf += string(r) 263 | goto start 264 | 265 | case '1', '2', '3', '4', '5', '6', '7', '8', '9': 266 | state = stateDecimalInteger 267 | inputBuf += string(r) 268 | valueBuf += string(r) 269 | goto start 270 | 271 | case '.': 272 | state = stateDecimalPointLeading 273 | inputBuf += string(r) 274 | valueBuf += string(r) 275 | goto start 276 | 277 | case 'I': 278 | inputBuf += string(r) 279 | valueBuf += string(r) 280 | 281 | for _, i := range "nfinity" { 282 | r, _, err = l.reader.ReadRune() 283 | if err != nil { 284 | if err == io.EOF { 285 | err = l.invalidEOF() 286 | } 287 | 288 | return 289 | } 290 | 291 | if r != i { 292 | err = l.invalidChar(r) 293 | return 294 | } 295 | 296 | inputBuf += string(r) 297 | valueBuf += string(r) 298 | } 299 | 300 | l.newTokenV(typeNumber, inputBuf, math.Inf(sign)) 301 | return 302 | 303 | case 'N': 304 | inputBuf += string(r) 305 | valueBuf += string(r) 306 | 307 | for _, i := range "aN" { 308 | r, _, err = l.reader.ReadRune() 309 | if err != nil { 310 | if err == io.EOF { 311 | err = l.invalidEOF() 312 | } 313 | 314 | return 315 | } 316 | 317 | if r != i { 318 | err = l.invalidChar(r) 319 | return 320 | } 321 | 322 | inputBuf += string(r) 323 | valueBuf += string(r) 324 | } 325 | 326 | l.newTokenV(typeNumber, inputBuf, math.NaN()) 327 | return 328 | } 329 | 330 | err = l.invalidChar(r) 331 | return 332 | 333 | case stateZero: 334 | if err != io.EOF { 335 | switch r { 336 | case '.': 337 | state = stateDecimalPoint 338 | inputBuf += string(r) 339 | valueBuf += string(r) 340 | goto start 341 | 342 | case 'e', 'E': 343 | state = stateDecimalExponent 344 | inputBuf += string(r) 345 | valueBuf += string(r) 346 | goto start 347 | 348 | case 'x', 'X': 349 | state = stateHexadecimal 350 | inputBuf += string(r) 351 | valueBuf = "" 352 | goto start 353 | 354 | case '0', '1', '2', '3', '4', '5', '6', '7': 355 | err = l.invalidOctal() 356 | return 357 | 358 | case '8', '9': 359 | err = l.invalidZeroPrefix() 360 | return 361 | } 362 | } 363 | 364 | t, err = l.newTokenV(typeNumber, inputBuf, 0.0), nil 365 | return 366 | 367 | case stateDecimalInteger: 368 | if err != io.EOF { 369 | switch r { 370 | case '.': 371 | state = stateDecimalPoint 372 | inputBuf += string(r) 373 | valueBuf += string(r) 374 | goto start 375 | 376 | case 'e', 'E': 377 | state = stateDecimalExponent 378 | inputBuf += string(r) 379 | valueBuf += string(r) 380 | goto start 381 | } 382 | 383 | if isDigit(r) { 384 | inputBuf += string(r) 385 | valueBuf += string(r) 386 | goto start 387 | } 388 | } 389 | 390 | n, _ := strconv.ParseFloat(valueBuf, 64) 391 | t, err = l.newTokenV(typeNumber, inputBuf, n), nil 392 | return 393 | 394 | case stateDecimalPointLeading: 395 | if err == io.EOF { 396 | err = l.invalidEOF() 397 | return 398 | } 399 | 400 | if isDigit(r) { 401 | state = stateDecimalFraction 402 | inputBuf += string(r) 403 | valueBuf += string(r) 404 | goto start 405 | } 406 | 407 | err = l.invalidChar(r) 408 | return 409 | 410 | case stateDecimalPoint: 411 | if err != io.EOF { 412 | switch r { 413 | case 'e', 'E': 414 | state = stateDecimalExponent 415 | inputBuf += string(r) 416 | valueBuf += string(r) 417 | goto start 418 | } 419 | 420 | if isDigit(r) { 421 | state = stateDecimalFraction 422 | inputBuf += string(r) 423 | valueBuf += string(r) 424 | goto start 425 | } 426 | } 427 | 428 | n, _ := strconv.ParseFloat(valueBuf, 64) 429 | t, err = l.newTokenV(typeNumber, inputBuf, n), nil 430 | return 431 | 432 | case stateDecimalFraction: 433 | if err == io.EOF { 434 | err = l.invalidEOF() 435 | return 436 | } 437 | 438 | switch r { 439 | case '+', '-': 440 | state = stateDecimalExponentSign 441 | inputBuf += string(r) 442 | valueBuf += string(r) 443 | goto start 444 | } 445 | 446 | if isDigit(r) { 447 | state = stateDecimalExponentInteger 448 | inputBuf += string(r) 449 | valueBuf += string(r) 450 | goto start 451 | } 452 | 453 | err = l.invalidChar(r) 454 | return 455 | 456 | case stateDecimalExponentSign: 457 | if err == io.EOF { 458 | err = l.invalidEOF() 459 | return 460 | } 461 | 462 | if isDigit(r) { 463 | state = stateDecimalExponentInteger 464 | inputBuf += string(r) 465 | valueBuf += string(r) 466 | goto start 467 | } 468 | 469 | err = l.invalidChar(r) 470 | return 471 | 472 | case stateDecimalExponentInteger: 473 | if err != io.EOF && isDigit(r) { 474 | inputBuf += string(r) 475 | valueBuf += string(r) 476 | goto start 477 | } 478 | 479 | n, _ := strconv.ParseFloat(valueBuf, 64) 480 | t, err = l.newTokenV(typeNumber, inputBuf, n), nil 481 | return 482 | 483 | case stateHexadecimal: 484 | if err == io.EOF { 485 | err = l.invalidEOF() 486 | return 487 | } 488 | 489 | if isHexDigit(r) { 490 | state = stateHexadecimalInteger 491 | inputBuf += string(r) 492 | valueBuf += string(r) 493 | goto start 494 | } 495 | 496 | err = l.invalidChar(r) 497 | return 498 | 499 | case stateHexadecimalInteger: 500 | if err != io.EOF && isHexDigit(r) { 501 | state = stateHexadecimalInteger 502 | inputBuf += string(r) 503 | valueBuf += string(r) 504 | goto start 505 | } 506 | 507 | n, _ := strconv.ParseFloat(valueBuf, 64) 508 | t, err = l.newTokenV(typeNumber, inputBuf, n), nil 509 | return 510 | 511 | case stateString: 512 | if err == io.EOF { 513 | err = l.invalidEOF() 514 | return 515 | } 516 | 517 | switch r { 518 | case '\\': 519 | state = stateEscape 520 | inputBuf += string(r) 521 | goto start 522 | 523 | case '"', '\'': 524 | if doubleQuote && r == '"' { 525 | inputBuf += string(r) 526 | t = l.newTokenVPos(typeString, inputBuf, valueBuf, line, column) 527 | return 528 | } 529 | 530 | inputBuf += string(r) 531 | valueBuf += string(r) 532 | goto start 533 | 534 | case '\n', '\r': 535 | err = l.invalidChar(r) 536 | return 537 | } 538 | 539 | inputBuf += string(r) 540 | valueBuf += string(r) 541 | goto start 542 | 543 | case stateEscape: 544 | if err == io.EOF { 545 | err = l.invalidEOF() 546 | return 547 | } 548 | 549 | switch r { 550 | case 'b': 551 | state = stateString 552 | inputBuf += string(r) 553 | valueBuf += string('\b') 554 | goto start 555 | 556 | case 'f': 557 | state = stateString 558 | inputBuf += string(r) 559 | valueBuf += string('\f') 560 | goto start 561 | 562 | case 'n': 563 | state = stateString 564 | inputBuf += string(r) 565 | valueBuf += string('\n') 566 | goto start 567 | 568 | case 'r': 569 | state = stateString 570 | inputBuf += string(r) 571 | valueBuf += string('\r') 572 | goto start 573 | 574 | case 't': 575 | state = stateString 576 | inputBuf += string(r) 577 | valueBuf += string('\t') 578 | goto start 579 | 580 | case 'v': 581 | state = stateString 582 | inputBuf += string(r) 583 | valueBuf += string('\v') 584 | goto start 585 | 586 | case '0': 587 | var p rune 588 | p, _, err = l.reader.ReadRune() 589 | if err != nil { 590 | if err == io.EOF { 591 | err = l.invalidEOF() 592 | } 593 | 594 | return 595 | } 596 | 597 | if isDigit(p) { 598 | err = l.invalidOctal() 599 | return 600 | } 601 | 602 | if err = l.reader.UnreadRune(); err != nil { 603 | return 604 | } 605 | 606 | state = stateString 607 | inputBuf += string(r) 608 | valueBuf += string(rune(0)) 609 | goto start 610 | 611 | case 'x': 612 | inputBuf += string(r) 613 | var hexBuf string 614 | for i := 0; i < 2; i++ { 615 | r, _, err = l.reader.ReadRune() 616 | if err != nil { 617 | if err == io.EOF { 618 | err = l.invalidEOF() 619 | } 620 | 621 | return 622 | } 623 | 624 | if !isHexDigit(r) { 625 | err = l.invalidChar(r) 626 | return 627 | } 628 | 629 | inputBuf += string(r) 630 | hexBuf += string(r) 631 | } 632 | 633 | n, _ := strconv.ParseUint(hexBuf, 16, 8) 634 | valueBuf += string(rune(n)) 635 | state = stateString 636 | goto start 637 | 638 | case 'u': 639 | inputBuf += string(r) 640 | var hexBuf string 641 | for i := 0; i < 4; i++ { 642 | r, _, err = l.reader.ReadRune() 643 | if err != nil { 644 | if err == io.EOF { 645 | err = l.invalidEOF() 646 | } 647 | 648 | return 649 | } 650 | 651 | if !isHexDigit(r) { 652 | err = l.invalidChar(r) 653 | return 654 | } 655 | 656 | inputBuf += string(r) 657 | hexBuf += string(r) 658 | } 659 | 660 | n, _ := strconv.ParseUint(hexBuf, 16, 16) 661 | valueBuf += string(rune(n)) 662 | state = stateString 663 | goto start 664 | 665 | case '\n': 666 | case '\r': 667 | case '\u2028': 668 | case '\u2029': 669 | state = stateString 670 | inputBuf += string(r) 671 | if r == '\r' { 672 | var p rune 673 | p, _, err = l.reader.ReadRune() 674 | if err != nil { 675 | if err == io.EOF { 676 | err = l.invalidEOF() 677 | } 678 | 679 | return 680 | } 681 | 682 | if p == '\n' { 683 | inputBuf += string(r) 684 | } else if err = l.reader.UnreadRune(); err != nil { 685 | return 686 | } 687 | } 688 | 689 | goto start 690 | } 691 | 692 | state = stateString 693 | inputBuf += string(r) 694 | valueBuf += string(r) 695 | goto start 696 | } 697 | 698 | err = errors.New("json5: invalid state - data changed under foot?") 699 | return 700 | } 701 | 702 | func (l *lexer) newToken(tokenType int, input string) token { 703 | return token{tokenType, input, input, l.reader.line, l.reader.column} 704 | } 705 | 706 | func (l *lexer) newTokenV(tokenType int, input string, value interface{}) token { 707 | return token{tokenType, input, value, l.reader.line, l.reader.column} 708 | } 709 | 710 | func (l *lexer) newTokenVPos(tokenType int, input string, value interface{}, line, column int) token { 711 | return token{tokenType, input, value, l.reader.line, l.reader.column} 712 | } 713 | 714 | func (l *lexer) invalidChar(r rune) *SyntaxError { 715 | return &SyntaxError{fmt.Sprintf("json5: invalid character '%v'", r), l.reader.line, l.reader.column} 716 | } 717 | 718 | func (l *lexer) invalidCharPos(r rune, line, column int) *SyntaxError { 719 | return &SyntaxError{fmt.Sprintf("json5: invalid character '%v'", r), line, column} 720 | } 721 | 722 | func (l *lexer) invalidEOF() *SyntaxError { 723 | return &SyntaxError{"json5: invalid end of input", l.reader.line, l.reader.column} 724 | } 725 | 726 | func (l *lexer) invalidEscape(r rune) *SyntaxError { 727 | return &SyntaxError{fmt.Sprintf("json5: invalid escape '\\u%X' in object key", r), l.reader.line, l.reader.column} 728 | } 729 | 730 | func (l *lexer) invalidOctal() *SyntaxError { 731 | return &SyntaxError{"json5: octal numbers are not supported", l.reader.line, l.reader.column} 732 | } 733 | 734 | func (l *lexer) invalidOctalEscape() *SyntaxError { 735 | return &SyntaxError{"json5: octal escapes are not supported", l.reader.line, l.reader.column} 736 | } 737 | 738 | func (l *lexer) invalidZeroPrefix() *SyntaxError { 739 | return &SyntaxError{"json5: non-zero numbers must not start with zero", l.reader.line, l.reader.column} 740 | } 741 | 742 | func isUnicodeIDStartRune(r rune) bool { 743 | return unicode.In(r, unicode.L, unicode.Nl) 744 | } 745 | 746 | func isUnicodeIDRune(r rune) bool { 747 | return unicode.In(r, 748 | unicode.L, 749 | unicode.Nl, 750 | unicode.Mn, 751 | unicode.Mc, 752 | unicode.Nd, 753 | unicode.Pc) 754 | } 755 | 756 | func isDigit(r rune) bool { 757 | return r >= '0' && r <= '9' 758 | } 759 | 760 | func isHexDigit(r rune) bool { 761 | return r >= '0' && r <= '9' || 762 | r >= 'A' && r <= 'Z' || 763 | r >= 'a' && r <= 'z' 764 | } 765 | 766 | type reader struct { 767 | rd *bufio.Reader 768 | last rune 769 | line, column, lastColumn int 770 | } 771 | 772 | func newReader(rd io.Reader) *reader { 773 | return &reader{rd: bufio.NewReader(rd), line: 1, column: 1} 774 | } 775 | 776 | func (b *reader) ReadRune() (r rune, size int, err error) { 777 | r, size, err = b.rd.ReadRune() 778 | if err != nil { 779 | return 780 | } 781 | 782 | if r == '\n' { 783 | b.line++ 784 | b.lastColumn = b.column 785 | b.column = 1 786 | } else { 787 | b.column++ 788 | } 789 | 790 | b.last = r 791 | return 792 | } 793 | 794 | func (b *reader) UnreadRune() error { 795 | err := b.rd.UnreadRune() 796 | if err != nil { 797 | return err 798 | } 799 | 800 | if b.last == '\n' { 801 | b.line-- 802 | b.column = b.lastColumn 803 | } else { 804 | b.column-- 805 | } 806 | 807 | return nil 808 | } 809 | 810 | type token struct { 811 | tokenType int 812 | input string 813 | value interface{} 814 | line, column int 815 | } 816 | 817 | func (t *token) rune() rune { 818 | return t.value.(rune) 819 | } 820 | 821 | func (t *token) number() float64 { 822 | return t.value.(float64) 823 | } 824 | 825 | func (t *token) string() string { 826 | return t.value.(string) 827 | } 828 | 829 | const ( 830 | typeNone = iota 831 | typeIdentifier 832 | typeNumber 833 | typePunctuator 834 | typeString 835 | ) 836 | 837 | const ( 838 | stateDefault = iota 839 | stateComment 840 | stateMultiLineComment 841 | stateMultiLineCommentAsterisk 842 | stateSingleLineComment 843 | stateIdentifier 844 | stateIdentifierStartEscapeSlash 845 | stateIdentifierEscapeSlash 846 | stateSign 847 | stateZero 848 | stateDecimalInteger 849 | stateDecimalPointLeading 850 | stateDecimalPoint 851 | stateDecimalFraction 852 | stateDecimalExponent 853 | stateDecimalExponentSign 854 | stateDecimalExponentInteger 855 | stateHexadecimal 856 | stateHexadecimalInteger 857 | stateString 858 | stateEscape 859 | ) 860 | 861 | type SyntaxError struct { 862 | msg string 863 | Line, Column int 864 | } 865 | 866 | func (e *SyntaxError) Error() string { 867 | return fmt.Sprintf(e.msg+" at line %v, column %v", e.Line, e.Column) 868 | } 869 | -------------------------------------------------------------------------------- /parse.go: -------------------------------------------------------------------------------- 1 | package json5 2 | 3 | import ( 4 | "fmt" 5 | "io" 6 | "math" 7 | ) 8 | 9 | type parser struct { 10 | lexer *lexer 11 | state int 12 | root interface{} 13 | container interface{} 14 | stack []interface{} 15 | parsed bool 16 | } 17 | 18 | func newParser(rd io.Reader) *parser { 19 | return &parser{lexer: newLexer(rd)} 20 | } 21 | 22 | func (p *parser) parse() (v interface{}, err error) { 23 | p.state = stateValue 24 | var key string 25 | 26 | start: 27 | t, err := p.lexer.lex() 28 | 29 | state: 30 | switch p.state { 31 | case stateValue: 32 | switch t.tokenType { 33 | case typeString: 34 | p.add(t.string(), key) 35 | goto start 36 | 37 | case typeNumber: 38 | p.add(t.number(), key) 39 | goto start 40 | 41 | case typePunctuator: 42 | switch t.rune() { 43 | case '[': 44 | p.add(make([]interface{}, 0), key) 45 | goto start 46 | 47 | case '{': 48 | p.add(make(map[string]interface{}), key) 49 | goto start 50 | } 51 | 52 | err = invalidToken(t) 53 | return 54 | 55 | case typeIdentifier: 56 | switch t.input { 57 | case "true": 58 | p.add(true, key) 59 | goto start 60 | 61 | case "false": 62 | p.add(false, key) 63 | goto start 64 | 65 | case "null": 66 | p.add(nil, key) 67 | goto start 68 | 69 | case "Infinity": 70 | p.add(math.Inf(1), key) 71 | goto start 72 | 73 | case "NaN": 74 | p.add(math.NaN(), key) 75 | goto start 76 | } 77 | } 78 | 79 | case stateBeforeArrayElement: 80 | if t.tokenType == typePunctuator && t.rune() == ']' { 81 | p.pop() 82 | goto start 83 | } 84 | 85 | p.state = stateValue 86 | goto state 87 | 88 | case stateAfterArrayElement: 89 | if t.tokenType == typePunctuator { 90 | switch t.rune() { 91 | case ',': 92 | p.state = stateBeforeArrayElement 93 | goto start 94 | 95 | case ']': 96 | p.pop() 97 | goto start 98 | } 99 | } 100 | 101 | case stateBeforeObjectKey: 102 | switch t.tokenType { 103 | case typePunctuator: 104 | if t.rune() == '}' { 105 | p.pop() 106 | goto start 107 | } 108 | 109 | break 110 | 111 | case typeIdentifier, typeString, typeNumber: 112 | key = t.string() 113 | p.state = stateAfterObjectKey 114 | goto start 115 | } 116 | 117 | case stateAfterObjectKey: 118 | if t.tokenType != typePunctuator || t.rune() != ':' { 119 | break 120 | } 121 | 122 | p.state = stateValue 123 | goto start 124 | 125 | case stateAfterObjectValue: 126 | if t.tokenType == typePunctuator { 127 | switch t.rune() { 128 | case ',': 129 | p.state = stateBeforeObjectKey 130 | goto start 131 | 132 | case '}': 133 | p.pop() 134 | goto start 135 | } 136 | } 137 | 138 | case stateEnd: 139 | if err == io.EOF { 140 | v, err = p.root, nil 141 | return 142 | } 143 | } 144 | 145 | if err == io.EOF { 146 | err = p.lexer.invalidEOF() 147 | return 148 | } 149 | 150 | err = invalidToken(t) 151 | return 152 | } 153 | 154 | func (p *parser) add(v interface{}, key string) { 155 | if p.root == nil { 156 | p.root = v 157 | } 158 | 159 | switch c := p.container.(type) { 160 | case []interface{}: 161 | c = append(c, v) 162 | case map[string]interface{}: 163 | c[key] = v 164 | } 165 | 166 | switch v.(type) { 167 | case []interface{}, map[string]interface{}: 168 | p.push(v) 169 | default: 170 | p.resetState() 171 | } 172 | } 173 | 174 | func (p *parser) push(v interface{}) { 175 | p.stack = append(p.stack, v) 176 | p.container = v 177 | 178 | switch v.(type) { 179 | case []interface{}: 180 | p.state = stateBeforeArrayElement 181 | case map[string]interface{}: 182 | p.state = stateBeforeObjectKey 183 | } 184 | } 185 | 186 | func (p *parser) pop() { 187 | p.stack = p.stack[:len(p.stack)-1] 188 | p.container = p.stack[len(p.stack)-1] 189 | p.resetState() 190 | } 191 | 192 | func (p *parser) resetState() { 193 | switch p.container.(type) { 194 | case nil: 195 | p.state = stateEnd 196 | case []interface{}: 197 | p.state = stateAfterArrayElement 198 | case map[string]interface{}: 199 | p.state = stateAfterObjectValue 200 | } 201 | } 202 | 203 | func invalidToken(t token) error { 204 | return &SyntaxError{fmt.Sprintf("json5: invalid input '%v'", t.input), t.line, t.column} 205 | } 206 | 207 | const ( 208 | stateBeforeArrayElement = iota 209 | stateAfterArrayElement 210 | stateBeforeObjectKey 211 | stateAfterObjectKey 212 | stateAfterObjectValue 213 | stateValue 214 | stateEnd 215 | ) 216 | --------------------------------------------------------------------------------