source: imaps-frontend/node_modules/json5/lib/parse.js

main
Last change on this file was d565449, checked in by stefan toskovski <stefantoska84@…>, 4 weeks ago

Update repo after prototype presentation

  • Property mode set to 100644
File size: 21.9 KB
RevLine 
[d565449]1const util = require('./util')
2
3let source
4let parseState
5let stack
6let pos
7let line
8let column
9let token
10let key
11let root
12
13module.exports = function parse (text, reviver) {
14 source = String(text)
15 parseState = 'start'
16 stack = []
17 pos = 0
18 line = 1
19 column = 0
20 token = undefined
21 key = undefined
22 root = undefined
23
24 do {
25 token = lex()
26
27 // This code is unreachable.
28 // if (!parseStates[parseState]) {
29 // throw invalidParseState()
30 // }
31
32 parseStates[parseState]()
33 } while (token.type !== 'eof')
34
35 if (typeof reviver === 'function') {
36 return internalize({'': root}, '', reviver)
37 }
38
39 return root
40}
41
42function internalize (holder, name, reviver) {
43 const value = holder[name]
44 if (value != null && typeof value === 'object') {
45 if (Array.isArray(value)) {
46 for (let i = 0; i < value.length; i++) {
47 const key = String(i)
48 const replacement = internalize(value, key, reviver)
49 if (replacement === undefined) {
50 delete value[key]
51 } else {
52 Object.defineProperty(value, key, {
53 value: replacement,
54 writable: true,
55 enumerable: true,
56 configurable: true,
57 })
58 }
59 }
60 } else {
61 for (const key in value) {
62 const replacement = internalize(value, key, reviver)
63 if (replacement === undefined) {
64 delete value[key]
65 } else {
66 Object.defineProperty(value, key, {
67 value: replacement,
68 writable: true,
69 enumerable: true,
70 configurable: true,
71 })
72 }
73 }
74 }
75 }
76
77 return reviver.call(holder, name, value)
78}
79
80let lexState
81let buffer
82let doubleQuote
83let sign
84let c
85
86function lex () {
87 lexState = 'default'
88 buffer = ''
89 doubleQuote = false
90 sign = 1
91
92 for (;;) {
93 c = peek()
94
95 // This code is unreachable.
96 // if (!lexStates[lexState]) {
97 // throw invalidLexState(lexState)
98 // }
99
100 const token = lexStates[lexState]()
101 if (token) {
102 return token
103 }
104 }
105}
106
107function peek () {
108 if (source[pos]) {
109 return String.fromCodePoint(source.codePointAt(pos))
110 }
111}
112
113function read () {
114 const c = peek()
115
116 if (c === '\n') {
117 line++
118 column = 0
119 } else if (c) {
120 column += c.length
121 } else {
122 column++
123 }
124
125 if (c) {
126 pos += c.length
127 }
128
129 return c
130}
131
132const lexStates = {
133 default () {
134 switch (c) {
135 case '\t':
136 case '\v':
137 case '\f':
138 case ' ':
139 case '\u00A0':
140 case '\uFEFF':
141 case '\n':
142 case '\r':
143 case '\u2028':
144 case '\u2029':
145 read()
146 return
147
148 case '/':
149 read()
150 lexState = 'comment'
151 return
152
153 case undefined:
154 read()
155 return newToken('eof')
156 }
157
158 if (util.isSpaceSeparator(c)) {
159 read()
160 return
161 }
162
163 // This code is unreachable.
164 // if (!lexStates[parseState]) {
165 // throw invalidLexState(parseState)
166 // }
167
168 return lexStates[parseState]()
169 },
170
171 comment () {
172 switch (c) {
173 case '*':
174 read()
175 lexState = 'multiLineComment'
176 return
177
178 case '/':
179 read()
180 lexState = 'singleLineComment'
181 return
182 }
183
184 throw invalidChar(read())
185 },
186
187 multiLineComment () {
188 switch (c) {
189 case '*':
190 read()
191 lexState = 'multiLineCommentAsterisk'
192 return
193
194 case undefined:
195 throw invalidChar(read())
196 }
197
198 read()
199 },
200
201 multiLineCommentAsterisk () {
202 switch (c) {
203 case '*':
204 read()
205 return
206
207 case '/':
208 read()
209 lexState = 'default'
210 return
211
212 case undefined:
213 throw invalidChar(read())
214 }
215
216 read()
217 lexState = 'multiLineComment'
218 },
219
220 singleLineComment () {
221 switch (c) {
222 case '\n':
223 case '\r':
224 case '\u2028':
225 case '\u2029':
226 read()
227 lexState = 'default'
228 return
229
230 case undefined:
231 read()
232 return newToken('eof')
233 }
234
235 read()
236 },
237
238 value () {
239 switch (c) {
240 case '{':
241 case '[':
242 return newToken('punctuator', read())
243
244 case 'n':
245 read()
246 literal('ull')
247 return newToken('null', null)
248
249 case 't':
250 read()
251 literal('rue')
252 return newToken('boolean', true)
253
254 case 'f':
255 read()
256 literal('alse')
257 return newToken('boolean', false)
258
259 case '-':
260 case '+':
261 if (read() === '-') {
262 sign = -1
263 }
264
265 lexState = 'sign'
266 return
267
268 case '.':
269 buffer = read()
270 lexState = 'decimalPointLeading'
271 return
272
273 case '0':
274 buffer = read()
275 lexState = 'zero'
276 return
277
278 case '1':
279 case '2':
280 case '3':
281 case '4':
282 case '5':
283 case '6':
284 case '7':
285 case '8':
286 case '9':
287 buffer = read()
288 lexState = 'decimalInteger'
289 return
290
291 case 'I':
292 read()
293 literal('nfinity')
294 return newToken('numeric', Infinity)
295
296 case 'N':
297 read()
298 literal('aN')
299 return newToken('numeric', NaN)
300
301 case '"':
302 case "'":
303 doubleQuote = (read() === '"')
304 buffer = ''
305 lexState = 'string'
306 return
307 }
308
309 throw invalidChar(read())
310 },
311
312 identifierNameStartEscape () {
313 if (c !== 'u') {
314 throw invalidChar(read())
315 }
316
317 read()
318 const u = unicodeEscape()
319 switch (u) {
320 case '$':
321 case '_':
322 break
323
324 default:
325 if (!util.isIdStartChar(u)) {
326 throw invalidIdentifier()
327 }
328
329 break
330 }
331
332 buffer += u
333 lexState = 'identifierName'
334 },
335
336 identifierName () {
337 switch (c) {
338 case '$':
339 case '_':
340 case '\u200C':
341 case '\u200D':
342 buffer += read()
343 return
344
345 case '\\':
346 read()
347 lexState = 'identifierNameEscape'
348 return
349 }
350
351 if (util.isIdContinueChar(c)) {
352 buffer += read()
353 return
354 }
355
356 return newToken('identifier', buffer)
357 },
358
359 identifierNameEscape () {
360 if (c !== 'u') {
361 throw invalidChar(read())
362 }
363
364 read()
365 const u = unicodeEscape()
366 switch (u) {
367 case '$':
368 case '_':
369 case '\u200C':
370 case '\u200D':
371 break
372
373 default:
374 if (!util.isIdContinueChar(u)) {
375 throw invalidIdentifier()
376 }
377
378 break
379 }
380
381 buffer += u
382 lexState = 'identifierName'
383 },
384
385 sign () {
386 switch (c) {
387 case '.':
388 buffer = read()
389 lexState = 'decimalPointLeading'
390 return
391
392 case '0':
393 buffer = read()
394 lexState = 'zero'
395 return
396
397 case '1':
398 case '2':
399 case '3':
400 case '4':
401 case '5':
402 case '6':
403 case '7':
404 case '8':
405 case '9':
406 buffer = read()
407 lexState = 'decimalInteger'
408 return
409
410 case 'I':
411 read()
412 literal('nfinity')
413 return newToken('numeric', sign * Infinity)
414
415 case 'N':
416 read()
417 literal('aN')
418 return newToken('numeric', NaN)
419 }
420
421 throw invalidChar(read())
422 },
423
424 zero () {
425 switch (c) {
426 case '.':
427 buffer += read()
428 lexState = 'decimalPoint'
429 return
430
431 case 'e':
432 case 'E':
433 buffer += read()
434 lexState = 'decimalExponent'
435 return
436
437 case 'x':
438 case 'X':
439 buffer += read()
440 lexState = 'hexadecimal'
441 return
442 }
443
444 return newToken('numeric', sign * 0)
445 },
446
447 decimalInteger () {
448 switch (c) {
449 case '.':
450 buffer += read()
451 lexState = 'decimalPoint'
452 return
453
454 case 'e':
455 case 'E':
456 buffer += read()
457 lexState = 'decimalExponent'
458 return
459 }
460
461 if (util.isDigit(c)) {
462 buffer += read()
463 return
464 }
465
466 return newToken('numeric', sign * Number(buffer))
467 },
468
469 decimalPointLeading () {
470 if (util.isDigit(c)) {
471 buffer += read()
472 lexState = 'decimalFraction'
473 return
474 }
475
476 throw invalidChar(read())
477 },
478
479 decimalPoint () {
480 switch (c) {
481 case 'e':
482 case 'E':
483 buffer += read()
484 lexState = 'decimalExponent'
485 return
486 }
487
488 if (util.isDigit(c)) {
489 buffer += read()
490 lexState = 'decimalFraction'
491 return
492 }
493
494 return newToken('numeric', sign * Number(buffer))
495 },
496
497 decimalFraction () {
498 switch (c) {
499 case 'e':
500 case 'E':
501 buffer += read()
502 lexState = 'decimalExponent'
503 return
504 }
505
506 if (util.isDigit(c)) {
507 buffer += read()
508 return
509 }
510
511 return newToken('numeric', sign * Number(buffer))
512 },
513
514 decimalExponent () {
515 switch (c) {
516 case '+':
517 case '-':
518 buffer += read()
519 lexState = 'decimalExponentSign'
520 return
521 }
522
523 if (util.isDigit(c)) {
524 buffer += read()
525 lexState = 'decimalExponentInteger'
526 return
527 }
528
529 throw invalidChar(read())
530 },
531
532 decimalExponentSign () {
533 if (util.isDigit(c)) {
534 buffer += read()
535 lexState = 'decimalExponentInteger'
536 return
537 }
538
539 throw invalidChar(read())
540 },
541
542 decimalExponentInteger () {
543 if (util.isDigit(c)) {
544 buffer += read()
545 return
546 }
547
548 return newToken('numeric', sign * Number(buffer))
549 },
550
551 hexadecimal () {
552 if (util.isHexDigit(c)) {
553 buffer += read()
554 lexState = 'hexadecimalInteger'
555 return
556 }
557
558 throw invalidChar(read())
559 },
560
561 hexadecimalInteger () {
562 if (util.isHexDigit(c)) {
563 buffer += read()
564 return
565 }
566
567 return newToken('numeric', sign * Number(buffer))
568 },
569
570 string () {
571 switch (c) {
572 case '\\':
573 read()
574 buffer += escape()
575 return
576
577 case '"':
578 if (doubleQuote) {
579 read()
580 return newToken('string', buffer)
581 }
582
583 buffer += read()
584 return
585
586 case "'":
587 if (!doubleQuote) {
588 read()
589 return newToken('string', buffer)
590 }
591
592 buffer += read()
593 return
594
595 case '\n':
596 case '\r':
597 throw invalidChar(read())
598
599 case '\u2028':
600 case '\u2029':
601 separatorChar(c)
602 break
603
604 case undefined:
605 throw invalidChar(read())
606 }
607
608 buffer += read()
609 },
610
611 start () {
612 switch (c) {
613 case '{':
614 case '[':
615 return newToken('punctuator', read())
616
617 // This code is unreachable since the default lexState handles eof.
618 // case undefined:
619 // return newToken('eof')
620 }
621
622 lexState = 'value'
623 },
624
625 beforePropertyName () {
626 switch (c) {
627 case '$':
628 case '_':
629 buffer = read()
630 lexState = 'identifierName'
631 return
632
633 case '\\':
634 read()
635 lexState = 'identifierNameStartEscape'
636 return
637
638 case '}':
639 return newToken('punctuator', read())
640
641 case '"':
642 case "'":
643 doubleQuote = (read() === '"')
644 lexState = 'string'
645 return
646 }
647
648 if (util.isIdStartChar(c)) {
649 buffer += read()
650 lexState = 'identifierName'
651 return
652 }
653
654 throw invalidChar(read())
655 },
656
657 afterPropertyName () {
658 if (c === ':') {
659 return newToken('punctuator', read())
660 }
661
662 throw invalidChar(read())
663 },
664
665 beforePropertyValue () {
666 lexState = 'value'
667 },
668
669 afterPropertyValue () {
670 switch (c) {
671 case ',':
672 case '}':
673 return newToken('punctuator', read())
674 }
675
676 throw invalidChar(read())
677 },
678
679 beforeArrayValue () {
680 if (c === ']') {
681 return newToken('punctuator', read())
682 }
683
684 lexState = 'value'
685 },
686
687 afterArrayValue () {
688 switch (c) {
689 case ',':
690 case ']':
691 return newToken('punctuator', read())
692 }
693
694 throw invalidChar(read())
695 },
696
697 end () {
698 // This code is unreachable since it's handled by the default lexState.
699 // if (c === undefined) {
700 // read()
701 // return newToken('eof')
702 // }
703
704 throw invalidChar(read())
705 },
706}
707
708function newToken (type, value) {
709 return {
710 type,
711 value,
712 line,
713 column,
714 }
715}
716
717function literal (s) {
718 for (const c of s) {
719 const p = peek()
720
721 if (p !== c) {
722 throw invalidChar(read())
723 }
724
725 read()
726 }
727}
728
729function escape () {
730 const c = peek()
731 switch (c) {
732 case 'b':
733 read()
734 return '\b'
735
736 case 'f':
737 read()
738 return '\f'
739
740 case 'n':
741 read()
742 return '\n'
743
744 case 'r':
745 read()
746 return '\r'
747
748 case 't':
749 read()
750 return '\t'
751
752 case 'v':
753 read()
754 return '\v'
755
756 case '0':
757 read()
758 if (util.isDigit(peek())) {
759 throw invalidChar(read())
760 }
761
762 return '\0'
763
764 case 'x':
765 read()
766 return hexEscape()
767
768 case 'u':
769 read()
770 return unicodeEscape()
771
772 case '\n':
773 case '\u2028':
774 case '\u2029':
775 read()
776 return ''
777
778 case '\r':
779 read()
780 if (peek() === '\n') {
781 read()
782 }
783
784 return ''
785
786 case '1':
787 case '2':
788 case '3':
789 case '4':
790 case '5':
791 case '6':
792 case '7':
793 case '8':
794 case '9':
795 throw invalidChar(read())
796
797 case undefined:
798 throw invalidChar(read())
799 }
800
801 return read()
802}
803
804function hexEscape () {
805 let buffer = ''
806 let c = peek()
807
808 if (!util.isHexDigit(c)) {
809 throw invalidChar(read())
810 }
811
812 buffer += read()
813
814 c = peek()
815 if (!util.isHexDigit(c)) {
816 throw invalidChar(read())
817 }
818
819 buffer += read()
820
821 return String.fromCodePoint(parseInt(buffer, 16))
822}
823
824function unicodeEscape () {
825 let buffer = ''
826 let count = 4
827
828 while (count-- > 0) {
829 const c = peek()
830 if (!util.isHexDigit(c)) {
831 throw invalidChar(read())
832 }
833
834 buffer += read()
835 }
836
837 return String.fromCodePoint(parseInt(buffer, 16))
838}
839
840const parseStates = {
841 start () {
842 if (token.type === 'eof') {
843 throw invalidEOF()
844 }
845
846 push()
847 },
848
849 beforePropertyName () {
850 switch (token.type) {
851 case 'identifier':
852 case 'string':
853 key = token.value
854 parseState = 'afterPropertyName'
855 return
856
857 case 'punctuator':
858 // This code is unreachable since it's handled by the lexState.
859 // if (token.value !== '}') {
860 // throw invalidToken()
861 // }
862
863 pop()
864 return
865
866 case 'eof':
867 throw invalidEOF()
868 }
869
870 // This code is unreachable since it's handled by the lexState.
871 // throw invalidToken()
872 },
873
874 afterPropertyName () {
875 // This code is unreachable since it's handled by the lexState.
876 // if (token.type !== 'punctuator' || token.value !== ':') {
877 // throw invalidToken()
878 // }
879
880 if (token.type === 'eof') {
881 throw invalidEOF()
882 }
883
884 parseState = 'beforePropertyValue'
885 },
886
887 beforePropertyValue () {
888 if (token.type === 'eof') {
889 throw invalidEOF()
890 }
891
892 push()
893 },
894
895 beforeArrayValue () {
896 if (token.type === 'eof') {
897 throw invalidEOF()
898 }
899
900 if (token.type === 'punctuator' && token.value === ']') {
901 pop()
902 return
903 }
904
905 push()
906 },
907
908 afterPropertyValue () {
909 // This code is unreachable since it's handled by the lexState.
910 // if (token.type !== 'punctuator') {
911 // throw invalidToken()
912 // }
913
914 if (token.type === 'eof') {
915 throw invalidEOF()
916 }
917
918 switch (token.value) {
919 case ',':
920 parseState = 'beforePropertyName'
921 return
922
923 case '}':
924 pop()
925 }
926
927 // This code is unreachable since it's handled by the lexState.
928 // throw invalidToken()
929 },
930
931 afterArrayValue () {
932 // This code is unreachable since it's handled by the lexState.
933 // if (token.type !== 'punctuator') {
934 // throw invalidToken()
935 // }
936
937 if (token.type === 'eof') {
938 throw invalidEOF()
939 }
940
941 switch (token.value) {
942 case ',':
943 parseState = 'beforeArrayValue'
944 return
945
946 case ']':
947 pop()
948 }
949
950 // This code is unreachable since it's handled by the lexState.
951 // throw invalidToken()
952 },
953
954 end () {
955 // This code is unreachable since it's handled by the lexState.
956 // if (token.type !== 'eof') {
957 // throw invalidToken()
958 // }
959 },
960}
961
962function push () {
963 let value
964
965 switch (token.type) {
966 case 'punctuator':
967 switch (token.value) {
968 case '{':
969 value = {}
970 break
971
972 case '[':
973 value = []
974 break
975 }
976
977 break
978
979 case 'null':
980 case 'boolean':
981 case 'numeric':
982 case 'string':
983 value = token.value
984 break
985
986 // This code is unreachable.
987 // default:
988 // throw invalidToken()
989 }
990
991 if (root === undefined) {
992 root = value
993 } else {
994 const parent = stack[stack.length - 1]
995 if (Array.isArray(parent)) {
996 parent.push(value)
997 } else {
998 Object.defineProperty(parent, key, {
999 value,
1000 writable: true,
1001 enumerable: true,
1002 configurable: true,
1003 })
1004 }
1005 }
1006
1007 if (value !== null && typeof value === 'object') {
1008 stack.push(value)
1009
1010 if (Array.isArray(value)) {
1011 parseState = 'beforeArrayValue'
1012 } else {
1013 parseState = 'beforePropertyName'
1014 }
1015 } else {
1016 const current = stack[stack.length - 1]
1017 if (current == null) {
1018 parseState = 'end'
1019 } else if (Array.isArray(current)) {
1020 parseState = 'afterArrayValue'
1021 } else {
1022 parseState = 'afterPropertyValue'
1023 }
1024 }
1025}
1026
1027function pop () {
1028 stack.pop()
1029
1030 const current = stack[stack.length - 1]
1031 if (current == null) {
1032 parseState = 'end'
1033 } else if (Array.isArray(current)) {
1034 parseState = 'afterArrayValue'
1035 } else {
1036 parseState = 'afterPropertyValue'
1037 }
1038}
1039
1040// This code is unreachable.
1041// function invalidParseState () {
1042// return new Error(`JSON5: invalid parse state '${parseState}'`)
1043// }
1044
1045// This code is unreachable.
1046// function invalidLexState (state) {
1047// return new Error(`JSON5: invalid lex state '${state}'`)
1048// }
1049
1050function invalidChar (c) {
1051 if (c === undefined) {
1052 return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
1053 }
1054
1055 return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
1056}
1057
1058function invalidEOF () {
1059 return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
1060}
1061
1062// This code is unreachable.
1063// function invalidToken () {
1064// if (token.type === 'eof') {
1065// return syntaxError(`JSON5: invalid end of input at ${line}:${column}`)
1066// }
1067
1068// const c = String.fromCodePoint(token.value.codePointAt(0))
1069// return syntaxError(`JSON5: invalid character '${formatChar(c)}' at ${line}:${column}`)
1070// }
1071
1072function invalidIdentifier () {
1073 column -= 5
1074 return syntaxError(`JSON5: invalid identifier character at ${line}:${column}`)
1075}
1076
1077function separatorChar (c) {
1078 console.warn(`JSON5: '${formatChar(c)}' in strings is not valid ECMAScript; consider escaping`)
1079}
1080
1081function formatChar (c) {
1082 const replacements = {
1083 "'": "\\'",
1084 '"': '\\"',
1085 '\\': '\\\\',
1086 '\b': '\\b',
1087 '\f': '\\f',
1088 '\n': '\\n',
1089 '\r': '\\r',
1090 '\t': '\\t',
1091 '\v': '\\v',
1092 '\0': '\\0',
1093 '\u2028': '\\u2028',
1094 '\u2029': '\\u2029',
1095 }
1096
1097 if (replacements[c]) {
1098 return replacements[c]
1099 }
1100
1101 if (c < ' ') {
1102 const hexString = c.charCodeAt(0).toString(16)
1103 return '\\x' + ('00' + hexString).substring(hexString.length)
1104 }
1105
1106 return c
1107}
1108
1109function syntaxError (message) {
1110 const err = new SyntaxError(message)
1111 err.lineNumber = line
1112 err.columnNumber = column
1113 return err
1114}
Note: See TracBrowser for help on using the repository browser.