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
@@ -3,13 +3,15 @@ export const element: (element: Element) => list.List<string>;
3
3
  export const html: f.Func<Element, list.List<string>>;
4
4
  export const htmlToString: f.Func<Element, string>;
5
5
  export type Tag = string;
6
- export type Element1 = readonly [Tag];
7
- export type Element2A = readonly [Tag, Attributes];
8
- export type Element2N = readonly [Tag, readonly Node[]];
9
- export type Element3 = readonly [Tag, Attributes, Nodes];
10
- export type Element = Element1 | Element2A | Element2N | Element3;
6
+ export type VoidTagList = typeof voidTagList;
7
+ export type VoidTag = keyof readonly ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"];
8
+ export type Element1 = readonly [Tag, ...Node[]];
9
+ export type Element2 = readonly [Tag, Attributes, ...Node[]];
10
+ export type Element = Element1 | Element2;
11
11
  export type Attributes = { readonly [k in string]: string; };
12
- export type Nodes = list.List<Node>;
13
12
  export type Node = Element | string;
14
13
  import * as list from '../types/list/module.f.mjs';
15
14
  import * as f from '../types/function/module.f.mjs';
15
+ /** @typedef {string} Tag */
16
+ declare const voidTagList: readonly ["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"];
17
+ export {};
@@ -12,7 +12,7 @@ const { fromCharCode } = String;
12
12
  const { entries } = Object;
13
13
  /** @typedef {string} Tag */
14
14
  // https://developer.mozilla.org/en-US/docs/Glossary/Void_element
15
- const voidTagList = [
15
+ const voidTagList = /** @type {const} */ ([
16
16
  'area',
17
17
  'base',
18
18
  'br',
@@ -27,20 +27,20 @@ const voidTagList = [
27
27
  'source',
28
28
  'track',
29
29
  'wbr',
30
- ];
30
+ ]);
31
+ /** @typedef {typeof voidTagList} VoidTagList */
32
+ /** @typedef {keyof voidTagList} VoidTag */
31
33
  /** @type {(tag: string) => boolean} */
32
- const isVoid = tag => voidTagList.includes(tag);
33
- /** @typedef {readonly[Tag]} Element1*/
34
- /** @typedef {readonly[Tag, Attributes]} Element2A */
35
- /** @typedef {readonly[Tag, readonly Node[]]} Element2N */
36
- /** @typedef {readonly[Tag, Attributes, Nodes]} Element3*/
37
- /** @typedef {Element1 | Element2A | Element2N | Element3} Element */
34
+ const isVoid = tag => voidTagList.includes(/** @type {any} */ (tag));
35
+ /** @typedef {readonly[Tag, ...Node[]]} Element1*/
36
+ /** @typedef {readonly[Tag, Attributes, ...Node[]]} Element2 */
37
+ /** @typedef {Element1 | Element2 } Element */
38
38
  /**
39
39
  * @typedef {{
40
40
  * readonly[k in string]: string
41
41
  * }} Attributes
42
42
  */
43
- /** @typedef {list.List<Node>} Nodes */
43
+ // /** @typedef {list.List<Node>} Nodes */
44
44
  /** @typedef {Element | string} Node */
45
45
  /**
46
46
  * https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-in-html
@@ -64,31 +64,17 @@ const nodes = flatMap(node);
64
64
  const attribute = ([name, value]) => flat([[' ', name, '="'], escape(value), ['"']]);
65
65
  /** @type {(a: Attributes) => list.List<string>} */
66
66
  const attributes = compose(entries)(flatMap(attribute));
67
- const open = (/** @type {Element2A} */ [tag, a]) => flat([[`<`, tag], attributes(a), [`>`]]);
68
- const close = (/** @type {string}*/ tag) => ['</', tag, '>'];
69
- /** @type {(_: Element3) => list.List<string>} */
70
- const element3 = ([tag, a, ns]) => flat([open([tag, a]), nodes(ns), close(tag)]);
71
- /** @type {(_: Element2A) => list.List<string>} */
72
- const element2a = e => {
73
- const [tag] = e;
74
- return flat([open(e), isVoid(tag) ? [] : close(tag)]);
67
+ /** @type {(t: string) => (a: Attributes) => list.List<string>} */
68
+ const open = t => a => flat([[`<`, t], attributes(a), [`>`]]);
69
+ /** @type {(t: string) => (an: readonly[Attributes, readonly Node[]]) => list.List<string>} */
70
+ const element3 = t => ([a, n]) => {
71
+ const o = flat([[`<`, t], attributes(a), [`>`]]);
72
+ return isVoid(t) ? o : flat([o, nodes(n), ['</', t, '>']]);
75
73
  };
76
74
  /** @type {(element: Element) => list.List<string>} */
77
75
  export const element = e => {
78
- switch (e.length) {
79
- case 1: {
80
- return element2a([e[0], {}]);
81
- }
82
- case 2: {
83
- const [tag, a] = e;
84
- return a instanceof Array ?
85
- element3([tag, {}, a]) :
86
- element2a([tag, a]);
87
- }
88
- default: {
89
- return element3(e);
90
- }
91
- }
76
+ const [t, a, ...n] = e;
77
+ return element3(t)(a === undefined ? [{}, []] : typeof a === 'object' && !(a instanceof Array) ? [a, n] : [{}, [a, ...n]]);
92
78
  };
93
79
  export const html = compose(element)(listConcat(['<!DOCTYPE html>']));
94
80
  export const htmlToString = compose(html)(stringConcat);
@@ -1,9 +1,9 @@
1
1
  import * as _ from './module.f.mjs';
2
2
  export default {
3
3
  empty: () => {
4
- const r = _.htmlToString(['html', []]);
4
+ const r = _.htmlToString(['html']);
5
5
  if (r !== '<!DOCTYPE html><html></html>') {
6
- throw r;
6
+ throw `empty: ${r}`;
7
7
  }
8
8
  },
9
9
  empty2: () => {
@@ -20,7 +20,7 @@ export default {
20
20
  },
21
21
  some: () => {
22
22
  /** @type {_.Element} */
23
- const x = ['div', {}, ['<div>&amp;</div>', ['a', { href: 'hello"' }, []]]];
23
+ const x = ['div', {}, '<div>&amp;</div>', ['a', { href: 'hello"' }]];
24
24
  const s = _.htmlToString(x);
25
25
  if (s !== '<!DOCTYPE html><div>&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') {
26
26
  throw s;
@@ -28,7 +28,7 @@ export default {
28
28
  },
29
29
  some2: () => {
30
30
  /** @type {_.Element} */
31
- const x = ['div', ['<div>&amp;</div>', ['a', { href: 'hello"' }, []]]];
31
+ const x = ['div', '<div>&amp;</div>', ['a', { href: 'hello"' }]];
32
32
  const s = _.htmlToString(x);
33
33
  if (s !== '<!DOCTYPE html><div>&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') {
34
34
  throw s;
@@ -36,7 +36,7 @@ export default {
36
36
  },
37
37
  someVoid: () => {
38
38
  /** @type {_.Element} */
39
- const x = ['div', [['br', { id: '5' }], '<div>&amp;</div>', ['a', { href: 'hello"' }, []]]];
39
+ const x = ['div', ['br', { id: '5' }], '<div>&amp;</div>', ['a', { href: 'hello"' }]];
40
40
  const s = _.htmlToString(x);
41
41
  if (s !== '<!DOCTYPE html><div><br id="5">&lt;div&gt;&amp;amp;&lt;/div&gt;<a href="hello&quot;"></a></div>') {
42
42
  throw s;
@@ -34,6 +34,9 @@ export type FalseToken = {
34
34
  export type NullToken = {
35
35
  readonly kind: "null";
36
36
  };
37
+ export type UndefinedToken = {
38
+ readonly kind: "undefined";
39
+ };
37
40
  export type KeywordToken = {
38
41
  readonly kind: "arguments" | "await" | "break" | "case" | "catch" | "class" | "const" | "continue";
39
42
  } | {
@@ -74,9 +77,13 @@ export type OperatorToken = {
74
77
  } | {
75
78
  readonly kind: "?" | "?." | "=>";
76
79
  };
77
- export type JsToken = KeywordToken | TrueToken | FalseToken | NullToken | WhitespaceToken | NewLineToken | StringToken | NumberToken | ErrorToken | IdToken | BigIntToken | OperatorToken;
78
- export type TokenizerState = InitialState | ParseIdState | ParseStringState | ParseEscapeCharState | ParseUnicodeCharState | ParseNumberState | InvalidNumberState | ParseOperatorState | ParseMinusState | ParseWhitespaceState | ParseNewLineState | EofState;
79
- export type ErrorMessage = "\" are missing" | "unescaped character" | "invalid hex value" | "unexpected character" | "invalid number" | "invalid token" | "eof";
80
+ export type CommentToken = {
81
+ readonly kind: "//" | "/*";
82
+ readonly value: string;
83
+ };
84
+ export type JsToken = KeywordToken | TrueToken | FalseToken | NullToken | WhitespaceToken | NewLineToken | StringToken | NumberToken | ErrorToken | IdToken | BigIntToken | UndefinedToken | OperatorToken | CommentToken;
85
+ export type TokenizerState = InitialState | ParseIdState | ParseStringState | ParseEscapeCharState | ParseUnicodeCharState | ParseNumberState | InvalidNumberState | ParseOperatorState | ParseWhitespaceState | ParseNewLineState | ParseCommentState | EofState;
86
+ export type ErrorMessage = "\" are missing" | "unescaped character" | "invalid hex value" | "unexpected character" | "invalid number" | "invalid token" | "*/ expected" | "unterminated string literal" | "eof";
80
87
  export type InitialState = {
81
88
  readonly kind: "initial";
82
89
  };
@@ -105,6 +112,11 @@ export type ParseOperatorState = {
105
112
  export type ParseMinusState = {
106
113
  readonly kind: "-";
107
114
  };
115
+ export type ParseCommentState = {
116
+ readonly kind: "//" | "/*" | "/**";
117
+ readonly value: string;
118
+ readonly newLine: boolean;
119
+ };
108
120
  export type ParseUnicodeCharState = {
109
121
  readonly kind: "unicodeChar";
110
122
  readonly value: string;
@@ -54,6 +54,7 @@ leftCurlyBracket, rightCurlyBracket, dollarSign } = ascii.ascii;
54
54
  /** @typedef {{readonly kind: 'true'}} TrueToken */
55
55
  /** @typedef {{readonly kind: 'false'}} FalseToken */
56
56
  /** @typedef {{readonly kind: 'null'}} NullToken */
57
+ /** @typedef {{readonly kind: 'undefined'}} UndefinedToken */
57
58
  /**
58
59
  * @typedef {|
59
60
  * {readonly kind: 'arguments' | 'await' | 'break' | 'case' | 'catch' | 'class' | 'const' | 'continue' } |
@@ -85,6 +86,12 @@ leftCurlyBracket, rightCurlyBracket, dollarSign } = ascii.ascii;
85
86
  * {readonly kind: '?' | '?.' | '=>'}
86
87
  * } OperatorToken
87
88
  */
89
+ /**
90
+ * @typedef {{
91
+ * readonly kind: '//' | '/*'
92
+ * readonly value: string
93
+ * }} CommentToken
94
+ * */
88
95
  /**
89
96
  * @typedef {|
90
97
  * KeywordToken |
@@ -98,7 +105,9 @@ leftCurlyBracket, rightCurlyBracket, dollarSign } = ascii.ascii;
98
105
  * ErrorToken |
99
106
  * IdToken |
100
107
  * BigIntToken |
101
- * OperatorToken
108
+ * UndefinedToken |
109
+ * OperatorToken |
110
+ * CommentToken
102
111
  * } JsToken
103
112
  */
104
113
  const rangeOneNine = range('19');
@@ -178,20 +187,22 @@ const rangeId = [digitRange, ...rangeIdStart];
178
187
  * ParseNumberState |
179
188
  * InvalidNumberState |
180
189
  * ParseOperatorState |
181
- * ParseMinusState |
182
190
  * ParseWhitespaceState |
183
191
  * ParseNewLineState |
192
+ * ParseCommentState |
184
193
  * EofState
185
194
  * } TokenizerState
186
195
  */
187
196
  /**
188
197
  * @typedef {|
189
- * '" are missing' |
198
+ * '" are missing' |
190
199
  * 'unescaped character' |
191
200
  * 'invalid hex value' |
192
201
  * 'unexpected character' |
193
202
  * 'invalid number' |
194
203
  * 'invalid token' |
204
+ * '*\/ expected' |
205
+ * 'unterminated string literal' |
195
206
  * 'eof'
196
207
  * } ErrorMessage
197
208
  */
@@ -203,6 +214,13 @@ const rangeId = [digitRange, ...rangeIdStart];
203
214
  /** @typedef {{ readonly kind: 'escapeChar', readonly value: string}} ParseEscapeCharState */
204
215
  /** @typedef {{ readonly kind: 'op', readonly value: string}} ParseOperatorState */
205
216
  /** @typedef {{ readonly kind: '-'}} ParseMinusState */
217
+ /**
218
+ * @typedef {{
219
+ * readonly kind: '//' | '/*' | '/**'
220
+ * readonly value: string
221
+ * readonly newLine: boolean
222
+ * }} ParseCommentState
223
+ */
206
224
  /**
207
225
  * @typedef {{
208
226
  * readonly kind: 'unicodeChar'
@@ -213,7 +231,7 @@ const rangeId = [digitRange, ...rangeIdStart];
213
231
  */
214
232
  /**
215
233
  * @typedef {{
216
- * readonly kind: 'number',
234
+ * readonly kind: 'number'
217
235
  * readonly numberKind: '0' | 'int' | '.' | 'fractional' | 'e' | 'e+' | 'e-' | 'expDigits' | 'bigint'
218
236
  * readonly value: string
219
237
  * readonly b: ParseNumberBuffer
@@ -352,6 +370,7 @@ const keywordEntries = [
352
370
  ['true', { kind: 'true' }],
353
371
  ['try', { kind: 'try' }],
354
372
  ['typeof', { kind: 'typeof' }],
373
+ ['undefined', { kind: 'undefined' }],
355
374
  ['var', { kind: 'var' }],
356
375
  ['void', { kind: 'void' }],
357
376
  ['while', { kind: 'while' }],
@@ -431,8 +450,8 @@ const hasOperatorToken = op => at(op)(operatorMap) !== null;
431
450
  const initialStateOp = create(state => () => [[{ kind: 'error', message: 'unexpected character' }], state])([
432
451
  rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: 'int' }]),
433
452
  rangeSetFunc(rangeIdStart)(() => input => [empty, { kind: 'id', value: fromCharCode(input) }]),
434
- rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, { kind: 'ws' }]),
435
- rangeSetFunc(rangeSetNewLine)(state => () => [empty, { kind: 'nl' }]),
453
+ rangeSetFunc(rangeSetWhiteSpace)(() => () => [empty, { kind: 'ws' }]),
454
+ rangeSetFunc(rangeSetNewLine)(() => () => [empty, { kind: 'nl' }]),
436
455
  rangeFunc(one(quotationMark))(() => () => [empty, { kind: 'string', value: '' }]),
437
456
  rangeFunc(one(digit0))(() => input => [empty, { kind: 'number', value: fromCharCode(input), b: startNumber(input), numberKind: '0' }]),
438
457
  rangeSetFunc(rangeOpStart)(() => input => [empty, { kind: 'op', value: fromCharCode(input) }])
@@ -550,16 +569,11 @@ const invalidNumberStateOp = create(() => () => [empty, { kind: 'invalidNumber'
550
569
  return [{ first: { kind: 'error', message: 'invalid number' }, tail: next[0] }, next[1]];
551
570
  })
552
571
  ]);
553
- /** @type {(state: ParseMinusState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
554
- const parseMinusStateOp = create(() => input => tokenizeOp({ kind: 'op', value: '-' })(input))([
555
- rangeFunc(one(fullStop))(() => input => tokenizeOp({ kind: 'invalidNumber' })(input)),
556
- rangeFunc(one(digit0))(() => () => [empty, { kind: 'number', value: '-0', b: startNegativeNumber, numberKind: '0' }]),
557
- rangeFunc(rangeOneNine)(() => input => [empty, { kind: 'number', value: appendChar('-')(input), b: addIntDigit(input)(startNegativeNumber), numberKind: 'int' }]),
558
- ]);
559
572
  /** @type {(state: ParseStringState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
560
573
  const parseStringStateOp = create(state => input => [empty, { kind: 'string', value: appendChar(state.value)(input) }])([
561
574
  rangeFunc(one(quotationMark))(state => () => [[{ kind: 'string', value: state.value }], { kind: 'initial' }]),
562
- rangeFunc(one(reverseSolidus))(state => () => [empty, { kind: 'escapeChar', value: state.value }])
575
+ rangeFunc(one(reverseSolidus))(state => () => [empty, { kind: 'escapeChar', value: state.value }]),
576
+ rangeSetFunc(rangeSetNewLine)(() => () => [[{ kind: 'error', message: 'unterminated string literal' }], { kind: 'nl' }])
563
577
  ]);
564
578
  /** @type {(state: ParseEscapeCharState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
565
579
  const parseEscapeDefault = state => input => {
@@ -610,20 +624,45 @@ const parseIdStateOp = create(parseIdDefault)([
610
624
  /** @type {(state: ParseOperatorState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
611
625
  const parseOperatorStateOp = state => input => {
612
626
  const nextStateValue = appendChar(state.value)(input);
613
- if (hasOperatorToken(nextStateValue))
614
- return [empty, { kind: 'op', value: nextStateValue }];
615
- const next = tokenizeOp({ kind: 'initial' })(input);
616
- return [{ first: getOperatorToken(state.value), tail: next[0] }, next[1]];
627
+ switch (nextStateValue) {
628
+ case '//': return [empty, { kind: '//', value: '', newLine: false }];
629
+ case '/*': return [empty, { kind: '/*', value: '', newLine: false }];
630
+ default: {
631
+ if (hasOperatorToken(nextStateValue))
632
+ return [empty, { kind: 'op', value: nextStateValue }];
633
+ const next = tokenizeOp({ kind: 'initial' })(input);
634
+ return [{ first: getOperatorToken(state.value), tail: next[0] }, next[1]];
635
+ }
636
+ }
617
637
  };
638
+ /** @type {(state: ParseCommentState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
639
+ const parseSinglelineCommentStateOp = create(state => input => [empty, { ...state, value: appendChar(state.value)(input) }])([
640
+ rangeSetFunc(rangeSetNewLine)(state => () => [[{ kind: '//', value: state.value }], { kind: 'nl' }])
641
+ ]);
642
+ /** @type {(state: ParseCommentState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
643
+ const parseMultilineCommentStateOp = create(state => input => [empty, { ...state, value: appendChar(state.value)(input) }])([
644
+ rangeFunc(one(asterisk))(state => () => [empty, { ...state, kind: '/**' }]),
645
+ rangeSetFunc(rangeSetNewLine)(state => input => [empty, { ...state, value: appendChar(state.value)(input), newLine: true }]),
646
+ ]);
647
+ /** @type {(state: ParseCommentState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
648
+ const parseMultilineCommentAsteriskStateOp = create(state => input => [empty, { ...state, kind: '/*', value: appendChar(appendChar(state.value)(asterisk))(input) }])([
649
+ rangeFunc(one(asterisk))(state => () => [empty, { ...state, value: appendChar(state.value)(asterisk) }]),
650
+ rangeSetFunc(rangeSetNewLine)(state => input => [empty, { kind: '/*', value: appendChar(appendChar(state.value)(asterisk))(input), newLine: true }]),
651
+ rangeFunc(one(solidus))(state => () => {
652
+ /** @type {list.List<JsToken>} */
653
+ const tokens = state.newLine ? [{ kind: '/*', value: state.value }, { kind: 'nl' }] : [{ kind: '/*', value: state.value }];
654
+ return [tokens, { kind: 'initial' }];
655
+ })
656
+ ]);
618
657
  /** @type {(state: ParseWhitespaceState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
619
- const parseWhitespaceDefault = state => input => {
658
+ const parseWhitespaceDefault = () => input => {
620
659
  const next = tokenizeOp({ kind: 'initial' })(input);
621
660
  return [{ first: { kind: 'ws' }, tail: next[0] }, next[1]];
622
661
  };
623
662
  /** @type {(state: ParseWhitespaceState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
624
663
  const parseWhitespaceStateOp = create(parseWhitespaceDefault)([
625
664
  rangeSetFunc(rangeSetWhiteSpace)(state => () => [empty, state]),
626
- rangeSetFunc(rangeSetNewLine)(state => () => [empty, { kind: 'nl' }])
665
+ rangeSetFunc(rangeSetNewLine)(() => () => [empty, { kind: 'nl' }])
627
666
  ]);
628
667
  /** @type {(state: ParseNewLineState) => (input: number) => readonly[list.List<JsToken>, TokenizerState]} */
629
668
  const parseNewLineDefault = state => input => {
@@ -648,7 +687,9 @@ const tokenizeCharCodeOp = state => {
648
687
  case 'invalidNumber': return invalidNumberStateOp(state);
649
688
  case 'number': return parseNumberStateOp(state);
650
689
  case 'op': return parseOperatorStateOp(state);
651
- case '-': return parseMinusStateOp(state);
690
+ case '//': return parseSinglelineCommentStateOp(state);
691
+ case '/*': return parseMultilineCommentStateOp(state);
692
+ case '/**': return parseMultilineCommentAsteriskStateOp(state);
652
693
  case 'ws': return parseWhitespaceStateOp(state);
653
694
  case 'nl': return parseNewLineStateOp(state);
654
695
  case 'eof': return eofStateOp(state);
@@ -668,11 +709,13 @@ const tokenizeEofOp = state => {
668
709
  case '.':
669
710
  case 'e':
670
711
  case 'e+':
671
- case 'e-': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'invalidNumber', }];
712
+ case 'e-': return [[{ kind: 'error', message: 'invalid number' }], { kind: 'eof', }];
672
713
  default: return [[bufferToNumberToken(state)], { kind: 'eof' }];
673
714
  }
674
715
  case 'op': return [[getOperatorToken(state.value)], { kind: 'eof' }];
675
- case '-': return [[{ kind: '-' }], { kind: 'eof' }];
716
+ case '//': return [[{ kind: '//', value: state.value }], { kind: 'eof' }];
717
+ case '/*':
718
+ case '/**': return [[{ kind: 'error', message: '*/ expected' }], { kind: 'eof', }];
676
719
  case 'ws': return [[{ kind: 'ws' }], { kind: 'eof' }];
677
720
  case 'nl': return [[{ kind: 'nl' }], { kind: 'eof' }];
678
721
  case 'eof': return [[{ kind: 'error', message: 'eof' }], state];
@@ -4,5 +4,6 @@ declare namespace _default {
4
4
  let ws: (() => void)[];
5
5
  let id: (() => void)[];
6
6
  let keywords: (() => void)[];
7
+ let comments: (() => void)[];
7
8
  }
8
9
  export default _default;
@@ -124,6 +124,18 @@ export default {
124
124
  throw result;
125
125
  }
126
126
  },
127
+ () => {
128
+ const result = stringify(tokenizeString('"\r"'));
129
+ if (result !== '[{"kind":"error","message":"unterminated string literal"},{"kind":"nl"},{"kind":"error","message":"\\" are missing"}]') {
130
+ throw result;
131
+ }
132
+ },
133
+ () => {
134
+ const result = stringify(tokenizeString('"\n null'));
135
+ if (result !== '[{"kind":"error","message":"unterminated string literal"},{"kind":"nl"},{"kind":"null"}]') {
136
+ throw result;
137
+ }
138
+ },
127
139
  () => {
128
140
  const result = stringify(tokenizeString('"\\b\\f\\n\\r\\t"'));
129
141
  if (result !== '[{"kind":"string","value":"\\b\\f\\n\\r\\t"}]') {
@@ -564,6 +576,12 @@ export default {
564
576
  throw result;
565
577
  }
566
578
  },
579
+ () => {
580
+ const result = stringify(tokenizeString('undefined'));
581
+ if (result !== '[{"kind":"undefined"}]') {
582
+ throw result;
583
+ }
584
+ },
567
585
  () => {
568
586
  const result = stringify(tokenizeString('[null]'));
569
587
  if (result !== '[{"kind":"["},{"kind":"null"},{"kind":"]"}]') {
@@ -840,5 +858,49 @@ export default {
840
858
  throw result;
841
859
  }
842
860
  },
861
+ ],
862
+ comments: [
863
+ () => {
864
+ const result = stringify(tokenizeString('//singleline comment'));
865
+ if (result !== '[{"kind":"//","value":"singleline comment"}]') {
866
+ throw result;
867
+ }
868
+ },
869
+ () => {
870
+ const result = stringify(tokenizeString('true//singleline comment\nfalse'));
871
+ if (result !== '[{"kind":"true"},{"kind":"//","value":"singleline comment"},{"kind":"nl"},{"kind":"false"}]') {
872
+ throw result;
873
+ }
874
+ },
875
+ () => {
876
+ const result = stringify(tokenizeString('/* multiline comment */'));
877
+ if (result !== '[{"kind":"/*","value":" multiline comment "}]') {
878
+ throw result;
879
+ }
880
+ },
881
+ () => {
882
+ const result = stringify(tokenizeString('/* multiline comment *'));
883
+ if (result !== '[{"kind":"error","message":"*/ expected"}]') {
884
+ throw result;
885
+ }
886
+ },
887
+ () => {
888
+ const result = stringify(tokenizeString('/* multiline comment '));
889
+ if (result !== '[{"kind":"error","message":"*/ expected"}]') {
890
+ throw result;
891
+ }
892
+ },
893
+ () => {
894
+ const result = stringify(tokenizeString('/* multiline comment \n * **/'));
895
+ if (result !== '[{"kind":"/*","value":" multiline comment \\n * *"},{"kind":"nl"}]') {
896
+ throw result;
897
+ }
898
+ },
899
+ () => {
900
+ const result = stringify(tokenizeString('/* multiline comment *\n * **/'));
901
+ if (result !== '[{"kind":"/*","value":" multiline comment *\\n * *"},{"kind":"nl"}]') {
902
+ throw result;
903
+ }
904
+ },
843
905
  ]
844
906
  };
@@ -317,5 +317,13 @@ export default {
317
317
  throw result;
318
318
  }
319
319
  },
320
+ () => {
321
+ const tokenList = tokenizeString('undefined');
322
+ const obj = parser.parse(tokenList);
323
+ const result = stringify(obj);
324
+ if (result !== '["error","unexpected token"]') {
325
+ throw result;
326
+ }
327
+ },
320
328
  ]
321
329
  };
@@ -10,62 +10,148 @@ export const empty: 1n;
10
10
  /**
11
11
  * Calculates the length of the given vector of bits.
12
12
  */
13
- export const len: (v: bigint) => bigint;
13
+ export const length: (v: bigint) => bigint;
14
14
  /**
15
- * Extract an unsigned integer of the given `uintLen` from the given vector.
15
+ * Creates a vector of bits of the given `len` and the given unsigned integer.
16
+ *
17
+ * @type {(len: bigint) => (ui: bigint) => Vec}
18
+ *
19
+ * @example
20
+ *
21
+ * ```js
22
+ * const vec4 = vec(4n)
23
+ * const v0 = vec4(5n) // 0x15n
24
+ * const v1 = vec4(0x5FEn) // 0x1En
25
+ * ```
26
+ */
27
+ export const vec: (len: bigint) => (ui: bigint) => Vec;
28
+ /**
29
+ * Returns the unsigned integer of the given vector by removing a stop bit.
30
+ *
31
+ * @type {(len: Vec) => bigint}
32
+ *
33
+ * @example
34
+ *
35
+ * ```js
36
+ * const vector = vec(8n)(0x5n) // 0x105n
37
+ * const result = uint(vector); // result is 0x5n
38
+ * ```
39
+ */
40
+ export const uint: (len: Vec) => bigint;
41
+ /**
42
+ * Extract the least significant unsigned integer from the given vector.
16
43
  *
17
44
  * @type {(uintLen: bigint) => (v: Vec) => bigint}
18
45
  *
19
46
  * @example
20
47
  *
21
48
  * ```js
22
- * const vector = 0b110101n;
23
- * const extract3Bits = uint(3n);
24
- * const result = extract3Bits(vector); // result is 0b101n (5n)
49
+ * const vector = vec(8n)(0xF5n) // 0x1F5n
50
+ * const result = uintLsb(4n)(vector); // result is 5n
51
+ * const result2 = uintLsb(16n)(vector); // result2 is 0xF5n
25
52
  * ```
26
53
  */
27
- export const uint: (uintLen: bigint) => (v: Vec) => bigint;
54
+ export const uintLsb: (uintLen: bigint) => (v: Vec) => bigint;
28
55
  /**
29
- * Creates a vector of bits of the given `vecLen` from the given unsigned integer.
56
+ * Removes the first `len` least significant bits from the given vector.
30
57
  *
31
- * @type {(vecLen: bigint) => (ui: bigint) => Vec}
58
+ * @type {(len: bigint) => (v: Vec) => Vec}
32
59
  *
33
60
  * @example
34
61
  *
35
62
  * ```js
36
- * const createVector = vec(4n);
37
- * const vector = createVector(5n); // vector is 0b10101n
63
+ * const v = vec(16n)(0x3456n) // 0x13456n
64
+ * const r = removeLsb(4n)(v) // 0x1345n
65
+ * const r2 = removeLsb(24n)(v) // 0x1n
38
66
  * ```
39
67
  */
40
- export const vec: (vecLen: bigint) => (ui: bigint) => Vec;
68
+ export const removeLsb: (len: bigint) => (v: Vec) => Vec;
41
69
  /**
42
- * Appends the vector `b` to the back of the vector `a`.
70
+ * Extracts the least significant unsigned integer and removes it from the vector.
43
71
  *
44
- * @type {(a: Vec) => (b: Vec) => Vec}
72
+ * @type {(len: bigint) => (v: Vec) => [bigint, Vec]}
73
+ *
74
+ * @example
75
+ *
76
+ * ```js
77
+ * const vector = vec(8n)(0xF5n) // 0x1F5n
78
+ * const [result, rest] = popUintLsb(4n)(vector); // result is 5n, rest is 0x1Fn
79
+ * const [result2, rest2] = popUintLsb(16n)(vector); // result2 is 0xF5n, rest2 is 1n
80
+ * ```
81
+ */
82
+ export const popUintLsb: (len: bigint) => (v: Vec) => [bigint, Vec];
83
+ /**
84
+ * Extract the most significant unsigned integer of the given `len` from the given vector.
85
+ *
86
+ * @type {(len: bigint) => (v: Vec) => bigint}
45
87
  *
46
88
  * @example
47
89
  *
48
90
  * ```js
49
- * const vec8 = vec(8n)
50
- * const a = vec8(0x345n)
51
- * const b = vec8(0x789n)
52
- * const ab = appendBack(a)(b) // 0x18945n
91
+ * const vector = vec(8n)(0xF5n) // 0x1F5n
92
+ * const result = uintMsb(4n)(vector); // result is 0xFn
93
+ * const result2 = uintMsb(16n)(vector); // result2 is 0xF500n
53
94
  * ```
54
95
  */
55
- export const appendBack: (a: Vec) => (b: Vec) => Vec;
96
+ export const uintMsb: (len: bigint) => (v: Vec) => bigint;
56
97
  /**
57
- * Removes the first `len` bits from the given vector.
98
+ * Removes the first `len` most significant bits from the given vector.
58
99
  *
59
100
  * @type {(len: bigint) => (v: Vec) => Vec}
60
101
  *
61
102
  * @example
62
103
  *
63
104
  * ```js
64
- * const v = vec(17n)(0x12345n) // v = 0x32345n
65
- * const r = removeFront(9n)(v) // r = 0x191n
105
+ * const v = vec(16n)(0x3456n) // 0x13456n
106
+ * const r = removeMsb(4n)(v) // 0x1456n
107
+ * const r2 = removeMsb(24n)(v) // 0x1n
108
+ * ```
109
+ */
110
+ export const removeMsb: (len: bigint) => (v: Vec) => Vec;
111
+ /**
112
+ * Extracts the most significant unsigned integer and removes it from the vector.
113
+ *
114
+ * @type {(len: bigint) => (v: Vec) => [bigint, Vec]}
115
+ *
116
+ * @example
117
+ *
118
+ * ```js
119
+ * const vector = vec(8n)(0xF5n) // 0x1F5n
120
+ * const [result, rest] = popUintMsb(4n)(vector); // [0xFn, 0x15n]
121
+ * const [result2, rest2] = popUintMsb(16n)(vector); // [0xF500n, 1n]
122
+ * ```
123
+ */
124
+ export const popUintMsb: (len: bigint) => (v: Vec) => [bigint, Vec];
125
+ /**
126
+ * Concat the given vectors of bits. The first vector is the least significant.
127
+ *
128
+ * @type {(a: Vec) => (b: Vec) => Vec}
129
+ *
130
+ * @example
131
+ *
132
+ * ```js
133
+ * const u8 = vec(8n)
134
+ * const a = u8(0x45n) // 0x145n
135
+ * const b = u8(0x89n) // 0x189n
136
+ * const ab = concatLsb(a)(b) // 0x18945n
137
+ * ```
138
+ */
139
+ export const concatLsb: (a: Vec) => (b: Vec) => Vec;
140
+ /**
141
+ * Concat the given vectors of bits. The first vector is the most significant.
142
+ *
143
+ * @type {(b: Vec) => (a: Vec) => Vec}
144
+ *
145
+ * @example
146
+ *
147
+ * ```js
148
+ * const u8 = vec(8n)
149
+ * const a = u8(0x45n) // 0x145n
150
+ * const b = u8(0x89n) // 0x189n
151
+ * const ab = concatMsb(a)(b) // 0x14589n
66
152
  * ```
67
153
  */
68
- export const removeFront: (len: bigint) => (v: Vec) => Vec;
154
+ export const concatMsb: (b: Vec) => (a: Vec) => Vec;
69
155
  /**
70
156
  * A vector of bits represented as a `bigint`.
71
157
  */