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.
Files changed (55) hide show
  1. package/CHANGELOG.md +6 -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/module.f.mjs +18 -33
  14. package/html/test.f.mjs +6 -6
  15. package/issues/05-publish.md +17 -22
  16. package/issues/README.md +10 -2
  17. package/js/tokenizer/module.f.mjs +75 -26
  18. package/js/tokenizer/test.f.mjs +42 -0
  19. package/json/parser/test.f.mjs +6 -0
  20. package/jsr.json +4 -4
  21. package/nanvm-lib/src/extension.rs +1 -1
  22. package/nanvm-lib/src/nanenum.rs +22 -20
  23. package/out/{prime_field → crypto/prime_field}/module.f.d.mts +1 -1
  24. package/out/{prime_field → crypto/prime_field}/module.f.mjs +2 -2
  25. package/out/{secp → crypto/secp}/module.f.d.mts +1 -1
  26. package/out/{secp → crypto/secp}/module.f.mjs +2 -2
  27. package/out/{sha2 → crypto/sha2}/module.f.d.mts +3 -3
  28. package/out/{sha2 → crypto/sha2}/module.f.mjs +4 -4
  29. package/out/{sha2 → crypto/sha2}/test.f.mjs +2 -2
  30. package/out/djs/module.f.d.mts +1 -1
  31. package/out/djs/module.f.mjs +5 -1
  32. package/out/djs/parser/module.f.d.mts +1 -1
  33. package/out/djs/parser/module.f.mjs +105 -89
  34. package/out/djs/parser/test.f.d.mts +1 -0
  35. package/out/djs/parser/test.f.mjs +38 -4
  36. package/out/djs/tokenizer/module.f.d.mts +2 -2
  37. package/out/djs/tokenizer/module.f.mjs +6 -2
  38. package/out/djs/tokenizer/test.f.d.mts +1 -0
  39. package/out/djs/tokenizer/test.f.mjs +50 -0
  40. package/out/html/module.f.d.mts +8 -6
  41. package/out/html/module.f.mjs +17 -31
  42. package/out/html/test.f.mjs +5 -5
  43. package/out/js/tokenizer/module.f.d.mts +15 -3
  44. package/out/js/tokenizer/module.f.mjs +65 -22
  45. package/out/js/tokenizer/test.f.d.mts +1 -0
  46. package/out/js/tokenizer/test.f.mjs +62 -0
  47. package/out/json/parser/test.f.mjs +8 -0
  48. package/package.json +1 -1
  49. /package/{prime_field → crypto/prime_field}/test.f.mjs +0 -0
  50. /package/{secp → crypto/secp}/test.f.mjs +0 -0
  51. /package/out/{prime_field → crypto/prime_field}/test.f.d.mts +0 -0
  52. /package/out/{prime_field → crypto/prime_field}/test.f.mjs +0 -0
  53. /package/out/{secp → crypto/secp}/test.f.d.mts +0 -0
  54. /package/out/{secp → crypto/secp}/test.f.mjs +0 -0
  55. /package/out/{sha2 → crypto/sha2}/test.f.d.mts +0 -0
@@ -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
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.2.4",
3
+ "version": "0.2.5",
4
4
  "type": "module",
5
5
  "description": "FunctionalScript is a functional subset of JavaScript",
6
6
  "scripts": {
File without changes
File without changes
File without changes
File without changes
File without changes