functionalscript 0.0.336 → 0.0.339
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 +46 -23
- package/json/tokenizer/test.js +12 -15
- package/package.json +1 -1
package/json/tokenizer/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const operator = require('../../types/function/operator/index.js')
|
|
2
2
|
const list = require('../../types/list/index.js')
|
|
3
|
+
const range = require('../../types/range/index.js')
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* @typedef {{
|
|
@@ -67,6 +68,12 @@ const letterT = 0x74
|
|
|
67
68
|
const letterU = 0x75
|
|
68
69
|
const letterZ = 0x7a
|
|
69
70
|
|
|
71
|
+
const containsDigit = range.contains([digit0, digit9])
|
|
72
|
+
const containsDigitOneNine = range.contains([digit1, digit9])
|
|
73
|
+
const containsSmallAF = range.contains([letterA, letterF])
|
|
74
|
+
const containsCapitalAF = range.contains([capitalLetterA, capitalLetterF])
|
|
75
|
+
const containsSmallLetter = range.contains([letterA, letterZ])
|
|
76
|
+
|
|
70
77
|
/**
|
|
71
78
|
* @typedef {|
|
|
72
79
|
* InitialState |
|
|
@@ -116,22 +123,23 @@ const letterZ = 0x7a
|
|
|
116
123
|
|
|
117
124
|
/** @typedef {number|undefined} CharCodeOrEof */
|
|
118
125
|
|
|
119
|
-
/** @type {(old: string) => (input:
|
|
120
|
-
const appendChar = old => input =>
|
|
121
|
-
|
|
122
|
-
/** @type {(input: CharCodeOrEof) => string} */
|
|
123
|
-
const charToString = input => input === undefined ? '' : String.fromCharCode(input)
|
|
126
|
+
/** @type {(old: string) => (input: number) => string} */
|
|
127
|
+
const appendChar = old => input => `${old}${String.fromCharCode(input)}`
|
|
124
128
|
|
|
125
129
|
/** @type {(state: InitialState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
126
130
|
const initialStateOp = initialState => input =>
|
|
127
131
|
{
|
|
128
|
-
if (input
|
|
132
|
+
if (containsDigitOneNine(input))
|
|
133
|
+
{
|
|
134
|
+
return [undefined, { kind: 'number', value: String.fromCharCode(input), numberKind: 'int'}]
|
|
135
|
+
}
|
|
136
|
+
if (containsSmallLetter(input))
|
|
129
137
|
{
|
|
130
|
-
return [undefined, { kind: '
|
|
138
|
+
return [undefined, { kind: 'keyword', value: String.fromCharCode(input)}]
|
|
131
139
|
}
|
|
132
|
-
if (input
|
|
140
|
+
if (isWhiteSpace(input))
|
|
133
141
|
{
|
|
134
|
-
return [undefined,
|
|
142
|
+
return [undefined, initialState]
|
|
135
143
|
}
|
|
136
144
|
switch(input)
|
|
137
145
|
{
|
|
@@ -142,12 +150,8 @@ const initialStateOp = initialState => input =>
|
|
|
142
150
|
case leftBracket: return [[{kind: '['}], initialState]
|
|
143
151
|
case rightBracket: return [[{kind: ']'}], initialState]
|
|
144
152
|
case quotationMark: return[undefined, {kind: 'string', value: ''}]
|
|
145
|
-
case digit0: return [undefined, { kind: 'number', value:
|
|
146
|
-
case signMinus: return [undefined, { kind: 'number', value:
|
|
147
|
-
case horizontalTab:
|
|
148
|
-
case newLine:
|
|
149
|
-
case carriageReturn:
|
|
150
|
-
case space: return[undefined, initialState]
|
|
153
|
+
case digit0: return [undefined, { kind: 'number', value: String.fromCharCode(input), numberKind: '0'}]
|
|
154
|
+
case signMinus: return [undefined, { kind: 'number', value: String.fromCharCode(input), numberKind: '-'}]
|
|
151
155
|
default: return [[{kind: 'error', message: 'unexpected character'}], initialState]
|
|
152
156
|
}
|
|
153
157
|
}
|
|
@@ -177,7 +181,7 @@ const parseNumberStateOp = state => input =>
|
|
|
177
181
|
default: return [undefined, {kind:'number', value: appendChar(state.value)(input), numberKind: state.numberKind}]
|
|
178
182
|
}
|
|
179
183
|
}
|
|
180
|
-
if (input
|
|
184
|
+
if (containsDigitOneNine(input))
|
|
181
185
|
{
|
|
182
186
|
switch (state.numberKind)
|
|
183
187
|
{
|
|
@@ -242,6 +246,10 @@ const parseNumberStateOp = state => input =>
|
|
|
242
246
|
/** @type {(char: number) => boolean} */
|
|
243
247
|
const isTerminalForNumber = char =>
|
|
244
248
|
{
|
|
249
|
+
if (isWhiteSpace(char))
|
|
250
|
+
{
|
|
251
|
+
return true;
|
|
252
|
+
}
|
|
245
253
|
switch (char)
|
|
246
254
|
{
|
|
247
255
|
case quotationMark:
|
|
@@ -255,6 +263,19 @@ const isTerminalForNumber = char =>
|
|
|
255
263
|
}
|
|
256
264
|
}
|
|
257
265
|
|
|
266
|
+
/** @type {(char: number) => boolean} */
|
|
267
|
+
const isWhiteSpace = char =>
|
|
268
|
+
{
|
|
269
|
+
switch (char)
|
|
270
|
+
{
|
|
271
|
+
case horizontalTab:
|
|
272
|
+
case newLine:
|
|
273
|
+
case carriageReturn:
|
|
274
|
+
case space: return true
|
|
275
|
+
default: return false
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
258
279
|
/** @type {(state: InvalidNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
259
280
|
const invalidNumberStateOp = state => input =>
|
|
260
281
|
{
|
|
@@ -301,9 +322,9 @@ const parseEscapeCharStateOp = state => input =>
|
|
|
301
322
|
/** @type {(hex: number) => number|undefined} */
|
|
302
323
|
const hexDigitToNumber = hex =>
|
|
303
324
|
{
|
|
304
|
-
if (hex
|
|
305
|
-
if (hex
|
|
306
|
-
if (hex
|
|
325
|
+
if (containsDigit(hex)) { return hex - digit0 }
|
|
326
|
+
if (containsCapitalAF(hex)) { return hex - capitalLetterA + 10 }
|
|
327
|
+
if (containsSmallAF(hex)) { return hex - letterA + 10 }
|
|
307
328
|
}
|
|
308
329
|
|
|
309
330
|
/** @type {(state: ParseUnicodeCharState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
@@ -336,7 +357,7 @@ const stringToKeywordToken = s =>
|
|
|
336
357
|
/** @type {(state: ParseKeywordState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
337
358
|
const parseKeyWordStateOp = state => input =>
|
|
338
359
|
{
|
|
339
|
-
if (input
|
|
360
|
+
if (containsSmallLetter(input))
|
|
340
361
|
{
|
|
341
362
|
return [undefined, {kind: 'keyword', value: appendChar(state.value)(input)}]
|
|
342
363
|
}
|
|
@@ -390,10 +411,12 @@ const tokenizeEofOp = state => {
|
|
|
390
411
|
/** @type {operator.StateScan<CharCodeOrEof, TokenizerState, list.List<JsonToken>>} */
|
|
391
412
|
const tokenizeOp = state => input => input === undefined ? tokenizeEofOp(state) : tokenizeCharCodeOp(state)(input)
|
|
392
413
|
|
|
393
|
-
|
|
394
|
-
|
|
414
|
+
const initial = list.stateScan(tokenizeOp)({ kind: 'initial' })
|
|
415
|
+
|
|
416
|
+
/** @type {(input: list.List<number>) => list.List<JsonToken>} */
|
|
417
|
+
const tokenize = input => list.flat(initial(list.concat(/** @type {list.List<CharCodeOrEof>} */(input))([undefined])))
|
|
395
418
|
|
|
396
419
|
module.exports = {
|
|
397
420
|
/** @readonly */
|
|
398
|
-
tokenize
|
|
421
|
+
tokenize
|
|
399
422
|
}
|
package/json/tokenizer/test.js
CHANGED
|
@@ -3,23 +3,10 @@ const list = require('../../types/list/index.js')
|
|
|
3
3
|
const json = require('../index.js')
|
|
4
4
|
const { sort } = require('../../types/object/index.js')
|
|
5
5
|
|
|
6
|
-
/** @type {(s: string) => list.List<tokenizer.CharCodeOrEof>} */
|
|
7
|
-
const toCharacters = s =>
|
|
8
|
-
{
|
|
9
|
-
/** @type {list.List<tokenizer.CharCodeOrEof>} */
|
|
10
|
-
const charCodes = list.toCharCodes(s)
|
|
11
|
-
return list.concat(charCodes)([undefined])
|
|
12
|
-
}
|
|
13
|
-
|
|
14
6
|
/** @type {(s: string) => readonly tokenizer.JsonToken[]} */
|
|
15
|
-
const tokenizeString = s =>
|
|
16
|
-
{
|
|
17
|
-
const characters = toCharacters(s)
|
|
18
|
-
return list.toArray(tokenizer.tokenize(characters))
|
|
19
|
-
}
|
|
7
|
+
const tokenizeString = s => list.toArray(tokenizer.tokenize(list.toCharCodes(s)))
|
|
20
8
|
|
|
21
|
-
|
|
22
|
-
const stringify = a => json.stringify(sort)(a)
|
|
9
|
+
const stringify = json.stringify(sort)
|
|
23
10
|
|
|
24
11
|
{
|
|
25
12
|
const result = tokenizeString('')
|
|
@@ -201,6 +188,16 @@ const stringify = a => json.stringify(sort)(a)
|
|
|
201
188
|
if (result !== '[{"kind":"{"},{"kind":"number","value":"90"},{"kind":"}"}]') { throw result }
|
|
202
189
|
}
|
|
203
190
|
|
|
191
|
+
{
|
|
192
|
+
const result = stringify(tokenizeString('1 2'))
|
|
193
|
+
if (result !== '[{"kind":"number","value":"1"},{"kind":"number","value":"2"}]') { throw result }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
{
|
|
197
|
+
const result = stringify(tokenizeString('0. 2'))
|
|
198
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"number","value":"2"}]') { throw result }
|
|
199
|
+
}
|
|
200
|
+
|
|
204
201
|
{
|
|
205
202
|
const result = stringify(tokenizeString('10-0'))
|
|
206
203
|
if (result !== '[{"kind":"error","message":"invalid number"}]') { throw result }
|