functionalscript 0.0.496 → 0.0.498

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.
@@ -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
- }