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.
- package/README.md +123 -171
- package/feature/access.js +67 -7
- package/feature/accessor.js +49 -0
- package/feature/asi.js +15 -0
- package/feature/async.js +45 -0
- package/feature/block.js +41 -0
- package/feature/class.js +69 -0
- package/feature/collection.js +40 -0
- package/feature/comment.js +25 -6
- package/feature/destruct.js +33 -0
- package/feature/function.js +44 -0
- package/feature/group.js +41 -12
- package/feature/if.js +28 -0
- package/feature/literal.js +13 -0
- package/feature/loop.js +123 -0
- package/feature/module.js +42 -0
- package/feature/number.js +45 -10
- package/feature/op/arithmetic.js +29 -0
- package/feature/op/arrow.js +33 -0
- package/feature/op/assign-logical.js +33 -0
- package/feature/op/assignment.js +47 -0
- package/feature/op/bitwise-unsigned.js +17 -0
- package/feature/op/bitwise.js +29 -0
- package/feature/op/comparison.js +19 -0
- package/feature/op/defer.js +15 -0
- package/feature/op/equality.js +16 -0
- package/feature/op/identity.js +15 -0
- package/feature/op/increment.js +23 -0
- package/feature/op/logical.js +21 -0
- package/feature/op/membership.js +17 -0
- package/feature/op/nullish.js +13 -0
- package/feature/op/optional.js +61 -0
- package/feature/op/pow.js +19 -0
- package/feature/op/range.js +26 -0
- package/feature/op/spread.js +15 -0
- package/feature/op/ternary.js +15 -0
- package/feature/op/type.js +18 -0
- package/feature/op/unary.js +41 -0
- package/feature/prop.js +34 -0
- package/feature/regex.js +31 -0
- package/feature/seq.js +21 -0
- package/feature/string.js +24 -16
- package/feature/switch.js +48 -0
- package/feature/template.js +39 -0
- package/feature/try.js +57 -0
- package/feature/unit.js +35 -0
- package/feature/var.js +59 -0
- package/jessie.js +31 -0
- package/jessie.min.js +8 -0
- package/justin.js +39 -48
- package/justin.min.js +8 -1
- package/package.json +18 -23
- package/parse.js +153 -0
- package/subscript.d.ts +45 -5
- package/subscript.js +62 -22
- package/subscript.min.js +5 -1
- package/util/bundle.js +507 -0
- package/util/stringify.js +172 -0
- package/feature/add.js +0 -22
- package/feature/array.js +0 -11
- package/feature/arrow.js +0 -23
- package/feature/assign.js +0 -11
- package/feature/bitwise.js +0 -11
- package/feature/bool.js +0 -5
- package/feature/call.js +0 -15
- package/feature/compare.js +0 -11
- package/feature/increment.js +0 -11
- package/feature/logic.js +0 -11
- package/feature/mult.js +0 -25
- package/feature/object.js +0 -17
- package/feature/optional.js +0 -30
- package/feature/pow.js +0 -5
- package/feature/shift.js +0 -12
- package/feature/spread.js +0 -6
- package/feature/ternary.js +0 -10
- package/src/compile.d.ts +0 -17
- package/src/compile.js +0 -28
- package/src/const.js +0 -42
- package/src/parse.d.ts +0 -22
- package/src/parse.js +0 -114
- package/src/stringify.js +0 -31
- /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
|
-
))
|
package/feature/bitwise.js
DELETED
|
@@ -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
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
|
-
)
|
package/feature/compare.js
DELETED
|
@@ -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)))
|
package/feature/increment.js
DELETED
|
@@ -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)]]))
|
package/feature/optional.js
DELETED
|
@@ -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
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
package/feature/ternary.js
DELETED
|
@@ -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;
|