functionalscript 0.2.4 → 0.2.5
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/CHANGELOG.md +6 -0
- package/README.md +1 -1
- package/crypto/README.md +3 -0
- package/{prime_field → crypto/prime_field}/module.f.mjs +2 -2
- package/{secp → crypto/secp}/module.f.mjs +2 -2
- package/{sha2 → crypto/sha2}/module.f.mjs +4 -4
- package/{sha2 → crypto/sha2}/test.f.mjs +2 -2
- package/djs/module.f.mjs +4 -1
- package/djs/parser/module.f.mjs +122 -45
- package/djs/parser/test.f.mjs +30 -4
- package/djs/tokenizer/module.f.mjs +6 -2
- package/djs/tokenizer/test.f.mjs +34 -0
- package/html/module.f.mjs +18 -33
- package/html/test.f.mjs +6 -6
- package/issues/05-publish.md +17 -22
- package/issues/README.md +10 -2
- package/js/tokenizer/module.f.mjs +75 -26
- package/js/tokenizer/test.f.mjs +42 -0
- package/json/parser/test.f.mjs +6 -0
- package/jsr.json +4 -4
- package/nanvm-lib/src/extension.rs +1 -1
- package/nanvm-lib/src/nanenum.rs +22 -20
- package/out/{prime_field → crypto/prime_field}/module.f.d.mts +1 -1
- package/out/{prime_field → crypto/prime_field}/module.f.mjs +2 -2
- package/out/{secp → crypto/secp}/module.f.d.mts +1 -1
- package/out/{secp → crypto/secp}/module.f.mjs +2 -2
- package/out/{sha2 → crypto/sha2}/module.f.d.mts +3 -3
- package/out/{sha2 → crypto/sha2}/module.f.mjs +4 -4
- package/out/{sha2 → crypto/sha2}/test.f.mjs +2 -2
- package/out/djs/module.f.d.mts +1 -1
- package/out/djs/module.f.mjs +5 -1
- package/out/djs/parser/module.f.d.mts +1 -1
- package/out/djs/parser/module.f.mjs +105 -89
- package/out/djs/parser/test.f.d.mts +1 -0
- package/out/djs/parser/test.f.mjs +38 -4
- package/out/djs/tokenizer/module.f.d.mts +2 -2
- package/out/djs/tokenizer/module.f.mjs +6 -2
- package/out/djs/tokenizer/test.f.d.mts +1 -0
- package/out/djs/tokenizer/test.f.mjs +50 -0
- package/out/html/module.f.d.mts +8 -6
- package/out/html/module.f.mjs +17 -31
- package/out/html/test.f.mjs +5 -5
- package/out/js/tokenizer/module.f.d.mts +15 -3
- package/out/js/tokenizer/module.f.mjs +65 -22
- package/out/js/tokenizer/test.f.d.mts +1 -0
- package/out/js/tokenizer/test.f.mjs +62 -0
- package/out/json/parser/test.f.mjs +8 -0
- package/package.json +1 -1
- /package/{prime_field → crypto/prime_field}/test.f.mjs +0 -0
- /package/{secp → crypto/secp}/test.f.mjs +0 -0
- /package/out/{prime_field → crypto/prime_field}/test.f.d.mts +0 -0
- /package/out/{prime_field → crypto/prime_field}/test.f.mjs +0 -0
- /package/out/{secp → crypto/secp}/test.f.d.mts +0 -0
- /package/out/{secp → crypto/secp}/test.f.mjs +0 -0
- /package/out/{sha2 → crypto/sha2}/test.f.d.mts +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.2.5
|
|
11
|
+
|
|
12
|
+
- new [crypto/] directory [PR #327](https://github.com/functionalscript/functionalscript/pull/327).
|
|
13
|
+
- simplified HTML [PR #327](https://github.com/functionalscript/functionalscript/pull/327).
|
|
14
|
+
- djs: add undefined and comments [PR #325](https://github.com/functionalscript/functionalscript/pull/325).
|
|
15
|
+
|
|
10
16
|
## 0.2.3
|
|
11
17
|
|
|
12
18
|
- BitVec and documentation update [PR #322](https://github.com/functionalscript/functionalscript/pull/322).
|
package/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Learn more about
|
|
|
18
18
|
- [Purely Functional Programming in JavaScript](https://blog.bitsrc.io/purely-functional-programming-in-javascript-91114b1b2dff?sk=5f7132e56902f38fcf4c6164bfa681ed),
|
|
19
19
|
- [FunctionalScript and I/O](https://medium.com/@sergeyshandar/functionalscript-5cf817345376?sk=30b32189a81d1a2dad16c2244f32328d).
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
This repository is a [monorepo](https://en.wikipedia.org/wiki/Monorepo) and distributted under under [AGPL-3.0](https://www.gnu.org/licenses/agpl-3.0.en.html#license-text). Let us know if you need another license by sending an [email](mailto:sergey.oss@proton.me).
|
|
22
22
|
|
|
23
23
|
## Vision
|
|
24
24
|
|
package/crypto/README.md
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// @ts-self-types="./module.f.d.mts"
|
|
2
|
-
import * as Operator from '
|
|
3
|
-
import * as bi from '
|
|
2
|
+
import * as Operator from '../../types/function/operator/module.f.mjs'
|
|
3
|
+
import * as bi from '../../types/bigint/module.f.mjs'
|
|
4
4
|
const { scalar_mul } = bi
|
|
5
5
|
|
|
6
6
|
/** @typedef {Operator.Reduce<bigint>} Reduce */
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// @ts-self-types="./module.f.d.mts"
|
|
2
|
-
import * as Operator from '
|
|
2
|
+
import * as Operator from '../../types/function/operator/module.f.mjs'
|
|
3
3
|
import * as pf from '../prime_field/module.f.mjs'
|
|
4
|
-
import * as bi from '
|
|
4
|
+
import * as bi from '../../types/bigint/module.f.mjs'
|
|
5
5
|
const { scalar_mul } = bi
|
|
6
6
|
const { prime_field, sqrt } = pf
|
|
7
7
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// @ts-self-types="./module.f.d.mts"
|
|
2
|
-
import * as
|
|
2
|
+
import * as array from '../../types/array/module.f.mjs'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* @typedef {{
|
|
@@ -8,9 +8,9 @@ import * as arrayT from '../types/array/module.f.mjs'
|
|
|
8
8
|
* }} HashInput
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
/** @typedef {
|
|
11
|
+
/** @typedef {array.Array8<number>} Hash8 */
|
|
12
12
|
|
|
13
|
-
/** @typedef {
|
|
13
|
+
/** @typedef {array.Array16<number>} Array16 */
|
|
14
14
|
|
|
15
15
|
/** @type {(input: number) => (pos: number) => number} */
|
|
16
16
|
const appendOneWithZeros = input => pos => (input >> pos << pos) | (1 << pos)
|
|
@@ -74,7 +74,7 @@ const smallSigma0 = smallSigma(7)(18)(3)
|
|
|
74
74
|
|
|
75
75
|
const smallSigma1 = smallSigma(17)(19)(10)
|
|
76
76
|
|
|
77
|
-
/** @type {(a:
|
|
77
|
+
/** @type {(a: array.Array4<number>) => number} */
|
|
78
78
|
const wi = ([a0, a1, a2, a3]) => (smallSigma1(a0) + a1 + smallSigma0(a2) + a3) | 0
|
|
79
79
|
|
|
80
80
|
/** @type {(w: Array16) => Array16} */
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as _ from './module.f.mjs'
|
|
2
|
-
import * as json from '
|
|
3
|
-
import * as o from '
|
|
2
|
+
import * as json from '../../json/module.f.mjs'
|
|
3
|
+
import * as o from '../../types/object/module.f.mjs'
|
|
4
4
|
const { sort } = o
|
|
5
5
|
|
|
6
6
|
/** @type {(a: number) => number} */
|
package/djs/module.f.mjs
CHANGED
|
@@ -21,10 +21,12 @@ const { objectWrap, arrayWrap, stringSerialize, numberSerialize, nullSerialize,
|
|
|
21
21
|
|
|
22
22
|
/** @typedef {readonly Unknown[]} Array */
|
|
23
23
|
|
|
24
|
-
/** @typedef {Object|boolean|string|number|null|Array|bigint} Unknown */
|
|
24
|
+
/** @typedef {Object|boolean|string|number|null|Array|bigint|undefined} Unknown */
|
|
25
25
|
|
|
26
26
|
const colon = [':']
|
|
27
27
|
|
|
28
|
+
const undefinedSerialize = ['undefined']
|
|
29
|
+
|
|
28
30
|
/** @typedef {O.Entry<Unknown>} Entry*/
|
|
29
31
|
|
|
30
32
|
/** @typedef {(list.List<Entry>)} Entries */
|
|
@@ -55,6 +57,7 @@ export const serialize = sort => {
|
|
|
55
57
|
case 'bigint': { return [bigintSerialize(value)] }
|
|
56
58
|
default: {
|
|
57
59
|
if (value === null) { return nullSerialize }
|
|
60
|
+
if (value === undefined) { return undefinedSerialize }
|
|
58
61
|
if (value instanceof Array) { return arraySerialize(value) }
|
|
59
62
|
return objectSerialize(value)
|
|
60
63
|
}
|
package/djs/parser/module.f.mjs
CHANGED
|
@@ -12,7 +12,7 @@ const { fromMap } = o
|
|
|
12
12
|
|
|
13
13
|
/** @typedef {[readonly string[], readonly DjsConst[]] } DjsModule */
|
|
14
14
|
|
|
15
|
-
/** @typedef {boolean|string|number|null|bigint|DjsModuleRef|DjsArray|DjsObject} DjsConst */
|
|
15
|
+
/** @typedef {boolean|string|number|null|bigint|undefined|DjsModuleRef|DjsArray|DjsObject} DjsConst */
|
|
16
16
|
|
|
17
17
|
/** @typedef {['aref' | 'cref', number]} DjsModuleRef */
|
|
18
18
|
|
|
@@ -113,7 +113,9 @@ const parseInitialOp = token => state => {
|
|
|
113
113
|
switch (token.kind)
|
|
114
114
|
{
|
|
115
115
|
case 'ws':
|
|
116
|
-
case 'nl':
|
|
116
|
+
case 'nl':
|
|
117
|
+
case '//':
|
|
118
|
+
case '/*': return state
|
|
117
119
|
case 'id': {
|
|
118
120
|
switch (token.value) {
|
|
119
121
|
case 'import': return { ... state, state: 'import' }
|
|
@@ -128,7 +130,9 @@ const parseInitialOp = token => state => {
|
|
|
128
130
|
/** @type {(token: tokenizerT.DjsToken) => (state: NewLineRequiredState) => ParserState}} */
|
|
129
131
|
const parseNewLineRequiredOp = token => state => {
|
|
130
132
|
switch (token.kind) {
|
|
131
|
-
case 'ws':
|
|
133
|
+
case 'ws':
|
|
134
|
+
case '//':
|
|
135
|
+
case '/*': return state
|
|
132
136
|
case 'nl': return { ... state, state: '' }
|
|
133
137
|
default: return { state: 'error', message: 'unexpected token' }
|
|
134
138
|
}
|
|
@@ -138,7 +142,9 @@ const parseNewLineRequiredOp = token => state => {
|
|
|
138
142
|
const parseExportOp = token => state => {
|
|
139
143
|
switch (token.kind) {
|
|
140
144
|
case 'ws':
|
|
141
|
-
case 'nl':
|
|
145
|
+
case 'nl':
|
|
146
|
+
case '//':
|
|
147
|
+
case '/*': return state
|
|
142
148
|
case 'id': {
|
|
143
149
|
if (token.value === 'default') return { ... state, state: 'exportValue', valueState: '', top: null, stack: null }
|
|
144
150
|
}
|
|
@@ -146,11 +152,24 @@ const parseExportOp = token => state => {
|
|
|
146
152
|
return { state: 'error', message: 'unexpected token' }
|
|
147
153
|
}
|
|
148
154
|
|
|
155
|
+
/** @type {(token: tokenizerT.DjsToken) => (state: ResultState) => ParserState}} */
|
|
156
|
+
const parseResultOp = token => state => {
|
|
157
|
+
switch (token.kind) {
|
|
158
|
+
case 'ws':
|
|
159
|
+
case 'nl':
|
|
160
|
+
case '//':
|
|
161
|
+
case '/*': return state
|
|
162
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
149
166
|
/** @type {(token: tokenizerT.DjsToken) => (state: ConstState) => ParserState}} */
|
|
150
167
|
const parseConstOp = token => state => {
|
|
151
168
|
switch (token.kind) {
|
|
152
169
|
case 'ws':
|
|
153
|
-
case 'nl':
|
|
170
|
+
case 'nl':
|
|
171
|
+
case '//':
|
|
172
|
+
case '/*': return state
|
|
154
173
|
case 'id': {
|
|
155
174
|
if (map.at(token.value)(state.module.refs) !== null)
|
|
156
175
|
return { state: 'error', message: 'duplicate id' }
|
|
@@ -167,7 +186,9 @@ const parseConstOp = token => state => {
|
|
|
167
186
|
const parseConstNameOp = token => state => {
|
|
168
187
|
switch (token.kind) {
|
|
169
188
|
case 'ws':
|
|
170
|
-
case 'nl':
|
|
189
|
+
case 'nl':
|
|
190
|
+
case '//':
|
|
191
|
+
case '/*': return state
|
|
171
192
|
case '=': return { ... state, state: 'constValue', valueState: '', top: null, stack: null }
|
|
172
193
|
default: return { state: 'error', message: 'unexpected token' }
|
|
173
194
|
}
|
|
@@ -177,7 +198,9 @@ const parseConstNameOp = token => state => {
|
|
|
177
198
|
const parseImportOp = token => state => {
|
|
178
199
|
switch (token.kind) {
|
|
179
200
|
case 'ws':
|
|
180
|
-
case 'nl':
|
|
201
|
+
case 'nl':
|
|
202
|
+
case '//':
|
|
203
|
+
case '/*': return state
|
|
181
204
|
case 'id': {
|
|
182
205
|
if (map.at(token.value)(state.module.refs) !== null)
|
|
183
206
|
return { state: 'error', message: 'duplicate id' }
|
|
@@ -194,7 +217,9 @@ const parseImportOp = token => state => {
|
|
|
194
217
|
const parseImportNameOp = token => state => {
|
|
195
218
|
switch (token.kind) {
|
|
196
219
|
case 'ws':
|
|
197
|
-
case 'nl':
|
|
220
|
+
case 'nl':
|
|
221
|
+
case '//':
|
|
222
|
+
case '/*': return state
|
|
198
223
|
case 'id': {
|
|
199
224
|
if (token.value === 'from') return { ... state, state: 'import+from' }
|
|
200
225
|
}
|
|
@@ -206,7 +231,9 @@ const parseImportNameOp = token => state => {
|
|
|
206
231
|
const parseImportFromOp = token => state => {
|
|
207
232
|
switch (token.kind) {
|
|
208
233
|
case 'ws':
|
|
209
|
-
case 'nl':
|
|
234
|
+
case 'nl':
|
|
235
|
+
case '//':
|
|
236
|
+
case '/*': return state
|
|
210
237
|
case 'string': {
|
|
211
238
|
const modules = list.concat(state.module.modules)([token.value])
|
|
212
239
|
return { ... state, state: 'nl', module: { ...state.module, modules: modules } }
|
|
@@ -295,6 +322,7 @@ const tokenToValue = token => {
|
|
|
295
322
|
case 'number': return parseFloat(token.value)
|
|
296
323
|
case 'string': return token.value
|
|
297
324
|
case 'bigint': return token.value
|
|
325
|
+
case 'undefined': return undefined
|
|
298
326
|
default: return null
|
|
299
327
|
}
|
|
300
328
|
}
|
|
@@ -307,7 +335,8 @@ const isValueToken = token => {
|
|
|
307
335
|
case 'true':
|
|
308
336
|
case 'number':
|
|
309
337
|
case 'string':
|
|
310
|
-
case 'bigint':
|
|
338
|
+
case 'bigint':
|
|
339
|
+
case 'undefined': return true
|
|
311
340
|
default: return false
|
|
312
341
|
}
|
|
313
342
|
}
|
|
@@ -315,70 +344,118 @@ const isValueToken = token => {
|
|
|
315
344
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
316
345
|
const parseValueOp = token => state => {
|
|
317
346
|
if (isValueToken(token)) { return pushValue(state)(tokenToValue(token)) }
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
347
|
+
switch (token.kind)
|
|
348
|
+
{
|
|
349
|
+
case 'id': return pushRef(state)(token.value)
|
|
350
|
+
case '[': return startArray(state)
|
|
351
|
+
case '{': return startObject(state)
|
|
352
|
+
case 'ws':
|
|
353
|
+
case 'nl':
|
|
354
|
+
case '//':
|
|
355
|
+
case '/*': return state
|
|
356
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
357
|
+
}
|
|
323
358
|
}
|
|
324
359
|
|
|
325
360
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
326
361
|
const parseArrayStartOp = token => state => {
|
|
327
362
|
if (isValueToken(token)) { return pushValue(state)(tokenToValue(token)) }
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
363
|
+
switch (token.kind)
|
|
364
|
+
{
|
|
365
|
+
case 'id': return pushRef(state)(token.value)
|
|
366
|
+
case '[': return startArray(state)
|
|
367
|
+
case ']': return endArray(state)
|
|
368
|
+
case '{': return startObject(state)
|
|
369
|
+
case 'ws':
|
|
370
|
+
case 'nl':
|
|
371
|
+
case '//':
|
|
372
|
+
case '/*': return state
|
|
373
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
374
|
+
}
|
|
334
375
|
}
|
|
335
376
|
|
|
336
377
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
337
378
|
const parseArrayValueOp = token => state => {
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
379
|
+
switch (token.kind)
|
|
380
|
+
{
|
|
381
|
+
case ']': return endArray(state)
|
|
382
|
+
case ',': return { ... state, valueState: '[,', top: state.top, stack: state.stack }
|
|
383
|
+
case 'ws':
|
|
384
|
+
case 'nl':
|
|
385
|
+
case '//':
|
|
386
|
+
case '/*': return state
|
|
387
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
388
|
+
}
|
|
342
389
|
}
|
|
343
390
|
|
|
344
391
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
345
392
|
const parseObjectStartOp = token => state => {
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
393
|
+
switch (token.kind)
|
|
394
|
+
{
|
|
395
|
+
case 'string': return pushKey(state)(token.value)
|
|
396
|
+
case '}': return endObject(state)
|
|
397
|
+
case 'ws':
|
|
398
|
+
case 'nl':
|
|
399
|
+
case '//':
|
|
400
|
+
case '/*': return state
|
|
401
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
402
|
+
}
|
|
350
403
|
}
|
|
351
404
|
|
|
352
405
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
353
406
|
const parseObjectKeyOp = token => state => {
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
407
|
+
switch (token.kind)
|
|
408
|
+
{
|
|
409
|
+
case ':': return { ... state, valueState: '{:', top: state.top, stack: state.stack }
|
|
410
|
+
case 'ws':
|
|
411
|
+
case 'nl':
|
|
412
|
+
case '//':
|
|
413
|
+
case '/*': return state
|
|
414
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
415
|
+
}
|
|
357
416
|
}
|
|
358
417
|
|
|
359
418
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
360
419
|
const parseObjectColonOp = token => state => {
|
|
361
420
|
if (isValueToken(token)) { return pushValue(state)(tokenToValue(token)) }
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
421
|
+
switch (token.kind)
|
|
422
|
+
{
|
|
423
|
+
case 'id': return pushRef(state)(token.value)
|
|
424
|
+
case '[': return startArray(state)
|
|
425
|
+
case '{': return startObject(state)
|
|
426
|
+
case 'ws':
|
|
427
|
+
case 'nl':
|
|
428
|
+
case '//':
|
|
429
|
+
case '/*': return state
|
|
430
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
431
|
+
}
|
|
367
432
|
}
|
|
368
433
|
|
|
369
434
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
370
435
|
const parseObjectNextOp = token => state => {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
436
|
+
switch (token.kind)
|
|
437
|
+
{
|
|
438
|
+
case '}': return endObject(state)
|
|
439
|
+
case ',': return { ... state, valueState: '{,', top: state.top, stack: state.stack }
|
|
440
|
+
case 'ws':
|
|
441
|
+
case 'nl':
|
|
442
|
+
case '//':
|
|
443
|
+
case '/*': return state
|
|
444
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
445
|
+
}
|
|
375
446
|
}
|
|
376
447
|
|
|
377
448
|
/** @type {(token: tokenizerT.DjsToken) => (state: ParseValueState) => ParserState}} */
|
|
378
449
|
const parseObjectCommaOp = token => state => {
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
450
|
+
switch (token.kind)
|
|
451
|
+
{
|
|
452
|
+
case 'string': return pushKey(state)(token.value)
|
|
453
|
+
case 'ws':
|
|
454
|
+
case 'nl':
|
|
455
|
+
case '//':
|
|
456
|
+
case '/*': return state
|
|
457
|
+
default: return { state: 'error', message: 'unexpected token' }
|
|
458
|
+
}
|
|
382
459
|
}
|
|
383
460
|
|
|
384
461
|
/** @type {Operator.Fold<tokenizerT.DjsToken, ParserState>} */
|
|
@@ -392,7 +469,7 @@ const foldOp = token => state => {
|
|
|
392
469
|
case 'const': return parseConstOp(token)(state)
|
|
393
470
|
case 'const+name': return parseConstNameOp(token)(state)
|
|
394
471
|
case 'export': return parseExportOp(token)(state)
|
|
395
|
-
case 'result': return
|
|
472
|
+
case 'result': return parseResultOp(token)(state)
|
|
396
473
|
case 'error': return { state: 'error', message: state.message }
|
|
397
474
|
case 'constValue':
|
|
398
475
|
case 'exportValue':
|
package/djs/parser/test.f.mjs
CHANGED
|
@@ -32,6 +32,12 @@ export default {
|
|
|
32
32
|
const result = stringify(obj)
|
|
33
33
|
if (result !== '["ok",[[],[false]]]') { throw result }
|
|
34
34
|
},
|
|
35
|
+
() => {
|
|
36
|
+
const tokenList = tokenizeString('export default undefined')
|
|
37
|
+
const obj = parser.parse(tokenList)
|
|
38
|
+
const result = stringify(obj)
|
|
39
|
+
if (result !== '["ok",[[],[undefined]]]') { throw result }
|
|
40
|
+
},
|
|
35
41
|
() => {
|
|
36
42
|
const tokenList = tokenizeString('export default 0.1')
|
|
37
43
|
const obj = parser.parse(tokenList)
|
|
@@ -87,10 +93,10 @@ export default {
|
|
|
87
93
|
if (result !== '["ok",[[],[["array",[{}]]]]]') { throw result }
|
|
88
94
|
},
|
|
89
95
|
() => {
|
|
90
|
-
const tokenList = tokenizeString('export default {"a":true,"b":false,"c":null}')
|
|
96
|
+
const tokenList = tokenizeString('export default {"a":true,"b":false,"c":null,"d":undefined}')
|
|
91
97
|
const obj = parser.parse(tokenList)
|
|
92
98
|
const result = stringify(obj)
|
|
93
|
-
if (result !== '["ok",[[],[{"a":true,"b":false,"c":null}]]]') { throw result }
|
|
99
|
+
if (result !== '["ok",[[],[{"a":true,"b":false,"c":null,"d":undefined}]]]') { throw result }
|
|
94
100
|
},
|
|
95
101
|
() => {
|
|
96
102
|
const tokenList = tokenizeString('export default {"a":{"b":{"c":["d"]}}}')
|
|
@@ -259,13 +265,25 @@ export default {
|
|
|
259
265
|
],
|
|
260
266
|
validWhiteSpaces:[
|
|
261
267
|
() => {
|
|
262
|
-
const tokenList = tokenizeString('export default [ 0 , 1 , 2 ]')
|
|
268
|
+
const tokenList = tokenizeString(' export default [ 0 , 1 , 2 ] ')
|
|
263
269
|
const obj = parser.parse(tokenList)
|
|
264
270
|
const result = stringify(obj)
|
|
265
271
|
if (result !== '["ok",[[],[["array",[0,1,2]]]]]') { throw result }
|
|
266
272
|
},
|
|
267
273
|
() => {
|
|
268
|
-
const tokenList = tokenizeString('export default { "a" : 0 , "b" : 1 }')
|
|
274
|
+
const tokenList = tokenizeString(' export default { "a" : 0 , "b" : 1 } ')
|
|
275
|
+
const obj = parser.parse(tokenList)
|
|
276
|
+
const result = stringify(obj)
|
|
277
|
+
if (result !== '["ok",[[],[{"a":0,"b":1}]]]') { throw result }
|
|
278
|
+
},
|
|
279
|
+
() => {
|
|
280
|
+
const tokenList = tokenizeString('\nexport\ndefault\n[\n0\n,\n1\n,\n2\n]\n')
|
|
281
|
+
const obj = parser.parse(tokenList)
|
|
282
|
+
const result = stringify(obj)
|
|
283
|
+
if (result !== '["ok",[[],[["array",[0,1,2]]]]]') { throw result }
|
|
284
|
+
},
|
|
285
|
+
() => {
|
|
286
|
+
const tokenList = tokenizeString('\rexport\rdefault\r{\r"a"\r:\r0\r,\r"b"\r:\r1\r}\r')
|
|
269
287
|
const obj = parser.parse(tokenList)
|
|
270
288
|
const result = stringify(obj)
|
|
271
289
|
if (result !== '["ok",[[],[{"a":0,"b":1}]]]') { throw result }
|
|
@@ -409,4 +427,12 @@ export default {
|
|
|
409
427
|
if (result !== '["error","duplicate id"]') { throw result }
|
|
410
428
|
},
|
|
411
429
|
],
|
|
430
|
+
comments: [
|
|
431
|
+
() => {
|
|
432
|
+
const tokenList = tokenizeString('export //comment \n default /* comment */ null //comment')
|
|
433
|
+
const obj = parser.parse(tokenList)
|
|
434
|
+
const result = stringify(obj)
|
|
435
|
+
if (result !== '["ok",[[],[null]]]') { throw result }
|
|
436
|
+
},
|
|
437
|
+
]
|
|
412
438
|
}
|
|
@@ -9,7 +9,7 @@ import * as jsTokenizer from '../../js/tokenizer/module.f.mjs'
|
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* @typedef {|
|
|
12
|
-
* {readonly kind: 'true' | 'false' | 'null'} |
|
|
12
|
+
* {readonly kind: 'true' | 'false' | 'null' | 'undefined'} |
|
|
13
13
|
* {readonly kind: '{' | '}' | ':' | ',' | '[' | ']' | '.' | '=' } |
|
|
14
14
|
* jsTokenizer.StringToken |
|
|
15
15
|
* jsTokenizer.NumberToken |
|
|
@@ -17,7 +17,8 @@ import * as jsTokenizer from '../../js/tokenizer/module.f.mjs'
|
|
|
17
17
|
* jsTokenizer.IdToken |
|
|
18
18
|
* jsTokenizer.BigIntToken |
|
|
19
19
|
* jsTokenizer.WhitespaceToken |
|
|
20
|
-
* jsTokenizer.NewLineToken
|
|
20
|
+
* jsTokenizer.NewLineToken |
|
|
21
|
+
* jsTokenizer.CommentToken
|
|
21
22
|
* } DjsToken
|
|
22
23
|
*/
|
|
23
24
|
|
|
@@ -55,6 +56,9 @@ const mapToken = input =>
|
|
|
55
56
|
case 'number':
|
|
56
57
|
case 'ws':
|
|
57
58
|
case 'nl':
|
|
59
|
+
case 'undefined':
|
|
60
|
+
case '//':
|
|
61
|
+
case '/*':
|
|
58
62
|
case 'error': return [input]
|
|
59
63
|
default: return jsTokenizer.isKeywordToken(input) ? [{ kind: 'id', value: input.kind }] : [{ kind: 'error', message: 'invalid token' }]
|
|
60
64
|
}
|
package/djs/tokenizer/test.f.mjs
CHANGED
|
@@ -321,9 +321,43 @@ export default {
|
|
|
321
321
|
const result = stringify(tokenizeString('null'))
|
|
322
322
|
if (result !== '[{"kind":"null"}]') { throw result }
|
|
323
323
|
},
|
|
324
|
+
() => {
|
|
325
|
+
const result = stringify(tokenizeString('undefined'))
|
|
326
|
+
if (result !== '[{"kind":"undefined"}]') { throw result }
|
|
327
|
+
},
|
|
324
328
|
() => {
|
|
325
329
|
const result = stringify(tokenizeString('[null]'))
|
|
326
330
|
if (result !== '[{"kind":"["},{"kind":"null"},{"kind":"]"}]') { throw result }
|
|
327
331
|
},
|
|
332
|
+
],
|
|
333
|
+
comments: [
|
|
334
|
+
() => {
|
|
335
|
+
const result = stringify(tokenizeString('//singleline comment'))
|
|
336
|
+
if (result !== '[{"kind":"//","value":"singleline comment"}]') { throw result }
|
|
337
|
+
},
|
|
338
|
+
() => {
|
|
339
|
+
const result = stringify(tokenizeString('true//singleline comment\nfalse'))
|
|
340
|
+
if (result !== '[{"kind":"true"},{"kind":"//","value":"singleline comment"},{"kind":"nl"},{"kind":"false"}]') { throw result }
|
|
341
|
+
},
|
|
342
|
+
() => {
|
|
343
|
+
const result = stringify(tokenizeString('/* multiline comment */'))
|
|
344
|
+
if (result !== '[{"kind":"/*","value":" multiline comment "}]') { throw result }
|
|
345
|
+
},
|
|
346
|
+
() => {
|
|
347
|
+
const result = stringify(tokenizeString('/* multiline comment *'))
|
|
348
|
+
if (result !== '[{"kind":"error","message":"*/ expected"}]') { throw result }
|
|
349
|
+
},
|
|
350
|
+
() => {
|
|
351
|
+
const result = stringify(tokenizeString('/* multiline comment '))
|
|
352
|
+
if (result !== '[{"kind":"error","message":"*/ expected"}]') { throw result }
|
|
353
|
+
},
|
|
354
|
+
() => {
|
|
355
|
+
const result = stringify(tokenizeString('/* multiline comment \n * **/'))
|
|
356
|
+
if (result !== '[{"kind":"/*","value":" multiline comment \\n * *"},{"kind":"nl"}]') { throw result }
|
|
357
|
+
},
|
|
358
|
+
() => {
|
|
359
|
+
const result = stringify(tokenizeString('/* multiline comment *\n * **/'))
|
|
360
|
+
if (result !== '[{"kind":"/*","value":" multiline comment *\\n * *"},{"kind":"nl"}]') { throw result }
|
|
361
|
+
},
|
|
328
362
|
]
|
|
329
363
|
}
|
package/html/module.f.mjs
CHANGED
|
@@ -14,7 +14,7 @@ const { entries } = Object
|
|
|
14
14
|
/** @typedef {string} Tag */
|
|
15
15
|
|
|
16
16
|
// https://developer.mozilla.org/en-US/docs/Glossary/Void_element
|
|
17
|
-
const voidTagList = [
|
|
17
|
+
const voidTagList = /** @type {const} */([
|
|
18
18
|
'area',
|
|
19
19
|
'base',
|
|
20
20
|
'br',
|
|
@@ -29,20 +29,20 @@ const voidTagList = [
|
|
|
29
29
|
'source',
|
|
30
30
|
'track',
|
|
31
31
|
'wbr',
|
|
32
|
-
]
|
|
32
|
+
])
|
|
33
33
|
|
|
34
|
-
/** @
|
|
35
|
-
const isVoid = tag => voidTagList.includes(tag)
|
|
34
|
+
/** @typedef {typeof voidTagList} VoidTagList */
|
|
36
35
|
|
|
37
|
-
/** @typedef {
|
|
36
|
+
/** @typedef {keyof voidTagList} VoidTag */
|
|
38
37
|
|
|
39
|
-
/** @
|
|
38
|
+
/** @type {(tag: string) => boolean} */
|
|
39
|
+
const isVoid = tag => voidTagList.includes(/** @type {any} */(tag))
|
|
40
40
|
|
|
41
|
-
/** @typedef {readonly[Tag,
|
|
41
|
+
/** @typedef {readonly[Tag, ...Node[]]} Element1*/
|
|
42
42
|
|
|
43
|
-
/** @typedef {readonly[Tag, Attributes,
|
|
43
|
+
/** @typedef {readonly[Tag, Attributes, ...Node[]]} Element2 */
|
|
44
44
|
|
|
45
|
-
/** @typedef {Element1 |
|
|
45
|
+
/** @typedef {Element1 | Element2 } Element */
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* @typedef {{
|
|
@@ -50,7 +50,7 @@ const isVoid = tag => voidTagList.includes(tag)
|
|
|
50
50
|
* }} Attributes
|
|
51
51
|
*/
|
|
52
52
|
|
|
53
|
-
/** @typedef {list.List<Node>} Nodes */
|
|
53
|
+
// /** @typedef {list.List<Node>} Nodes */
|
|
54
54
|
|
|
55
55
|
/** @typedef {Element | string} Node */
|
|
56
56
|
|
|
@@ -82,34 +82,19 @@ const attribute = ([name, value]) => flat([[' ', name, '="'], escape(value), ['"
|
|
|
82
82
|
/** @type {(a: Attributes) => list.List<string>} */
|
|
83
83
|
const attributes = compose(entries)(flatMap(attribute))
|
|
84
84
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const close = (/** @type {string}*/tag) => ['</', tag, '>']
|
|
85
|
+
/** @type {(t: string) => (a: Attributes) => list.List<string>} */
|
|
86
|
+
const open = t => a => flat([[`<`, t], attributes(a), [`>`]])
|
|
88
87
|
|
|
89
|
-
/** @type {(
|
|
90
|
-
const element3 = ([
|
|
91
|
-
flat([
|
|
92
|
-
|
|
93
|
-
/** @type {(_: Element2A) => list.List<string>} */
|
|
94
|
-
const element2a = e => {
|
|
95
|
-
const [tag] = e
|
|
96
|
-
return flat([open(e), isVoid(tag) ? [] : close(tag)])
|
|
88
|
+
/** @type {(t: string) => (an: readonly[Attributes, readonly Node[]]) => list.List<string>} */
|
|
89
|
+
const element3 = t => ([a, n]) => {
|
|
90
|
+
const o = flat([[`<`, t], attributes(a), [`>`]])
|
|
91
|
+
return isVoid(t) ? o : flat([o, nodes(n), ['</', t, '>']])
|
|
97
92
|
}
|
|
98
93
|
|
|
99
94
|
/** @type {(element: Element) => list.List<string>} */
|
|
100
95
|
export const element = e => {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
case 2: {
|
|
104
|
-
const [tag, a] = e
|
|
105
|
-
return a instanceof Array ?
|
|
106
|
-
element3([tag, {}, a]) :
|
|
107
|
-
element2a([tag, a])
|
|
108
|
-
}
|
|
109
|
-
default: {
|
|
110
|
-
return element3(e)
|
|
111
|
-
}
|
|
112
|
-
}
|
|
96
|
+
const [t, a, ...n] = e
|
|
97
|
+
return element3(t)(a === undefined ? [{}, []]: typeof a === 'object' && !(a instanceof Array) ? [a, n] : [{}, [a, ...n]])
|
|
113
98
|
}
|
|
114
99
|
|
|
115
100
|
export const html = compose(element)(listConcat(['<!DOCTYPE html>']))
|