functionalscript 0.0.387 → 0.0.390
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/doc/vm.md +111 -146
- package/html/module.f.cjs +2 -1
- package/json/tokenizer/test.f.cjs +2 -1
- package/package.json +1 -1
- package/text/encoding/module.f.cjs +24 -6
- package/text/encoding/test.f.cjs +14 -0
- package/types/list/module.f.cjs +1 -17
- package/types/list/test.f.cjs +1 -5
package/doc/vm.md
CHANGED
|
@@ -1,17 +1,35 @@
|
|
|
1
|
-
#
|
|
1
|
+
# NaNVM
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
https://en.wikipedia.org/wiki/Double-precision_floating-point_format
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
https://anniecherkaev.com/the-secret-life-of-nan
|
|
6
|
+
https://brionv.com/log/2018/05/17/javascript-engine-internals-nan-boxing/
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
|
|
9
|
+
- 1 bit - sign (S)
|
|
10
|
+
- 11 bit - exponent (E)
|
|
11
|
+
- 52 bit - fraction (F)
|
|
12
|
+
|
|
13
|
+
|SE |F |Value |
|
|
14
|
+
|---|--------------|----------------|
|
|
15
|
+
|000|00000_00000000|+000000_00000000|
|
|
16
|
+
|...| | |
|
|
17
|
+
|3FF|00000_00000000|+000000_00000001|
|
|
18
|
+
|...| | |
|
|
19
|
+
|434|00000_00000000|+200000_00000000|
|
|
20
|
+
|...| | |
|
|
21
|
+
|7FF|00000_00000000|+inf |
|
|
22
|
+
|...| |NaN |
|
|
23
|
+
|800|00000_00000000|-0.0 |
|
|
24
|
+
|...| | |
|
|
25
|
+
|BFF|00000_00000000|-000000_00000001|
|
|
26
|
+
|...| | |
|
|
27
|
+
|C34|00000_00000000|-200000_00000000|
|
|
28
|
+
|...| | |
|
|
29
|
+
|FFF|00000_00000000|-inf |
|
|
30
|
+
|...| |NaN |
|
|
31
|
+
|
|
32
|
+
integer range: `[-2^53; +2^53]`.
|
|
15
33
|
|
|
16
34
|
## 6-bit Id String
|
|
17
35
|
|
|
@@ -23,143 +41,90 @@
|
|
|
23
41
|
|`_` |`\x5F` | 1| 26|
|
|
24
42
|
|`a`..`z`|`\x61`..`\x7A`|1A| 40|
|
|
25
43
|
|
|
26
|
-
##
|
|
27
|
-
|
|
28
|
-
Alignment: 8 bytes.
|
|
29
|
-
|
|
30
|
-
Pointer: 2^64 / 2^3 = 2^61 bit
|
|
31
|
-
|
|
32
|
-
### Value
|
|
33
|
-
|
|
34
|
-
- `63`: 9 x 7 bit string
|
|
35
|
-
- `63`:
|
|
36
|
-
- `61`: pointer + null, alignment - 8 bytes
|
|
37
|
-
- `61`:
|
|
38
|
-
- `60`: 4 x 15 bit string
|
|
39
|
-
- `60`: 10 x 6 bit string
|
|
40
|
-
- `61`:
|
|
41
|
-
- `60`: 6 x 10 bit string
|
|
42
|
-
- `60`: 5 x 12 bit string
|
|
43
|
-
- `61`
|
|
44
|
-
- `60`: float60
|
|
45
|
-
- `60`:
|
|
46
|
-
- `59`: bigInt59 (-576_460_752_303_423_488..576_460_752_303_423_487)
|
|
47
|
-
- `59`:
|
|
48
|
-
- `56`: 8 x 7-bit string
|
|
49
|
-
- `56`: 7 x 8-bit string
|
|
50
|
-
- `53`: int53
|
|
51
|
-
- `53`: stringUInt53
|
|
52
|
-
- `48`: 3 x 16 bit string
|
|
53
|
-
- `32`: 2 x 16 bit string
|
|
54
|
-
- `16`: 1 x UTF16 string
|
|
55
|
-
- `3`: common
|
|
56
|
-
|
|
57
|
-
## Float64
|
|
44
|
+
## 7FF & FFF
|
|
58
45
|
|
|
59
|
-
|
|
46
|
+
53 bits.
|
|
60
47
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
-
|
|
48
|
+
Other values:
|
|
49
|
+
|
|
50
|
+
- `NaN`
|
|
51
|
+
- `+Inf`: 0x7FF00000_00000000
|
|
52
|
+
- `-Inf`: 0xFFF00000_00000000
|
|
53
|
+
- pointer + null:
|
|
54
|
+
- 32 bit for 32 bit platforms.
|
|
55
|
+
- 48 bit for current AMD64 https://en.wikipedia.org/wiki/X86-64#Canonical_form_addresses and ARM64
|
|
56
|
+
note: with alignments it can be further narrowed to 44-45 bit.
|
|
57
|
+
- `true`
|
|
58
|
+
- `false`
|
|
59
|
+
- `undefined`
|
|
64
60
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
-
|
|
81
|
-
-
|
|
82
|
-
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
```
|
|
134
|
-
|
|
135
|
-
### BigInt
|
|
136
|
-
|
|
137
|
-
```rust
|
|
138
|
-
struct BigInt {
|
|
139
|
-
length: u32,
|
|
140
|
-
array: [u64; self.length],
|
|
141
|
-
}
|
|
142
|
-
```
|
|
143
|
-
|
|
144
|
-
### Array
|
|
145
|
-
|
|
146
|
-
```rust
|
|
147
|
-
struct Array {
|
|
148
|
-
length: u32,
|
|
149
|
-
array: [Value; self.length],
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
### Object
|
|
154
|
-
|
|
155
|
-
```rust
|
|
156
|
-
struct Object {
|
|
157
|
-
length: u32,
|
|
158
|
-
array: [(Value, Value), self.length],
|
|
159
|
-
indexArray: [u32, (self.length * log2(self.length) + 31) / u32],
|
|
160
|
-
}
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
Note: see https://262.ecma-international.org/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys and https://262.ecma-international.org/6.0/#sec-object-type
|
|
61
|
+
Optimization for
|
|
62
|
+
- string
|
|
63
|
+
- bigInt
|
|
64
|
+
|
|
65
|
+
Least used letters in English: Q, J, Z and X.
|
|
66
|
+
|
|
67
|
+
### Layout 52
|
|
68
|
+
|
|
69
|
+
Starts with `0xFFF`
|
|
70
|
+
|
|
71
|
+
- `50`:
|
|
72
|
+
- `48`: stringUInt48 (0..281_474_976_710_655)
|
|
73
|
+
- `48`: 8 x 6 string
|
|
74
|
+
- `48`: `42` 7 x 6 string
|
|
75
|
+
- `48`: 6 x 8 string
|
|
76
|
+
- `50`:
|
|
77
|
+
- `48`: `45` 5 x 9 string
|
|
78
|
+
- `48`: 4 x 12 string
|
|
79
|
+
- `48`: 3 x 16 string
|
|
80
|
+
- `48`: `32`: 2 x 16 string
|
|
81
|
+
- `50`:
|
|
82
|
+
- `48`: `16`: 1 x 16 string
|
|
83
|
+
- `48`: `0`: ""
|
|
84
|
+
- `48`: false
|
|
85
|
+
- `48`: true
|
|
86
|
+
- `50`:
|
|
87
|
+
- `48`: ptr
|
|
88
|
+
- `48`: bigInt48 (140_737_488_355_328..140_737_488_355_327)
|
|
89
|
+
- `48`: undefined
|
|
90
|
+
- `48`: `-inf`
|
|
91
|
+
|
|
92
|
+
| | | |type |
|
|
93
|
+
|------|--|-------------|-----------|
|
|
94
|
+
|`1111`|48|stringUInt48 |`string` |
|
|
95
|
+
|`1110`|48|8 x 6 string | |
|
|
96
|
+
|`1101`|48|7 x 7 stringA| |
|
|
97
|
+
|`1100`|48|7 x 7 stringB| |
|
|
98
|
+
|`1011`|48|6 x 8 string | |
|
|
99
|
+
|`1010`|45|5 x 9 string | |
|
|
100
|
+
|`1001`|48|4 x 12 string| |
|
|
101
|
+
|`1000`|48|3 x 16 string| |
|
|
102
|
+
|`0111`|32|2 x 16 string| |
|
|
103
|
+
|`0110`|16|1 x 16 string| |
|
|
104
|
+
|`0101`| 0|empty string | |
|
|
105
|
+
|`0100`| 0|undefined |`undefined`|
|
|
106
|
+
|`0011`|48|ptr |... |
|
|
107
|
+
|`0010`|48|bigInt48 |`bigint` |
|
|
108
|
+
|`0001`| 0|bool |`bool` |
|
|
109
|
+
|`0000`| 0|-inf |`number` |
|
|
110
|
+
|
|
111
|
+
## Pointer Kind
|
|
112
|
+
|
|
113
|
+
Alignment 8 bytes. 3 bits.
|
|
114
|
+
|
|
115
|
+
| |type | |
|
|
116
|
+
|----|----------|---------------|
|
|
117
|
+
|00.0|`object` |null |
|
|
118
|
+
|00.1| |object |
|
|
119
|
+
|01.0|`string` |string |
|
|
120
|
+
|01.1| | |
|
|
121
|
+
|10.0|`function`|function |
|
|
122
|
+
|10.1| |static function|
|
|
123
|
+
|11.0|`bigint` |bigint |
|
|
124
|
+
|11.1| | |
|
|
125
|
+
|
|
126
|
+
## Order of object properties
|
|
127
|
+
|
|
128
|
+
See https://262.ecma-international.org/6.0/#sec-ordinary-object-internal-methods-and-internal-slots-ownpropertykeys and https://262.ecma-international.org/6.0/#sec-object-type
|
|
164
129
|
|
|
165
130
|
An integer index for Node.js, Deno and Bun means a value from `0` to `4294967294` including. 4_294_967_294 = 0xFFFF_FFFE. But an integer index in the ES6 standard is +0..2^53-1.
|
package/html/module.f.cjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const list = require('../types/list/module.f.cjs')
|
|
2
2
|
const object = require('../types/object/module.f.cjs')
|
|
3
3
|
const { operator, compose } = require('../types/function/module.f.cjs')
|
|
4
|
+
const encoding = require('../text/encoding/module.f.cjs');
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* @typedef {|
|
|
@@ -73,7 +74,7 @@ const escapeCharCode = code => {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
|
|
76
|
-
const escape = compose(
|
|
77
|
+
const escape = compose(encoding.stringToUtf16List)(list.map(escapeCharCode))
|
|
77
78
|
|
|
78
79
|
/** @type {(n: Node) => list.List<string>} */
|
|
79
80
|
const node = n => typeof n === 'string' ? escape(n) : element(n)
|
|
@@ -2,9 +2,10 @@ const tokenizer = require('./module.f.cjs')
|
|
|
2
2
|
const list = require('../../types/list/module.f.cjs')
|
|
3
3
|
const json = require('../module.f.cjs')
|
|
4
4
|
const { sort } = require('../../types/object/module.f.cjs')
|
|
5
|
+
const encoding = require('../../text/encoding/module.f.cjs');
|
|
5
6
|
|
|
6
7
|
/** @type {(s: string) => readonly tokenizer.JsonToken[]} */
|
|
7
|
-
const tokenizeString = s => list.toArray(tokenizer.tokenize(
|
|
8
|
+
const tokenizeString = s => list.toArray(tokenizer.tokenize(encoding.stringToUtf16List(s)))
|
|
8
9
|
|
|
9
10
|
const stringify = json.stringify(sort)
|
|
10
11
|
|
package/package.json
CHANGED
|
@@ -3,6 +3,8 @@ const list = require('../../types/list/module.f.cjs')
|
|
|
3
3
|
const operator = require('../../types/function/operator/module.f.cjs')
|
|
4
4
|
const array = require('../../types/array/module.f.cjs')
|
|
5
5
|
const { contains } = require('../../types/range/module.f.cjs')
|
|
6
|
+
const { compose } = require('../../types/function/module.f.cjs')
|
|
7
|
+
const { map, flat, stateScan, concat, fold, toArray, flatMap } = list
|
|
6
8
|
const { ok, error } = result
|
|
7
9
|
|
|
8
10
|
/** @typedef {result.Result<number,number>} ByteResult */
|
|
@@ -54,10 +56,10 @@ const codePointToUtf16 = input =>
|
|
|
54
56
|
}
|
|
55
57
|
|
|
56
58
|
/** @type {(input: list.List<number>) => list.List<ByteResult>} */
|
|
57
|
-
const codePointListToUtf8List =
|
|
59
|
+
const codePointListToUtf8List = flatMap(codePointToUtf8)
|
|
58
60
|
|
|
59
61
|
/** @type {(input: list.List<i32>) => list.List<u16>} */
|
|
60
|
-
const codePointListToUtf16List =
|
|
62
|
+
const codePointListToUtf16List = flatMap(codePointToUtf16)
|
|
61
63
|
|
|
62
64
|
/** @type {operator.StateScan<number, Utf8State, list.List<CodePointResult>>} */
|
|
63
65
|
const utf8ByteToCodePointOp = state => byte => {
|
|
@@ -85,7 +87,7 @@ const utf8ByteToCodePointOp = state => byte => {
|
|
|
85
87
|
return [[ok(((state[0] & 0x07) << 18) + ((state[1] & 0x3f) << 12) + ((state[2] & 0x3f) << 6) + (byte & 0x3f))], undefined]
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
|
-
return [[error(
|
|
90
|
+
return [[error(toArray(concat(state)([byte])))], undefined]
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
/** @type {(state: Utf8State) => readonly[list.List<CodePointResult>, Utf8State]} */
|
|
@@ -95,7 +97,7 @@ const utf8EofToCodePointOp = state => [state === undefined ? undefined : [error(
|
|
|
95
97
|
const utf8ByteOrEofToCodePointOp = state => input => input === undefined ? utf8EofToCodePointOp(state) : utf8ByteToCodePointOp(state)(input)
|
|
96
98
|
|
|
97
99
|
/** @type {(input: list.List<number>) => list.List<CodePointResult>} */
|
|
98
|
-
const utf8ListToCodePointList = input =>
|
|
100
|
+
const utf8ListToCodePointList = input => flat(stateScan(utf8ByteOrEofToCodePointOp)(undefined)(concat(/** @type {list.List<ByteOrEof>} */(input))([undefined])))
|
|
99
101
|
|
|
100
102
|
/** @type {operator.StateScan<u16, Utf16State, list.List<i32>>} */
|
|
101
103
|
const utf16ByteToCodePointOp = state => byte => {
|
|
@@ -124,7 +126,19 @@ const utf16EofToCodePointOp = state => [state === undefined ? undefined : [state
|
|
|
124
126
|
const utf16ByteOrEofToCodePointOp = state => input => input === undefined ? utf16EofToCodePointOp(state) : utf16ByteToCodePointOp(state)(input)
|
|
125
127
|
|
|
126
128
|
/** @type {(input: list.List<u16>) => list.List<i32>} */
|
|
127
|
-
const utf16ListToCodePointList = input =>
|
|
129
|
+
const utf16ListToCodePointList = input => flat(stateScan(utf16ByteOrEofToCodePointOp)(undefined)(concat(/** @type {list.List<WordOrEof>} */(input))([undefined])))
|
|
130
|
+
|
|
131
|
+
/** @type {(s: string) => list.List<u16>} */
|
|
132
|
+
const stringToUtf16List = s => {
|
|
133
|
+
/** @type {(i: number) => list.Result<number>} */
|
|
134
|
+
const at = i => {
|
|
135
|
+
const first = s.charCodeAt(i)
|
|
136
|
+
return isNaN(first) ? undefined : { first, tail: () => at(i + 1) }
|
|
137
|
+
}
|
|
138
|
+
return at(0)
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const utf16ListToString = compose(map(String.fromCharCode))(fold(operator.concat)(''))
|
|
128
142
|
|
|
129
143
|
module.exports = {
|
|
130
144
|
/** @readonly */
|
|
@@ -134,5 +148,9 @@ module.exports = {
|
|
|
134
148
|
/** @readonly */
|
|
135
149
|
utf8ListToCodePointList,
|
|
136
150
|
/** @readonly */
|
|
137
|
-
utf16ListToCodePointList
|
|
151
|
+
utf16ListToCodePointList,
|
|
152
|
+
/** @readonly */
|
|
153
|
+
stringToUtf16List,
|
|
154
|
+
/** @readonly */
|
|
155
|
+
utf16ListToString
|
|
138
156
|
}
|
package/text/encoding/test.f.cjs
CHANGED
|
@@ -206,4 +206,18 @@ const stringify = a => json.stringify(sort)(a)
|
|
|
206
206
|
if (result !== '[-2147427328,0]') { throw result }
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
{
|
|
210
|
+
const utf16List = encoding.stringToUtf16List("Hello world!😂🚜🚲")
|
|
211
|
+
const result = encoding.utf16ListToString(utf16List)
|
|
212
|
+
if (result !== "Hello world!😂🚜🚲") { throw result }
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
{
|
|
216
|
+
const a = encoding.stringToUtf16List("Hello world!😂🚜🚲")
|
|
217
|
+
const b = encoding.utf16ListToCodePointList(a)
|
|
218
|
+
const c = encoding.codePointListToUtf16List(b)
|
|
219
|
+
const result = encoding.utf16ListToString(c)
|
|
220
|
+
if (result !== "Hello world!😂🚜🚲") { throw result }
|
|
221
|
+
}
|
|
222
|
+
|
|
209
223
|
module.exports = {}
|
package/types/list/module.f.cjs
CHANGED
|
@@ -296,18 +296,6 @@ const equalZip = e => a => b => () => {
|
|
|
296
296
|
/** @type {<T>(e: operator.Equal<T>) => (a: List<T>) => (b: List<T>) => boolean} */
|
|
297
297
|
const equal = e => a => b => every(equalZip(e)(a)(b))
|
|
298
298
|
|
|
299
|
-
/** @type {(s: string) => List<number>} */
|
|
300
|
-
const toCharCodeList = s => {
|
|
301
|
-
/** @type {(i: number) => Result<number>} */
|
|
302
|
-
const at = i => {
|
|
303
|
-
const first = s.charCodeAt(i)
|
|
304
|
-
return isNaN(first) ? undefined : { first, tail: () => at(i + 1) }
|
|
305
|
-
}
|
|
306
|
-
return at(0)
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const fromCharCodeList = compose(map(String.fromCharCode))(fold(operator.concat)(''))
|
|
310
|
-
|
|
311
299
|
module.exports = {
|
|
312
300
|
/** @readonly */
|
|
313
301
|
empty: undefined,
|
|
@@ -384,9 +372,5 @@ module.exports = {
|
|
|
384
372
|
/** @readonly */
|
|
385
373
|
zip,
|
|
386
374
|
/** @readonly */
|
|
387
|
-
equal
|
|
388
|
-
/** @readonly */
|
|
389
|
-
toCharCodeList,
|
|
390
|
-
/** @readonly */
|
|
391
|
-
fromCharCodeList,
|
|
375
|
+
equal
|
|
392
376
|
}
|
package/types/list/test.f.cjs
CHANGED
|
@@ -236,11 +236,7 @@ const map5 = _.map(x => x > 5)
|
|
|
236
236
|
if (result !== false) { throw result }
|
|
237
237
|
}
|
|
238
238
|
|
|
239
|
-
|
|
240
|
-
const r = _.toCharCodeList("Hello world!")
|
|
241
|
-
const x = _.fromCharCodeList(r)
|
|
242
|
-
if (x !== "Hello world!") { throw x }
|
|
243
|
-
}
|
|
239
|
+
|
|
244
240
|
|
|
245
241
|
// stress tests
|
|
246
242
|
|