functionalscript 0.0.329 → 0.0.330
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/index.js +44 -48
- package/json/tokenizer/test.js +4 -4
- package/package.json +1 -1
package/json/tokenizer/index.js
CHANGED
|
@@ -50,7 +50,7 @@ const newLine = 0x0a
|
|
|
50
50
|
const carriageReturn = 0x0d
|
|
51
51
|
const space = 0x20
|
|
52
52
|
|
|
53
|
-
const
|
|
53
|
+
const backslash = 0x5c
|
|
54
54
|
const slash = 0x2f
|
|
55
55
|
const backspace = 0x08
|
|
56
56
|
const formfeed = 0x0c
|
|
@@ -116,21 +116,17 @@ const letterZ = 0x7a
|
|
|
116
116
|
|
|
117
117
|
/** @typedef {{ readonly kind: 'eof'}} EofState */
|
|
118
118
|
|
|
119
|
-
/** @typedef {number|undefined}
|
|
119
|
+
/** @typedef {number|undefined} CharCodeOrEof */
|
|
120
120
|
|
|
121
|
-
/** @type {(old: string) => (input:
|
|
121
|
+
/** @type {(old: string) => (input: CharCodeOrEof) => string} */
|
|
122
122
|
const appendChar = old => input => input === undefined ? old : operator.concat(charToString(input))(old)
|
|
123
123
|
|
|
124
|
-
/** @type {(input:
|
|
124
|
+
/** @type {(input: CharCodeOrEof) => string} */
|
|
125
125
|
const charToString = input => input === undefined ? '' : String.fromCharCode(input)
|
|
126
126
|
|
|
127
|
-
/** @type {(state: InitialState) => (input:
|
|
127
|
+
/** @type {(state: InitialState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
128
128
|
const initialStateOp = initialState => input =>
|
|
129
129
|
{
|
|
130
|
-
if (input === undefined)
|
|
131
|
-
{
|
|
132
|
-
return[undefined, {kind: 'eof'}]
|
|
133
|
-
}
|
|
134
130
|
if (input >= digit1 && input <= digit9)
|
|
135
131
|
{
|
|
136
132
|
return [undefined, { kind: 'number', value: charToString(input), numberKind: 'int'}]
|
|
@@ -158,21 +154,9 @@ const initialStateOp = initialState => input =>
|
|
|
158
154
|
}
|
|
159
155
|
}
|
|
160
156
|
|
|
161
|
-
/** @type {(state: ParseNumberState) => (input:
|
|
157
|
+
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
162
158
|
const parseNumberStateOp = state => input =>
|
|
163
159
|
{
|
|
164
|
-
if (input === undefined)
|
|
165
|
-
{
|
|
166
|
-
switch (state.numberKind)
|
|
167
|
-
{
|
|
168
|
-
case '-':
|
|
169
|
-
case '.':
|
|
170
|
-
case 'e':
|
|
171
|
-
case 'e+':
|
|
172
|
-
case 'e-': return [[{kind: 'error', message: 'invalid number'}], {kind: 'invalidNumber', }]
|
|
173
|
-
default: return [[{kind: 'number', value: state.value}], {kind: 'eof'}]
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
160
|
if (input === decimalPoint)
|
|
177
161
|
{
|
|
178
162
|
switch (state.numberKind)
|
|
@@ -273,13 +257,9 @@ const isTerminalForNumber = char =>
|
|
|
273
257
|
}
|
|
274
258
|
}
|
|
275
259
|
|
|
276
|
-
/** @type {(state: InvalidNumberState) => (input:
|
|
260
|
+
/** @type {(state: InvalidNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
277
261
|
const invalidNumberStateOp = state => input =>
|
|
278
262
|
{
|
|
279
|
-
if (input === undefined)
|
|
280
|
-
{
|
|
281
|
-
return [[{kind: 'error', message: 'invalid number'}], {kind: 'eof'}]
|
|
282
|
-
}
|
|
283
263
|
if (isTerminalForNumber(input))
|
|
284
264
|
{
|
|
285
265
|
const next = tokenizeOp({kind: 'initial'})(input)
|
|
@@ -288,25 +268,24 @@ const invalidNumberStateOp = state => input =>
|
|
|
288
268
|
return [undefined, {kind: 'invalidNumber'}]
|
|
289
269
|
}
|
|
290
270
|
|
|
291
|
-
/** @type {(state: ParseStringState) => (input:
|
|
271
|
+
/** @type {(state: ParseStringState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
292
272
|
const parseStringStateOp = state => input =>
|
|
293
273
|
{
|
|
294
274
|
switch(input)
|
|
295
275
|
{
|
|
296
276
|
case quotationMark: return[[{kind: 'string', value: state.value}], {kind: 'initial'}]
|
|
297
|
-
case
|
|
298
|
-
case undefined: return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
|
|
277
|
+
case backslash: return [undefined, {kind:'escapeChar', value: state.value}]
|
|
299
278
|
default: return [undefined, {kind:'string', value: appendChar(state.value)(input)}]
|
|
300
279
|
}
|
|
301
280
|
}
|
|
302
281
|
|
|
303
|
-
/** @type {(state: ParseEscapeCharState) => (input:
|
|
282
|
+
/** @type {(state: ParseEscapeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
304
283
|
const parseEscapeCharStateOp = state => input =>
|
|
305
284
|
{
|
|
306
285
|
switch(input)
|
|
307
286
|
{
|
|
308
287
|
case quotationMark:
|
|
309
|
-
case
|
|
288
|
+
case backslash:
|
|
310
289
|
case slash: return [undefined, {kind: 'string', value: appendChar(state.value)(input)}]
|
|
311
290
|
case letterB: return [undefined, {kind: 'string', value: appendChar(state.value)(backspace)}]
|
|
312
291
|
case letterF: return [undefined, {kind: 'string', value: appendChar(state.value)(formfeed)}]
|
|
@@ -314,7 +293,6 @@ const parseEscapeCharStateOp = state => input =>
|
|
|
314
293
|
case letterR: return [undefined, {kind: 'string', value: appendChar(state.value)(carriageReturn)}]
|
|
315
294
|
case letterT: return [undefined, {kind: 'string', value: appendChar(state.value)(horizontalTab)}]
|
|
316
295
|
case letterU: return [undefined, {kind: 'unicodeChar', value: state.value, unicode: 0, hexIndex: 0}]
|
|
317
|
-
case undefined: return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
|
|
318
296
|
default: {
|
|
319
297
|
const next = tokenizeOp({kind: 'string', value: state.value})(input)
|
|
320
298
|
return [{first: {kind: 'error', message: 'unescaped character'}, tail: next[0]}, next[1]]
|
|
@@ -330,13 +308,9 @@ const hexDigitToNumber = hex =>
|
|
|
330
308
|
if (hex >= letterA && hex <= letterF) { return hex - letterA + 10 }
|
|
331
309
|
}
|
|
332
310
|
|
|
333
|
-
/** @type {(state: ParseUnicodeCharState) => (input:
|
|
311
|
+
/** @type {(state: ParseUnicodeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
334
312
|
const parseUnicodeCharStateOp = state => input =>
|
|
335
313
|
{
|
|
336
|
-
if (input === undefined)
|
|
337
|
-
{
|
|
338
|
-
return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
|
|
339
|
-
}
|
|
340
314
|
const hexValue = hexDigitToNumber(input)
|
|
341
315
|
if (hexValue === undefined)
|
|
342
316
|
{
|
|
@@ -361,14 +335,9 @@ const stringToKeywordToken = s =>
|
|
|
361
335
|
}
|
|
362
336
|
}
|
|
363
337
|
|
|
364
|
-
/** @type {(state: ParseKeywordState) => (input:
|
|
338
|
+
/** @type {(state: ParseKeywordState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
365
339
|
const parseKeyWordStateOp = state => input =>
|
|
366
340
|
{
|
|
367
|
-
if (input === undefined)
|
|
368
|
-
{
|
|
369
|
-
const keyWordToken = stringToKeywordToken(state.value)
|
|
370
|
-
return [[keyWordToken], {kind: 'eof'}]
|
|
371
|
-
}
|
|
372
341
|
if (input >= letterA && input <= letterZ)
|
|
373
342
|
{
|
|
374
343
|
return [undefined, {kind: 'keyword', value: appendChar(state.value)(input)}]
|
|
@@ -378,11 +347,11 @@ const parseKeyWordStateOp = state => input =>
|
|
|
378
347
|
return [{first: keyWordToken, tail: next[0]}, next[1]]
|
|
379
348
|
}
|
|
380
349
|
|
|
381
|
-
/** @type {(state: EofState) => (input:
|
|
350
|
+
/** @type {(state: EofState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
382
351
|
const eofStateOp = state => input => [[{kind: 'error', message: 'eof'}], state]
|
|
383
352
|
|
|
384
|
-
/** @type {operator.StateScan<
|
|
385
|
-
const
|
|
353
|
+
/** @type {operator.StateScan<number, TokenizerState, list.List<JsonToken>>} */
|
|
354
|
+
const tokenizeCharCodeOp = state => {
|
|
386
355
|
switch(state.kind)
|
|
387
356
|
{
|
|
388
357
|
case 'initial': return initialStateOp(state)
|
|
@@ -396,7 +365,34 @@ const tokenizeOp = state => {
|
|
|
396
365
|
}
|
|
397
366
|
}
|
|
398
367
|
|
|
399
|
-
/** @type {(
|
|
368
|
+
/** @type {(state: TokenizerState) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
369
|
+
const tokenizeEofOp = state => {
|
|
370
|
+
switch(state.kind)
|
|
371
|
+
{
|
|
372
|
+
case 'initial': return[undefined, {kind: 'eof'}]
|
|
373
|
+
case 'keyword': return [[stringToKeywordToken(state.value)], {kind: 'eof'}]
|
|
374
|
+
case 'string':
|
|
375
|
+
case 'escapeChar':
|
|
376
|
+
case 'unicodeChar': return [[{kind: 'error', message: '" are missing'}], {kind: 'eof'}]
|
|
377
|
+
case 'invalidNumber': return [[{kind: 'error', message: 'invalid number'}], {kind: 'eof'}]
|
|
378
|
+
case 'number':
|
|
379
|
+
switch (state.numberKind)
|
|
380
|
+
{
|
|
381
|
+
case '-':
|
|
382
|
+
case '.':
|
|
383
|
+
case 'e':
|
|
384
|
+
case 'e+':
|
|
385
|
+
case 'e-': return [[{kind: 'error', message: 'invalid number'}], {kind: 'invalidNumber', }]
|
|
386
|
+
default: return [[{kind: 'number', value: state.value}], {kind: 'eof'}]
|
|
387
|
+
}
|
|
388
|
+
case 'eof': return [[{kind: 'error', message: 'eof'}], state]
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
/** @type {operator.StateScan<CharCodeOrEof, TokenizerState, list.List<JsonToken>>} */
|
|
393
|
+
const tokenizeOp = state => input => input === undefined ? tokenizeEofOp(state) : tokenizeCharCodeOp(state)(input)
|
|
394
|
+
|
|
395
|
+
/** @type {(input: list.List<CharCodeOrEof>) => list.List<JsonToken>} */
|
|
400
396
|
const tokenize = input => list.flat(list.stateScan(tokenizeOp)({kind: 'initial'})(input))
|
|
401
397
|
|
|
402
398
|
module.exports = {
|
package/json/tokenizer/test.js
CHANGED
|
@@ -3,17 +3,17 @@ const list = require('../../types/list')
|
|
|
3
3
|
const json = require('..')
|
|
4
4
|
const { sort } = require('../../types/object')
|
|
5
5
|
|
|
6
|
-
/** @type {(s: string) => list.List<tokenizer.
|
|
6
|
+
/** @type {(s: string) => list.List<tokenizer.CharCodeOrEof>} */
|
|
7
7
|
const toCharacters = s =>
|
|
8
8
|
{
|
|
9
|
-
/** @type {list.List<tokenizer.
|
|
9
|
+
/** @type {list.List<tokenizer.CharCodeOrEof>} */
|
|
10
10
|
const charCodes = list.toCharCodes(s)
|
|
11
11
|
return list.concat(charCodes)([undefined])
|
|
12
|
-
}
|
|
12
|
+
}
|
|
13
13
|
|
|
14
14
|
/** @type {(s: string) => readonly tokenizer.JsonToken[]} */
|
|
15
15
|
const tokenizeString = s =>
|
|
16
|
-
{
|
|
16
|
+
{
|
|
17
17
|
const characters = toCharacters(s)
|
|
18
18
|
return list.toArray(tokenizer.tokenize(characters))
|
|
19
19
|
}
|