functionalscript 0.2.4 → 0.2.6

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +1 -1
  3. package/crypto/README.md +3 -0
  4. package/{prime_field → crypto/prime_field}/module.f.mjs +2 -2
  5. package/{secp → crypto/secp}/module.f.mjs +2 -2
  6. package/{sha2 → crypto/sha2}/module.f.mjs +4 -4
  7. package/{sha2 → crypto/sha2}/test.f.mjs +2 -2
  8. package/djs/module.f.mjs +4 -1
  9. package/djs/parser/module.f.mjs +122 -45
  10. package/djs/parser/test.f.mjs +30 -4
  11. package/djs/tokenizer/module.f.mjs +6 -2
  12. package/djs/tokenizer/test.f.mjs +34 -0
  13. package/html/README.md +10 -9
  14. package/html/module.f.mjs +18 -33
  15. package/html/test.f.mjs +6 -6
  16. package/issues/05-publish.md +17 -22
  17. package/issues/README.md +13 -2
  18. package/js/tokenizer/module.f.mjs +75 -26
  19. package/js/tokenizer/test.f.mjs +42 -0
  20. package/json/parser/test.f.mjs +6 -0
  21. package/jsr.json +4 -4
  22. package/nanvm-lib/src/extension.rs +1 -1
  23. package/nanvm-lib/src/nanenum.rs +22 -20
  24. package/out/{prime_field → crypto/prime_field}/module.f.d.mts +1 -1
  25. package/out/{prime_field → crypto/prime_field}/module.f.mjs +2 -2
  26. package/out/{secp → crypto/secp}/module.f.d.mts +1 -1
  27. package/out/{secp → crypto/secp}/module.f.mjs +2 -2
  28. package/out/{sha2 → crypto/sha2}/module.f.d.mts +3 -3
  29. package/out/{sha2 → crypto/sha2}/module.f.mjs +4 -4
  30. package/out/{sha2 → crypto/sha2}/test.f.mjs +2 -2
  31. package/out/djs/module.f.d.mts +1 -1
  32. package/out/djs/module.f.mjs +5 -1
  33. package/out/djs/parser/module.f.d.mts +1 -1
  34. package/out/djs/parser/module.f.mjs +105 -89
  35. package/out/djs/parser/test.f.d.mts +1 -0
  36. package/out/djs/parser/test.f.mjs +38 -4
  37. package/out/djs/tokenizer/module.f.d.mts +2 -2
  38. package/out/djs/tokenizer/module.f.mjs +6 -2
  39. package/out/djs/tokenizer/test.f.d.mts +1 -0
  40. package/out/djs/tokenizer/test.f.mjs +50 -0
  41. package/out/html/module.f.d.mts +8 -6
  42. package/out/html/module.f.mjs +17 -31
  43. package/out/html/test.f.mjs +5 -5
  44. package/out/js/tokenizer/module.f.d.mts +15 -3
  45. package/out/js/tokenizer/module.f.mjs +65 -22
  46. package/out/js/tokenizer/test.f.d.mts +1 -0
  47. package/out/js/tokenizer/test.f.mjs +62 -0
  48. package/out/json/parser/test.f.mjs +8 -0
  49. package/out/types/bit_vec/module.f.d.mts +108 -22
  50. package/out/types/bit_vec/module.f.mjs +142 -31
  51. package/out/types/bit_vec/test.f.d.mts +20 -6
  52. package/out/types/bit_vec/test.f.mjs +160 -10
  53. package/package.json +1 -1
  54. package/types/bit_vec/README.md +18 -0
  55. package/types/bit_vec/module.f.mjs +147 -31
  56. package/types/bit_vec/test.f.mjs +101 -13
  57. /package/{prime_field → crypto/prime_field}/test.f.mjs +0 -0
  58. /package/{secp → crypto/secp}/test.f.mjs +0 -0
  59. /package/out/{prime_field → crypto/prime_field}/test.f.d.mts +0 -0
  60. /package/out/{prime_field → crypto/prime_field}/test.f.mjs +0 -0
  61. /package/out/{secp → crypto/secp}/test.f.d.mts +0 -0
  62. /package/out/{secp → crypto/secp}/test.f.mjs +0 -0
  63. /package/out/{sha2 → crypto/sha2}/test.f.d.mts +0 -0
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
- /** @type {(tag: string) => boolean} */
35
- const isVoid = tag => voidTagList.includes(tag)
34
+ /** @typedef {typeof voidTagList} VoidTagList */
36
35
 
37
- /** @typedef {readonly[Tag]} Element1*/
36
+ /** @typedef {keyof voidTagList} VoidTag */
38
37
 
39
- /** @typedef {readonly[Tag, Attributes]} Element2A */
38
+ /** @type {(tag: string) => boolean} */
39
+ const isVoid = tag => voidTagList.includes(/** @type {any} */(tag))
40
40
 
41
- /** @typedef {readonly[Tag, readonly Node[]]} Element2N */
41
+ /** @typedef {readonly[Tag, ...Node[]]} Element1*/
42
42
 
43
- /** @typedef {readonly[Tag, Attributes, Nodes]} Element3*/
43
+ /** @typedef {readonly[Tag, Attributes, ...Node[]]} Element2 */
44
44
 
45
- /** @typedef {Element1 | Element2A | Element2N | Element3} Element */
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
- const open = (/** @type {Element2A} */[tag, a]) => flat([[`<`, tag], attributes(a), [`>`]])
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 {(_: Element3) => list.List<string>} */
90
- const element3 = ([tag, a, ns]) =>
91
- flat([open([tag, a]), nodes(ns), close(tag)])
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
- switch (e.length) {
102
- case 1: { return element2a([e[0], {}]) }
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>']))
package/html/test.f.mjs CHANGED
@@ -2,8 +2,8 @@ import * as _ from './module.f.mjs'
2
2
 
3
3
  export default {
4
4
  empty: () => {
5
- const r = _.htmlToString(['html', []])
6
- if (r !== '<!DOCTYPE html><html></html>') { throw r }
5
+ const r = _.htmlToString(['html'])
6
+ if (r !== '<!DOCTYPE html><html></html>') { throw `empty: ${r}` }
7
7
  },
8
8
  empty2: () => {
9
9
  const r = _.htmlToString(['html'])
@@ -15,20 +15,20 @@ export default {
15
15
  },
16
16
  some: () => {
17
17
  /** @type {_.Element} */
18
- const x = ['div', {}, ['<div>&amp;</div>', ['a', { href: 'hello"' }, []]]]
18
+ const x = ['div', {}, '<div>&amp;</div>', ['a', { href: 'hello"' }]]
19
19
  const s = _.htmlToString(x)
20
20
  if (s !== '<!DOCTYPE html><div>&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') { throw s }
21
21
  },
22
22
  some2: () => {
23
23
  /** @type {_.Element} */
24
- const x = ['div', ['<div>&amp;</div>', ['a', { href: 'hello"' }, []]]]
24
+ const x = ['div', '<div>&amp;</div>', ['a', { href: 'hello"' }]]
25
25
  const s = _.htmlToString(x)
26
26
  if (s !== '<!DOCTYPE html><div>&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') { throw s }
27
27
  },
28
28
  someVoid: () => {
29
29
  /** @type {_.Element} */
30
- const x = ['div', [['br', {id: '5'}], '<div>&amp;</div>', ['a', { href: 'hello"' }, []]]]
30
+ const x = ['div', ['br', {id: '5'}], '<div>&amp;</div>', ['a', { href: 'hello"' }]]
31
31
  const s = _.htmlToString(x)
32
32
  if (s !== '<!DOCTYPE html><div><br id="5">&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') { throw s }
33
33
  }
34
- }
34
+ }
@@ -9,37 +9,32 @@ We are targeting the following systems:
9
9
  - Rust:
10
10
  - [ ] https://crates.io/
11
11
 
12
- ## Creating `./index.f.mjs`
12
+ The main principle is that we should be able to install FunctionalScript from Git/GitHub. Currently,
13
13
 
14
- Currently, we regenerate [./index.f.mjs](./index.f.mjs) using `npm run index` during CD (publishing). However, we don't check in CI if it was regenerated. The idea is that CI should check if all generated files in Git are updated:
14
+ - `NPM` works with Git links and `.mjs` files.
15
+ - `JSR`. Unfortunately, JSR doesn't support JSDoc type information, see [jsr-io/jsr/issues/494](https://github.com/jsr-io/jsr/issues/494).
16
+ - Browsers. `import * from 'https://...'`.
15
17
 
16
- - [package.json](./package.json) `version` property
17
- - [jsr.json](./jsr.json), `version` property
18
- - [index.f.mjs](./index.f.mjs)
19
-
20
- `version` property should be `version` calculated on a `main` branch.
18
+ We have two options:
21
19
 
22
- We may abandon the idea to publish on every commit on `main`. Instead, we will publish only we when we update a version in the `main` branch. This strategy can also work for Rust packages. The idea is that people can still reference from Git if they would like to have a not-published version of a package. We will still release in CI but only when there is a new version.
20
+ - Continue to use JavaScript source files and generate JSR package before publishing,
21
+ - Switch to TypeScript source files and write [prepack](https://docs.npmjs.com/cli/v7/using-npm/scripts) script. TS files could be a problem for our parser because it doesn't strip type annotations yet.
23
22
 
24
- ## Publishing
23
+ This problem will go away as soon as ECMAScript supports for [Type Annotations](https://github.com/tc39/proposal-type-annotations).
25
24
 
26
- Before publishing, we have to be sure that
25
+ ## Updating Packages
27
26
 
28
- 1. [index.f.mjs](./index.f.mjs) is up to date
29
- 2. `version` is updated in [jsr.json](./jsr.json) and [package.json](./package.json).
27
+ Currently, we regenerate `exports` in [./jsr.json](./index.f.mjs) using `npm run index` during CD (publishing) and `version` using `npm run version`. We should combine it into `update` script.
30
28
 
31
- ## CI Jobs
29
+ We don't check in CI if it was regenerated. The idea is that CI should check if all generated files in Git are updated:
32
30
 
33
- ### 1. Publishing (merge to `main`)
34
-
35
- Check if the version is new, then publish.
36
-
37
- ### 2. CI
31
+ - [package.json](./package.json) `version` property
32
+ - [jsr.json](./jsr.json), `version` and `exports` property.
38
33
 
39
- Errors:
34
+ `version` property should be the same in `package.json` and `jsr.json`.
40
35
 
41
- - correct `index.f.mjs` is merged.
36
+ We abandoned the idea to publish on every commit on `main`. Instead, we publish only when there is an new version in the `main`. This strategy can also work for Rust packages.
42
37
 
43
- Warnings (not blocking CI):
38
+ ## CI Publishing (merge to `main`)
44
39
 
45
- - out of date lock files, such as `package-lock.json` and `Cargo.lock`.
40
+ Check if the version is new, then publish.
package/issues/README.md CHANGED
@@ -27,5 +27,16 @@
27
27
  18. [ ] Formatter for `.f.js` and `.f.ts` files.
28
28
  19. [ ] Convert FunctionalScript code using non-default `export`.
29
29
  20. [ ] Test framework should be able to run a subset of tests.
30
- 21. [ ] Test Framework silent mode. Show progress and failled tests only.
31
- 22. [ ] bit sequences based on bigint
30
+ 21. [ ] Test Framework silent mode. Show progress and failed tests only.
31
+ 22. [x] bit sequences based on bigint
32
+ 23. [ ] a console program similar to one that we have in the NaNVM repo.
33
+ 24. [ ] create `./module.mjs` that supports the same behavior like current NaNVM Rust implementation:
34
+ - [ ] run `node ./module.mjs input.f.mjs output.f.mjs`
35
+ - [ ] run `deno ./module.mjs input.f.mjs output.f.mjs`
36
+ 25. [ ] Switch to Deno an `.ts`?
37
+ 1. Deno TypeScript and Microsoft TypeScript are different https://bsky.app/profile/macwright.com/post/3lbrwioa5zs27
38
+ 2. One day we may switch back to `.js` extension if [Type Annotation Proposal](https://github.com/tc39/proposal-type-annotations) is included into ECMAScript. BTW, we should only use JS with type annotations instead of full TypeScript.
39
+
40
+ ## Language Specification
41
+
42
+ See [lang/README.md](./lang/README.md).
@@ -104,6 +104,8 @@ const {
104
104
 
105
105
  /** @typedef {{readonly kind: 'null'}} NullToken */
106
106
 
107
+ /** @typedef {{readonly kind: 'undefined'}} UndefinedToken */
108
+
107
109
  /**
108
110
  * @typedef {|
109
111
  * {readonly kind: 'arguments' | 'await' | 'break' | 'case' | 'catch' | 'class' | 'const' | 'continue' } |
@@ -138,6 +140,13 @@ const {
138
140
  * } OperatorToken
139
141
  */
140
142
 
143
+ /**
144
+ * @typedef {{
145
+ * readonly kind: '//' | '/*'
146
+ * readonly value: string
147
+ * }} CommentToken
148
+ * */
149
+
141
150
  /**
142
151
  * @typedef {|
143
152
  * KeywordToken |
@@ -151,7 +160,9 @@ const {
151
160
  * ErrorToken |
152
161
  * IdToken |
153
162
  * BigIntToken |
154
- * OperatorToken
163
+ * UndefinedToken |
164
+ * OperatorToken |
165
+ * CommentToken
155
166
  * } JsToken
156
167
  */
157
168
 
@@ -240,21 +251,23 @@ const rangeId = [digitRange, ...rangeIdStart]
240
251
  * ParseNumberState |
241
252
  * InvalidNumberState |
242
253
  * ParseOperatorState |
243
- * ParseMinusState |
244
254
  * ParseWhitespaceState |
245
255
  * ParseNewLineState |
256
+ * ParseCommentState |
246
257
  * EofState
247
258
  * } TokenizerState
248
259
  */
249
260
 
250
261
  /**
251
262
  * @typedef {|
252
- * '" are missing' |
263
+ * '" are missing' |
253
264
  * 'unescaped character' |
254
265
  * 'invalid hex value' |
255
266
  * 'unexpected character' |
256
267
  * 'invalid number' |
257
268
  * 'invalid token' |
269
+ * '*\/ expected' |
270
+ * 'unterminated string literal' |
258
271
  * 'eof'
259
272
  * } ErrorMessage
260
273
  */
@@ -275,6 +288,14 @@ const rangeId = [digitRange, ...rangeIdStart]
275
288
 
276
289
  /** @typedef {{ readonly kind: '-'}} ParseMinusState */
277
290
 
291
+ /**
292
+ * @typedef {{
293
+ * readonly kind: '//' | '/*' | '/**'
294
+ * readonly value: string
295
+ * readonly newLine: boolean
296
+ * }} ParseCommentState
297
+ */
298
+
278
299
  /**
279
300
  * @typedef {{
280
301
  * readonly kind: 'unicodeChar'
@@ -286,7 +307,7 @@ const rangeId = [digitRange, ...rangeIdStart]
286
307
 
287
308
  /**
288
309
  * @typedef {{
289
- * readonly kind: 'number',
310
+ * readonly kind: 'number'
290
311
  * readonly numberKind: '0' | 'int' | '.' | 'fractional' | 'e' | 'e+' | 'e-' | 'expDigits' | 'bigint'
291
312
  * readonly value: string
292
313
  * readonly b: ParseNumberBuffer
@@ -448,6 +469,7 @@ const keywordEntries = [
448
469
  ['true', { kind: 'true'}],
449
470
  ['try', { kind: 'try'}],
450
471
  ['typeof', { kind: 'typeof'}],
472
+ ['undefined', { kind: 'undefined'}],
451
473
  ['var', { kind: 'var'}],
452
474
  ['void', { kind: 'void'}],
453
475
  ['while', { kind: 'while'}],
@@ -534,8 +556,8 @@ const hasOperatorToken = op => at(op)(operatorMap) !== null
534
556
  const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpected character' }], state])([
535
557
  rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: 'int' }]),
536
558
  rangeSetFunc(rangeIdStart)(() => input => [empty, { kind: 'id', value: fromCharCode(input) }]),
537
- rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, { kind: 'ws' }]),
538
- rangeSetFunc(rangeSetNewLine)(state => () => [empty, { kind: 'nl' }]),
559
+ rangeSetFunc(rangeSetWhiteSpace)(() => () => [empty, { kind: 'ws' }]),
560
+ rangeSetFunc(rangeSetNewLine)(() => () => [empty, { kind: 'nl' }]),
539
561
  rangeFunc(one(quotationMark))(() => () => [empty, { kind: 'string', value: '' }]),
540
562
  rangeFunc(one(digit0))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: '0' }]),
541
563
  rangeSetFunc(rangeOpStart)(() => input => [empty, { kind: 'op', value: fromCharCode(input) }])
@@ -666,17 +688,11 @@ const invalidNumberStateOp = create(() => () => [empty, { kind: 'invalidNumber'
666
688
  })
667
689
  ])
668
690
 
669
- /** @type {(state: ParseMinusState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
670
- const parseMinusStateOp = create(() => input => tokenizeOp({ kind: 'op', value: '-' })(input))([
671
- rangeFunc(one(fullStop))(() => input => tokenizeOp({ kind: 'invalidNumber' })(input)),
672
- rangeFunc(one(digit0))(() => () => [empty, { kind: 'number', value: '-0', b: startNegativeNumber, numberKind: '0' }]),
673
- rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: appendChar('-')(input), b: addIntDigit(input)(startNegativeNumber), numberKind: 'int' }]),
674
- ])
675
-
676
691
  /** @type {(state: ParseStringState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
677
- const parseStringStateOp = create(state => input => [empty, { kind: 'string', value: appendChar(state.value)(input) }])([
692
+ const parseStringStateOp = create(state => input => [empty, { kind: 'string', value: appendChar(state.value)(input) }])([
678
693
  rangeFunc(one(quotationMark))(state => () => [[{ kind: 'string', value: state.value }], { kind: 'initial' }]),
679
- rangeFunc(one(reverseSolidus))(state => () => [empty, { kind: 'escapeChar', value: state.value }])
694
+ rangeFunc(one(reverseSolidus))(state => () => [empty, { kind: 'escapeChar', value: state.value }]),
695
+ rangeSetFunc(rangeSetNewLine)(() => () => [[{ kind: 'error', message: 'unterminated string literal'}], { kind: 'nl'}])
680
696
  ])
681
697
 
682
698
  /** @type {(state: ParseEscapeCharState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
@@ -736,14 +752,43 @@ const parseIdStateOp = create(parseIdDefault)([
736
752
  /** @type {(state: ParseOperatorState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
737
753
  const parseOperatorStateOp = state => input => {
738
754
  const nextStateValue = appendChar(state.value)(input)
739
- if (hasOperatorToken(nextStateValue))
740
- return [empty, { kind: 'op', value: nextStateValue }]
741
- const next = tokenizeOp({ kind: 'initial' })(input)
742
- return [{ first: getOperatorToken(state.value), tail: next[0] }, next[1]]
755
+ switch (nextStateValue)
756
+ {
757
+ case '//': return [empty, { kind: '//', value: '', newLine: false }]
758
+ case '/*': return [empty, { kind: '/*', value: '', newLine: false }]
759
+ default: {
760
+ if (hasOperatorToken(nextStateValue))
761
+ return [empty, { kind: 'op', value: nextStateValue }]
762
+ const next = tokenizeOp({ kind: 'initial' })(input)
763
+ return [{ first: getOperatorToken(state.value), tail: next[0] }, next[1]]
764
+ }
765
+ }
743
766
  }
744
767
 
768
+ /** @type {(state: ParseCommentState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
769
+ const parseSinglelineCommentStateOp = create(state => input => [empty, { ...state, value: appendChar(state.value)(input) }])([
770
+ rangeSetFunc(rangeSetNewLine)(state => () => [[{ kind: '//', value: state.value }], { kind: 'nl' }])
771
+ ])
772
+
773
+ /** @type {(state: ParseCommentState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
774
+ const parseMultilineCommentStateOp = create(state => input => [empty, { ...state, value: appendChar(state.value)(input) }])([
775
+ rangeFunc(one(asterisk))(state => () => [empty, { ...state, kind: '/**' }]),
776
+ rangeSetFunc(rangeSetNewLine)(state => input => [empty, { ...state, value: appendChar(state.value)(input), newLine: true }]),
777
+ ])
778
+
779
+ /** @type {(state: ParseCommentState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
780
+ const parseMultilineCommentAsteriskStateOp = create(state => input => [empty, { ...state, kind: '/*', value: appendChar(appendChar(state.value)(asterisk))(input)}])([
781
+ rangeFunc(one(asterisk))(state => () => [empty, { ...state, value: appendChar(state.value)(asterisk) }]),
782
+ rangeSetFunc(rangeSetNewLine)(state => input => [empty, { kind: '/*', value: appendChar(appendChar(state.value)(asterisk))(input), newLine: true }]),
783
+ rangeFunc(one(solidus))(state => () => {
784
+ /** @type {list.List<JsToken>} */
785
+ const tokens = state.newLine ? [{ kind: '/*', value: state.value }, { kind: 'nl' }] : [{ kind: '/*', value: state.value }]
786
+ return [tokens, { kind: 'initial' }]
787
+ })
788
+ ])
789
+
745
790
  /** @type {(state: ParseWhitespaceState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
746
- const parseWhitespaceDefault = state => input => {
791
+ const parseWhitespaceDefault = () => input => {
747
792
  const next = tokenizeOp({ kind: 'initial' })(input)
748
793
  return [{ first: { kind: 'ws' }, tail: next[0] }, next[1]]
749
794
  }
@@ -751,7 +796,7 @@ const parseWhitespaceDefault = state => input => {
751
796
  /** @type {(state: ParseWhitespaceState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
752
797
  const parseWhitespaceStateOp = create(parseWhitespaceDefault)([
753
798
  rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state]),
754
- rangeSetFunc(rangeSetNewLine)(state => () => [empty, { kind: 'nl' }])
799
+ rangeSetFunc(rangeSetNewLine)(() => () => [empty, { kind: 'nl' }])
755
800
  ])
756
801
 
757
802
  /** @type {(state: ParseNewLineState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
@@ -780,7 +825,9 @@ const tokenizeCharCodeOp = state => {
780
825
  case 'invalidNumber': return invalidNumberStateOp(state)
781
826
  case 'number': return parseNumberStateOp(state)
782
827
  case 'op': return parseOperatorStateOp(state)
783
- case '-': return parseMinusStateOp(state)
828
+ case '//': return parseSinglelineCommentStateOp(state)
829
+ case '/*': return parseMultilineCommentStateOp(state)
830
+ case '/**': return parseMultilineCommentAsteriskStateOp(state)
784
831
  case 'ws': return parseWhitespaceStateOp(state)
785
832
  case 'nl': return parseNewLineStateOp(state)
786
833
  case 'eof': return eofStateOp(state)
@@ -801,11 +848,13 @@ const tokenizeEofOp = state => {
801
848
  case '.':
802
849
  case 'e':
803
850
  case 'e+':
804
- case 'e-': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'invalidNumber', }]
851
+ case 'e-': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'eof', }]
805
852
  default: return [[bufferToNumberToken(state)], { kind: 'eof' }]
806
853
  }
807
- case 'op': return [[getOperatorToken(state.value)], { kind: 'eof' }]
808
- case '-': return [[{kind: '-'}], { kind: 'eof' }]
854
+ case 'op': return [[getOperatorToken(state.value)], { kind: 'eof' }]
855
+ case '//': return [[{kind: '//', value: state.value}], { kind: 'eof' }]
856
+ case '/*':
857
+ case '/**': return [[{ kind: 'error', message: '*/ expected' }], { kind: 'eof', }]
809
858
  case 'ws': return [[{kind: 'ws'}], { kind: 'eof' }]
810
859
  case 'nl': return [[{kind: 'nl'}], { kind: 'eof' }]
811
860
  case 'eof': return [[{ kind: 'error', message: 'eof' }], state]
@@ -820,4 +869,4 @@ const scanTokenize = stateScan(tokenizeOp)
820
869
  const initial = scanTokenize({ kind: 'initial' })
821
870
 
822
871
  /** @type {(input: list.List<number>) => list.List<JsToken>} */
823
- export const tokenize = input => flat(initial(flat([/** @type {list.List<CharCodeOrEof>} */(input), [null]])))
872
+ export const tokenize = input => flat(initial(flat([/** @type {list.List<CharCodeOrEof>} */(input), [null]])))
@@ -89,6 +89,14 @@ export default {
89
89
  const result = stringify(tokenizeString('"\\'))
90
90
  if (result !== '[{"kind":"error","message":"\\" are missing"}]') { throw result }
91
91
  },
92
+ () => {
93
+ const result = stringify(tokenizeString('"\r"'))
94
+ if (result !== '[{"kind":"error","message":"unterminated string literal"},{"kind":"nl"},{"kind":"error","message":"\\" are missing"}]') { throw result }
95
+ },
96
+ () => {
97
+ const result = stringify(tokenizeString('"\n null'))
98
+ if (result !== '[{"kind":"error","message":"unterminated string literal"},{"kind":"nl"},{"kind":"null"}]') { throw result }
99
+ },
92
100
  () => {
93
101
  const result = stringify(tokenizeString('"\\b\\f\\n\\r\\t"'))
94
102
  if (result !== '[{"kind":"string","value":"\\b\\f\\n\\r\\t"}]') { throw result }
@@ -386,6 +394,10 @@ export default {
386
394
  const result = stringify(tokenizeString('null'))
387
395
  if (result !== '[{"kind":"null"}]') { throw result }
388
396
  },
397
+ () => {
398
+ const result = stringify(tokenizeString('undefined'))
399
+ if (result !== '[{"kind":"undefined"}]') { throw result }
400
+ },
389
401
  () => {
390
402
  const result = stringify(tokenizeString('[null]'))
391
403
  if (result !== '[{"kind":"["},{"kind":"null"},{"kind":"]"}]') { throw result }
@@ -570,5 +582,35 @@ export default {
570
582
  const result = stringify(tokenizeString('yield'))
571
583
  if (result !== '[{"kind":"yield"}]') { throw result }
572
584
  },
585
+ ],
586
+ comments: [
587
+ () => {
588
+ const result = stringify(tokenizeString('//singleline comment'))
589
+ if (result !== '[{"kind":"//","value":"singleline comment"}]') { throw result }
590
+ },
591
+ () => {
592
+ const result = stringify(tokenizeString('true//singleline comment\nfalse'))
593
+ if (result !== '[{"kind":"true"},{"kind":"//","value":"singleline comment"},{"kind":"nl"},{"kind":"false"}]') { throw result }
594
+ },
595
+ () => {
596
+ const result = stringify(tokenizeString('/* multiline comment */'))
597
+ if (result !== '[{"kind":"/*","value":" multiline comment "}]') { throw result }
598
+ },
599
+ () => {
600
+ const result = stringify(tokenizeString('/* multiline comment *'))
601
+ if (result !== '[{"kind":"error","message":"*/ expected"}]') { throw result }
602
+ },
603
+ () => {
604
+ const result = stringify(tokenizeString('/* multiline comment '))
605
+ if (result !== '[{"kind":"error","message":"*/ expected"}]') { throw result }
606
+ },
607
+ () => {
608
+ const result = stringify(tokenizeString('/* multiline comment \n * **/'))
609
+ if (result !== '[{"kind":"/*","value":" multiline comment \\n * *"},{"kind":"nl"}]') { throw result }
610
+ },
611
+ () => {
612
+ const result = stringify(tokenizeString('/* multiline comment *\n * **/'))
613
+ if (result !== '[{"kind":"/*","value":" multiline comment *\\n * *"},{"kind":"nl"}]') { throw result }
614
+ },
573
615
  ]
574
616
  }
@@ -244,5 +244,11 @@ export default {
244
244
  const result = stringify(obj)
245
245
  if (result !== '["error","unexpected token"]') { throw result }
246
246
  },
247
+ () => {
248
+ const tokenList = tokenizeString('undefined')
249
+ const obj = parser.parse(tokenList)
250
+ const result = stringify(obj)
251
+ if (result !== '["error","unexpected token"]') { throw result }
252
+ },
247
253
  ]
248
254
  }
package/jsr.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@functionalscript/functionalscript",
3
- "version": "0.2.4",
3
+ "version": "0.2.6",
4
4
  "license": "AGPL-3.0-only",
5
5
  "exports": {
6
6
  "./com/cpp": "./out/com/cpp/module.f.mjs",
@@ -14,6 +14,9 @@
14
14
  "./commonjs/package/dependencies": "./out/commonjs/package/dependencies/module.f.mjs",
15
15
  "./commonjs/package": "./out/commonjs/package/module.f.mjs",
16
16
  "./commonjs/path": "./out/commonjs/path/module.f.mjs",
17
+ "./crypto/prime_field": "./out/crypto/prime_field/module.f.mjs",
18
+ "./crypto/secp": "./out/crypto/secp/module.f.mjs",
19
+ "./crypto/sha2": "./out/crypto/sha2/module.f.mjs",
17
20
  "./dev": "./out/dev/module.f.mjs",
18
21
  "./dev/test": "./out/dev/test/module.f.mjs",
19
22
  "./djs": "./out/djs/module.f.mjs",
@@ -28,9 +31,6 @@
28
31
  "./json/serializer": "./out/json/serializer/module.f.mjs",
29
32
  "./json/tokenizer": "./out/json/tokenizer/module.f.mjs",
30
33
  "./nodejs/version": "./out/nodejs/version/module.f.mjs",
31
- "./prime_field": "./out/prime_field/module.f.mjs",
32
- "./secp": "./out/secp/module.f.mjs",
33
- "./sha2": "./out/sha2/module.f.mjs",
34
34
  "./text/ascii": "./out/text/ascii/module.f.mjs",
35
35
  "./text": "./out/text/module.f.mjs",
36
36
  "./text/sgr": "./out/text/sgr/module.f.mjs",
@@ -1,4 +1,4 @@
1
- use crate::{interface::{Any, Container, Extension, Unpacked}, nullish::Nullish::*, simple::Simple};
1
+ use crate::{interface::{Any, Extension, Unpacked}, nullish::Nullish::*, simple::Simple};
2
2
 
3
3
  pub trait AnyExtension: Any {
4
4
  fn string(c: &str) -> Self::String16 {
@@ -99,7 +99,7 @@ impl<T: Raw64> Drop for NaNEnumPack<T> {
99
99
 
100
100
  #[cfg(test)]
101
101
  mod test {
102
- use core::{mem::{forget, needs_drop}, ptr::null};
102
+ use core::{mem::forget, ptr::null, sync::atomic::{AtomicUsize, Ordering}};
103
103
  use std::rc::Rc;
104
104
 
105
105
  use crate::nanenum::{Raw64, NEGATIVE, NOT_FINITE};
@@ -108,6 +108,7 @@ mod test {
108
108
 
109
109
  // See https://doc.rust-lang.org/std/mem/fn.needs_drop.html
110
110
 
111
+ /*
111
112
  trait Dropable {
112
113
  const _A: () = assert!(needs_drop::<Self>());
113
114
  }
@@ -115,6 +116,7 @@ mod test {
115
116
  trait NonDropable {
116
117
  const _A: () = assert!(!needs_drop::<Self>());
117
118
  }
119
+ */
118
120
 
119
121
  #[test]
120
122
  fn test_f64() {
@@ -125,13 +127,13 @@ mod test {
125
127
 
126
128
  #[test]
127
129
  fn test_pack() {
128
- static mut I: u64 = 0;
130
+ static I: AtomicUsize = AtomicUsize::new(0);
129
131
 
130
132
  struct P();
131
133
 
132
134
  impl Default for P {
133
135
  fn default() -> Self {
134
- unsafe { I += 1 };
136
+ I.fetch_add(1, Ordering::Relaxed);
135
137
  Self()
136
138
  }
137
139
  }
@@ -144,7 +146,7 @@ mod test {
144
146
 
145
147
  impl Drop for P {
146
148
  fn drop(&mut self) {
147
- unsafe { I -= 1 };
149
+ I.fetch_sub(1, Ordering::Relaxed);
148
150
  }
149
151
  }
150
152
 
@@ -162,20 +164,20 @@ mod test {
162
164
  //
163
165
 
164
166
  {
165
- unsafe { assert_eq!(I, 0) };
167
+ assert_eq!(I.load(Ordering::Relaxed), 0);
166
168
  {
167
169
  let x = P::default();
168
- unsafe { assert_eq!(I, 1) };
170
+ assert_eq!(I.load(Ordering::Relaxed), 1);
169
171
  let m = NaNEnum::Else(x);
170
- unsafe { assert_eq!(I, 1) };
172
+ assert_eq!(I.load(Ordering::Relaxed), 1);
171
173
  let p = NaNEnumPack::pack(m);
172
- unsafe { assert_eq!(I, 1) };
174
+ assert_eq!(I.load(Ordering::Relaxed), 1);
173
175
  let p1 = p.clone();
174
- unsafe { assert_eq!(I, 2) };
176
+ assert_eq!(I.load(Ordering::Relaxed), 2);
175
177
  let m1 = p1.unpack();
176
- unsafe { assert_eq!(I, 2) };
178
+ assert_eq!(I.load(Ordering::Relaxed), 2);
177
179
  if let NaNEnum::Else(x1) = m1 {
178
- unsafe { assert_eq!(I, 2) };
180
+ assert_eq!(I.load(Ordering::Relaxed), 2);
179
181
  // assert_ne!(&x as *const _, null())
180
182
  // assert_ne!(&m as *const _, null())
181
183
  assert_ne!(&p as *const _, null());
@@ -186,26 +188,26 @@ mod test {
186
188
  panic!()
187
189
  }
188
190
  }
189
- unsafe { assert_eq!(I, 0) };
191
+ assert_eq!(I.load(Ordering::Relaxed), 0);
190
192
  }
191
193
 
192
194
  //
193
195
 
194
196
  {
195
- unsafe { assert_eq!(I, 0) };
197
+ assert_eq!(I.load(Ordering::Relaxed), 0);
196
198
  {
197
199
  let x = P::default();
198
- unsafe { assert_eq!(I, 1) };
200
+ assert_eq!(I.load(Ordering::Relaxed), 1);
199
201
  let m = NaNEnum::Else(x.clone());
200
- unsafe { assert_eq!(I, 2) };
202
+ assert_eq!(I.load(Ordering::Relaxed), 2);
201
203
  let p = NaNEnumPack::pack(m.clone());
202
- unsafe { assert_eq!(I, 3) };
204
+ assert_eq!(I.load(Ordering::Relaxed), 3);
203
205
  let p1 = p.clone();
204
- unsafe { assert_eq!(I, 4) };
206
+ assert_eq!(I.load(Ordering::Relaxed), 4);
205
207
  let m1 = p1.clone().unpack();
206
- unsafe { assert_eq!(I, 5) };
208
+ assert_eq!(I.load(Ordering::Relaxed), 5);
207
209
  if let NaNEnum::Else(x1) = m1.clone() {
208
- unsafe { assert_eq!(I, 6) };
210
+ assert_eq!(I.load(Ordering::Relaxed), 6);
209
211
  assert_ne!(&x as *const _, null());
210
212
  assert_ne!(&m as *const _, null());
211
213
  assert_ne!(&p as *const _, null());
@@ -216,7 +218,7 @@ mod test {
216
218
  panic!()
217
219
  }
218
220
  }
219
- unsafe { assert_eq!(I, 0) };
221
+ assert_eq!(I.load(Ordering::Relaxed), 0);
220
222
  }
221
223
  }
222
224