functionalscript 0.0.504 → 0.0.506
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fjson/README.md +8 -0
- package/fjson/module.f.cjs +111 -0
- package/fjson/test.f.cjs +65 -0
- package/json/tokenizer/module.f.cjs +54 -17
- package/json/tokenizer/test.f.cjs +24 -20
- package/package.json +1 -1
- package/types/bigint/module.f.cjs +5 -0
- package/types/bigint/test.f.cjs +15 -1
package/fjson/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
const list = require('../types/list/module.f.cjs')
|
|
2
|
+
const { next, flat, reduce, map, empty } = list
|
|
3
|
+
const { concat } = require('../types/string/module.f.cjs')
|
|
4
|
+
const object = require('../types/object/module.f.cjs')
|
|
5
|
+
const { at } = object
|
|
6
|
+
const operator = require('../types/function/operator/module.f.cjs')
|
|
7
|
+
const { compose, fn } = require('../types/function/module.f.cjs')
|
|
8
|
+
const { entries } = Object
|
|
9
|
+
const { serialize: bigintSerialize } = require('../types/bigint/module.f.cjs')
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @typedef {{
|
|
13
|
+
* readonly [k in string]: Unknown
|
|
14
|
+
* }} Object
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/** @typedef {readonly Unknown[]} Array */
|
|
18
|
+
|
|
19
|
+
/** @typedef {Object|boolean|string|number|null|Array|bigint} Unknown */
|
|
20
|
+
|
|
21
|
+
const jsonStringify = JSON.stringify
|
|
22
|
+
|
|
23
|
+
/** @type {(_: string) => list.List<string>} */
|
|
24
|
+
const stringSerialize = input => [jsonStringify(input)]
|
|
25
|
+
|
|
26
|
+
/** @type {(_: number) => list.List<string>} */
|
|
27
|
+
const numberSerialize = input => [jsonStringify(input)]
|
|
28
|
+
|
|
29
|
+
const nullSerialize = ['null']
|
|
30
|
+
|
|
31
|
+
const trueSerialize = ['true']
|
|
32
|
+
|
|
33
|
+
const falseSerialize = ['false']
|
|
34
|
+
|
|
35
|
+
/** @type {(_: boolean) => list.List<string>} */
|
|
36
|
+
const boolSerialize = value => value ? trueSerialize : falseSerialize
|
|
37
|
+
|
|
38
|
+
const colon = [':']
|
|
39
|
+
const comma = [',']
|
|
40
|
+
|
|
41
|
+
/** @type {operator.Reduce<list.List<string>>} */
|
|
42
|
+
const joinOp = b => prior => flat([prior, comma, b])
|
|
43
|
+
|
|
44
|
+
/** @type {(input: list.List<list.List<string>>) => list.List<string>} */
|
|
45
|
+
const join = reduce(joinOp)(empty)
|
|
46
|
+
|
|
47
|
+
/** @type {(open: string) => (close: string) => (input: list.List<list.List<string>>) => list.List<string>} */
|
|
48
|
+
const wrap = open => close => {
|
|
49
|
+
const seqOpen = [open]
|
|
50
|
+
const seqClose = [close]
|
|
51
|
+
return input => flat([seqOpen, join(input), seqClose])
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const objectWrap = wrap('{')('}')
|
|
55
|
+
|
|
56
|
+
const arrayWrap = wrap('[')(']')
|
|
57
|
+
|
|
58
|
+
/** @typedef {object.Entry<Unknown>} Entry*/
|
|
59
|
+
|
|
60
|
+
/** @typedef {(list.List<Entry>)} Entries */
|
|
61
|
+
|
|
62
|
+
/** @typedef {(entries: Entries) => Entries} MapEntries */
|
|
63
|
+
|
|
64
|
+
/** @type {(mapEntries: MapEntries) => (value: Unknown) => list.List<string>} */
|
|
65
|
+
const serialize = sort => {
|
|
66
|
+
/** @type {(kv: readonly[string, Unknown]) => list.List<string>} */
|
|
67
|
+
const propertySerialize = ([k, v]) => flat([
|
|
68
|
+
stringSerialize(k),
|
|
69
|
+
colon,
|
|
70
|
+
f(v)
|
|
71
|
+
])
|
|
72
|
+
const mapPropertySerialize = map(propertySerialize)
|
|
73
|
+
/** @type {(object: Object) => list.List<string>} */
|
|
74
|
+
const objectSerialize = fn(entries)
|
|
75
|
+
.then(sort)
|
|
76
|
+
.then(mapPropertySerialize)
|
|
77
|
+
.then(objectWrap)
|
|
78
|
+
.result
|
|
79
|
+
/** @type {(value: Unknown) => list.List<string>} */
|
|
80
|
+
const f = value => {
|
|
81
|
+
switch (typeof value) {
|
|
82
|
+
case 'boolean': { return boolSerialize(value) }
|
|
83
|
+
case 'number': { return numberSerialize(value) }
|
|
84
|
+
case 'string': { return stringSerialize(value) }
|
|
85
|
+
case 'bigint': { return [bigintSerialize(value)] }
|
|
86
|
+
default: {
|
|
87
|
+
if (value === null) { return nullSerialize }
|
|
88
|
+
if (value instanceof Array) { return arraySerialize(value) }
|
|
89
|
+
return objectSerialize(value)
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const arraySerialize = compose(map(f))(arrayWrap)
|
|
94
|
+
return f
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* The standard `JSON.stringify` rules determined by
|
|
99
|
+
* https://262.ecma-international.org/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys
|
|
100
|
+
*
|
|
101
|
+
* @type {(mapEntries: MapEntries) => (value: Unknown) => string}
|
|
102
|
+
*/
|
|
103
|
+
const stringify = sort => compose(serialize(sort))(concat)
|
|
104
|
+
|
|
105
|
+
module.exports = {
|
|
106
|
+
|
|
107
|
+
/** @readonly */
|
|
108
|
+
stringify,
|
|
109
|
+
/** @readonly */
|
|
110
|
+
serialize,
|
|
111
|
+
}
|
package/fjson/test.f.cjs
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
const json = require('../json/module.f.cjs')
|
|
2
|
+
const { sort } = require('../types/object/module.f.cjs')
|
|
3
|
+
const { identity } = require('../types/function/module.f.cjs')
|
|
4
|
+
const fjson= require('./module.f.cjs')
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
stringify: [
|
|
8
|
+
{
|
|
9
|
+
sort: () => {
|
|
10
|
+
const r = json.setProperty("Hello")(['a'])({})
|
|
11
|
+
const x = fjson.stringify(sort)(r)
|
|
12
|
+
if (x !== '{"a":"Hello"}') { throw x }
|
|
13
|
+
},
|
|
14
|
+
identity: () => {
|
|
15
|
+
const x = fjson.stringify(identity)(json.setProperty("Hello")(['a'])({}))
|
|
16
|
+
if (x !== '{"a":"Hello"}') { throw x }
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
sort: () => {
|
|
21
|
+
const x = fjson.stringify(sort)(json.setProperty("Hello")(['a'])({ c: [], b: 12 }))
|
|
22
|
+
if (x !== '{"a":"Hello","b":12,"c":[]}') { throw x }
|
|
23
|
+
},
|
|
24
|
+
identity: () => {
|
|
25
|
+
const x = fjson.stringify(identity)(json.setProperty("Hello")(['a'])({ c: [], b: 12 }))
|
|
26
|
+
if (x !== '{"c":[],"b":12,"a":"Hello"}') { throw x }
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
sort: () => {
|
|
31
|
+
const _0 = { a: { y: [24] }, c: [], b: 12 }
|
|
32
|
+
const _1 = json.setProperty("Hello")(['a', 'x'])(_0)
|
|
33
|
+
const _2 = fjson.stringify(sort)(_1)
|
|
34
|
+
if (_2 !== '{"a":{"x":"Hello","y":[24]},"b":12,"c":[]}') { throw _2 }
|
|
35
|
+
},
|
|
36
|
+
identity: () => {
|
|
37
|
+
const _0 = { a: { y: [24] }, c: [], b: 12 }
|
|
38
|
+
const _1 = json.setProperty("Hello")(['a', 'x'])(_0)
|
|
39
|
+
const _2 = fjson.stringify(identity)(_1)
|
|
40
|
+
if (_2 !== '{"a":{"y":[24],"x":"Hello"},"c":[],"b":12}') { throw _2 }
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
stringify: () => {
|
|
45
|
+
const bi = 1234567890n
|
|
46
|
+
const result = fjson.stringify(sort)(bi)
|
|
47
|
+
if (result !== '1234567890n') { throw result }
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
stringify: () => {
|
|
52
|
+
const arr = [0n, 1, 2n]
|
|
53
|
+
const result = fjson.stringify(sort)(arr)
|
|
54
|
+
if (result !== '[0n,1,2n]') { throw result }
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
stringify: () => {
|
|
59
|
+
const obj = {"a": 0n, "b": 1, "c": 2n}
|
|
60
|
+
const result = fjson.stringify(sort)(obj)
|
|
61
|
+
if (result !== '{"a":0n,"b":1,"c":2n}') { throw result }
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
@@ -5,6 +5,7 @@ const list = require('../../types/list/module.f.cjs')
|
|
|
5
5
|
const _range = require('../../types/range/module.f.cjs')
|
|
6
6
|
const { one } = _range
|
|
7
7
|
const { empty, stateScan, flat, toArray, reduce: listReduce, scan } = list
|
|
8
|
+
const bigfloat = require('../../types/bigfloat/module.f.cjs')
|
|
8
9
|
const { fromCharCode } = String
|
|
9
10
|
const {
|
|
10
11
|
range,
|
|
@@ -59,6 +60,7 @@ const {
|
|
|
59
60
|
* @typedef {{
|
|
60
61
|
* readonly kind: 'number'
|
|
61
62
|
* readonly value: string
|
|
63
|
+
* readonly bf: bigfloat.BigFloat
|
|
62
64
|
* }} NumberToken
|
|
63
65
|
* */
|
|
64
66
|
|
|
@@ -148,9 +150,20 @@ const rangeCapitalAF = range('AF')
|
|
|
148
150
|
* readonly kind: 'number',
|
|
149
151
|
* readonly numberKind: '0' | '-' | 'int' | '.' | 'fractional' | 'e' | 'e+' | 'e-' | 'expDigits'
|
|
150
152
|
* readonly value: string
|
|
153
|
+
* readonly b: ParseNumberBuffer
|
|
151
154
|
* }} ParseNumberState
|
|
152
155
|
*/
|
|
153
156
|
|
|
157
|
+
/**
|
|
158
|
+
* @typedef {{
|
|
159
|
+
* readonly s: -1n | 1n
|
|
160
|
+
* readonly m: bigint
|
|
161
|
+
* readonly f: number
|
|
162
|
+
* readonly es: -1 | 1
|
|
163
|
+
* readonly e: number
|
|
164
|
+
* }} ParseNumberBuffer
|
|
165
|
+
*/
|
|
166
|
+
|
|
154
167
|
/** @typedef {{ readonly kind: 'invalidNumber'}} InvalidNumberState */
|
|
155
168
|
|
|
156
169
|
/** @typedef {{ readonly kind: 'eof'}} EofState */
|
|
@@ -222,9 +235,30 @@ const create = def => a => {
|
|
|
222
235
|
return v => c => x(c)(i)(v)(c)
|
|
223
236
|
}
|
|
224
237
|
|
|
238
|
+
/** @type {(digit: number) => bigint} */
|
|
239
|
+
const digitToBigInt = d => BigInt(d - digit0)
|
|
240
|
+
|
|
241
|
+
/** @type {(digit: number) => ParseNumberBuffer} */
|
|
242
|
+
const startNumber = digit => ({ s: 1n, m: digitToBigInt(digit), f: 0, es: 1, e: 0 })
|
|
243
|
+
|
|
244
|
+
/** @type {ParseNumberBuffer} */
|
|
245
|
+
const startNegativeNumber = { s: -1n, m: 0n, f: 0, es: 1, e: 0 }
|
|
246
|
+
|
|
247
|
+
/** @type {(digit: number) => (b: ParseNumberBuffer) => ParseNumberBuffer} */
|
|
248
|
+
const addIntDigit = digit => b => ({ ... b, m: b.m * 10n + digitToBigInt(digit)})
|
|
249
|
+
|
|
250
|
+
/** @type {(digit: number) => (b: ParseNumberBuffer) => ParseNumberBuffer} */
|
|
251
|
+
const addFracDigit = digit => b => ({ ... b, m: b.m * 10n + digitToBigInt(digit), f: b.f - 1})
|
|
252
|
+
|
|
253
|
+
/** @type {(digit: number) => (b: ParseNumberBuffer) => ParseNumberBuffer} */
|
|
254
|
+
const addExpDigit = digit => b => ({ ... b, e: b.e * 10 + digit - digit0})
|
|
255
|
+
|
|
256
|
+
/** @type {(s: ParseNumberState) => NumberToken} */
|
|
257
|
+
const bufferToNumberToken = ({value, b}) => ({ kind: 'number', value: value, bf: [b.s * b.m, b.f + b.es * b.e] })
|
|
258
|
+
|
|
225
259
|
/** @type {(state: InitialState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
226
260
|
const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpected character' }], state])([
|
|
227
|
-
rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: fromCharCode(input), numberKind: 'int' }]),
|
|
261
|
+
rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: 'int' }]),
|
|
228
262
|
rangeFunc(latinSmallLetterRange)(() => input => [empty, { kind: 'keyword', value: fromCharCode(input) }]),
|
|
229
263
|
rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state]),
|
|
230
264
|
rangeFunc(one(leftCurlyBracket))(state => () => [[{ kind: '{' }], state]),
|
|
@@ -234,8 +268,8 @@ const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpe
|
|
|
234
268
|
rangeFunc(one(leftSquareBracket))(state => () => [[{ kind: '[' }], state]),
|
|
235
269
|
rangeFunc(one(rightSquareBracket))(state => () => [[{ kind: ']' }], state]),
|
|
236
270
|
rangeFunc(one(quotationMark))(() => () => [empty, { kind: 'string', value: '' }]),
|
|
237
|
-
rangeFunc(one(digit0))(() => input => [empty, { kind: 'number', value: fromCharCode(input), numberKind: '0' }]),
|
|
238
|
-
rangeFunc(one(hyphenMinus))(() => input => [empty, { kind: 'number', value: fromCharCode(input), numberKind: '-' }])
|
|
271
|
+
rangeFunc(one(digit0))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: '0' }]),
|
|
272
|
+
rangeFunc(one(hyphenMinus))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNegativeNumber, numberKind: '-' }])
|
|
239
273
|
])
|
|
240
274
|
|
|
241
275
|
/** @type {() => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
@@ -245,7 +279,7 @@ const invalidNumberToToken = () => input => tokenizeOp({ kind: 'invalidNumber' }
|
|
|
245
279
|
const fullStopToToken = state => input => {
|
|
246
280
|
switch (state.numberKind) {
|
|
247
281
|
case '0':
|
|
248
|
-
case 'int': return [empty, { kind: 'number', value: appendChar(state.value)(input), numberKind: '.' }]
|
|
282
|
+
case 'int': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: '.' }]
|
|
249
283
|
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
250
284
|
}
|
|
251
285
|
}
|
|
@@ -254,12 +288,14 @@ const fullStopToToken = state => input => {
|
|
|
254
288
|
const digit0ToToken = state => input => {
|
|
255
289
|
switch (state.numberKind) {
|
|
256
290
|
case '0': return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
257
|
-
case '-': return [empty, { kind: 'number', value: appendChar(state.value)(input), numberKind: '0' }]
|
|
258
|
-
case '.':
|
|
291
|
+
case '-': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: '0' }]
|
|
292
|
+
case '.':
|
|
293
|
+
case 'fractional': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addFracDigit(input)(state.b), numberKind: 'fractional' }]
|
|
259
294
|
case 'e':
|
|
260
295
|
case 'e+':
|
|
261
|
-
case 'e-':
|
|
262
|
-
|
|
296
|
+
case 'e-':
|
|
297
|
+
case 'expDigits': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addExpDigit(input)(state.b), numberKind: 'expDigits' }]
|
|
298
|
+
default: return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addIntDigit(input)(state.b), numberKind: state.numberKind }]
|
|
263
299
|
}
|
|
264
300
|
}
|
|
265
301
|
|
|
@@ -267,12 +303,13 @@ const digit0ToToken = state => input => {
|
|
|
267
303
|
const digit19ToToken = state => input => {
|
|
268
304
|
switch (state.numberKind) {
|
|
269
305
|
case '0': return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
270
|
-
case '
|
|
271
|
-
case '
|
|
306
|
+
case '.':
|
|
307
|
+
case 'fractional': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addFracDigit(input)(state.b), numberKind: 'fractional' }]
|
|
272
308
|
case 'e':
|
|
273
309
|
case 'e+':
|
|
274
|
-
case 'e-':
|
|
275
|
-
|
|
310
|
+
case 'e-':
|
|
311
|
+
case 'expDigits': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addExpDigit(input)(state.b), numberKind: 'expDigits' }]
|
|
312
|
+
default: return [empty, { kind: 'number', value: appendChar(state.value)(input), b: addIntDigit(input)(state.b), numberKind: 'int' }]
|
|
276
313
|
}
|
|
277
314
|
}
|
|
278
315
|
|
|
@@ -281,7 +318,7 @@ const expToToken = state => input => {
|
|
|
281
318
|
switch (state.numberKind) {
|
|
282
319
|
case '0':
|
|
283
320
|
case 'int':
|
|
284
|
-
case 'fractional': return [empty, { kind: 'number', value: appendChar(state.value)(input), numberKind: 'e' }]
|
|
321
|
+
case 'fractional': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: 'e' }]
|
|
285
322
|
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
286
323
|
}
|
|
287
324
|
}
|
|
@@ -289,7 +326,7 @@ const expToToken = state => input => {
|
|
|
289
326
|
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
290
327
|
const hyphenMinusToToken = state => input => {
|
|
291
328
|
switch (state.numberKind) {
|
|
292
|
-
case 'e': return [empty, { kind: 'number', value: appendChar(state.value)(input), numberKind: 'e-' }]
|
|
329
|
+
case 'e': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: { ... state.b, es: -1}, numberKind: 'e-' }]
|
|
293
330
|
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
294
331
|
}
|
|
295
332
|
}
|
|
@@ -297,7 +334,7 @@ const hyphenMinusToToken = state => input => {
|
|
|
297
334
|
/** @type {(state: ParseNumberState) => (input: number) => readonly[list.List<JsonToken>, TokenizerState]} */
|
|
298
335
|
const plusSignToToken = state => input => {
|
|
299
336
|
switch (state.numberKind) {
|
|
300
|
-
case 'e': return [empty, { kind: 'number', value: appendChar(state.value)(input), numberKind: 'e+' }]
|
|
337
|
+
case 'e': return [empty, { kind: 'number', value: appendChar(state.value)(input), b: state.b, numberKind: 'e+' }]
|
|
301
338
|
default: return tokenizeOp({ kind: 'invalidNumber' })(input)
|
|
302
339
|
}
|
|
303
340
|
}
|
|
@@ -317,7 +354,7 @@ const terminalToToken = state => input => {
|
|
|
317
354
|
default:
|
|
318
355
|
{
|
|
319
356
|
const next = tokenizeOp({ kind: 'initial' })(input)
|
|
320
|
-
return [{ first:
|
|
357
|
+
return [{ first: bufferToNumberToken(state), tail: next[0] }, next[1]]
|
|
321
358
|
}
|
|
322
359
|
}
|
|
323
360
|
}
|
|
@@ -441,7 +478,7 @@ const tokenizeEofOp = state => {
|
|
|
441
478
|
case 'e':
|
|
442
479
|
case 'e+':
|
|
443
480
|
case 'e-': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'invalidNumber', }]
|
|
444
|
-
default: return [[
|
|
481
|
+
default: return [[bufferToNumberToken(state)], { kind: 'eof' }]
|
|
445
482
|
}
|
|
446
483
|
case 'eof': return [[{ kind: 'error', message: 'eof' }], state]
|
|
447
484
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
const tokenizer = require('./module.f.cjs')
|
|
2
2
|
const { toArray, countdown } = require('../../types/list/module.f.cjs')
|
|
3
|
-
const
|
|
3
|
+
const fjson = require('../../fjson/module.f.cjs')
|
|
4
4
|
const { sort } = require('../../types/object/module.f.cjs')
|
|
5
5
|
const encoding = require('../../text/utf16/module.f.cjs');
|
|
6
6
|
|
|
7
7
|
/** @type {(s: string) => readonly tokenizer.JsonToken[]} */
|
|
8
8
|
const tokenizeString = s => toArray(tokenizer.tokenize(encoding.stringToList(s)))
|
|
9
9
|
|
|
10
|
-
const stringify =
|
|
10
|
+
const stringify = fjson.stringify(sort)
|
|
11
11
|
|
|
12
12
|
module.exports = {
|
|
13
13
|
testing: [
|
|
@@ -133,11 +133,11 @@ module.exports = {
|
|
|
133
133
|
},
|
|
134
134
|
() => {
|
|
135
135
|
const result = stringify(tokenizeString('0'))
|
|
136
|
-
if (result !== '[{"kind":"number","value":"0"}]') { throw result }
|
|
136
|
+
if (result !== '[{"bf":[0n,0],"kind":"number","value":"0"}]') { throw result }
|
|
137
137
|
},
|
|
138
138
|
() => {
|
|
139
139
|
const result = stringify(tokenizeString('[0]'))
|
|
140
|
-
if (result !== '[{"kind":"["},{"kind":"number","value":"0"},{"kind":"]"}]') { throw result }
|
|
140
|
+
if (result !== '[{"kind":"["},{"bf":[0n,0],"kind":"number","value":"0"},{"kind":"]"}]') { throw result }
|
|
141
141
|
},
|
|
142
142
|
() => {
|
|
143
143
|
const result = stringify(tokenizeString('00'))
|
|
@@ -148,20 +148,20 @@ module.exports = {
|
|
|
148
148
|
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":","}]') { throw result }
|
|
149
149
|
},
|
|
150
150
|
() => {
|
|
151
|
-
const result = stringify(tokenizeString('
|
|
152
|
-
if (result !== '[{"kind":"number","value":"
|
|
151
|
+
const result = stringify(tokenizeString('123456789012345678901234567890'))
|
|
152
|
+
if (result !== '[{"bf":[123456789012345678901234567890n,0],"kind":"number","value":"123456789012345678901234567890"}]') { throw result }
|
|
153
153
|
},
|
|
154
154
|
() => {
|
|
155
155
|
const result = stringify(tokenizeString('{90}'))
|
|
156
|
-
if (result !== '[{"kind":"{"},{"kind":"number","value":"90"},{"kind":"}"}]') { throw result }
|
|
156
|
+
if (result !== '[{"kind":"{"},{"bf":[90n,0],"kind":"number","value":"90"},{"kind":"}"}]') { throw result }
|
|
157
157
|
},
|
|
158
158
|
() => {
|
|
159
159
|
const result = stringify(tokenizeString('1 2'))
|
|
160
|
-
if (result !== '[{"kind":"number","value":"1"},{"kind":"number","value":"2"}]') { throw result }
|
|
160
|
+
if (result !== '[{"bf":[1n,0],"kind":"number","value":"1"},{"bf":[2n,0],"kind":"number","value":"2"}]') { throw result }
|
|
161
161
|
},
|
|
162
162
|
() => {
|
|
163
163
|
const result = stringify(tokenizeString('0. 2'))
|
|
164
|
-
if (result !== '[{"kind":"error","message":"invalid number"},{"kind":"number","value":"2"}]') { throw result }
|
|
164
|
+
if (result !== '[{"kind":"error","message":"invalid number"},{"bf":[2n,0],"kind":"number","value":"2"}]') { throw result }
|
|
165
165
|
},
|
|
166
166
|
() => {
|
|
167
167
|
const result = stringify(tokenizeString('10-0'))
|
|
@@ -173,11 +173,11 @@ module.exports = {
|
|
|
173
173
|
},
|
|
174
174
|
() => {
|
|
175
175
|
const result = stringify(tokenizeString('-10'))
|
|
176
|
-
if (result !== '[{"kind":"number","value":"-10"}]') { throw result }
|
|
176
|
+
if (result !== '[{"bf":[-10n,0],"kind":"number","value":"-10"}]') { throw result }
|
|
177
177
|
},
|
|
178
178
|
() => {
|
|
179
179
|
const result = stringify(tokenizeString('-0'))
|
|
180
|
-
if (result !== '[{"kind":"number","value":"-0"}]') { throw result }
|
|
180
|
+
if (result !== '[{"bf":[0n,0],"kind":"number","value":"-0"}]') { throw result }
|
|
181
181
|
},
|
|
182
182
|
() => {
|
|
183
183
|
const result = stringify(tokenizeString('-00'))
|
|
@@ -189,11 +189,11 @@ module.exports = {
|
|
|
189
189
|
},
|
|
190
190
|
() => {
|
|
191
191
|
const result = stringify(tokenizeString('0.01'))
|
|
192
|
-
if (result !== '[{"kind":"number","value":"0.01"}]') { throw result }
|
|
192
|
+
if (result !== '[{"bf":[1n,-2],"kind":"number","value":"0.01"}]') { throw result }
|
|
193
193
|
},
|
|
194
194
|
() => {
|
|
195
195
|
const result = stringify(tokenizeString('-0.9'))
|
|
196
|
-
if (result !== '[{"kind":"number","value":"-0.9"}]') { throw result }
|
|
196
|
+
if (result !== '[{"bf":[-9n,-1],"kind":"number","value":"-0.9"}]') { throw result }
|
|
197
197
|
},
|
|
198
198
|
() => {
|
|
199
199
|
const result = stringify(tokenizeString('-0.'))
|
|
@@ -205,11 +205,11 @@ module.exports = {
|
|
|
205
205
|
},
|
|
206
206
|
() => {
|
|
207
207
|
const result = stringify(tokenizeString('12.34'))
|
|
208
|
-
if (result !== '[{"kind":"number","value":"12.34"}]') { throw result }
|
|
208
|
+
if (result !== '[{"bf":[1234n,-2],"kind":"number","value":"12.34"}]') { throw result }
|
|
209
209
|
},
|
|
210
210
|
() => {
|
|
211
211
|
const result = stringify(tokenizeString('-12.00'))
|
|
212
|
-
if (result !== '[{"kind":"number","value":"-12.00"}]') { throw result }
|
|
212
|
+
if (result !== '[{"bf":[-1200n,-2],"kind":"number","value":"-12.00"}]') { throw result }
|
|
213
213
|
},
|
|
214
214
|
() => {
|
|
215
215
|
const result = stringify(tokenizeString('-12.'))
|
|
@@ -221,23 +221,27 @@ module.exports = {
|
|
|
221
221
|
},
|
|
222
222
|
() => {
|
|
223
223
|
const result = stringify(tokenizeString('0e1'))
|
|
224
|
-
if (result !== '[{"kind":"number","value":"0e1"}]') { throw result }
|
|
224
|
+
if (result !== '[{"bf":[0n,1],"kind":"number","value":"0e1"}]') { throw result }
|
|
225
225
|
},
|
|
226
226
|
() => {
|
|
227
227
|
const result = stringify(tokenizeString('0e+2'))
|
|
228
|
-
if (result !== '[{"kind":"number","value":"0e+2"}]') { throw result }
|
|
228
|
+
if (result !== '[{"bf":[0n,2],"kind":"number","value":"0e+2"}]') { throw result }
|
|
229
229
|
},
|
|
230
230
|
() => {
|
|
231
231
|
const result = stringify(tokenizeString('0e-0'))
|
|
232
|
-
if (result !== '[{"kind":"number","value":"0e-0"}]') { throw result }
|
|
232
|
+
if (result !== '[{"bf":[0n,0],"kind":"number","value":"0e-0"}]') { throw result }
|
|
233
233
|
},
|
|
234
234
|
() => {
|
|
235
235
|
const result = stringify(tokenizeString('12e0000'))
|
|
236
|
-
if (result !== '[{"kind":"number","value":"12e0000"}]') { throw result }
|
|
236
|
+
if (result !== '[{"bf":[12n,0],"kind":"number","value":"12e0000"}]') { throw result }
|
|
237
237
|
},
|
|
238
238
|
() => {
|
|
239
239
|
const result = stringify(tokenizeString('-12e-0001'))
|
|
240
|
-
if (result !== '[{"kind":"number","value":"-12e-0001"}]') { throw result }
|
|
240
|
+
if (result !== '[{"bf":[-12n,-1],"kind":"number","value":"-12e-0001"}]') { throw result }
|
|
241
|
+
},
|
|
242
|
+
() => {
|
|
243
|
+
const result = stringify(tokenizeString('-12.34e1234'))
|
|
244
|
+
if (result !== '[{"bf":[-1234n,1232],"kind":"number","value":"-12.34e1234"}]') { throw result }
|
|
241
245
|
},
|
|
242
246
|
() => {
|
|
243
247
|
const result = stringify(tokenizeString('0e'))
|
package/package.json
CHANGED
|
@@ -13,6 +13,9 @@ const abs = a => a >= 0 ? a : -a
|
|
|
13
13
|
/** @type {(a: bigint) => compare.Sign} */
|
|
14
14
|
const sign = a => unsafeCmp(a)(0n)
|
|
15
15
|
|
|
16
|
+
/** @type {(a: bigint) => string} */
|
|
17
|
+
const serialize = a => `${a}n`
|
|
18
|
+
|
|
16
19
|
module.exports = {
|
|
17
20
|
/** @readonly */
|
|
18
21
|
addition,
|
|
@@ -22,4 +25,6 @@ module.exports = {
|
|
|
22
25
|
abs,
|
|
23
26
|
/** @readonly */
|
|
24
27
|
sign,
|
|
28
|
+
/** @readonly */
|
|
29
|
+
serialize,
|
|
25
30
|
}
|
package/types/bigint/test.f.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { sum, abs } = require('./module.f.cjs')
|
|
1
|
+
const { sum, abs, serialize } = require('./module.f.cjs')
|
|
2
2
|
|
|
3
3
|
module.exports = {
|
|
4
4
|
sum: () => {
|
|
@@ -14,5 +14,19 @@ module.exports = {
|
|
|
14
14
|
const result = abs(-10n)
|
|
15
15
|
if (result !== 10n) { throw result }
|
|
16
16
|
}
|
|
17
|
+
],
|
|
18
|
+
serialize: [
|
|
19
|
+
() => {
|
|
20
|
+
const result = serialize(0n)
|
|
21
|
+
if (result !== '0n') { throw result }
|
|
22
|
+
},
|
|
23
|
+
() => {
|
|
24
|
+
const result = serialize(123456789012345678901234567890n)
|
|
25
|
+
if (result !== '123456789012345678901234567890n') { throw result }
|
|
26
|
+
},
|
|
27
|
+
() => {
|
|
28
|
+
const result = serialize(-55555n)
|
|
29
|
+
if (result !== '-55555n') { throw result }
|
|
30
|
+
},
|
|
17
31
|
]
|
|
18
32
|
}
|