subscript 9.2.0 → 10.0.0

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 (83) hide show
  1. package/README.md +115 -169
  2. package/feature/access.js +67 -7
  3. package/feature/accessor.js +49 -0
  4. package/feature/asi.js +15 -0
  5. package/feature/async.js +45 -0
  6. package/feature/block.js +41 -0
  7. package/feature/class.js +69 -0
  8. package/feature/collection.js +40 -0
  9. package/feature/comment.js +25 -5
  10. package/feature/destruct.js +33 -0
  11. package/feature/function.js +44 -0
  12. package/feature/group.js +39 -9
  13. package/feature/if.js +23 -38
  14. package/feature/literal.js +13 -0
  15. package/feature/loop.js +107 -106
  16. package/feature/module.js +42 -0
  17. package/feature/number.js +41 -38
  18. package/feature/op/arithmetic.js +29 -0
  19. package/feature/op/arrow.js +33 -0
  20. package/feature/op/assign-logical.js +33 -0
  21. package/feature/op/assignment.js +47 -0
  22. package/feature/op/bitwise-unsigned.js +17 -0
  23. package/feature/op/bitwise.js +29 -0
  24. package/feature/op/comparison.js +19 -0
  25. package/feature/op/defer.js +15 -0
  26. package/feature/op/equality.js +16 -0
  27. package/feature/op/identity.js +15 -0
  28. package/feature/op/increment.js +23 -0
  29. package/feature/op/logical.js +21 -0
  30. package/feature/op/membership.js +17 -0
  31. package/feature/op/nullish.js +13 -0
  32. package/feature/op/optional.js +61 -0
  33. package/feature/op/pow.js +19 -0
  34. package/feature/op/range.js +26 -0
  35. package/feature/op/spread.js +15 -0
  36. package/feature/op/ternary.js +15 -0
  37. package/feature/op/type.js +18 -0
  38. package/feature/op/unary.js +41 -0
  39. package/feature/prop.js +34 -0
  40. package/feature/regex.js +31 -0
  41. package/feature/seq.js +21 -0
  42. package/feature/string.js +24 -17
  43. package/feature/switch.js +48 -0
  44. package/feature/template.js +39 -0
  45. package/feature/try.js +57 -0
  46. package/feature/unit.js +35 -0
  47. package/feature/var.js +51 -41
  48. package/jessie.js +31 -0
  49. package/jessie.min.js +8 -0
  50. package/justin.js +39 -48
  51. package/justin.min.js +8 -4
  52. package/package.json +15 -16
  53. package/parse.js +153 -0
  54. package/subscript.d.ts +45 -5
  55. package/subscript.js +62 -22
  56. package/subscript.min.js +5 -4
  57. package/util/bundle.js +507 -0
  58. package/util/stringify.js +172 -0
  59. package/feature/add.js +0 -22
  60. package/feature/array.js +0 -11
  61. package/feature/arrow.js +0 -23
  62. package/feature/assign.js +0 -11
  63. package/feature/bitwise.js +0 -11
  64. package/feature/bool.js +0 -5
  65. package/feature/call.js +0 -15
  66. package/feature/compare.js +0 -11
  67. package/feature/control.js +0 -142
  68. package/feature/increment.js +0 -11
  69. package/feature/logic.js +0 -11
  70. package/feature/mult.js +0 -25
  71. package/feature/object.js +0 -17
  72. package/feature/optional.js +0 -23
  73. package/feature/pow.js +0 -5
  74. package/feature/shift.js +0 -12
  75. package/feature/spread.js +0 -6
  76. package/feature/ternary.js +0 -10
  77. package/src/compile.d.ts +0 -17
  78. package/src/compile.js +0 -28
  79. package/src/const.js +0 -45
  80. package/src/parse.d.ts +0 -22
  81. package/src/parse.js +0 -113
  82. package/src/stringify.js +0 -27
  83. /package/{LICENSE → license} +0 -0
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Arithmetic operators
3
+ *
4
+ * + - * / %
5
+ * Unary: + -
6
+ */
7
+ import { binary, unary, operator, compile } from '../../parse.js';
8
+
9
+ const ADD = 110, MULT = 120, PREFIX = 140;
10
+
11
+ binary('+', ADD);
12
+ binary('-', ADD);
13
+ binary('*', MULT);
14
+ binary('/', MULT);
15
+ binary('%', MULT);
16
+
17
+ unary('+', PREFIX);
18
+ unary('-', PREFIX);
19
+
20
+ // Compile
21
+ operator('+', (a, b) => b !== undefined ?
22
+ (a = compile(a), b = compile(b), ctx => a(ctx) + b(ctx)) :
23
+ (a = compile(a), ctx => +a(ctx)));
24
+ operator('-', (a, b) => b !== undefined ?
25
+ (a = compile(a), b = compile(b), ctx => a(ctx) - b(ctx)) :
26
+ (a = compile(a), ctx => -a(ctx)));
27
+ operator('*', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) * b(ctx)));
28
+ operator('/', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) / b(ctx)));
29
+ operator('%', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) % b(ctx)));
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Arrow function operator
3
+ *
4
+ * (a, b) => expr → arrow function
5
+ *
6
+ * Common in: JS, TS, Java, C#, Kotlin, Scala
7
+ */
8
+ import { binary, operator, compile } from '../../parse.js';
9
+
10
+ const ASSIGN = 20;
11
+
12
+ binary('=>', ASSIGN, true);
13
+
14
+ // Compile
15
+ operator('=>', (a, b) => {
16
+ a = a[0] === '()' ? a[1] : a;
17
+ a = !a ? [] : a[0] === ',' ? a.slice(1) : [a];
18
+ let restIdx = -1, restName = null;
19
+ if (a.length && Array.isArray(a[a.length - 1]) && a[a.length - 1][0] === '...') {
20
+ restIdx = a.length - 1;
21
+ restName = a[restIdx][1];
22
+ a = a.slice(0, -1);
23
+ }
24
+ b = compile(b[0] === '{}' ? b[1] : b);
25
+ return (ctx = null) => {
26
+ ctx = Object.create(ctx);
27
+ return (...args) => {
28
+ a.forEach((p, i) => ctx[p] = args[i]);
29
+ if (restName) ctx[restName] = args.slice(restIdx);
30
+ return b(ctx);
31
+ };
32
+ };
33
+ });
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Logical/nullish assignment operators + destructuring
3
+ *
4
+ * ||= &&= ??= + destructuring support for let/const/var
5
+ */
6
+ import { binary, operator, compile } from '../../parse.js';
7
+ import { destructure } from '../destruct.js';
8
+ import { isLval, prop } from '../access.js';
9
+
10
+ const ASSIGN = 20;
11
+ const err = msg => { throw Error(msg) };
12
+
13
+ binary('||=', ASSIGN, true);
14
+ binary('&&=', ASSIGN, true);
15
+ binary('??=', ASSIGN, true);
16
+
17
+ // Override = to support destructuring
18
+ operator('=', (a, b) => {
19
+ // Handle let/const/var declarations: ['=', ['let', pattern], value]
20
+ if (Array.isArray(a) && (a[0] === 'let' || a[0] === 'const' || a[0] === 'var')) {
21
+ const pattern = a[1];
22
+ b = compile(b);
23
+ if (typeof pattern === 'string') return ctx => { ctx[pattern] = b(ctx); };
24
+ return ctx => destructure(pattern, b(ctx), ctx);
25
+ }
26
+ isLval(a) || err('Invalid assignment target');
27
+ return (b = compile(b), prop(a, (obj, path, ctx) => obj[path] = b(ctx)));
28
+ });
29
+
30
+ // Compile
31
+ operator('||=', (a, b) => (isLval(a) || err('Invalid assignment target'), b = compile(b), prop(a, (o, k, ctx) => o[k] ||= b(ctx))));
32
+ operator('&&=', (a, b) => (isLval(a) || err('Invalid assignment target'), b = compile(b), prop(a, (o, k, ctx) => o[k] &&= b(ctx))));
33
+ operator('??=', (a, b) => (isLval(a) || err('Invalid assignment target'), b = compile(b), prop(a, (o, k, ctx) => o[k] ??= b(ctx))));
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Assignment operators (C-family)
3
+ *
4
+ * = += -= *= /= %= |= &= ^= >>= <<=
5
+ * Note: **= is in pow.js, >>>= ||= &&= ??= are JS-specific (in assignment-js.js)
6
+ */
7
+ import { binary, operator, compile } from '../../parse.js';
8
+
9
+ const ASSIGN = 20;
10
+
11
+ // Base assignment
12
+ binary('=', ASSIGN, true);
13
+
14
+ // Compound arithmetic
15
+ binary('+=', ASSIGN, true);
16
+ binary('-=', ASSIGN, true);
17
+ binary('*=', ASSIGN, true);
18
+ binary('/=', ASSIGN, true);
19
+ binary('%=', ASSIGN, true);
20
+
21
+ // Compound bitwise
22
+ binary('|=', ASSIGN, true);
23
+ binary('&=', ASSIGN, true);
24
+ binary('^=', ASSIGN, true);
25
+ binary('>>=', ASSIGN, true);
26
+ binary('<<=', ASSIGN, true);
27
+
28
+ // Simple assign helper for x, a.b, a[b], (x)
29
+ const assign = (a, fn, obj, key) =>
30
+ typeof a === 'string' ? ctx => fn(ctx, a, ctx) :
31
+ a[0] === '.' ? (obj = compile(a[1]), key = a[2], ctx => fn(obj(ctx), key, ctx)) :
32
+ a[0] === '[]' && a.length === 3 ? (obj = compile(a[1]), key = compile(a[2]), ctx => fn(obj(ctx), key(ctx), ctx)) :
33
+ a[0] === '()' && a.length === 2 ? assign(a[1], fn) : // unwrap parens: (x) = 1
34
+ (() => { throw Error('Invalid assignment target') })();
35
+
36
+ // Compile
37
+ operator('=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] = b(ctx))));
38
+ operator('+=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] += b(ctx))));
39
+ operator('-=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] -= b(ctx))));
40
+ operator('*=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] *= b(ctx))));
41
+ operator('/=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] /= b(ctx))));
42
+ operator('%=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] %= b(ctx))));
43
+ operator('|=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] |= b(ctx))));
44
+ operator('&=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] &= b(ctx))));
45
+ operator('^=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] ^= b(ctx))));
46
+ operator('>>=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] >>= b(ctx))));
47
+ operator('<<=', (a, b) => (b = compile(b), assign(a, (o, k, ctx) => o[k] <<= b(ctx))));
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Unsigned right shift operators
3
+ *
4
+ * >>> >>>=
5
+ */
6
+ import { binary, operator, compile } from '../../parse.js';
7
+ import { isLval, prop } from '../access.js';
8
+
9
+ const ASSIGN = 20, SHIFT = 100;
10
+ const err = msg => { throw Error(msg) };
11
+
12
+ binary('>>>', SHIFT);
13
+ binary('>>>=', ASSIGN, true);
14
+
15
+ // Compile
16
+ operator('>>>', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) >>> b(ctx)));
17
+ operator('>>>=', (a, b) => (isLval(a) || err('Invalid assignment target'), b = compile(b), prop(a, (o, k, ctx) => o[k] >>>= b(ctx))));
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Bitwise operators (C-family)
3
+ *
4
+ * | & ^ ~ >> <<
5
+ * Note: >>> is JS-specific (in bitwise-js.js)
6
+ */
7
+ import { binary, unary, operator, compile } from '../../parse.js';
8
+
9
+ const OR = 50, XOR = 60, AND = 70, SHIFT = 100, PREFIX = 140;
10
+
11
+ // Base operators first (tried last in chain)
12
+ binary('|', OR);
13
+ binary('&', AND);
14
+ binary('^', XOR);
15
+
16
+ // Shifts (after < >)
17
+ binary('>>', SHIFT);
18
+ binary('<<', SHIFT);
19
+
20
+ // Unary
21
+ unary('~', PREFIX);
22
+
23
+ // Compile
24
+ operator('~', a => (a = compile(a), ctx => ~a(ctx)));
25
+ operator('|', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) | b(ctx)));
26
+ operator('&', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) & b(ctx)));
27
+ operator('^', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) ^ b(ctx)));
28
+ operator('>>', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) >> b(ctx)));
29
+ operator('<<', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) << b(ctx)));
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Comparison operators
3
+ *
4
+ * < > <= >=
5
+ */
6
+ import { binary, operator, compile } from '../../parse.js';
7
+
8
+ const COMP = 90;
9
+
10
+ binary('<', COMP);
11
+ binary('>', COMP);
12
+ binary('<=', COMP);
13
+ binary('>=', COMP);
14
+
15
+ // Compile
16
+ operator('>', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) > b(ctx)));
17
+ operator('<', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) < b(ctx)));
18
+ operator('>=', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) >= b(ctx)));
19
+ operator('<=', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) <= b(ctx)));
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Defer operator
3
+ *
4
+ * defer expr: registers cleanup to run at scope exit
5
+ *
6
+ * Common in: Go, Swift, Zig
7
+ */
8
+ import { unary, operator, compile } from '../../parse.js';
9
+
10
+ const PREFIX = 140;
11
+
12
+ unary('defer', PREFIX);
13
+
14
+ // Compile
15
+ operator('defer', a => (a = compile(a), ctx => { ctx.__deferred__ = ctx.__deferred__ || []; ctx.__deferred__.push(a); }));
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Equality operators (base)
3
+ *
4
+ * == !=
5
+ * For === !== see equality-strict.js
6
+ */
7
+ import { binary, operator, compile } from '../../parse.js';
8
+
9
+ const EQ = 80;
10
+
11
+ binary('==', EQ);
12
+ binary('!=', EQ);
13
+
14
+ // Compile
15
+ operator('==', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) == b(ctx)));
16
+ operator('!=', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) != b(ctx)));
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Identity operators
3
+ *
4
+ * === !==
5
+ */
6
+ import { binary, operator, compile } from '../../parse.js';
7
+
8
+ const EQ = 80;
9
+
10
+ binary('===', EQ);
11
+ binary('!==', EQ);
12
+
13
+ // Compile
14
+ operator('===', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) === b(ctx)));
15
+ operator('!==', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) !== b(ctx)));
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Increment/decrement operators
3
+ *
4
+ * ++ -- (prefix and postfix)
5
+ */
6
+ import { token, expr, operator, compile } from '../../parse.js';
7
+
8
+ const POSTFIX = 150;
9
+
10
+ token('++', POSTFIX, a => a ? ['++', a, null] : ['++', expr(POSTFIX - 1)]);
11
+ token('--', POSTFIX, a => a ? ['--', a, null] : ['--', expr(POSTFIX - 1)]);
12
+
13
+ // Compile (b=null means postfix, b=undefined means prefix)
14
+ // Simple prop helper for increment - handles x, a.b, a[b], (x)
15
+ const inc = (a, fn, obj, key) =>
16
+ typeof a === 'string' ? ctx => fn(ctx, a) :
17
+ a[0] === '.' ? (obj = compile(a[1]), key = a[2], ctx => fn(obj(ctx), key)) :
18
+ a[0] === '[]' && a.length === 3 ? (obj = compile(a[1]), key = compile(a[2]), ctx => fn(obj(ctx), key(ctx))) :
19
+ a[0] === '()' && a.length === 2 ? inc(a[1], fn) : // unwrap parens: (x)++
20
+ (() => { throw Error('Invalid increment target') })();
21
+
22
+ operator('++', (a, b) => inc(a, b === null ? (o, k) => o[k]++ : (o, k) => ++o[k]));
23
+ operator('--', (a, b) => inc(a, b === null ? (o, k) => o[k]-- : (o, k) => --o[k]));
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Logical operators (base)
3
+ *
4
+ * ! && ||
5
+ * For ?? see nullish.js
6
+ */
7
+ import { binary, unary, operator, compile } from '../../parse.js';
8
+
9
+ const LOR = 30, LAND = 40, PREFIX = 140;
10
+
11
+ // ! must be registered before != and !==
12
+ binary('!', PREFIX);
13
+ unary('!', PREFIX);
14
+
15
+ binary('||', LOR);
16
+ binary('&&', LAND);
17
+
18
+ // Compile
19
+ operator('!', a => (a = compile(a), ctx => !a(ctx)));
20
+ operator('||', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) || b(ctx)));
21
+ operator('&&', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) && b(ctx)));
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Membership operator
3
+ *
4
+ * in: key in object
5
+ * of: for-of iteration (parsed as binary in for head)
6
+ *
7
+ * Note: instanceof is in class.js (jessie feature)
8
+ */
9
+ import { binary, operator, compile } from '../../parse.js';
10
+
11
+ const COMP = 90;
12
+
13
+ binary('in', COMP);
14
+ binary('of', COMP);
15
+
16
+ // Compile
17
+ operator('in', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) in b(ctx)));
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Nullish coalescing operator (JS-specific)
3
+ *
4
+ * ??
5
+ */
6
+ import { binary, operator, compile } from '../../parse.js';
7
+
8
+ const LOR = 30;
9
+
10
+ binary('??', LOR);
11
+
12
+ // Compile
13
+ operator('??', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) ?? b(ctx)));
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Optional chaining operators
3
+ *
4
+ * a?.b → optional member access
5
+ * a?.[x] → optional computed access
6
+ * a?.() → optional call
7
+ *
8
+ * Common in: JS, TS, Swift, Kotlin, C#
9
+ */
10
+ import { token, expr, skip, space, operator, compile } from '../../parse.js';
11
+ import { unsafe } from '../access.js';
12
+
13
+ const ACCESS = 170;
14
+
15
+ token('?.', ACCESS, (a, b) => {
16
+ if (!a) return;
17
+ const cc = space();
18
+ // Optional call: a?.()
19
+ if (cc === 40) { skip(); return ['?.()', a, expr(0, 41) || null]; }
20
+ // Optional computed: a?.[x]
21
+ if (cc === 91) { skip(); return ['?.[]', a, expr(0, 93)]; }
22
+ // Optional member: a?.b
23
+ b = expr(ACCESS);
24
+ return b ? ['?.', a, b] : void 0;
25
+ });
26
+
27
+ // Compile
28
+ operator('?.', (a, b) => (a = compile(a), unsafe(b) ? () => undefined : ctx => a(ctx)?.[b]));
29
+ operator('?.[]', (a, b) => (a = compile(a), b = compile(b), ctx => { const k = b(ctx); return unsafe(k) ? undefined : a(ctx)?.[k]; }));
30
+ operator('?.()', (a, b) => {
31
+ const args = !b ? () => [] :
32
+ b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(arg => arg(ctx))) :
33
+ (b = compile(b), ctx => [b(ctx)]);
34
+
35
+ // Handle nested optional chain: a?.method?.() or a?.["method"]?.()
36
+ if (a[0] === '?.') {
37
+ const container = compile(a[1]);
38
+ const prop = a[2];
39
+ return unsafe(prop) ? () => undefined :
40
+ ctx => { const c = container(ctx); return c?.[prop]?.(...args(ctx)); };
41
+ }
42
+ if (a[0] === '?.[]') {
43
+ const container = compile(a[1]);
44
+ const prop = compile(a[2]);
45
+ return ctx => { const c = container(ctx); const p = prop(ctx); return unsafe(p) ? undefined : c?.[p]?.(...args(ctx)); };
46
+ }
47
+ // Handle a?.() where a is a.method or a[method] - need to bind this
48
+ if (a[0] === '.') {
49
+ const obj = compile(a[1]);
50
+ const prop = a[2];
51
+ return unsafe(prop) ? () => undefined :
52
+ ctx => { const o = obj(ctx); return o?.[prop]?.(...args(ctx)); };
53
+ }
54
+ if (a[0] === '[]' && a.length === 3) {
55
+ const obj = compile(a[1]);
56
+ const prop = compile(a[2]);
57
+ return ctx => { const o = obj(ctx); const p = prop(ctx); return unsafe(p) ? undefined : o?.[p]?.(...args(ctx)); };
58
+ }
59
+ const fn = compile(a);
60
+ return ctx => fn(ctx)?.(...args(ctx));
61
+ });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Exponentiation operator
3
+ *
4
+ * ** **=
5
+ *
6
+ * ES2016+, not in classic JS/C
7
+ */
8
+ import { binary, operator, compile } from '../../parse.js';
9
+ import { isLval, prop } from '../access.js';
10
+
11
+ const EXP = 130, ASSIGN = 20;
12
+
13
+ binary('**', EXP, true);
14
+ binary('**=', ASSIGN, true);
15
+
16
+ // Compile
17
+ operator('**', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) ** b(ctx)));
18
+ const err = msg => { throw Error(msg) };
19
+ operator('**=', (a, b) => (isLval(a) || err('Invalid assignment target'), b = compile(b), prop(a, (obj, path, ctx) => obj[path] **= b(ctx))));
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Range operators
3
+ *
4
+ * .. (inclusive range): 1..5 → [1,2,3,4,5]
5
+ * ..< (exclusive range): 1..<5 → [1,2,3,4]
6
+ *
7
+ * Common in: Swift, Kotlin, Rust, Ruby
8
+ */
9
+ import { binary, operator, compile } from '../../parse.js';
10
+
11
+ const COMP = 90;
12
+
13
+ binary('..', COMP);
14
+ binary('..<', COMP);
15
+
16
+ // Compile
17
+ operator('..', (a, b) => (a = compile(a), b = compile(b), ctx => {
18
+ const start = a(ctx), end = b(ctx), arr = [];
19
+ for (let i = start; i <= end; i++) arr.push(i);
20
+ return arr;
21
+ }));
22
+ operator('..<', (a, b) => (a = compile(a), b = compile(b), ctx => {
23
+ const start = a(ctx), end = b(ctx), arr = [];
24
+ for (let i = start; i < end; i++) arr.push(i);
25
+ return arr;
26
+ }));
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Spread/rest operator
3
+ *
4
+ * ...x → spread in arrays/calls, rest in params
5
+ *
6
+ * Common in: JS, TS, Python (*args), Ruby (*splat)
7
+ */
8
+ import { unary, operator, compile } from '../../parse.js';
9
+
10
+ const PREFIX = 140;
11
+
12
+ unary('...', PREFIX);
13
+
14
+ // Compile (for arrays/objects spread)
15
+ operator('...', a => (a = compile(a), ctx => Object.entries(a(ctx))));
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Ternary conditional operator
3
+ *
4
+ * a ? b : c → conditional expression
5
+ *
6
+ * Common in: C, JS, Java, PHP, etc.
7
+ */
8
+ import { token, expr, next, operator, compile } from '../../parse.js';
9
+
10
+ const ASSIGN = 20;
11
+
12
+ token('?', ASSIGN, (a, b, c) => a && (b = expr(ASSIGN - 1)) && next(c => c === 58) && (c = expr(ASSIGN - 1), ['?', a, b, c]));
13
+
14
+ // Compile
15
+ operator('?', (a, b, c) => (a = compile(a), b = compile(b), c = compile(c), ctx => a(ctx) ? b(ctx) : c(ctx)));
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Type operators
3
+ *
4
+ * as: type cast/assertion (identity in JS)
5
+ * is: type check (instanceof in JS)
6
+ *
7
+ * Common in: TypeScript, Kotlin, Swift, C#
8
+ */
9
+ import { binary, operator, compile } from '../../parse.js';
10
+
11
+ const COMP = 90;
12
+
13
+ binary('as', COMP);
14
+ binary('is', COMP);
15
+
16
+ // Compile (identity in JS)
17
+ operator('as', (a, b) => (a = compile(a), ctx => a(ctx)));
18
+ operator('is', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) instanceof b(ctx)));
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Unary keyword operators
3
+ *
4
+ * typeof x → type string
5
+ * void x → undefined
6
+ * delete x → remove property
7
+ * new X() → construct instance
8
+ *
9
+ * JS-specific keywords
10
+ */
11
+ import { unary, operator, compile } from '../../parse.js';
12
+
13
+ const PREFIX = 140;
14
+
15
+ unary('typeof', PREFIX);
16
+ unary('void', PREFIX);
17
+ unary('delete', PREFIX);
18
+ unary('new', PREFIX);
19
+
20
+ // Compile
21
+ operator('typeof', a => (a = compile(a), ctx => typeof a(ctx)));
22
+ operator('void', a => (a = compile(a), ctx => (a(ctx), undefined)));
23
+ operator('delete', a => {
24
+ if (a[0] === '.') {
25
+ const obj = compile(a[1]), key = a[2];
26
+ return ctx => delete obj(ctx)[key];
27
+ }
28
+ if (a[0] === '[]') {
29
+ const obj = compile(a[1]), key = compile(a[2]);
30
+ return ctx => delete obj(ctx)[key(ctx)];
31
+ }
32
+ return () => true;
33
+ });
34
+ operator('new', (call) => {
35
+ const target = compile(call?.[0] === '()' ? call[1] : call);
36
+ const args = call?.[0] === '()' ? call[2] : null;
37
+ const argList = !args ? () => [] :
38
+ args[0] === ',' ? (a => ctx => a.map(f => f(ctx)))(args.slice(1).map(compile)) :
39
+ (a => ctx => [a(ctx)])(compile(args));
40
+ return ctx => new (target(ctx))(...argList(ctx));
41
+ });
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Minimal property access: a.b, a[b], f()
3
+ * For array literals, private fields, see member.js
4
+ */
5
+ import { access, binary, group, operator, compile } from '../parse.js';
6
+
7
+ const ACCESS = 170;
8
+
9
+ // a[b] - computed member access only (no array literal support)
10
+ access('[]', ACCESS);
11
+
12
+ // a.b - dot member access
13
+ binary('.', ACCESS);
14
+
15
+ // (a) - grouping only (no sequences)
16
+ group('()', ACCESS);
17
+
18
+ // a(b,c,d), a() - function calls
19
+ access('()', ACCESS);
20
+
21
+ // Compile
22
+ const err = msg => { throw Error(msg) };
23
+ operator('[]', (a, b) => (b == null && err('Missing index'), a = compile(a), b = compile(b), ctx => a(ctx)[b(ctx)]));
24
+ operator('.', (a, b) => (a = compile(a), b = !b[0] ? b[1] : b, ctx => a(ctx)[b]));
25
+ operator('()', (a, b) => {
26
+ // Group: (expr) - no second argument means grouping, not call
27
+ if (b === undefined) return a == null ? err('Empty ()') : compile(a);
28
+ // Function call: a(b,c)
29
+ const args = !b ? () => [] :
30
+ b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(arg => arg(ctx))) :
31
+ (b = compile(b), ctx => [b(ctx)]);
32
+ a = compile(a);
33
+ return ctx => a(ctx)(...args(ctx));
34
+ });
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Regex literals: /pattern/flags
3
+ *
4
+ * AST:
5
+ * /abc/gi → [, /abc/gi]
6
+ *
7
+ * Note: Disambiguates from division by context:
8
+ * - `/` after value = division (falls through to prev)
9
+ * - `/` at start or after operator = regex
10
+ */
11
+ import { token, skip, err, next, idx, cur } from '../parse.js';
12
+
13
+ const PREFIX = 140, SLASH = 47, BSLASH = 92;
14
+
15
+ const regexChar = c => c === BSLASH ? 2 : c && c !== SLASH; // \x = 2 chars, else 1 until /
16
+ const regexFlag = c => c === 103 || c === 105 || c === 109 || c === 115 || c === 117 || c === 121; // g i m s u y
17
+
18
+ token('/', PREFIX, a => {
19
+ if (a) return; // has left operand = division, fall through
20
+
21
+ // Invalid regex start (quantifiers) or /= - fall through
22
+ const first = cur.charCodeAt(idx);
23
+ if (first === SLASH || first === 42 || first === 43 || first === 63 || first === 61) return;
24
+
25
+ const pattern = next(regexChar);
26
+ cur.charCodeAt(idx) === SLASH || err('Unterminated regex');
27
+ skip(); // consume closing /
28
+
29
+ try { return [, new RegExp(pattern, next(regexFlag))]; }
30
+ catch (e) { err('Invalid regex: ' + e.message); }
31
+ });
package/feature/seq.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Sequence operators (C-family)
3
+ *
4
+ * , ; — returns last evaluated value
5
+ */
6
+ import { nary, operator, compile } from '../parse.js';
7
+
8
+ const STATEMENT = 5, SEQ = 10;
9
+
10
+ // Sequences
11
+ nary(',', SEQ);
12
+ nary(';', STATEMENT, true); // right-assoc to allow same-prec statements
13
+
14
+ // Compile - returns last evaluated value
15
+ const seq = (...args) => (args = args.map(compile), ctx => {
16
+ let r;
17
+ for (const arg of args) r = arg(ctx);
18
+ return r;
19
+ });
20
+ operator(',', seq);
21
+ operator(';', seq);