subscript 9.1.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 (82) hide show
  1. package/README.md +123 -171
  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 -6
  10. package/feature/destruct.js +33 -0
  11. package/feature/function.js +44 -0
  12. package/feature/group.js +41 -12
  13. package/feature/if.js +28 -0
  14. package/feature/literal.js +13 -0
  15. package/feature/loop.js +123 -0
  16. package/feature/module.js +42 -0
  17. package/feature/number.js +45 -10
  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 -16
  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 +59 -0
  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 -1
  52. package/package.json +18 -23
  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 -1
  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/increment.js +0 -11
  68. package/feature/logic.js +0 -11
  69. package/feature/mult.js +0 -25
  70. package/feature/object.js +0 -17
  71. package/feature/optional.js +0 -30
  72. package/feature/pow.js +0 -5
  73. package/feature/shift.js +0 -12
  74. package/feature/spread.js +0 -6
  75. package/feature/ternary.js +0 -10
  76. package/src/compile.d.ts +0 -17
  77. package/src/compile.js +0 -28
  78. package/src/const.js +0 -42
  79. package/src/parse.d.ts +0 -22
  80. package/src/parse.js +0 -114
  81. package/src/stringify.js +0 -31
  82. /package/{LICENSE → license} +0 -0
@@ -0,0 +1,172 @@
1
+ /**
2
+ * AST → JS Source String (codegen)
3
+ *
4
+ * Simple recursive stringifier using pattern matching on AST structure.
5
+ */
6
+
7
+ // Operator-specific overrides
8
+ export const generators = {};
9
+
10
+ // Register custom generator
11
+ export const generator = (op, fn) => generators[op] = fn;
12
+
13
+ // Stringify AST to JS source
14
+ export const codegen = node => {
15
+ // Handle undefined/null
16
+ if (node === undefined) return 'undefined';
17
+ if (node === null) return 'null';
18
+ if (node === '') return '';
19
+
20
+ // Identifier
21
+ if (!Array.isArray(node)) return String(node);
22
+
23
+ const [op, ...args] = node;
24
+
25
+ // Literal: [, value]
26
+ if (op === undefined) return typeof args[0] === 'string' ? JSON.stringify(args[0]) : String(args[0]);
27
+
28
+ // Custom generator
29
+ if (generators[op]) return generators[op](...args);
30
+
31
+ // Brackets: [], {}, ()
32
+ if (op === '[]' || op === '{}' || op === '()') {
33
+ const prefix = args.length > 1 ? codegen(args.shift()) : '';
34
+ // Empty brackets
35
+ if (args[0] === undefined || args[0] === null) return prefix + op;
36
+ // Comma sequence: [',', a, b, c] → a, b, c (null → empty for sparse arrays)
37
+ const inner = args[0]?.[0] === ','
38
+ ? args[0].slice(1).map(a => a === null ? '' : codegen(a)).join(', ')
39
+ : codegen(args[0]);
40
+ return prefix + op[0] + inner + op[1];
41
+ }
42
+
43
+ // Unary: [op, a]
44
+ if (args.length === 1) return op + codegen(args[0]);
45
+
46
+ // N-ary/sequence: comma, semicolon
47
+ if (op === ',' || op === ';') return args.filter(Boolean).map(codegen).join(op === ';' ? '; ' : ', ');
48
+
49
+ // Binary: [op, a, b]
50
+ if (args.length === 2) {
51
+ const [a, b] = args;
52
+ // Postfix: [op, a, null]
53
+ if (b === null) return codegen(a) + op;
54
+ // Property access: no spaces
55
+ if (op === '.') return codegen(a) + '.' + b;
56
+ return codegen(a) + ' ' + op + ' ' + codegen(b);
57
+ }
58
+
59
+ // Ternary: a ? b : c
60
+ if (op === '?' && args.length === 3) {
61
+ return codegen(args[0]) + ' ? ' + codegen(args[1]) + ' : ' + codegen(args[2]);
62
+ }
63
+
64
+ // Fallback n-ary
65
+ return args.filter(Boolean).map(codegen).join(op === ';' ? '; ' : ', ');
66
+ };
67
+
68
+ // --- Statement generators (need structure) ---
69
+
70
+ generator('block', body => body === undefined ? '{}' : '{ ' + codegen(body) + ' }');
71
+
72
+ // Variables: ['let', decl] or ['let', decl1, decl2, ...]
73
+ const varGen = kw => (...args) => kw + ' ' + args.map(codegen).join(', ');
74
+ generator('let', varGen('let'));
75
+ generator('const', varGen('const'));
76
+ generator('var', varGen('var'));
77
+
78
+ // Control flow
79
+ const wrap = s => s?.[0] === 'block' ? codegen(s) : '{ ' + (s ? codegen(s) : '') + ' }';
80
+ generator('if', (cond, then, els) => 'if (' + codegen(cond) + ') ' + wrap(then) + (els ? ' else ' + wrap(els) : ''));
81
+ generator('while', (cond, body) => 'while (' + codegen(cond) + ') ' + wrap(body));
82
+ generator('do', (body, cond) => 'do ' + wrap(body) + ' while (' + codegen(cond) + ')');
83
+ generator('for', (head, body) => {
84
+ if (head?.[0] === ';') {
85
+ const [, init, cond, step] = head;
86
+ return 'for (' + (init ? codegen(init) : '') + '; ' + (cond ? codegen(cond) : '') + '; ' + (step ? codegen(step) : '') + ') ' + wrap(body);
87
+ }
88
+ return 'for (' + codegen(head) + ') ' + wrap(body);
89
+ });
90
+
91
+ generator('return', a => a === undefined ? 'return' : 'return ' + codegen(a));
92
+ generator('break', () => 'break');
93
+ generator('continue', () => 'continue');
94
+ generator('throw', a => 'throw ' + codegen(a));
95
+
96
+ // Try/Catch - nested structure
97
+ generator('try', body => 'try { ' + codegen(body) + ' }');
98
+ generator('catch', (tryExpr, param, body) => codegen(tryExpr) + ' catch (' + codegen(param) + ') { ' + codegen(body) + ' }');
99
+ generator('finally', (expr, body) => codegen(expr) + ' finally { ' + codegen(body) + ' }');
100
+
101
+ // Functions
102
+ generator('function', (name, params, body) => {
103
+ const args = !params ? '' : params[0] === ',' ? params.slice(1).map(codegen).join(', ') : codegen(params);
104
+ const b = body?.[0] === 'block' ? codegen(body) : '{ ' + (body ? codegen(body) : '') + ' }';
105
+ return 'function' + (name ? ' ' + name : '') + '(' + args + ') ' + b;
106
+ });
107
+
108
+ generator('=>', (params, body) => {
109
+ if (params?.[0] === '()') params = params[1];
110
+ const args = !params ? '()' : typeof params === 'string' ? params :
111
+ params[0] === ',' ? '(' + params.slice(1).map(codegen).join(', ') + ')' : '(' + codegen(params) + ')';
112
+ return args + ' => ' + codegen(body);
113
+ });
114
+
115
+ // Class
116
+ generator('class', (name, base, body) =>
117
+ 'class' + (name ? ' ' + name : '') + (base ? ' extends ' + codegen(base) : '') + ' { ' + (body ? codegen(body) : '') + ' }');
118
+
119
+ // Async/Await/Yield
120
+ generator('async', fn => 'async ' + codegen(fn));
121
+ generator('await', a => 'await ' + codegen(a));
122
+ generator('yield', a => a !== undefined ? 'yield ' + codegen(a) : 'yield');
123
+ generator('yield*', a => 'yield* ' + codegen(a));
124
+
125
+ // Switch
126
+ generator('switch', (expr, body) => 'switch (' + codegen(expr) + ') ' + codegen(body));
127
+ generator('case', (test, body) => 'case ' + codegen(test) + ':' + (body ? ' ' + codegen(body) : ''));
128
+ generator('default:', body => 'default:' + (body ? ' ' + codegen(body) : ''));
129
+
130
+ // Keywords
131
+ generator('typeof', a => '(typeof ' + codegen(a) + ')');
132
+ generator('void', a => '(void ' + codegen(a) + ')');
133
+ generator('delete', a => '(delete ' + codegen(a) + ')');
134
+ generator('new', a => 'new ' + codegen(a));
135
+ generator('instanceof', (a, b) => '(' + codegen(a) + ' instanceof ' + codegen(b) + ')');
136
+
137
+ // Optional chaining
138
+ generator('?.', (a, b) => codegen(a) + '?.' + b);
139
+ generator('?.[]', (a, b) => codegen(a) + '?.[' + codegen(b) + ']');
140
+ generator('?.()', (a, b) => codegen(a) + '?.(' + (!b ? '' : b[0] === ',' ? b.slice(1).map(codegen).join(', ') : codegen(b)) + ')');
141
+
142
+ // Object literal
143
+ generator(':', (k, v) => (typeof k === 'string' ? k : '[' + codegen(k) + ']') + ': ' + codegen(v));
144
+
145
+ // Template literals
146
+ generator('`', (...parts) => '`' + parts.map(p => p?.[0] === undefined ? String(p[1]).replace(/`/g, '\\`').replace(/\$/g, '\\$') : '${' + codegen(p) + '}').join('') + '`');
147
+ generator('``', (tag, ...parts) => codegen(tag) + '`' + parts.map(p => p?.[0] === undefined ? String(p[1]).replace(/`/g, '\\`').replace(/\$/g, '\\$') : '${' + codegen(p) + '}').join('') + '`');
148
+
149
+ // Getter/Setter
150
+ generator('get', (name, body) => 'get ' + name + '() { ' + (body ? codegen(body) : '') + ' }');
151
+ generator('set', (name, param, body) => 'set ' + name + '(' + param + ') { ' + (body ? codegen(body) : '') + ' }');
152
+ generator('static', a => 'static ' + codegen(a));
153
+
154
+ // Non-JS operators (emit as helpers)
155
+ generator('..', (a, b) => 'range(' + codegen(a) + ', ' + codegen(b) + ')');
156
+ generator('..<', (a, b) => 'range(' + codegen(a) + ', ' + codegen(b) + ', true)');
157
+ generator('as', (a, b) => b ? codegen(a) + ' as ' + b : codegen(a)); // import alias or type assertion
158
+ generator('is', (a, b) => '(' + codegen(a) + ' instanceof ' + codegen(b) + ')');
159
+ generator('defer', a => '/* defer */ ' + codegen(a));
160
+
161
+ // For-in/of helper
162
+ generator('in', (a, b) => codegen(a) + ' in ' + codegen(b));
163
+ generator('of', (a, b) => codegen(a) + ' of ' + codegen(b));
164
+ generator('for await', (head, body) => 'for await (' + codegen(head) + ') ' + wrap(body));
165
+
166
+ // Module syntax
167
+ generator('export', spec => 'export ' + codegen(spec));
168
+ generator('import', spec => 'import ' + codegen(spec));
169
+ generator('from', (what, path) => codegen(what) + ' from ' + codegen(path));
170
+ generator('default', a => 'default ' + codegen(a));
171
+
172
+ export default codegen;
package/feature/add.js DELETED
@@ -1,22 +0,0 @@
1
-
2
- import { binary, unary } from '../src/parse.js'
3
- import { PREC_ADD, PREC_PREFIX, PREC_ASSIGN } from '../src/const.js'
4
- import { compile, prop, operator } from '../src/compile.js'
5
-
6
- binary('+', PREC_ADD), operator('+', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) + b(ctx)))
7
- binary('-', PREC_ADD), operator('-', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) - b(ctx)))
8
-
9
- unary('+', PREC_PREFIX), operator('+', (a, b) => !b && (a = compile(a), ctx => +a(ctx)))
10
- unary('-', PREC_PREFIX), operator('-', (a, b) => !b && (a = compile(a), ctx => -a(ctx)))
11
-
12
- binary('+=', PREC_ASSIGN, true)
13
- operator('+=', (a, b) => (
14
- b = compile(b),
15
- prop(a, (container, path, ctx) => container[path] += b(ctx))
16
- ))
17
-
18
- binary('-=', PREC_ASSIGN, true)
19
- operator('-=', (a, b) => (
20
- b = compile(b),
21
- prop(a, (container, path, ctx) => (container[path] -= b(ctx)))
22
- ))
package/feature/array.js DELETED
@@ -1,11 +0,0 @@
1
- import { token, expr, group } from '../src/parse.js'
2
- import { operator, compile } from '../src/compile.js'
3
- import { PREC_TOKEN } from '../src/const.js'
4
-
5
- // [a,b,c]
6
- group('[]', PREC_TOKEN)
7
- operator('[]', (a, b) => b === undefined && (
8
- a = !a ? [] : a[0] === ',' ? a.slice(1) : [a],
9
- a = a.map(a => a[0] === '...' ? (a = compile(a[1]), ctx => a(ctx)) : (a = compile(a), ctx => [a(ctx)])),
10
- ctx => a.flatMap(a => (a(ctx))))
11
- )
package/feature/arrow.js DELETED
@@ -1,23 +0,0 @@
1
- import { binary, group } from "../src/parse.js"
2
- import { compile, operator } from "../src/compile.js"
3
- import { PREC_ASSIGN, PREC_TOKEN } from "../src/const.js"
4
-
5
- // arrow functions (useful for array methods)
6
- binary('=>', PREC_ASSIGN, true)
7
- operator('=>',
8
- (a, b) => (
9
- a = a[0] === '()' ? a[1] : a,
10
- a = !a ? [] : // () =>
11
- a[0] === ',' ? (a = a.slice(1)) : // (a,c) =>
12
- (a = [a]), // a =>
13
-
14
- b = compile(b[0] === '{}' ? b[1] : b), // `=> {x}` -> `=> x`
15
-
16
- (ctx = null) => (
17
- ctx = Object.create(ctx),
18
- (...args) => (a.map((a, i) => ctx[a] = args[i]), b(ctx))
19
- )
20
- )
21
- )
22
-
23
- binary('')
package/feature/assign.js DELETED
@@ -1,11 +0,0 @@
1
- import { binary, err } from "../src/parse.js";
2
- import { compile, operator, operators, prop } from "../src/compile.js";
3
- import { PREC_ASSIGN } from "../src/const.js";
4
-
5
- // assignments
6
- binary('=', PREC_ASSIGN, true)
7
- operator('=', (a, b) => (
8
- b = compile(b),
9
- // a = x, ((a)) = x, a.b = x, a['b'] = x
10
- prop(a, (container, path, ctx) => container[path] = b(ctx))
11
- ))
@@ -1,11 +0,0 @@
1
- import { PREC_OR, PREC_AND, PREC_SHIFT, PREC_XOR, PREC_PREFIX } from "../src/const.js"
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
- unary('~', PREC_PREFIX), operator('~', (a, b) => !b && (a = compile(a), ctx => ~a(ctx)))
6
-
7
- binary('|', PREC_OR), operator('|', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) | b(ctx)))
8
-
9
- binary('&', PREC_AND), operator('&', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) & b(ctx)))
10
-
11
- binary('^', PREC_XOR), operator('^', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) ^ b(ctx)))
package/feature/bool.js DELETED
@@ -1,5 +0,0 @@
1
- import { token } from "../src/parse.js"
2
- import { PREC_TOKEN } from "../src/const.js"
3
-
4
- token('true', PREC_TOKEN, a => a ? err() : [, true])
5
- token('false', PREC_TOKEN, a => a ? err() : [, false])
package/feature/call.js DELETED
@@ -1,15 +0,0 @@
1
- import { access } from '../src/parse.js'
2
- import { operator, compile, prop } from '../src/compile.js'
3
- import { PREC_ACCESS } from '../src/const.js'
4
-
5
- // a(b,c,d), a()
6
- access('()', PREC_ACCESS)
7
- operator('()', (a, b, args) => b !== undefined && (
8
- args = !b ? () => [] : // a()
9
- b[0] === ',' ? (b = b.slice(1).map(b => !b ? err() : compile(b)), ctx => b.map(arg => arg(ctx))) : // a(b,c)
10
- (b = compile(b), ctx => [b(ctx)]), // a(b)
11
-
12
- // a(...args), a.b(...args), a[b](...args)
13
- prop(a, (obj, path, ctx) => obj[path](...args(ctx)), true)
14
- )
15
- )
@@ -1,11 +0,0 @@
1
- import { PREC_EQ, PREC_COMP } from '../src/const.js'
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
-
6
- binary('==', PREC_EQ), operator('==', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) == b(ctx)))
7
- binary('!=', PREC_EQ), operator('!=', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) != b(ctx)))
8
- binary('>', PREC_COMP), operator('>', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) > b(ctx)))
9
- binary('<', PREC_COMP), operator('<', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) < b(ctx)))
10
- binary('>=', PREC_COMP), operator('>=', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) >= b(ctx)))
11
- binary('<=', PREC_COMP), operator('<=', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) <= b(ctx)))
@@ -1,11 +0,0 @@
1
- import { token, expr } from "../src/parse.js"
2
- import { operator, compile, prop } from "../src/compile.js"
3
- import { PREC_POSTFIX } from "../src/const.js"
4
-
5
- token('++', PREC_POSTFIX, a => a ? ['++', a, null,] : ['++', expr(PREC_POSTFIX - 1)])
6
- // ++a, ++((a)), ++a.b, ++a[b]
7
- operator('++', (a,b) => prop(a, b === null ? (obj, path) => obj[path]++ : (obj, path) => ++obj[path]))
8
-
9
- token('--', PREC_POSTFIX, a => a ? ['--', a, null,] : ['--', expr(PREC_POSTFIX - 1)])
10
- // --a, --a.b, --a[b]
11
- operator('--', (a, b) => prop(a, b === null ? (obj, path) => obj[path]-- : (obj, path) => --obj[path]))
package/feature/logic.js DELETED
@@ -1,11 +0,0 @@
1
- import { PREC_LOR, PREC_LAND, PREC_PREFIX, PREC_ASSIGN } from '../src/const.js';
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
- unary('!', PREC_PREFIX), operator('!', (a, b) => !b && (a = compile(a), ctx => !a(ctx)))
6
-
7
- binary('||', PREC_LOR)
8
- operator('||', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) || b(ctx)))
9
-
10
- binary('&&', PREC_LAND)
11
- operator('&&', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) && b(ctx)))
package/feature/mult.js DELETED
@@ -1,25 +0,0 @@
1
- import { binary } from '../src/parse.js'
2
- import { operator, compile, prop } from '../src/compile.js'
3
- import { PREC_MULT, PREC_ASSIGN } from '../src/const.js'
4
-
5
- binary('*', PREC_MULT), operator('*', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) * b(ctx)))
6
- binary('/', PREC_MULT), operator('/', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) / b(ctx)))
7
- binary('%', PREC_MULT), operator('%', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) % b(ctx)))
8
-
9
- binary('*=', PREC_ASSIGN, true)
10
- operator('*=', (a, b) => (
11
- b = compile(b),
12
- prop(a, (container, path, ctx) => container[path] *= b(ctx))
13
- ))
14
-
15
- binary('/=', PREC_ASSIGN, true)
16
- operator('/=', (a, b) => (
17
- b = compile(b),
18
- prop(a, (container, path, ctx) => container[path] /= b(ctx))
19
- ))
20
-
21
- binary('%=', PREC_ASSIGN, true)
22
- operator('%=', (a, b) => (
23
- b = compile(b),
24
- prop(a, (container, path, ctx) => container[path] %= b(ctx))
25
- ))
package/feature/object.js DELETED
@@ -1,17 +0,0 @@
1
- import { token, expr, group, binary } from '../src/parse.js'
2
- import { operator, compile } from '../src/compile.js'
3
- import { PREC_ASSIGN, PREC_SEQ, PREC_TOKEN } from '../src/const.js'
4
-
5
-
6
- // {a:1, b:2, c:3}
7
- group('{}', PREC_TOKEN)
8
- operator('{}', (a, b) => b === undefined && (
9
- // {}, {a:b}, {a}, {a, b}
10
- a = (!a ? [] : a[0] !== ',' ? [a] : a.slice(1)),
11
- a = a.map(p => compile(typeof p === 'string' ? [':', p, p] : p)),
12
- ctx => Object.fromEntries(a.flatMap(frag => frag(ctx)))
13
- ))
14
-
15
- binary(':', PREC_ASSIGN - 1, true)
16
- // "a": a, a: a
17
- operator(':', (a, b) => (b = compile(b), Array.isArray(a) ? (a = compile(a), ctx => [[a(ctx), b(ctx)]]) : ctx => [[a, b(ctx)]]))
@@ -1,30 +0,0 @@
1
- import { token, expr } from '../src/parse.js'
2
- import { operator, compile } from '../src/compile.js'
3
- import { PREC_ACCESS } from '../src/const.js'
4
-
5
- // a?.[, a?.( - postfix operator
6
- token('?.', PREC_ACCESS, a => a && ['?.', a])
7
- // a ?.
8
- operator('?.', a => (a = compile(a), ctx => a(ctx) || (() => { })))
9
-
10
- // a?.b, a?.() - optional chain operator
11
- token('?.', PREC_ACCESS, (a, b) => a && (b = expr(PREC_ACCESS), !b?.map) && ['?.', a, b])
12
- // a ?. b
13
- operator('?.', (a, b) => b && (a = compile(a), ctx => a(ctx)?.[b]))
14
-
15
- // a?.x() - keep context, but watch out a?.()
16
- operator('()', (a, b, container, args, path, optional) => b !== undefined && (a[0] === '?.') && (a[2] || Array.isArray(a[1])) && (
17
- args = !b ? () => [] : // a()
18
- b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(a => a(ctx))) : // a(b,c)
19
- (b = compile(b), ctx => [b(ctx)]), // a(b)
20
-
21
- // a?.()
22
- !a[2] && (optional = true, a = a[1]),
23
-
24
- // a?.['x']?.()
25
- a[0] === '[]' && a.length === 3 ? (path = compile(a[2])) : (path = () => a[2]),
26
- (container = compile(a[1]), optional ?
27
- ctx => (container(ctx)?.[path(ctx)]?.(...args(ctx))) :
28
- ctx => (container(ctx)?.[path(ctx)](...args(ctx)))
29
- )
30
- ))
package/feature/pow.js DELETED
@@ -1,5 +0,0 @@
1
- import { binary } from "../src/parse.js";
2
- import { compile, operator } from "../src/compile.js";
3
- import { PREC_EXP } from "../src/const.js";
4
-
5
- binary('**', PREC_EXP, true), operator('**', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) ** b(ctx)))
package/feature/shift.js DELETED
@@ -1,12 +0,0 @@
1
- import { PREC_OR, PREC_AND, PREC_SHIFT, PREC_XOR, PREC_PREFIX, PREC_ASSIGN } from "../src/const.js"
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
-
6
- binary('>>', PREC_SHIFT), operator('>>', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) >> b(ctx)))
7
- binary('<<', PREC_SHIFT), operator('<<', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) << b(ctx)))
8
-
9
- binary('>>=', PREC_ASSIGN, true)
10
- operator('>>=', (a, b) => (b = compile(b), prop(a, (obj, path, ctx) => (obj[path] >>= b(ctx)))))
11
- binary('<<=', PREC_ASSIGN, true)
12
- operator('<<=', (a, b) => (b = compile(b), prop(a, (obj, path, ctx) => (obj[path] <<= b(ctx)))))
package/feature/spread.js DELETED
@@ -1,6 +0,0 @@
1
- import { unary } from "../src/parse.js"
2
- import { PREC_PREFIX } from "../src/const.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
- unary('...', PREC_PREFIX)
6
- operator('...', (a) => (a = compile(a), ctx => Object.entries(a(ctx))))
@@ -1,10 +0,0 @@
1
- import { token, expr, next } from '../src/parse.js'
2
- import { operator, compile } from '../src/compile.js'
3
- import { PREC_ASSIGN, COLON } from '../src/const.js'
4
-
5
- // ?:
6
- // token('?', PREC_ASSIGN, (a, b, c) => a && (b = expr(PREC_ASSIGN - 1, COLON)) && (c = expr(PREC_ASSIGN - 1), ['?', a, b, c]))
7
- // ALT: not throwing
8
- token('?', PREC_ASSIGN, (a, b, c) => a && (b = expr(PREC_ASSIGN - 1)) && next(c => c === COLON) && (c = expr(PREC_ASSIGN - 1), ['?', a, b, c]))
9
-
10
- operator('?', (a, b, c) => (a = compile(a), b = compile(b), c = compile(c), ctx => a(ctx) ? b(ctx) : c(ctx)))
package/src/compile.d.ts DELETED
@@ -1,17 +0,0 @@
1
- export type OperatorFunction = (...args: any[]) => any;
2
- export type OperatorMap = {
3
- [key: string]: OperatorFunction;
4
- };
5
- export type Node = string | [string | undefined, ...Node[]];
6
- export function compile(node: Node): ((ctx?: any) => any) | OperatorFunction;
7
- export const operators: OperatorMap;
8
- export function operator(op: string, fn: OperatorFunction): void;
9
-
10
- type AccessorFunction = (ctx: any) => any;
11
- export function access(
12
- a: [string, ...any[]] | string,
13
- fn: Function,
14
- generic: boolean
15
- ): AccessorFunction;
16
-
17
- export default compile;
package/src/compile.js DELETED
@@ -1,28 +0,0 @@
1
- import { err } from "./parse.js"
2
-
3
- // build optimized evaluator for the tree
4
- export const compile = (node) => !Array.isArray(node) ? compile.id(node) : !node[0] ? () => node[1] : operators[node[0]].call(...node),
5
- // compile id getter
6
- id = compile.id = name => ctx => ctx?.[name],
7
-
8
- // registered operators
9
- operators = {},
10
-
11
- // register an operator
12
- operator = (op, fn, prev = operators[op]) => (operators[op] = (...args) => fn(...args) || prev?.(...args)),
13
-
14
- // takes node and returns evaluator depending on the case with passed params (container, path, ctx) =>
15
- prop = (a, fn, generic, obj, path) => (
16
- // (((x))) => x
17
- a[0] === '()' && a.length == 2 ? prop(a[1], fn, generic) :
18
- // (_, name, ctx) => ctx[path]
19
- typeof a === 'string' ? ctx => fn(ctx, a, ctx) :
20
- // (container, path, ctx) => container(ctx)[path]
21
- a[0] === '.' ? (obj = compile(a[1]), path = a[2], ctx => fn(obj(ctx), path, ctx)) :
22
- // (container, path, ctx) => container(ctx)[path(ctx)]
23
- a[0] === '[]' && a.length === 3 ? (obj = compile(a[1]), path = compile(a[2]), ctx => fn(obj(ctx), path(ctx), ctx)) :
24
- // (src, _, ctx) => src(ctx)
25
- generic ? (a = compile(a), ctx => fn([a(ctx)], 0, ctx)) : () => err('Bad left value')
26
- )
27
-
28
- export default compile
package/src/const.js DELETED
@@ -1,42 +0,0 @@
1
- export const
2
- PERIOD = 46,
3
- OPAREN = 40,
4
- CPAREN = 41,
5
- OBRACK = 91,
6
- CBRACK = 93,
7
- OBRACE = 123,
8
- CBRACE = 125,
9
- SPACE = 32,
10
- COLON = 58,
11
- DQUOTE = 34,
12
- QUOTE = 39,
13
- _0 = 48,
14
- _9 = 57,
15
- _E = 69,
16
- _e = 101,
17
- BSLASH = 92,
18
- SLASH = 47,
19
- STAR = 42
20
-
21
- // ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence
22
- // we mult by 10 to leave space for extensions
23
- export const
24
- PREC_STATEMENT = 5,
25
- PREC_SEQ = 10,
26
- PREC_ASSIGN = 20,
27
- PREC_LOR = 30,
28
- PREC_LAND = 40,
29
- PREC_OR = 50,
30
- PREC_XOR = 60,
31
- PREC_AND = 70,
32
- PREC_EQ = 80,
33
- PREC_COMP = 90,
34
- PREC_SHIFT = 100,
35
- PREC_ADD = 110,
36
- PREC_MULT = 120,
37
- PREC_EXP = 130,
38
- PREC_PREFIX = 140,
39
- PREC_POSTFIX = 150,
40
- PREC_ACCESS = 170,
41
- PREC_GROUP = 180,
42
- PREC_TOKEN = 200
package/src/parse.d.ts DELETED
@@ -1,22 +0,0 @@
1
- export let idx: any;
2
- export let cur: any;
3
- export function parse(s: string): any;
4
- export namespace parse {
5
- function space(cc: any): any;
6
- function id(n: any): any;
7
- }
8
- export function err(msg?: string, frag?: string): never;
9
- export function skip(n: number): string;
10
- export function next(is: ((c: number) => number)): string;
11
- export const lookup: ((a: any, b: any) => any)[];
12
- export function token(op: string, prec: number, map: (a: any, curPrec: number, from: number) => any): (a: any, curPrec: number, from?: any) => any;
13
- export function binary(op: string, prec: number, right?: boolean | undefined): (a: any, curPrec: number, from?: any) => any;
14
- export function access(op: string, prec: number): (a: any, curPrec: number, from?: any) => any;
15
- export function group(op: string, prec: number): (a: any, curPrec: number, from?: any) => any;
16
- export function unary(op: string, prec: number, post?: boolean | undefined): (a: any, curPrec: number, from?: any) => any;
17
- export function nary(op: string, prec: number, skips?: boolean | undefined): (a: any, curPrec: number, from?: any) => any;
18
- export function expr(prec: number, end?: string | undefined): any;
19
- export function isId(c: number): boolean;
20
- export function space(): number;
21
- export function id(): string;
22
- export default parse;