functionalscript 0.0.521 → 0.0.523
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fjson/tokenizer/module.f.cjs +65 -10
- package/fjson/tokenizer/test.f.cjs +33 -5
- package/fsc/README.md +1 -0
- package/json/tokenizer/module.f.cjs +25 -485
- package/json/tokenizer/test.f.cjs +5 -5
- package/package.json +1 -1
|
@@ -6,7 +6,6 @@ const _range = require('../../types/range/module.f.cjs')
|
|
|
6
6
|
const { one } = _range
|
|
7
7
|
const { empty, stateScan, flat, toArray, reduce: listReduce, scan } = list
|
|
8
8
|
const bigfloat = require('../../types/bigfloat/module.f.cjs')
|
|
9
|
-
const jsonTokenizer = require('../../json/tokenizer/module.f.cjs')
|
|
10
9
|
const { fromCharCode } = String
|
|
11
10
|
const {
|
|
12
11
|
range,
|
|
@@ -53,6 +52,32 @@ const {
|
|
|
53
52
|
dollarSign
|
|
54
53
|
} = require('../../text/ascii/module.f.cjs')
|
|
55
54
|
|
|
55
|
+
/**
|
|
56
|
+
* @typedef {{
|
|
57
|
+
* readonly kind: 'string'
|
|
58
|
+
* readonly value: string
|
|
59
|
+
* }} StringToken
|
|
60
|
+
* */
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @typedef {{
|
|
64
|
+
* readonly kind: 'number'
|
|
65
|
+
* readonly value: string
|
|
66
|
+
* readonly bf: bigfloat.BigFloat
|
|
67
|
+
* }} NumberToken
|
|
68
|
+
* */
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @typedef {{
|
|
72
|
+
* readonly kind: 'bigint'
|
|
73
|
+
* readonly value: bigint
|
|
74
|
+
* }} BigIntToken
|
|
75
|
+
* */
|
|
76
|
+
|
|
77
|
+
/** @typedef {{readonly kind: 'error', message: ErrorMessage}} ErrorToken */
|
|
78
|
+
|
|
79
|
+
/** @typedef {{readonly kind: '{' | '}' | ':' | ',' | '[' | ']' | 'true' | 'false' | 'null'}} SimpleToken */
|
|
80
|
+
|
|
56
81
|
/**
|
|
57
82
|
* @typedef {{
|
|
58
83
|
* readonly kind: 'id'
|
|
@@ -62,8 +87,12 @@ const {
|
|
|
62
87
|
|
|
63
88
|
/**
|
|
64
89
|
* @typedef {|
|
|
65
|
-
*
|
|
66
|
-
*
|
|
90
|
+
* SimpleToken |
|
|
91
|
+
* StringToken |
|
|
92
|
+
* NumberToken |
|
|
93
|
+
* ErrorToken |
|
|
94
|
+
* IdToken |
|
|
95
|
+
* BigIntToken
|
|
67
96
|
* } FjsonToken
|
|
68
97
|
*/
|
|
69
98
|
|
|
@@ -117,12 +146,12 @@ const rangeId = [digitRange, ...rangeIdStart]
|
|
|
117
146
|
|
|
118
147
|
/**
|
|
119
148
|
* @typedef {|
|
|
120
|
-
|
|
121
|
-
* '" are missing' |
|
|
149
|
+
* '" are missing' |
|
|
122
150
|
* 'unescaped character' |
|
|
123
151
|
* 'invalid hex value' |
|
|
124
152
|
* 'unexpected character' |
|
|
125
153
|
* 'invalid number' |
|
|
154
|
+
* 'invalid token' |
|
|
126
155
|
* 'eof'
|
|
127
156
|
* } ErrorMessage
|
|
128
157
|
*/
|
|
@@ -147,7 +176,7 @@ const rangeId = [digitRange, ...rangeIdStart]
|
|
|
147
176
|
/**
|
|
148
177
|
* @typedef {{
|
|
149
178
|
* readonly kind: 'number',
|
|
150
|
-
* readonly numberKind: '0' | '-' | 'int' | '.' | 'fractional' | 'e' | 'e+' | 'e-' | 'expDigits'
|
|
179
|
+
* readonly numberKind: '0' | '-' | 'int' | '.' | 'fractional' | 'e' | 'e+' | 'e-' | 'expDigits' | 'bigint'
|
|
151
180
|
* readonly value: string
|
|
152
181
|
* readonly b: ParseNumberBuffer
|
|
153
182
|
* }} ParseNumberState
|
|
@@ -252,8 +281,13 @@ const addFracDigit = digit => b => ({ ... b, m: b.m * 10n + digitToBigInt(digit)
|
|
|
252
281
|
/** @type {(digit: number) => (b: ParseNumberBuffer) => ParseNumberBuffer} */
|
|
253
282
|
const addExpDigit = digit => b => ({ ... b, e: b.e * 10 + digit - digit0})
|
|
254
283
|
|
|
255
|
-
/** @type {(s: ParseNumberState) =>
|
|
256
|
-
const bufferToNumberToken = ({value, b}) =>
|
|
284
|
+
/** @type {(s: ParseNumberState) => FjsonToken} */
|
|
285
|
+
const bufferToNumberToken = ({numberKind, value, b}) =>
|
|
286
|
+
{
|
|
287
|
+
if (numberKind === 'bigint')
|
|
288
|
+
return { kind: 'bigint', value: b.s * b.m }
|
|
289
|
+
return { kind: 'number', value: value, bf: [b.s * b.m, b.f + b.es * b.e] }
|
|
290
|
+
}
|
|
257
291
|
|
|
258
292
|
/** @type {(state: InitialState) => (input: number) => readonly[list.List<FjsonToken>, TokenizerState]} */
|
|
259
293
|
const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpected character' }], state])([
|
|
@@ -272,7 +306,11 @@ const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpe
|
|
|
272
306
|
])
|
|
273
307
|
|
|
274
308
|
/** @type {() => (input: number) => readonly[list.List<FjsonToken>, TokenizerState]} */
|
|
275
|
-
const invalidNumberToToken = () => input =>
|
|
309
|
+
const invalidNumberToToken = () => input =>
|
|
310
|
+
{
|
|
311
|
+
const next = tokenizeOp({ kind: 'initial' })(input)
|
|
312
|
+
return [{ first: { kind: 'error', message: 'invalid number' }, tail: next[0] }, next[1]]
|
|
313
|
+
}
|
|
276
314
|
|
|
277
315
|
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<FjsonToken>, TokenizerState]} */
|
|
278
316
|
const fullStopToToken = state => input => {
|
|
@@ -358,6 +396,22 @@ const terminalToToken = state => input => {
|
|
|
358
396
|
}
|
|
359
397
|
}
|
|
360
398
|
|
|
399
|
+
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<FjsonToken>, TokenizerState]} */
|
|
400
|
+
const bigintToToken = state => input => {
|
|
401
|
+
switch (state.numberKind) {
|
|
402
|
+
case '0':
|
|
403
|
+
case 'int':
|
|
404
|
+
{
|
|
405
|
+
return [empty, { kind: 'number', value: state.value, b: state.b, numberKind: 'bigint' }]
|
|
406
|
+
}
|
|
407
|
+
default:
|
|
408
|
+
{
|
|
409
|
+
const next = tokenizeOp({ kind: 'initial' })(input)
|
|
410
|
+
return [{ first: { kind: 'error', message: 'invalid number' }, tail: next[0] }, next[1]]
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
361
415
|
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<FjsonToken>, TokenizerState]} */
|
|
362
416
|
const parseNumberStateOp = create(invalidNumberToToken)([
|
|
363
417
|
rangeFunc(one(fullStop))(fullStopToToken),
|
|
@@ -366,7 +420,8 @@ const parseNumberStateOp = create(invalidNumberToToken)([
|
|
|
366
420
|
rangeSetFunc([one(latinSmallLetterE), one(latinCapitalLetterE)])(expToToken),
|
|
367
421
|
rangeFunc(one(hyphenMinus))(hyphenMinusToToken),
|
|
368
422
|
rangeFunc(one(plusSign))(plusSignToToken),
|
|
369
|
-
rangeSetFunc(rangeSetTerminalForNumber)(terminalToToken)
|
|
423
|
+
rangeSetFunc(rangeSetTerminalForNumber)(terminalToToken),
|
|
424
|
+
rangeFunc(one(latinSmallLetterN))(bigintToToken),
|
|
370
425
|
])
|
|
371
426
|
|
|
372
427
|
/** @type {(state: InvalidNumberState) => (input: number) => readonly[list.List<FjsonToken>, TokenizerState]} */
|
|
@@ -145,7 +145,7 @@ module.exports = {
|
|
|
145
145
|
},
|
|
146
146
|
() => {
|
|
147
147
|
const result = stringify(tokenizeString('0abc,'))
|
|
148
|
-
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":","}]') { throw result }
|
|
148
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"abc"},{"kind":","}]') { throw result }
|
|
149
149
|
},
|
|
150
150
|
() => {
|
|
151
151
|
const result = stringify(tokenizeString('123456789012345678901234567890'))
|
|
@@ -169,7 +169,7 @@ module.exports = {
|
|
|
169
169
|
},
|
|
170
170
|
() => {
|
|
171
171
|
const result = stringify(tokenizeString('9a:'))
|
|
172
|
-
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":":"}]') { throw result }
|
|
172
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"a"},{"kind":":"}]') { throw result }
|
|
173
173
|
},
|
|
174
174
|
() => {
|
|
175
175
|
const result = stringify(tokenizeString('-10'))
|
|
@@ -269,11 +269,39 @@ module.exports = {
|
|
|
269
269
|
},
|
|
270
270
|
() => {
|
|
271
271
|
const result = stringify(tokenizeString('123_123'))
|
|
272
|
-
if (result !== '[{"kind":"error","message":"invalid number"}]') { throw result }
|
|
272
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"_123"}]') { throw result }
|
|
273
273
|
},
|
|
274
|
-
|
|
274
|
+
() => {
|
|
275
275
|
const result = stringify(tokenizeString('123$123'))
|
|
276
|
-
if (result !== '[{"kind":"error","message":"invalid number"}]') { throw result }
|
|
276
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"$123"}]') { throw result }
|
|
277
|
+
},
|
|
278
|
+
() => {
|
|
279
|
+
const result = stringify(tokenizeString('1234567890n'))
|
|
280
|
+
if (result !== '[{"kind":"bigint","value":1234567890n}]') { throw result }
|
|
281
|
+
},
|
|
282
|
+
() => {
|
|
283
|
+
const result = stringify(tokenizeString('0n'))
|
|
284
|
+
if (result !== '[{"kind":"bigint","value":0n}]') { throw result }
|
|
285
|
+
},
|
|
286
|
+
() => {
|
|
287
|
+
const result = stringify(tokenizeString('[-1234567890n]'))
|
|
288
|
+
if (result !== '[{"kind":"["},{"kind":"bigint","value":-1234567890n},{"kind":"]"}]') { throw result }
|
|
289
|
+
},
|
|
290
|
+
() => {
|
|
291
|
+
const result = stringify(tokenizeString('123.456n'))
|
|
292
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"n"}]') { throw result }
|
|
293
|
+
},
|
|
294
|
+
() => {
|
|
295
|
+
const result = stringify(tokenizeString('123e456n'))
|
|
296
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"n"}]') { throw result }
|
|
297
|
+
},
|
|
298
|
+
() => {
|
|
299
|
+
const result = stringify(tokenizeString('1234567890na'))
|
|
300
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"a"}]') { throw result }
|
|
301
|
+
},
|
|
302
|
+
() => {
|
|
303
|
+
const result = stringify(tokenizeString('1234567890nn'))
|
|
304
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"id","value":"n"}]') { throw result }
|
|
277
305
|
},
|
|
278
306
|
]
|
|
279
307
|
}
|
package/fsc/README.md
CHANGED
|
@@ -1,498 +1,38 @@
|
|
|
1
|
-
const operator = require('../../types/function/operator/module.f.cjs')
|
|
2
|
-
const range_map = require('../../types/range_map/module.f.cjs')
|
|
3
|
-
const { merge, fromRange, get } = range_map
|
|
4
1
|
const list = require('../../types/list/module.f.cjs')
|
|
5
|
-
const
|
|
6
|
-
const { one } = _range
|
|
7
|
-
const { empty, stateScan, flat, toArray, reduce: listReduce, scan } = list
|
|
8
|
-
const bigfloat = require('../../types/bigfloat/module.f.cjs')
|
|
9
|
-
const { fromCharCode } = String
|
|
10
|
-
const {
|
|
11
|
-
range,
|
|
12
|
-
//
|
|
13
|
-
backspace,
|
|
14
|
-
ht,
|
|
15
|
-
lf,
|
|
16
|
-
ff,
|
|
17
|
-
cr,
|
|
18
|
-
//
|
|
19
|
-
space,
|
|
20
|
-
quotationMark,
|
|
21
|
-
plusSign,
|
|
22
|
-
comma,
|
|
23
|
-
hyphenMinus,
|
|
24
|
-
fullStop,
|
|
25
|
-
solidus,
|
|
26
|
-
//
|
|
27
|
-
digitRange,
|
|
28
|
-
digit0,
|
|
29
|
-
colon,
|
|
30
|
-
//
|
|
31
|
-
latinCapitalLetterA,
|
|
32
|
-
latinCapitalLetterE,
|
|
33
|
-
//
|
|
34
|
-
leftSquareBracket,
|
|
35
|
-
reverseSolidus,
|
|
36
|
-
rightSquareBracket,
|
|
37
|
-
//
|
|
38
|
-
latinSmallLetterRange,
|
|
39
|
-
latinSmallLetterA,
|
|
40
|
-
latinSmallLetterB,
|
|
41
|
-
latinSmallLetterE,
|
|
42
|
-
latinSmallLetterF,
|
|
43
|
-
latinSmallLetterN,
|
|
44
|
-
latinSmallLetterR,
|
|
45
|
-
latinSmallLetterT,
|
|
46
|
-
latinSmallLetterU,
|
|
47
|
-
//
|
|
48
|
-
leftCurlyBracket,
|
|
49
|
-
rightCurlyBracket
|
|
50
|
-
} = require('../../text/ascii/module.f.cjs')
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* @typedef {{
|
|
54
|
-
* readonly kind: 'string'
|
|
55
|
-
* readonly value: string
|
|
56
|
-
* }} StringToken
|
|
57
|
-
* */
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* @typedef {{
|
|
61
|
-
* readonly kind: 'number'
|
|
62
|
-
* readonly value: string
|
|
63
|
-
* readonly bf: bigfloat.BigFloat
|
|
64
|
-
* }} NumberToken
|
|
65
|
-
* */
|
|
66
|
-
|
|
67
|
-
/** @typedef {{readonly kind: 'error', message: ErrorMessage}} ErrorToken */
|
|
68
|
-
|
|
69
|
-
/** @typedef {{readonly kind: '{' | '}' | ':' | ',' | '[' | ']' | 'true' | 'false' | 'null'}} SimpleToken */
|
|
70
|
-
|
|
71
|
-
/**
|
|
72
|
-
* @typedef {|
|
|
73
|
-
* SimpleToken |
|
|
74
|
-
* StringToken |
|
|
75
|
-
* NumberToken |
|
|
76
|
-
* ErrorToken
|
|
77
|
-
* } JsonToken
|
|
78
|
-
*/
|
|
79
|
-
|
|
80
|
-
const rangeOneNine = range('19')
|
|
81
|
-
|
|
82
|
-
const rangeSetWhiteSpace = [
|
|
83
|
-
one(ht),
|
|
84
|
-
one(lf),
|
|
85
|
-
one(cr),
|
|
86
|
-
one(space)
|
|
87
|
-
]
|
|
88
|
-
|
|
89
|
-
const rangeSetTerminalForNumber = [
|
|
90
|
-
one(ht),
|
|
91
|
-
one(lf),
|
|
92
|
-
one(cr),
|
|
93
|
-
one(space),
|
|
94
|
-
one(quotationMark),
|
|
95
|
-
one(comma),
|
|
96
|
-
one(leftCurlyBracket),
|
|
97
|
-
one(rightCurlyBracket),
|
|
98
|
-
one(leftSquareBracket),
|
|
99
|
-
one(rightSquareBracket),
|
|
100
|
-
one(colon)
|
|
101
|
-
]
|
|
102
|
-
|
|
103
|
-
const rangeSmallAF = range('af')
|
|
104
|
-
const rangeCapitalAF = range('AF')
|
|
2
|
+
const fjsonTokenizer = require('../../fjson/tokenizer/module.f.cjs')
|
|
105
3
|
|
|
106
4
|
/**
|
|
107
5
|
* @typedef {|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
* ParseNumberState |
|
|
114
|
-
* InvalidNumberState |
|
|
115
|
-
* EofState
|
|
116
|
-
* } TokenizerState
|
|
117
|
-
*/
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* @typedef {|
|
|
121
|
-
* 'invalid keyword' |
|
|
122
|
-
* '" are missing' |
|
|
123
|
-
* 'unescaped character' |
|
|
124
|
-
* 'invalid hex value' |
|
|
125
|
-
* 'unexpected character' |
|
|
126
|
-
* 'invalid number' |
|
|
127
|
-
* 'eof'
|
|
128
|
-
* } ErrorMessage
|
|
129
|
-
*/
|
|
130
|
-
|
|
131
|
-
/** @typedef {{ readonly kind: 'initial'}} InitialState */
|
|
132
|
-
|
|
133
|
-
/** @typedef {{ readonly kind: 'keyword', readonly value: string}} ParseKeywordState */
|
|
134
|
-
|
|
135
|
-
/** @typedef {{ readonly kind: 'string', readonly value: string}} ParseStringState */
|
|
136
|
-
|
|
137
|
-
/** @typedef {{ readonly kind: 'escapeChar', readonly value: string}} ParseEscapeCharState */
|
|
138
|
-
|
|
139
|
-
/**
|
|
140
|
-
* @typedef {{
|
|
141
|
-
* readonly kind: 'unicodeChar'
|
|
142
|
-
* readonly value: string
|
|
143
|
-
* readonly unicode: number
|
|
144
|
-
* readonly hexIndex: number
|
|
145
|
-
* }} ParseUnicodeCharState
|
|
146
|
-
*/
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* @typedef {{
|
|
150
|
-
* readonly kind: 'number',
|
|
151
|
-
* readonly numberKind: '0' | '-' | 'int' | '.' | 'fractional' | 'e' | 'e+' | 'e-' | 'expDigits'
|
|
152
|
-
* readonly value: string
|
|
153
|
-
* readonly b: ParseNumberBuffer
|
|
154
|
-
* }} ParseNumberState
|
|
155
|
-
*/
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* @typedef {{
|
|
159
|
-
* readonly s: -1n | 1n
|
|
160
|
-
* readonly m: bigint
|
|
161
|
-
* readonly f: number
|
|
162
|
-
* readonly es: -1 | 1
|
|
163
|
-
* readonly e: number
|
|
164
|
-
* }} ParseNumberBuffer
|
|
6
|
+
* fjsonTokenizer.SimpleToken |
|
|
7
|
+
* fjsonTokenizer.StringToken |
|
|
8
|
+
* fjsonTokenizer.NumberToken |
|
|
9
|
+
* fjsonTokenizer.ErrorToken
|
|
10
|
+
* } JsonToken
|
|
165
11
|
*/
|
|
166
12
|
|
|
167
|
-
/** @
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
*/
|
|
186
|
-
|
|
187
|
-
/**
|
|
188
|
-
* @template T
|
|
189
|
-
* @typedef {range_map.RangeMapArray<CreateToToken<T>>} RangeMapToToken<T>
|
|
190
|
-
*/
|
|
191
|
-
|
|
192
|
-
/** @type {(old: string) => (input: number) => string} */
|
|
193
|
-
const appendChar = old => input => `${old}${fromCharCode(input)}`
|
|
194
|
-
|
|
195
|
-
/** @type {<T>(def: CreateToToken<T>) => (a: CreateToToken<T>) => (b: CreateToToken<T>) => CreateToToken<T>} */
|
|
196
|
-
const union = def => a => b => {
|
|
197
|
-
if (a === def || a === b) { return b }
|
|
198
|
-
if (b === def) { return a }
|
|
199
|
-
throw [a, b]
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/** @type {<T>(def: CreateToToken<T>) => range_map.RangeMerge<CreateToToken<T>>} */
|
|
203
|
-
const rangeMapMerge = def => merge({
|
|
204
|
-
union: union(def),
|
|
205
|
-
equal: operator.strictEqual,
|
|
206
|
-
})
|
|
207
|
-
|
|
208
|
-
/** @type {<T>(r: _range.Range) => (f: CreateToToken<T>) => RangeFunc<T>} */
|
|
209
|
-
const rangeFunc = r => f => def => fromRange(def)(r)(f)
|
|
210
|
-
|
|
211
|
-
/** @type {<T>(def: CreateToToken<T>) => (operator.Scan<RangeFunc<T>, RangeMapToToken<T>>)} */
|
|
212
|
-
const scanRangeOp = def => f => [f(def), scanRangeOp(def)]
|
|
213
|
-
|
|
214
|
-
/** @type {<T>(def: CreateToToken<T>) => (a: list.List<RangeFunc<T>>) => RangeMapToToken<T>} */
|
|
215
|
-
const reduceRangeMap = def => a => {
|
|
216
|
-
const rm = scan(scanRangeOp(def))(a)
|
|
217
|
-
return toArray(listReduce(rangeMapMerge(def))(empty)(rm))
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** @type {<T>(def: CreateToToken<T>) => (f: CreateToToken<T>) => (operator.Scan<_range.Range, RangeMapToToken<T>>)} */
|
|
221
|
-
const scanRangeSetOp = def => f => r => [fromRange(def)(r)(f), scanRangeSetOp(def)(f)]
|
|
222
|
-
|
|
223
|
-
/** @type {<T>(rs: list.List<_range.Range>) => (f: CreateToToken<T>) => RangeFunc<T>} */
|
|
224
|
-
const rangeSetFunc = rs => f => def => {
|
|
225
|
-
const rm = scan(scanRangeSetOp(def)(f))(rs)
|
|
226
|
-
return toArray(listReduce(rangeMapMerge(def))(empty)(rm))
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/** @type {<T>(def: CreateToToken<T>) => (a: list.List<RangeFunc<T>>) => CreateToToken<T>} */
|
|
230
|
-
const create = def => a => {
|
|
231
|
-
/** @typedef {typeof def extends CreateToToken<infer T> ? T : never} T */
|
|
232
|
-
const i = reduceRangeMap(def)(a)
|
|
233
|
-
/** @type {(v: number) => (i: RangeMapToToken<T>) => (v: T) => ToToken} */
|
|
234
|
-
const x = get(def)
|
|
235
|
-
return v => c => x(c)(i)(v)(c)
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
/** @type {(digit: number) => bigint} */
|
|
239
|
-
const digitToBigInt = d => BigInt(d - digit0)
|
|
240
|
-
|
|
241
|
-
/** @type {(digit: number) => ParseNumberBuffer} */
|
|
242
|
-
const startNumber = digit => ({ s: 1n, m: digitToBigInt(digit), f: 0, es: 1, e: 0 })
|
|
243
|
-
|
|
244
|
-
/** @type {ParseNumberBuffer} */
|
|
245
|
-
const startNegativeNumber = { s: -1n, m: 0n, f: 0, es: 1, e: 0 }
|
|
246
|
-
|
|
247
|
-
/** @type {(digit: number) => (b: ParseNumberBuffer) => ParseNumberBuffer} */
|
|
248
|
-
const addIntDigit = digit => b => ({ ... b, m: b.m * 10n + digitToBigInt(digit)})
|
|
249
|
-
|
|
250
|
-
/** @type {(digit: number) => (b: ParseNumberBuffer) => ParseNumberBuffer} */
|
|
251
|
-
const addFracDigit = digit => b => ({ ... b, m: b.m * 10n + digitToBigInt(digit), f: b.f - 1})
|
|
252
|
-
|
|
253
|
-
/** @type {(digit: number) => (b: ParseNumberBuffer) => ParseNumberBuffer} */
|
|
254
|
-
const addExpDigit = digit => b => ({ ... b, e: b.e * 10 + digit - digit0})
|
|
255
|
-
|
|
256
|
-
/** @type {(s: ParseNumberState) => NumberToken} */
|
|
257
|
-
const bufferToNumberToken = ({value, b}) => ({ kind: 'number', value: value, bf: [b.s * b.m, b.f + b.es * b.e] })
|
|
258
|
-
|
|
259
|
-
/** @type {(state: InitialState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
260
|
-
const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpected character' }], state])([
|
|
261
|
-
rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: 'int' }]),
|
|
262
|
-
rangeFunc(latinSmallLetterRange)(() => input => [empty, { kind: 'keyword', value: fromCharCode(input) }]),
|
|
263
|
-
rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state]),
|
|
264
|
-
rangeFunc(one(leftCurlyBracket))(state => () => [[{ kind: '{' }], state]),
|
|
265
|
-
rangeFunc(one(rightCurlyBracket))(state => () => [[{ kind: '}' }], state]),
|
|
266
|
-
rangeFunc(one(colon))(state => () => [[{ kind: ':' }], state]),
|
|
267
|
-
rangeFunc(one(comma))(state => () => [[{ kind: ',' }], state]),
|
|
268
|
-
rangeFunc(one(leftSquareBracket))(state => () => [[{ kind: '[' }], state]),
|
|
269
|
-
rangeFunc(one(rightSquareBracket))(state => () => [[{ kind: ']' }], state]),
|
|
270
|
-
rangeFunc(one(quotationMark))(() => () => [empty, { kind: 'string', value: '' }]),
|
|
271
|
-
rangeFunc(one(digit0))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: '0' }]),
|
|
272
|
-
rangeFunc(one(hyphenMinus))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNegativeNumber, numberKind: '-' }])
|
|
273
|
-
])
|
|
274
|
-
|
|
275
|
-
/** @type {() => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
276
|
-
const invalidNumberToToken = () => input => tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
277
|
-
|
|
278
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
279
|
-
const fullStopToToken = state => input => {
|
|
280
|
-
switch (state.numberKind) {
|
|
281
|
-
case '0':
|
|
282
|
-
case 'int': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: '.' }]
|
|
283
|
-
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
288
|
-
const digit0ToToken = state => input => {
|
|
289
|
-
switch (state.numberKind) {
|
|
290
|
-
case '0': return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
291
|
-
case '-': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: '0' }]
|
|
292
|
-
case '.':
|
|
293
|
-
case 'fractional': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addFracDigit(input)(state.b), numberKind: 'fractional' }]
|
|
294
|
-
case 'e':
|
|
295
|
-
case 'e+':
|
|
296
|
-
case 'e-':
|
|
297
|
-
case 'expDigits': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addExpDigit(input)(state.b), numberKind: 'expDigits' }]
|
|
298
|
-
default: return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addIntDigit(input)(state.b), numberKind: state.numberKind }]
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
303
|
-
const digit19ToToken = state => input => {
|
|
304
|
-
switch (state.numberKind) {
|
|
305
|
-
case '0': return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
306
|
-
case '.':
|
|
307
|
-
case 'fractional': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addFracDigit(input)(state.b), numberKind: 'fractional' }]
|
|
308
|
-
case 'e':
|
|
309
|
-
case 'e+':
|
|
310
|
-
case 'e-':
|
|
311
|
-
case 'expDigits': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addExpDigit(input)(state.b), numberKind: 'expDigits' }]
|
|
312
|
-
default: return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addIntDigit(input)(state.b), numberKind: 'int' }]
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
317
|
-
const expToToken = state => input => {
|
|
318
|
-
switch (state.numberKind) {
|
|
319
|
-
case '0':
|
|
320
|
-
case 'int':
|
|
321
|
-
case 'fractional': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: 'e' }]
|
|
322
|
-
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
327
|
-
const hyphenMinusToToken = state => input => {
|
|
328
|
-
switch (state.numberKind) {
|
|
329
|
-
case 'e': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: { ... state.b, es: -1}, numberKind: 'e-' }]
|
|
330
|
-
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
335
|
-
const plusSignToToken = state => input => {
|
|
336
|
-
switch (state.numberKind) {
|
|
337
|
-
case 'e': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: 'e+' }]
|
|
338
|
-
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
343
|
-
const terminalToToken = state => input => {
|
|
344
|
-
switch (state.numberKind) {
|
|
345
|
-
case '-':
|
|
346
|
-
case '.':
|
|
347
|
-
case 'e':
|
|
348
|
-
case 'e+':
|
|
349
|
-
case 'e-':
|
|
350
|
-
{
|
|
351
|
-
const next = tokenizeOp({ kind: 'initial' })(input)
|
|
352
|
-
return [{ first: { kind: 'error', message: 'invalid number' }, tail: next[0] }, next[1]]
|
|
353
|
-
}
|
|
354
|
-
default:
|
|
355
|
-
{
|
|
356
|
-
const next = tokenizeOp({ kind: 'initial' })(input)
|
|
357
|
-
return [{ first: bufferToNumberToken(state), tail: next[0] }, next[1]]
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
363
|
-
const parseNumberStateOp = create(invalidNumberToToken)([
|
|
364
|
-
rangeFunc(one(fullStop))(fullStopToToken),
|
|
365
|
-
rangeFunc(one(digit0))(digit0ToToken),
|
|
366
|
-
rangeFunc(rangeOneNine)(digit19ToToken),
|
|
367
|
-
rangeSetFunc([one(latinSmallLetterE), one(latinCapitalLetterE)])(expToToken),
|
|
368
|
-
rangeFunc(one(hyphenMinus))(hyphenMinusToToken),
|
|
369
|
-
rangeFunc(one(plusSign))(plusSignToToken),
|
|
370
|
-
rangeSetFunc(rangeSetTerminalForNumber)(terminalToToken)
|
|
371
|
-
])
|
|
372
|
-
|
|
373
|
-
/** @type {(state: InvalidNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
374
|
-
const invalidNumberStateOp = create(() => () => [empty, { kind: 'invalidNumber' }])([
|
|
375
|
-
rangeSetFunc(rangeSetTerminalForNumber)(() => input => {
|
|
376
|
-
const next = tokenizeOp({ kind: 'initial' })(input)
|
|
377
|
-
return [{ first: { kind: 'error', message: 'invalid number' }, tail: next[0] }, next[1]]
|
|
378
|
-
})
|
|
379
|
-
])
|
|
380
|
-
|
|
381
|
-
/** @type {(state: ParseStringState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
382
|
-
const parseStringStateOp = create(state => input => [empty, { kind: 'string', value: appendChar(state.value)(input) }])([
|
|
383
|
-
rangeFunc(one(quotationMark))(state => () => [[{ kind: 'string', value: state.value }], { kind: 'initial' }]),
|
|
384
|
-
rangeFunc(one(reverseSolidus))(state => () => [empty, { kind: 'escapeChar', value: state.value }])
|
|
385
|
-
])
|
|
386
|
-
|
|
387
|
-
/** @type {(state: ParseEscapeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
388
|
-
const parseEscapeDefault = state => input => {
|
|
389
|
-
const next = tokenizeOp({ kind: 'string', value: state.value })(input)
|
|
390
|
-
return [{ first: { kind: 'error', message: 'unescaped character' }, tail: next[0] }, next[1]]
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
/** @type {(state: ParseEscapeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
394
|
-
const parseEscapeCharStateOp = create(parseEscapeDefault)([
|
|
395
|
-
rangeSetFunc([one(quotationMark), one(reverseSolidus), one(solidus)])(state => input => [empty, { kind: 'string', value: appendChar(state.value)(input) }]),
|
|
396
|
-
rangeFunc(one(latinSmallLetterB))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(backspace) }]),
|
|
397
|
-
rangeFunc(one(latinSmallLetterF))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(ff) }]),
|
|
398
|
-
rangeFunc(one(latinSmallLetterN))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(lf) }]),
|
|
399
|
-
rangeFunc(one(latinSmallLetterR))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(cr) }]),
|
|
400
|
-
rangeFunc(one(latinSmallLetterT))(state => () => [empty, { kind: 'string', value: appendChar(state.value)(ht) }]),
|
|
401
|
-
rangeFunc(one(latinSmallLetterU))(state => () => [empty, { kind: 'unicodeChar', value: state.value, unicode: 0, hexIndex: 0 }]),
|
|
402
|
-
])
|
|
403
|
-
|
|
404
|
-
/** @type {(state: ParseUnicodeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
405
|
-
const parseUnicodeCharDefault = state => input => {
|
|
406
|
-
const next = tokenizeOp({ kind: 'string', value: state.value })(input)
|
|
407
|
-
return [{ first: { kind: 'error', message: 'invalid hex value' }, tail: next[0] }, next[1]]
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
/** @type {(offser: number) => (state: ParseUnicodeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
411
|
-
const parseUnicodeCharHex = offset => state => input => {
|
|
412
|
-
const hexValue = input - offset
|
|
413
|
-
const newUnicode = state.unicode | (hexValue << (3 - state.hexIndex) * 4)
|
|
414
|
-
return [empty, state.hexIndex === 3 ?
|
|
415
|
-
{ kind: 'string', value: appendChar(state.value)(newUnicode) } :
|
|
416
|
-
{ kind: 'unicodeChar', value: state.value, unicode: newUnicode, hexIndex: state.hexIndex + 1 }]
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/** @type {(state: ParseUnicodeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
420
|
-
const parseUnicodeCharStateOp = create(parseUnicodeCharDefault)([
|
|
421
|
-
rangeFunc(digitRange)(parseUnicodeCharHex(digit0)),
|
|
422
|
-
rangeFunc(rangeSmallAF)(parseUnicodeCharHex(latinSmallLetterA - 10)),
|
|
423
|
-
rangeFunc(rangeCapitalAF)(parseUnicodeCharHex(latinCapitalLetterA - 10))
|
|
424
|
-
])
|
|
425
|
-
|
|
426
|
-
/** @type {(s: string) => JsonToken} */
|
|
427
|
-
const stringToKeywordToken = s => {
|
|
428
|
-
switch (s) {
|
|
429
|
-
case 'true': return { kind: 'true' }
|
|
430
|
-
case 'false': return { kind: 'false' }
|
|
431
|
-
case 'null': return { kind: 'null' }
|
|
432
|
-
default: return { kind: 'error', message: 'invalid keyword' }
|
|
13
|
+
/** @type {(input: fjsonTokenizer.FjsonToken) => JsonToken} */
|
|
14
|
+
const mapToken = input =>
|
|
15
|
+
{
|
|
16
|
+
switch(input.kind)
|
|
17
|
+
{
|
|
18
|
+
case "{":
|
|
19
|
+
case "}":
|
|
20
|
+
case ":":
|
|
21
|
+
case ",":
|
|
22
|
+
case "[":
|
|
23
|
+
case "]":
|
|
24
|
+
case "true":
|
|
25
|
+
case "false":
|
|
26
|
+
case "null":
|
|
27
|
+
case "string":
|
|
28
|
+
case "number":
|
|
29
|
+
case "error": return input
|
|
30
|
+
default: return { kind: "error", message: "invalid token" }
|
|
433
31
|
}
|
|
434
32
|
}
|
|
435
33
|
|
|
436
|
-
/** @type {(state: ParseKeywordState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
437
|
-
const parseKeyWordDefault = state => input => {
|
|
438
|
-
const keyWordToken = stringToKeywordToken(state.value)
|
|
439
|
-
const next = tokenizeOp({ kind: 'initial' })(input)
|
|
440
|
-
return [{ first: keyWordToken, tail: next[0] }, next[1]]
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
/** @type {(state: ParseKeywordState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
444
|
-
const parseKeyWordStateOp = create(parseKeyWordDefault)([
|
|
445
|
-
rangeFunc(latinSmallLetterRange)(state => input => [empty, { kind: 'keyword', value: appendChar(state.value)(input) }])
|
|
446
|
-
])
|
|
447
|
-
|
|
448
|
-
/** @type {(state: EofState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
449
|
-
const eofStateOp = create(state => () => [[{ kind: 'error', message: 'eof' }], state])([])
|
|
450
|
-
|
|
451
|
-
/** @type {operator.StateScan<number, TokenizerState, list.List<JsonToken>>} */
|
|
452
|
-
const tokenizeCharCodeOp = state => {
|
|
453
|
-
switch (state.kind) {
|
|
454
|
-
case 'initial': return initialStateOp(state)
|
|
455
|
-
case 'keyword': return parseKeyWordStateOp(state)
|
|
456
|
-
case 'string': return parseStringStateOp(state)
|
|
457
|
-
case 'escapeChar': return parseEscapeCharStateOp(state)
|
|
458
|
-
case 'unicodeChar': return parseUnicodeCharStateOp(state)
|
|
459
|
-
case 'invalidNumber': return invalidNumberStateOp(state)
|
|
460
|
-
case 'number': return parseNumberStateOp(state)
|
|
461
|
-
case 'eof': return eofStateOp(state)
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
/** @type {(state: TokenizerState) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
466
|
-
const tokenizeEofOp = state => {
|
|
467
|
-
switch (state.kind) {
|
|
468
|
-
case 'initial': return [empty, { kind: 'eof' }]
|
|
469
|
-
case 'keyword': return [[stringToKeywordToken(state.value)], { kind: 'eof' }]
|
|
470
|
-
case 'string':
|
|
471
|
-
case 'escapeChar':
|
|
472
|
-
case 'unicodeChar': return [[{ kind: 'error', message: '" are missing' }], { kind: 'eof' }]
|
|
473
|
-
case 'invalidNumber': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'eof' }]
|
|
474
|
-
case 'number':
|
|
475
|
-
switch (state.numberKind) {
|
|
476
|
-
case '-':
|
|
477
|
-
case '.':
|
|
478
|
-
case 'e':
|
|
479
|
-
case 'e+':
|
|
480
|
-
case 'e-': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'invalidNumber', }]
|
|
481
|
-
default: return [[bufferToNumberToken(state)], { kind: 'eof' }]
|
|
482
|
-
}
|
|
483
|
-
case 'eof': return [[{ kind: 'error', message: 'eof' }], state]
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
/** @type {operator.StateScan<CharCodeOrEof, TokenizerState, list.List<JsonToken>>} */
|
|
488
|
-
const tokenizeOp = state => input => input === null ? tokenizeEofOp(state) : tokenizeCharCodeOp(state)(input)
|
|
489
|
-
|
|
490
|
-
const scanTokenize = stateScan(tokenizeOp)
|
|
491
|
-
|
|
492
|
-
const initial = scanTokenize({ kind: 'initial' })
|
|
493
|
-
|
|
494
34
|
/** @type {(input: list.List<number>) => list.List<JsonToken>} */
|
|
495
|
-
const tokenize = input =>
|
|
35
|
+
const tokenize = input => list.map(mapToken)(fjsonTokenizer.tokenize(input))
|
|
496
36
|
|
|
497
37
|
module.exports = {
|
|
498
38
|
/** @readonly */
|
|
@@ -45,11 +45,11 @@ module.exports = {
|
|
|
45
45
|
},
|
|
46
46
|
() => {
|
|
47
47
|
const result = stringify(tokenizeString('err'))
|
|
48
|
-
if (result !== '[{"kind":"error","message":"invalid
|
|
48
|
+
if (result !== '[{"kind":"error","message":"invalid token"}]') { throw result }
|
|
49
49
|
},
|
|
50
50
|
() => {
|
|
51
51
|
const result = stringify(tokenizeString('{e}'))
|
|
52
|
-
if (result !== '[{"kind":"{"},{"kind":"error","message":"invalid
|
|
52
|
+
if (result !== '[{"kind":"{"},{"kind":"error","message":"invalid token"},{"kind":"}"}]') { throw result }
|
|
53
53
|
},
|
|
54
54
|
() => {
|
|
55
55
|
const result = stringify(tokenizeString('{ \t\n\r}'))
|
|
@@ -61,7 +61,7 @@ module.exports = {
|
|
|
61
61
|
},
|
|
62
62
|
() => {
|
|
63
63
|
const result = stringify(tokenizeString('tru'))
|
|
64
|
-
if (result !== '[{"kind":"error","message":"invalid
|
|
64
|
+
if (result !== '[{"kind":"error","message":"invalid token"}]') { throw result }
|
|
65
65
|
},
|
|
66
66
|
() => {
|
|
67
67
|
const result = stringify(tokenizeString('false'))
|
|
@@ -145,7 +145,7 @@ module.exports = {
|
|
|
145
145
|
},
|
|
146
146
|
() => {
|
|
147
147
|
const result = stringify(tokenizeString('0abc,'))
|
|
148
|
-
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":","}]') { throw result }
|
|
148
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"error","message":"invalid token"},{"kind":","}]') { throw result }
|
|
149
149
|
},
|
|
150
150
|
() => {
|
|
151
151
|
const result = stringify(tokenizeString('123456789012345678901234567890'))
|
|
@@ -169,7 +169,7 @@ module.exports = {
|
|
|
169
169
|
},
|
|
170
170
|
() => {
|
|
171
171
|
const result = stringify(tokenizeString('9a:'))
|
|
172
|
-
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":":"}]') { throw result }
|
|
172
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"error","message":"invalid token"},{"kind":":"}]') { throw result }
|
|
173
173
|
},
|
|
174
174
|
() => {
|
|
175
175
|
const result = stringify(tokenizeString('-10'))
|