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