subscript 10.3.5 → 10.4.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 (93) hide show
  1. package/README.md +9 -2
  2. package/eval/access.js +57 -0
  3. package/eval/accessor.js +19 -0
  4. package/eval/async.js +13 -0
  5. package/eval/class.js +35 -0
  6. package/eval/collection.js +41 -0
  7. package/eval/function.js +37 -0
  8. package/eval/if.js +7 -0
  9. package/eval/jessie.js +19 -0
  10. package/eval/justin.js +21 -0
  11. package/eval/loop.js +108 -0
  12. package/eval/module.js +8 -0
  13. package/eval/op/arithmetic.js +12 -0
  14. package/eval/op/arrow.js +35 -0
  15. package/eval/op/assign-logical.js +23 -0
  16. package/eval/op/assignment.js +15 -0
  17. package/eval/op/bitwise-unsigned.js +8 -0
  18. package/eval/op/bitwise.js +9 -0
  19. package/eval/op/comparison.js +7 -0
  20. package/eval/op/defer.js +4 -0
  21. package/eval/op/equality.js +5 -0
  22. package/eval/op/identity.js +5 -0
  23. package/eval/op/increment.js +13 -0
  24. package/eval/op/logical.js +6 -0
  25. package/eval/op/membership.js +4 -0
  26. package/eval/op/nullish.js +4 -0
  27. package/eval/op/optional.js +38 -0
  28. package/eval/op/pow.js +8 -0
  29. package/eval/op/range.js +13 -0
  30. package/eval/op/spread.js +4 -0
  31. package/eval/op/ternary.js +4 -0
  32. package/eval/op/type.js +5 -0
  33. package/eval/op/unary.js +24 -0
  34. package/eval/prop.js +16 -0
  35. package/eval/regex.js +7 -0
  36. package/eval/seq.js +10 -0
  37. package/eval/subscript.js +15 -0
  38. package/eval/switch.js +27 -0
  39. package/eval/template.js +14 -0
  40. package/eval/try.js +36 -0
  41. package/eval/unit.js +10 -0
  42. package/eval/var.js +69 -0
  43. package/feature/access.js +2 -58
  44. package/feature/accessor.js +2 -21
  45. package/feature/asi.js +57 -12
  46. package/feature/async.js +2 -14
  47. package/feature/class.js +2 -35
  48. package/feature/collection.js +2 -43
  49. package/feature/function.js +2 -39
  50. package/feature/if.js +2 -8
  51. package/feature/jessie.js +32 -0
  52. package/feature/justin.js +36 -0
  53. package/feature/loop.js +2 -109
  54. package/feature/module.js +1 -10
  55. package/feature/op/arithmetic.js +2 -13
  56. package/feature/op/arrow.js +2 -38
  57. package/feature/op/assign-logical.js +3 -24
  58. package/feature/op/assignment.js +2 -18
  59. package/feature/op/bitwise-unsigned.js +2 -8
  60. package/feature/op/bitwise.js +2 -14
  61. package/feature/op/comparison.js +2 -8
  62. package/feature/op/defer.js +2 -7
  63. package/feature/op/equality.js +2 -7
  64. package/feature/op/identity.js +2 -6
  65. package/feature/op/increment.js +2 -14
  66. package/feature/op/logical.js +2 -8
  67. package/feature/op/membership.js +2 -7
  68. package/feature/op/nullish.js +2 -5
  69. package/feature/op/optional.js +2 -41
  70. package/feature/op/pow.js +2 -10
  71. package/feature/op/range.js +2 -16
  72. package/feature/op/spread.js +2 -7
  73. package/feature/op/ternary.js +2 -7
  74. package/feature/op/type.js +2 -8
  75. package/feature/op/unary.js +2 -27
  76. package/feature/prop.js +2 -17
  77. package/feature/regex.js +3 -12
  78. package/feature/seq.js +2 -11
  79. package/feature/shebang.js +7 -0
  80. package/feature/subscript.js +23 -0
  81. package/feature/switch.js +2 -28
  82. package/feature/template.js +4 -16
  83. package/feature/try.js +4 -38
  84. package/feature/unit.js +4 -7
  85. package/feature/var.js +2 -70
  86. package/jessie.js +4 -25
  87. package/jessie.min.js +9 -8
  88. package/justin.js +4 -30
  89. package/justin.min.js +8 -8
  90. package/package.json +10 -2
  91. package/parse.js +27 -29
  92. package/subscript.js +7 -16
  93. package/subscript.min.js +5 -5
@@ -1,26 +1,12 @@
1
1
  /**
2
- * Range operators
2
+ * Range operators - parse half
3
3
  *
4
4
  * .. (inclusive range): 1..5 → [1,2,3,4,5]
5
5
  * ..< (exclusive range): 1..<5 → [1,2,3,4]
6
- *
7
- * Common in: Swift, Kotlin, Rust, Ruby
8
6
  */
9
- import { binary, operator, compile } from '../../parse.js';
7
+ import { binary } from '../../parse.js';
10
8
 
11
9
  const COMP = 90;
12
10
 
13
11
  binary('..', COMP);
14
12
  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
- }));
@@ -1,15 +1,10 @@
1
1
  /**
2
- * Spread/rest operator
2
+ * Spread/rest operator - parse half
3
3
  *
4
4
  * ...x → spread in arrays/calls, rest in params
5
- *
6
- * Common in: JS, TS, Python (*args), Ruby (*splat)
7
5
  */
8
- import { unary, operator, compile } from '../../parse.js';
6
+ import { unary } from '../../parse.js';
9
7
 
10
8
  const PREFIX = 140;
11
9
 
12
10
  unary('...', PREFIX);
13
-
14
- // Compile (for arrays/objects spread)
15
- operator('...', a => (a = compile(a), ctx => Object.entries(a(ctx))));
@@ -1,15 +1,10 @@
1
1
  /**
2
- * Ternary conditional operator
2
+ * Ternary conditional operator - parse half
3
3
  *
4
4
  * a ? b : c → conditional expression
5
- *
6
- * Common in: C, JS, Java, PHP, etc.
7
5
  */
8
- import { token, expr, next, operator, compile } from '../../parse.js';
6
+ import { token, expr, next } from '../../parse.js';
9
7
 
10
8
  const ASSIGN = 20;
11
9
 
12
10
  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)));
@@ -1,18 +1,12 @@
1
1
  /**
2
- * Type operators
2
+ * Type operators - parse half
3
3
  *
4
4
  * as: type cast/assertion (identity in JS)
5
5
  * is: type check (instanceof in JS)
6
- *
7
- * Common in: TypeScript, Kotlin, Swift, C#
8
6
  */
9
- import { binary, operator, compile } from '../../parse.js';
7
+ import { binary } from '../../parse.js';
10
8
 
11
9
  const COMP = 90;
12
10
 
13
11
  binary('as', COMP);
14
12
  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)));
@@ -1,14 +1,12 @@
1
1
  /**
2
- * Unary keyword operators
2
+ * Unary keyword operators - parse half
3
3
  *
4
4
  * typeof x → type string
5
5
  * void x → undefined
6
6
  * delete x → remove property
7
7
  * new X() → construct instance
8
- *
9
- * JS-specific keywords
10
8
  */
11
- import { unary, keyword, operator, compile, skip, expr, word } from '../../parse.js';
9
+ import { unary, keyword, skip, expr, word } from '../../parse.js';
12
10
 
13
11
  const PREFIX = 140;
14
12
 
@@ -19,26 +17,3 @@ unary('delete', PREFIX);
19
17
  keyword('new', PREFIX, () =>
20
18
  word('.target') ? (skip(7), ['new.target']) : ['new', expr(PREFIX)]
21
19
  );
22
-
23
- // Compile
24
- operator('typeof', a => (a = compile(a), ctx => typeof a(ctx)));
25
- operator('void', a => (a = compile(a), ctx => (a(ctx), undefined)));
26
- operator('delete', a => {
27
- if (a[0] === '.') {
28
- const obj = compile(a[1]), key = a[2];
29
- return ctx => delete obj(ctx)[key];
30
- }
31
- if (a[0] === '[]') {
32
- const obj = compile(a[1]), key = compile(a[2]);
33
- return ctx => delete obj(ctx)[key(ctx)];
34
- }
35
- return () => true;
36
- });
37
- operator('new', (call) => {
38
- const target = compile(call?.[0] === '()' ? call[1] : call);
39
- const args = call?.[0] === '()' ? call[2] : null;
40
- const argList = !args ? () => [] :
41
- args[0] === ',' ? (a => ctx => a.map(f => f(ctx)))(args.slice(1).map(compile)) :
42
- (a => ctx => [a(ctx)])(compile(args));
43
- return ctx => new (target(ctx))(...argList(ctx));
44
- });
package/feature/prop.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
- * Minimal property access: a.b, a[b], f()
2
+ * Minimal property access: a.b, a[b], f() - parse half
3
3
  * For array literals, private fields, see member.js
4
4
  */
5
- import { access, binary, group, operator, compile } from '../parse.js';
5
+ import { access, binary, group } from '../parse.js';
6
6
 
7
7
  const ACCESS = 170;
8
8
 
@@ -17,18 +17,3 @@ group('()', ACCESS);
17
17
 
18
18
  // a(b,c,d), a() - function calls
19
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
- });
package/feature/regex.js CHANGED
@@ -1,18 +1,15 @@
1
1
  /**
2
- * Regex literals: /pattern/flags
2
+ * Regex literals: /pattern/flags - parse half
3
3
  *
4
4
  * AST (constructor form, JSON-serializable):
5
5
  * /abc/gi → ['//', 'abc', 'gi']
6
6
  * /abc/ → ['//', 'abc']
7
7
  *
8
- * Note: Disambiguates from division by context:
8
+ * Disambiguates from division by context:
9
9
  * - `/` after value = division (falls through to prev)
10
10
  * - `/` at start or after operator = regex
11
- *
12
- * Compile:
13
- * ['//', 'abc', 'gi'] → new RegExp('abc', 'gi')
14
11
  */
15
- import { token, skip, err, next, idx, cur, operator } from '../parse.js';
12
+ import { token, skip, err, next, idx, cur } from '../parse.js';
16
13
 
17
14
  const PREFIX = 140, SLASH = 47, BSLASH = 92;
18
15
 
@@ -37,9 +34,3 @@ token('/', PREFIX, a => {
37
34
 
38
35
  return flags ? ['//', pattern, flags] : ['//', pattern];
39
36
  });
40
-
41
- // Compile: ['//', pattern, flags?] → RegExp
42
- operator('//', (a, b) => {
43
- const re = new RegExp(a, b || '');
44
- return () => re;
45
- });
package/feature/seq.js CHANGED
@@ -1,21 +1,12 @@
1
1
  /**
2
- * Sequence operators (C-family)
2
+ * Sequence operators (C-family) - parse half
3
3
  *
4
4
  * , ; — returns last evaluated value
5
5
  */
6
- import { nary, operator, compile } from '../parse.js';
6
+ import { nary } from '../parse.js';
7
7
 
8
8
  const STATEMENT = 5, SEQ = 10;
9
9
 
10
10
  // Sequences
11
11
  nary(',', SEQ);
12
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);
@@ -0,0 +1,7 @@
1
+ // Shebang `#!...` line treated as a line comment.
2
+ // `#!` is not valid syntax outside the shebang context (private fields require an identifier),
3
+ // so registering it globally is safe and lets the existing comment machinery handle it.
4
+ import './comment.js';
5
+ import { parse } from '../parse.js';
6
+
7
+ parse.comment['#!'] = '\n';
@@ -0,0 +1,23 @@
1
+ /**
2
+ * subscript - parse aggregator
3
+ * Minimal expression parser. No eval - import 'subscript/eval/subscript.js' for runtime.
4
+ */
5
+
6
+ // Literals
7
+ import './number.js'; // Decimal numbers: 123, 1.5, 1e3
8
+ import './string.js'; // Double-quoted strings with escapes
9
+
10
+ // Operators (C-family common set) - order matters for token chain performance
11
+ import './op/assignment.js'; // = += -= *= /= %= |= &= ^= >>= <<=
12
+ import './op/logical.js'; // ! && ||
13
+ import './op/bitwise.js'; // ~ | & ^ >> <<
14
+ import './op/comparison.js'; // < > <= >=
15
+ import './op/equality.js'; // == !=
16
+ import './op/arithmetic.js'; // + - * / %
17
+ import './op/increment.js'; // ++ --
18
+
19
+ import './seq.js'; // Sequences: a, b; a; b
20
+ import './group.js'; // Grouping: (a)
21
+ import './access.js'; // Property access: a.b, a[b], f(), [a,b]
22
+
23
+ export * from '../parse.js';
package/feature/switch.js CHANGED
@@ -1,7 +1,6 @@
1
- // Switch/case/default
1
+ // Switch/case/default - parse half
2
2
  // AST: ['switch', val, ['case', test, body], ['default', body], ...]
3
- import { expr, skip, space, keyword, parens, operator, compile, idx, err, seek, parse, lookup, word, cur } from '../parse.js';
4
- import { BREAK } from './loop.js';
3
+ import { expr, skip, space, keyword, parens, idx, err, seek, lookup, word } from '../parse.js';
5
4
 
6
5
  const STATEMENT = 5, ASSIGN = 20, COLON = 58, SEMI = 59, CBRACE = 125;
7
6
 
@@ -49,28 +48,3 @@ const switchBody = () => {
49
48
 
50
49
  // switch (x) { ... }
51
50
  keyword('switch', STATEMENT + 1, () => space() === 40 && ['switch', parens(), ...switchBody()]);
52
-
53
- // Compile
54
- operator('switch', (val, ...cases) => {
55
- val = compile(val);
56
- if (!cases.length) return ctx => val(ctx);
57
-
58
- cases = cases.map(c => [
59
- c[0] === 'case' ? compile(c[1]) : null,
60
- (c[0] === 'case' ? c[2] : c[1])?.[0] === ';'
61
- ? (c[0] === 'case' ? c[2] : c[1]).slice(1).map(compile)
62
- : (c[0] === 'case' ? c[2] : c[1]) ? [compile(c[0] === 'case' ? c[2] : c[1])] : []
63
- ]);
64
-
65
- return ctx => {
66
- const v = val(ctx);
67
- let matched = false, r;
68
- for (const [test, stmts] of cases)
69
- if (matched || test === null || test(ctx) === v)
70
- for (matched = true, i = 0; i < stmts.length; i++)
71
- try { r = stmts[i](ctx); }
72
- catch (e) { if (e === BREAK) return r; throw e; }
73
- var i;
74
- return r;
75
- };
76
- });
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Template literals: `a ${x} b` → ['`', [,'a '], 'x', [,' b']]
3
- * Tagged templates: tag`...` → ['``', 'tag', ...]
2
+ * Template literals - parse half
3
+ * `a ${x} b` → ['`', [,'a '], 'x', [,' b']]
4
+ * Tagged: tag`...` → ['``', 'tag', ...]
4
5
  */
5
- import { parse, skip, err, expr, lookup, cur, idx, operator, compile } from '../parse.js';
6
+ import { parse, skip, err, expr, lookup, cur, idx } from '../parse.js';
6
7
 
7
8
  const ACCESS = 170, BACKTICK = 96, DOLLAR = 36, OBRACE = 123, BSLASH = 92;
8
9
  const esc = { n: '\n', r: '\r', t: '\t', b: '\b', f: '\f', v: '\v' };
@@ -24,16 +25,3 @@ lookup[BACKTICK] = (a, prec) =>
24
25
  a && prec < ACCESS ? (parse.asi && parse.newline ? void 0 : (skip(), ['``', a, ...parseBody()])) : // tagged
25
26
  !a ? (skip(), (p => p.length < 2 && p[0]?.[0] === undefined ? p[0] || [,''] : ['`', ...p])(parseBody())) : // plain
26
27
  prev?.(a, prec);
27
-
28
- // Compile
29
- operator('`', (...parts) => (parts = parts.map(compile), ctx => parts.map(p => p(ctx)).join('')));
30
- operator('``', (tag, ...parts) => {
31
- tag = compile(tag);
32
- const strings = [], exprs = [];
33
- for (const p of parts) {
34
- if (Array.isArray(p) && p[0] === undefined) strings.push(p[1]);
35
- else exprs.push(compile(p));
36
- }
37
- const strs = Object.assign([...strings], { raw: strings });
38
- return ctx => tag(ctx)(strs, ...exprs.map(e => e(ctx)));
39
- });
package/feature/try.js CHANGED
@@ -1,9 +1,7 @@
1
- // try/catch/finally/throw statements
1
+ // try/catch/finally/throw statements - parse half
2
2
  // AST (faithful): ['try', body, ['catch', param, handler]?, ['finally', cleanup]?]
3
- // Note: body/handler are raw block results, param is raw parens result
4
- import { space, parse, keyword, parens, expr, word, skip, operator, compile } from '../parse.js';
3
+ import { space, parse, keyword, parens, expr, word, skip, peek } from '../parse.js';
5
4
  import { block } from './if.js';
6
- import { RETURN } from './op/arrow.js';import { BREAK, CONTINUE } from './loop.js';
7
5
 
8
6
  const STATEMENT = 5;
9
7
 
@@ -13,7 +11,8 @@ keyword('try', STATEMENT + 1, () => {
13
11
  space();
14
12
  if (word('catch')) {
15
13
  skip(5); space();
16
- node.push(['catch', parens(), block()]);
14
+ // ES2019 optional catch binding: `catch { ... }` (no parameter)
15
+ node.push(['catch', peek() === 40 ? parens() : null, block()]);
17
16
  }
18
17
  space();
19
18
  if (word('finally')) {
@@ -29,36 +28,3 @@ keyword('throw', STATEMENT + 1, () => {
29
28
  if (parse.newline) throw SyntaxError('Unexpected newline after throw');
30
29
  return ['throw', expr(STATEMENT)];
31
30
  });
32
-
33
- // Compile try - normalize in compiler, not parser
34
- operator('try', (tryBody, ...clauses) => {
35
- tryBody = tryBody ? compile(tryBody) : null;
36
-
37
- let catchClause = clauses.find(c => c?.[0] === 'catch');
38
- let finallyClause = clauses.find(c => c?.[0] === 'finally');
39
-
40
- const catchParam = catchClause?.[1];
41
- const catchBody = catchClause?.[2] ? compile(catchClause[2]) : null;
42
- const finallyBody = finallyClause?.[1] ? compile(finallyClause[1]) : null;
43
-
44
- return ctx => {
45
- let result;
46
- try {
47
- result = tryBody?.(ctx);
48
- } catch (e) {
49
- if (e === BREAK || e === CONTINUE || e === RETURN) throw e;
50
- if (catchParam !== null && catchParam !== undefined && catchBody) {
51
- const had = catchParam in ctx, orig = ctx[catchParam];
52
- ctx[catchParam] = e;
53
- try { result = catchBody(ctx); }
54
- finally { had ? ctx[catchParam] = orig : delete ctx[catchParam]; }
55
- } else if (!catchBody) throw e;
56
- }
57
- finally {
58
- finallyBody?.(ctx);
59
- }
60
- return result;
61
- };
62
- });
63
-
64
- operator('throw', val => (val = compile(val), ctx => { throw val(ctx); }));
package/feature/unit.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Unit suffixes: 5px, 10rem, 2s, 500ms
2
+ * Unit suffixes - parse half: 5px, 10rem, 2s, 500ms
3
3
  *
4
4
  * AST:
5
5
  * 5px → ['px', [,5]]
@@ -9,14 +9,11 @@
9
9
  * import { unit } from 'subscript/feature/unit.js'
10
10
  * unit('px', 'em', 'rem', 's', 'ms')
11
11
  */
12
- import { lookup, next, parse, idx, seek, operator, compile } from '../parse.js';
12
+ import { lookup, next, parse, idx, seek } from '../parse.js';
13
13
 
14
- const units = {};
14
+ export const units = {};
15
15
 
16
- export const unit = (...names) => names.forEach(name => {
17
- units[name] = 1;
18
- operator(name, val => (val = compile(val), ctx => ({ value: val(ctx), unit: name })));
19
- });
16
+ export const unit = (...names) => names.forEach(name => { units[name] = 1; });
20
17
 
21
18
  // Wrap number handler to check for unit suffix
22
19
  const wrapNum = cc => {
package/feature/var.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Variable declarations: let, const, var
2
+ * Variable declarations: let, const, var - parse half
3
3
  *
4
4
  * AST:
5
5
  * let x = 1 → ['let', ['=', 'x', 1]]
@@ -8,55 +8,10 @@
8
8
  * for (let x in o) → ['for', ['in', ['let', 'x'], 'o'], body]
9
9
  * var x → ['var', 'x'] (acts as assignment target)
10
10
  */
11
- import { expr, space, keyword, operator, compile, seek, word, idx } from '../parse.js';
11
+ import { expr, space, keyword, seek, word, idx } from '../parse.js';
12
12
 
13
13
  const STATEMENT = 5, SEQ = 10, ASSIGN = 20;
14
14
 
15
- // Flatten comma into array: [',', a, b, c] → [a, b, c]
16
- const flatten = items => items[0]?.[0] === ',' ? items[0].slice(1) : items;
17
-
18
- // Destructure value into context
19
- export const destructure = (pattern, value, ctx) => {
20
- if (typeof pattern === 'string') { ctx[pattern] = value; return; }
21
- const [op, ...raw] = pattern;
22
- const items = flatten(raw);
23
- if (op === '{}') {
24
- const used = [];
25
- for (const item of items) {
26
- // Rest: {...rest}
27
- if (Array.isArray(item) && item[0] === '...') {
28
- const rest = {};
29
- for (const k in value) if (!used.includes(k)) rest[k] = value[k];
30
- ctx[item[1]] = rest;
31
- break;
32
- }
33
- let key, binding, def;
34
- // Shorthand: {x} → item is 'x'
35
- // With default: {x = 1} → ['=', 'x', default]
36
- // Rename: {x: y} → [':', 'x', 'y']
37
- if (typeof item === 'string') { key = binding = item }
38
- else if (item[0] === '=') { typeof item[1] === 'string' ? (key = binding = item[1]) : ([, key, binding] = item[1]); def = item[2] }
39
- else { [, key, binding] = item }
40
- used.push(key);
41
- let val = value[key];
42
- if (val === undefined && def) val = compile(def)(ctx);
43
- destructure(binding, val, ctx);
44
- }
45
- }
46
- else if (op === '[]') {
47
- let i = 0;
48
- for (const item of items) {
49
- if (item === null) { i++; continue; }
50
- if (Array.isArray(item) && item[0] === '...') { ctx[item[1]] = value.slice(i); break; }
51
- let binding = item, def;
52
- if (Array.isArray(item) && item[0] === '=') [, binding, def] = item;
53
- let val = value[i++];
54
- if (val === undefined && def) val = compile(def)(ctx);
55
- destructure(binding, val, ctx);
56
- }
57
- }
58
- };
59
-
60
15
  // let/const: expr(SEQ-1) consumes assignment, stops before comma
61
16
  // For for-in/of, return ['in/of', ['let', x], iterable] not ['let', ['in', x, it]]
62
17
  // For comma, return ['let', decl1, decl2, ...] not ['let', [',', ...]]
@@ -84,26 +39,3 @@ keyword('const', STATEMENT + 1, () => decl('const'));
84
39
  // var: just declares identifier, assignment happens separately
85
40
  // var x = 5 → ['=', ['var', 'x'], 5]
86
41
  keyword('var', STATEMENT, () => (space(), ['var', expr(ASSIGN)]));
87
-
88
- // Compile
89
- const varOp = (...decls) => {
90
- decls = decls.map(d => {
91
- // Just identifier: let x
92
- if (typeof d === 'string') return ctx => { ctx[d] = undefined; };
93
- // Assignment: let x = 1
94
- if (d[0] === '=') {
95
- const [, pattern, val] = d;
96
- const v = compile(val);
97
- if (typeof pattern === 'string') return ctx => { ctx[pattern] = v(ctx); };
98
- return ctx => destructure(pattern, v(ctx), ctx);
99
- }
100
- return compile(d);
101
- });
102
- return ctx => { for (const d of decls) d(ctx); };
103
- };
104
- operator('let', varOp);
105
- operator('const', varOp);
106
- // var just declares the variable (assignment handled by = operator)
107
- operator('var', name => (typeof name === 'string'
108
- ? ctx => { ctx[name] = undefined; }
109
- : () => {}));
package/jessie.js CHANGED
@@ -3,32 +3,11 @@
3
3
  *
4
4
  * Builds on justin with statements: blocks, variables, if/else,
5
5
  * loops, functions, try/catch, switch, throw.
6
+ *
7
+ * For parse-only: import { parse } from 'subscript/feature/jessie.js'
6
8
  */
7
- import './justin.js';
8
-
9
- // JS source compatibility
10
- import './feature/unicode.js';
11
-
12
- // Statement features
13
- import './feature/var.js';
14
- import './feature/function.js';
15
- import './feature/async.js';
16
- import './feature/class.js';
17
- import './feature/regex.js';
18
-
19
- // Control flow
20
- import './feature/if.js';
21
- import './feature/loop.js';
22
- import './feature/try.js';
23
- import './feature/switch.js';
24
- import './feature/statement.js'; // debugger, with, labeled statements
25
-
26
- // Module system
27
- import './feature/module.js';
28
- import './feature/accessor.js';
29
-
30
- // Automatic Semicolon Insertion
31
- import './feature/asi.js';
9
+ import './feature/jessie.js';
10
+ import './eval/jessie.js';
32
11
 
33
12
  export * from './parse.js';
34
13
  export { default } from './subscript.js';