subscript 10.3.6 → 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.
- package/README.md +9 -2
- package/eval/access.js +57 -0
- package/eval/accessor.js +19 -0
- package/eval/async.js +13 -0
- package/eval/class.js +35 -0
- package/eval/collection.js +41 -0
- package/eval/function.js +37 -0
- package/eval/if.js +7 -0
- package/eval/jessie.js +19 -0
- package/eval/justin.js +21 -0
- package/eval/loop.js +108 -0
- package/eval/module.js +8 -0
- package/eval/op/arithmetic.js +12 -0
- package/eval/op/arrow.js +35 -0
- package/eval/op/assign-logical.js +23 -0
- package/eval/op/assignment.js +15 -0
- package/eval/op/bitwise-unsigned.js +8 -0
- package/eval/op/bitwise.js +9 -0
- package/eval/op/comparison.js +7 -0
- package/eval/op/defer.js +4 -0
- package/eval/op/equality.js +5 -0
- package/eval/op/identity.js +5 -0
- package/eval/op/increment.js +13 -0
- package/eval/op/logical.js +6 -0
- package/eval/op/membership.js +4 -0
- package/eval/op/nullish.js +4 -0
- package/eval/op/optional.js +38 -0
- package/eval/op/pow.js +8 -0
- package/eval/op/range.js +13 -0
- package/eval/op/spread.js +4 -0
- package/eval/op/ternary.js +4 -0
- package/eval/op/type.js +5 -0
- package/eval/op/unary.js +24 -0
- package/eval/prop.js +16 -0
- package/eval/regex.js +7 -0
- package/eval/seq.js +10 -0
- package/eval/subscript.js +15 -0
- package/eval/switch.js +27 -0
- package/eval/template.js +14 -0
- package/eval/try.js +36 -0
- package/eval/unit.js +10 -0
- package/eval/var.js +69 -0
- package/feature/access.js +2 -58
- package/feature/accessor.js +2 -21
- package/feature/asi.js +50 -11
- package/feature/async.js +2 -14
- package/feature/class.js +2 -35
- package/feature/collection.js +2 -43
- package/feature/function.js +2 -39
- package/feature/if.js +2 -8
- package/feature/jessie.js +32 -0
- package/feature/justin.js +36 -0
- package/feature/loop.js +2 -109
- package/feature/module.js +1 -10
- package/feature/op/arithmetic.js +2 -13
- package/feature/op/arrow.js +2 -38
- package/feature/op/assign-logical.js +3 -24
- package/feature/op/assignment.js +2 -18
- package/feature/op/bitwise-unsigned.js +2 -8
- package/feature/op/bitwise.js +2 -14
- package/feature/op/comparison.js +2 -8
- package/feature/op/defer.js +2 -7
- package/feature/op/equality.js +2 -7
- package/feature/op/identity.js +2 -6
- package/feature/op/increment.js +2 -14
- package/feature/op/logical.js +2 -8
- package/feature/op/membership.js +2 -7
- package/feature/op/nullish.js +2 -5
- package/feature/op/optional.js +2 -41
- package/feature/op/pow.js +2 -10
- package/feature/op/range.js +2 -16
- package/feature/op/spread.js +2 -7
- package/feature/op/ternary.js +2 -7
- package/feature/op/type.js +2 -8
- package/feature/op/unary.js +2 -27
- package/feature/prop.js +2 -17
- package/feature/regex.js +3 -12
- package/feature/seq.js +2 -11
- package/feature/shebang.js +7 -0
- package/feature/subscript.js +23 -0
- package/feature/switch.js +2 -28
- package/feature/template.js +4 -16
- package/feature/try.js +4 -38
- package/feature/unit.js +4 -7
- package/feature/var.js +2 -70
- package/jessie.js +4 -25
- package/jessie.min.js +9 -8
- package/justin.js +4 -30
- package/justin.min.js +8 -8
- package/package.json +9 -1
- package/parse.js +27 -29
- package/subscript.js +7 -16
- package/subscript.min.js +5 -5
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* jessie - parse aggregator
|
|
3
|
+
* Practical JS subset. No eval - import 'subscript/eval/jessie.js' for runtime.
|
|
4
|
+
*/
|
|
5
|
+
import './justin.js';
|
|
6
|
+
|
|
7
|
+
// JS source compatibility
|
|
8
|
+
import './unicode.js';
|
|
9
|
+
|
|
10
|
+
// Statement features
|
|
11
|
+
import './var.js';
|
|
12
|
+
import './function.js';
|
|
13
|
+
import './async.js';
|
|
14
|
+
import './class.js';
|
|
15
|
+
import './regex.js';
|
|
16
|
+
|
|
17
|
+
// Control flow
|
|
18
|
+
import './if.js';
|
|
19
|
+
import './loop.js';
|
|
20
|
+
import './try.js';
|
|
21
|
+
import './switch.js';
|
|
22
|
+
import './statement.js'; // debugger, with, labeled statements
|
|
23
|
+
|
|
24
|
+
// Module system
|
|
25
|
+
import './module.js';
|
|
26
|
+
import './accessor.js';
|
|
27
|
+
|
|
28
|
+
// Shebang line + Automatic Semicolon Insertion
|
|
29
|
+
import './shebang.js';
|
|
30
|
+
import './asi.js';
|
|
31
|
+
|
|
32
|
+
export * from '../parse.js';
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* justin - parse aggregator
|
|
3
|
+
* JSON superset expression language. No eval - import 'subscript/eval/justin.js' for runtime.
|
|
4
|
+
*/
|
|
5
|
+
import './subscript.js';
|
|
6
|
+
import { parse } from '../parse.js';
|
|
7
|
+
|
|
8
|
+
// Add single quotes
|
|
9
|
+
parse.string["'"] = true;
|
|
10
|
+
|
|
11
|
+
// Add hex, binary, octal prefixes
|
|
12
|
+
parse.number = { '0x': 16, '0b': 2, '0o': 8 };
|
|
13
|
+
|
|
14
|
+
import './comment.js';
|
|
15
|
+
|
|
16
|
+
// Extended operators
|
|
17
|
+
// Note: assignment (=) is in subscript, must come BEFORE identity (===)
|
|
18
|
+
import './op/identity.js'; // === !==
|
|
19
|
+
import './op/nullish.js'; // ??
|
|
20
|
+
import './op/pow.js'; // ** **=
|
|
21
|
+
import './op/membership.js'; // in (instanceof is in jessie/class.js)
|
|
22
|
+
import './op/bitwise-unsigned.js'; // >>> >>>=
|
|
23
|
+
import './op/assign-logical.js'; // ||= &&= ??=
|
|
24
|
+
|
|
25
|
+
// JS-specific operators (ternary, arrow, spread, optional chaining, typeof/void/delete/new)
|
|
26
|
+
import './literal.js';
|
|
27
|
+
import './op/ternary.js';
|
|
28
|
+
import './op/arrow.js';
|
|
29
|
+
import './op/spread.js';
|
|
30
|
+
import './op/optional.js';
|
|
31
|
+
import './op/unary.js';
|
|
32
|
+
|
|
33
|
+
import './collection.js';
|
|
34
|
+
import './template.js';
|
|
35
|
+
|
|
36
|
+
export * from '../parse.js';
|
package/feature/loop.js
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
// Loops: while, do-while, for, for await, break, continue, return
|
|
2
|
-
import { expr, skip, space, parse, word, keyword, parens, cur, idx,
|
|
3
|
-
import { RETURN } from './op/arrow.js';
|
|
1
|
+
// Loops: while, do-while, for, for await, break, continue, return - parse half
|
|
2
|
+
import { expr, skip, space, parse, word, keyword, parens, cur, idx, next, seek } from '../parse.js';
|
|
4
3
|
import { body } from './if.js';
|
|
5
|
-
import { destructure } from './var.js';
|
|
6
|
-
|
|
7
|
-
export const BREAK = Symbol('break'), CONTINUE = Symbol('continue');
|
|
8
4
|
|
|
9
5
|
const STATEMENT = 5, CBRACE = 125, SEMI = 59;
|
|
10
6
|
|
|
@@ -57,106 +53,3 @@ keyword('return', STATEMENT + 1, () => {
|
|
|
57
53
|
const c = space();
|
|
58
54
|
return !c || c === CBRACE || c === SEMI || parse.newline ? ['return'] : ['return', expr(STATEMENT)];
|
|
59
55
|
});
|
|
60
|
-
|
|
61
|
-
// Compile - inline try/catch, use JS break/continue directly
|
|
62
|
-
operator('while', (cond, body) => {
|
|
63
|
-
cond = compile(cond); body = compile(body);
|
|
64
|
-
return ctx => {
|
|
65
|
-
let res;
|
|
66
|
-
while (cond(ctx)) try { res = body(ctx); } catch (e) {
|
|
67
|
-
if (e === BREAK) break;
|
|
68
|
-
if (e === CONTINUE) continue;
|
|
69
|
-
if (e === RETURN) return e[0];
|
|
70
|
-
throw e;
|
|
71
|
-
}
|
|
72
|
-
return res;
|
|
73
|
-
};
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
operator('do', (body, cond) => {
|
|
77
|
-
body = compile(body); cond = compile(cond);
|
|
78
|
-
return ctx => {
|
|
79
|
-
let res;
|
|
80
|
-
do try { res = body(ctx); } catch (e) {
|
|
81
|
-
if (e === BREAK) break;
|
|
82
|
-
if (e === CONTINUE) continue;
|
|
83
|
-
if (e === RETURN) return e[0];
|
|
84
|
-
throw e;
|
|
85
|
-
} while (cond(ctx));
|
|
86
|
-
return res;
|
|
87
|
-
};
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
operator('for', (head, body) => {
|
|
91
|
-
// Normalize head: [';', init, cond, step] or single expr (for-in/of)
|
|
92
|
-
if (Array.isArray(head) && head[0] === ';') {
|
|
93
|
-
let [, init, cond, step] = head;
|
|
94
|
-
init = init ? compile(init) : null;
|
|
95
|
-
cond = cond ? compile(cond) : () => true;
|
|
96
|
-
step = step ? compile(step) : null;
|
|
97
|
-
body = compile(body);
|
|
98
|
-
return ctx => {
|
|
99
|
-
let res;
|
|
100
|
-
for (init?.(ctx); cond(ctx); step?.(ctx)) try { res = body(ctx); } catch (e) {
|
|
101
|
-
if (e === BREAK) break;
|
|
102
|
-
if (e === CONTINUE) continue;
|
|
103
|
-
if (e === RETURN) return e[0];
|
|
104
|
-
throw e;
|
|
105
|
-
}
|
|
106
|
-
return res;
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
// For-in/of: head is ['in', lhs, rhs] or ['of', lhs, rhs]
|
|
110
|
-
if (Array.isArray(head) && (head[0] === 'in' || head[0] === 'of')) {
|
|
111
|
-
let [op, lhs, rhs] = head;
|
|
112
|
-
// Extract name from declaration: ['let', 'x'] → 'x'
|
|
113
|
-
if (Array.isArray(lhs) && (lhs[0] === 'let' || lhs[0] === 'const' || lhs[0] === 'var')) lhs = lhs[1];
|
|
114
|
-
if (op === 'in') return forIn(lhs, rhs, body);
|
|
115
|
-
if (op === 'of') return forOf(lhs, rhs, body);
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
const forOf = (name, iterable, body) => {
|
|
120
|
-
iterable = compile(iterable); body = compile(body);
|
|
121
|
-
const isPattern = Array.isArray(name);
|
|
122
|
-
return ctx => {
|
|
123
|
-
let res;
|
|
124
|
-
const prev = isPattern ? null : ctx[name];
|
|
125
|
-
for (const val of iterable(ctx)) {
|
|
126
|
-
if (isPattern) destructure(name, val, ctx); else ctx[name] = val;
|
|
127
|
-
try { res = body(ctx); } catch (e) {
|
|
128
|
-
if (e === BREAK) break;
|
|
129
|
-
if (e === CONTINUE) continue;
|
|
130
|
-
if (e === RETURN) return e[0];
|
|
131
|
-
throw e;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
if (!isPattern) ctx[name] = prev;
|
|
135
|
-
return res;
|
|
136
|
-
};
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const forIn = (name, obj, body) => {
|
|
140
|
-
obj = compile(obj); body = compile(body);
|
|
141
|
-
const isPattern = Array.isArray(name);
|
|
142
|
-
return ctx => {
|
|
143
|
-
let res;
|
|
144
|
-
const prev = isPattern ? null : ctx[name];
|
|
145
|
-
for (const key in obj(ctx)) {
|
|
146
|
-
if (isPattern) destructure(name, key, ctx); else ctx[name] = key;
|
|
147
|
-
try { res = body(ctx); } catch (e) {
|
|
148
|
-
if (e === BREAK) break;
|
|
149
|
-
if (e === CONTINUE) continue;
|
|
150
|
-
if (e === RETURN) return e[0];
|
|
151
|
-
throw e;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
if (!isPattern) ctx[name] = prev;
|
|
155
|
-
return res;
|
|
156
|
-
};
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
operator('break', () => () => { throw BREAK; });
|
|
160
|
-
operator('continue', () => () => { throw CONTINUE; });
|
|
161
|
-
operator('return', val => (val = val !== undefined ? compile(val) : null,
|
|
162
|
-
ctx => { throw (RETURN[0] = val?.(ctx), RETURN); }));
|
package/feature/module.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Import/Export with contextual 'from' operator
|
|
2
|
+
* Import/Export with contextual 'from' operator - parse half
|
|
3
3
|
*
|
|
4
|
-
* AST:
|
|
5
4
|
* import './x.js' → ['import', path]
|
|
6
5
|
* import X from './x.js' → ['import', ['from', 'X', path]]
|
|
7
6
|
* import { a, b } from './x' → ['import', ['from', ['{}', ...], path]]
|
|
@@ -34,11 +33,3 @@ keyword('export', STATEMENT, () => (space(), ['export', expr(STATEMENT)]));
|
|
|
34
33
|
|
|
35
34
|
// default: prefix for export default (NOT switch default: which has colon)
|
|
36
35
|
keyword('default', SEQ + 1, () => space() !== 58 && (space(), ['default', expr(SEQ)]));
|
|
37
|
-
|
|
38
|
-
// Compile stubs - import/export are parse-only (no runtime semantics)
|
|
39
|
-
import { operator, compile } from '../parse.js';
|
|
40
|
-
operator('import', () => () => undefined);
|
|
41
|
-
operator('export', () => () => undefined);
|
|
42
|
-
operator('from', (a, b) => () => undefined);
|
|
43
|
-
operator('as', (a, b) => () => undefined);
|
|
44
|
-
operator('default', (a) => compile(a));
|
package/feature/op/arithmetic.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Arithmetic operators
|
|
2
|
+
* Arithmetic operators - parse half
|
|
3
3
|
*
|
|
4
4
|
* + - * / %
|
|
5
5
|
* Unary: + -
|
|
6
6
|
*/
|
|
7
|
-
import { binary, unary
|
|
7
|
+
import { binary, unary } from '../../parse.js';
|
|
8
8
|
|
|
9
9
|
const ADD = 110, MULT = 120, PREFIX = 140;
|
|
10
10
|
|
|
@@ -16,14 +16,3 @@ binary('%', MULT);
|
|
|
16
16
|
|
|
17
17
|
unary('+', PREFIX);
|
|
18
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)));
|
package/feature/op/arrow.js
CHANGED
|
@@ -1,46 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Arrow function operator
|
|
2
|
+
* Arrow function operator - parse half
|
|
3
3
|
*
|
|
4
4
|
* (a, b) => expr → arrow function
|
|
5
|
-
*
|
|
6
|
-
* Common in: JS, TS, Java, C#, Kotlin, Scala
|
|
7
5
|
*/
|
|
8
|
-
import { binary
|
|
9
|
-
|
|
10
|
-
// RETURN: array to hold value - reused, no allocation per throw
|
|
11
|
-
export const RETURN = [];
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
12
7
|
|
|
13
8
|
const ASSIGN = 20;
|
|
14
9
|
|
|
15
10
|
binary('=>', ASSIGN, true);
|
|
16
|
-
|
|
17
|
-
// Compile
|
|
18
|
-
operator('=>', (a, b) => {
|
|
19
|
-
// Normalize params: () → [], x → [x], (a, b) → [a, b]
|
|
20
|
-
a = a?.[0] === '()' ? a[1] : a;
|
|
21
|
-
const ps = !a ? [] : a[0] === ',' ? a.slice(1) : [a];
|
|
22
|
-
// Check for rest param
|
|
23
|
-
let restIdx = -1, restName = null;
|
|
24
|
-
const last = ps[ps.length - 1];
|
|
25
|
-
if (Array.isArray(last) && last[0] === '...') {
|
|
26
|
-
restIdx = ps.length - 1;
|
|
27
|
-
restName = last[1];
|
|
28
|
-
ps.length--;
|
|
29
|
-
}
|
|
30
|
-
// Arrow body: {} is always block (need parens for object: ({...}))
|
|
31
|
-
// Block body returns undefined unless explicit return
|
|
32
|
-
const isBlock = b?.[0] === '{}';
|
|
33
|
-
b = compile(isBlock ? ['{', b[1]] : b);
|
|
34
|
-
return ctx => (...args) => {
|
|
35
|
-
const l = {};
|
|
36
|
-
ps.forEach((p, i) => l[p] = args[i]);
|
|
37
|
-
if (restName) l[restName] = args.slice(restIdx);
|
|
38
|
-
const fnCtx = new Proxy(l, {
|
|
39
|
-
get: (l, k) => k in l ? l[k] : ctx?.[k],
|
|
40
|
-
set: (l, k, v) => ((k in l ? l : ctx)[k] = v, true),
|
|
41
|
-
has: (l, k) => k in l || (ctx ? k in ctx : false)
|
|
42
|
-
});
|
|
43
|
-
try { const r = b(fnCtx); return isBlock ? undefined : r; }
|
|
44
|
-
catch (e) { if (e === RETURN) return e[0]; throw e; }
|
|
45
|
-
};
|
|
46
|
-
});
|
|
@@ -1,33 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Logical/nullish assignment operators
|
|
2
|
+
* Logical/nullish assignment operators - parse half
|
|
3
3
|
*
|
|
4
|
-
* ||= &&= ??=
|
|
4
|
+
* ||= &&= ??=
|
|
5
5
|
*/
|
|
6
|
-
import { binary
|
|
7
|
-
import { destructure } from '../var.js';
|
|
8
|
-
import { isLval, prop } from '../access.js';
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
9
7
|
|
|
10
8
|
const ASSIGN = 20;
|
|
11
|
-
const err = msg => { throw Error(msg) };
|
|
12
9
|
|
|
13
10
|
binary('||=', ASSIGN, true);
|
|
14
11
|
binary('&&=', ASSIGN, true);
|
|
15
12
|
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))));
|
package/feature/op/assignment.js
CHANGED
|
@@ -1,26 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Assignment operators (C-family)
|
|
2
|
+
* Assignment operators (C-family) - parse half
|
|
3
3
|
*
|
|
4
4
|
* = += -= *= /= %= |= &= ^= >>= <<=
|
|
5
|
-
* Note: **= is in pow.js, >>>= ||= &&= ??= are JS-specific (in assignment-js.js)
|
|
6
5
|
*/
|
|
7
|
-
import { binary
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
8
7
|
|
|
9
8
|
const ASSIGN = 20;
|
|
10
9
|
|
|
11
|
-
// Register all assignment operators
|
|
12
10
|
'= += -= *= /= %= |= &= ^= >>= <<='.split(' ').map(op => binary(op, ASSIGN, true));
|
|
13
|
-
|
|
14
|
-
// Simple assign helper for x, a.b, a[b], (x)
|
|
15
|
-
const assign = (a, fn, obj, key) =>
|
|
16
|
-
typeof a === 'string' ? ctx => fn(ctx, a, ctx) :
|
|
17
|
-
a[0] === '.' ? (obj = compile(a[1]), key = a[2], ctx => fn(obj(ctx), key, ctx)) :
|
|
18
|
-
a[0] === '[]' && a.length === 3 ? (obj = compile(a[1]), key = compile(a[2]), ctx => fn(obj(ctx), key(ctx), ctx)) :
|
|
19
|
-
a[0] === '()' && a.length === 2 ? assign(a[1], fn) :
|
|
20
|
-
(() => { throw Error('Invalid assignment target') })();
|
|
21
|
-
|
|
22
|
-
// Compile - use Function to generate operator implementations
|
|
23
|
-
const ops = { '=': (o,k,v)=>o[k]=v, '+=': (o,k,v)=>o[k]+=v, '-=': (o,k,v)=>o[k]-=v, '*=': (o,k,v)=>o[k]*=v,
|
|
24
|
-
'/=': (o,k,v)=>o[k]/=v, '%=': (o,k,v)=>o[k]%=v, '|=': (o,k,v)=>o[k]|=v, '&=': (o,k,v)=>o[k]&=v,
|
|
25
|
-
'^=': (o,k,v)=>o[k]^=v, '>>=': (o,k,v)=>o[k]>>=v, '<<=': (o,k,v)=>o[k]<<=v };
|
|
26
|
-
for (const op in ops) operator(op, (a, b) => (b = compile(b), assign(a, (o, k, ctx) => ops[op](o, k, b(ctx)))));
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Unsigned right shift operators
|
|
2
|
+
* Unsigned right shift operators - parse half
|
|
3
3
|
*
|
|
4
4
|
* >>> >>>=
|
|
5
5
|
*/
|
|
6
|
-
import { binary
|
|
7
|
-
import { isLval, prop } from '../access.js';
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
8
7
|
|
|
9
8
|
const ASSIGN = 20, SHIFT = 100;
|
|
10
|
-
const err = msg => { throw Error(msg) };
|
|
11
9
|
|
|
12
10
|
binary('>>>', SHIFT);
|
|
13
11
|
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))));
|
package/feature/op/bitwise.js
CHANGED
|
@@ -1,29 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Bitwise operators
|
|
2
|
+
* Bitwise operators - parse half
|
|
3
3
|
*
|
|
4
4
|
* | & ^ ~ >> <<
|
|
5
|
-
* Note: >>> is JS-specific (in bitwise-js.js)
|
|
6
5
|
*/
|
|
7
|
-
import { binary, unary
|
|
6
|
+
import { binary, unary } from '../../parse.js';
|
|
8
7
|
|
|
9
8
|
const OR = 50, XOR = 60, AND = 70, SHIFT = 100, PREFIX = 140;
|
|
10
9
|
|
|
11
|
-
// Base operators first (tried last in chain)
|
|
12
10
|
binary('|', OR);
|
|
13
11
|
binary('&', AND);
|
|
14
12
|
binary('^', XOR);
|
|
15
13
|
|
|
16
|
-
// Shifts (after < >)
|
|
17
14
|
binary('>>', SHIFT);
|
|
18
15
|
binary('<<', SHIFT);
|
|
19
16
|
|
|
20
|
-
// Unary
|
|
21
17
|
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)));
|
package/feature/op/comparison.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Comparison operators
|
|
2
|
+
* Comparison operators - parse half
|
|
3
3
|
*
|
|
4
4
|
* < > <= >=
|
|
5
5
|
*/
|
|
6
|
-
import { binary
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
7
7
|
|
|
8
8
|
const COMP = 90;
|
|
9
9
|
|
|
@@ -11,9 +11,3 @@ binary('<', COMP);
|
|
|
11
11
|
binary('>', COMP);
|
|
12
12
|
binary('<=', COMP);
|
|
13
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)));
|
package/feature/op/defer.js
CHANGED
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Defer operator
|
|
2
|
+
* Defer operator - parse half
|
|
3
3
|
*
|
|
4
4
|
* defer expr: registers cleanup to run at scope exit
|
|
5
|
-
*
|
|
6
|
-
* Common in: Go, Swift, Zig
|
|
7
5
|
*/
|
|
8
|
-
import { unary
|
|
6
|
+
import { unary } from '../../parse.js';
|
|
9
7
|
|
|
10
8
|
const PREFIX = 140;
|
|
11
9
|
|
|
12
10
|
unary('defer', PREFIX);
|
|
13
|
-
|
|
14
|
-
// Compile
|
|
15
|
-
operator('defer', a => (a = compile(a), ctx => { ctx.__deferred__ = ctx.__deferred__ || []; ctx.__deferred__.push(a); }));
|
package/feature/op/equality.js
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Equality operators (base)
|
|
2
|
+
* Equality operators (base) - parse half
|
|
3
3
|
*
|
|
4
4
|
* == !=
|
|
5
|
-
* For === !== see equality-strict.js
|
|
6
5
|
*/
|
|
7
|
-
import { binary
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
8
7
|
|
|
9
8
|
const EQ = 80;
|
|
10
9
|
|
|
11
10
|
binary('==', EQ);
|
|
12
11
|
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)));
|
package/feature/op/identity.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Identity operators
|
|
2
|
+
* Identity operators - parse half
|
|
3
3
|
*
|
|
4
4
|
* === !==
|
|
5
5
|
*/
|
|
6
|
-
import { binary
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
7
7
|
|
|
8
8
|
const EQ = 80;
|
|
9
9
|
|
|
10
10
|
binary('===', EQ);
|
|
11
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)));
|
package/feature/op/increment.js
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Increment/decrement operators
|
|
2
|
+
* Increment/decrement operators - parse half
|
|
3
3
|
*
|
|
4
4
|
* ++ -- (prefix and postfix)
|
|
5
5
|
*/
|
|
6
|
-
import { token, expr
|
|
6
|
+
import { token, expr } from '../../parse.js';
|
|
7
7
|
|
|
8
8
|
const POSTFIX = 150;
|
|
9
9
|
|
|
10
10
|
token('++', POSTFIX, a => a ? ['++', a, null] : ['++', expr(POSTFIX - 1)]);
|
|
11
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]));
|
package/feature/op/logical.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Logical operators (base)
|
|
2
|
+
* Logical operators (base) - parse half
|
|
3
3
|
*
|
|
4
4
|
* ! && ||
|
|
5
|
-
* For ?? see nullish.js
|
|
6
5
|
*/
|
|
7
|
-
import { binary, unary
|
|
6
|
+
import { binary, unary } from '../../parse.js';
|
|
8
7
|
|
|
9
8
|
const LOR = 30, LAND = 40, PREFIX = 140;
|
|
10
9
|
|
|
@@ -13,8 +12,3 @@ unary('!', PREFIX);
|
|
|
13
12
|
|
|
14
13
|
binary('||', LOR);
|
|
15
14
|
binary('&&', LAND);
|
|
16
|
-
|
|
17
|
-
// Compile
|
|
18
|
-
operator('!', a => (a = compile(a), ctx => !a(ctx)));
|
|
19
|
-
operator('||', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) || b(ctx)));
|
|
20
|
-
operator('&&', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) && b(ctx)));
|
package/feature/op/membership.js
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Membership operator
|
|
2
|
+
* Membership operator - parse half
|
|
3
3
|
*
|
|
4
4
|
* in: key in object
|
|
5
5
|
* of: for-of iteration (parsed as binary in for head)
|
|
6
|
-
*
|
|
7
|
-
* Note: instanceof is in class.js (jessie feature)
|
|
8
6
|
*/
|
|
9
|
-
import { binary
|
|
7
|
+
import { binary } from '../../parse.js';
|
|
10
8
|
|
|
11
9
|
const COMP = 90;
|
|
12
10
|
|
|
13
11
|
binary('in', COMP);
|
|
14
12
|
binary('of', COMP);
|
|
15
|
-
|
|
16
|
-
// Compile
|
|
17
|
-
operator('in', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) in b(ctx)));
|
package/feature/op/nullish.js
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Nullish coalescing operator
|
|
2
|
+
* Nullish coalescing operator - parse half
|
|
3
3
|
*
|
|
4
4
|
* ??
|
|
5
5
|
*/
|
|
6
|
-
import { binary
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
7
7
|
|
|
8
8
|
const LOR = 30;
|
|
9
9
|
|
|
10
10
|
binary('??', LOR);
|
|
11
|
-
|
|
12
|
-
// Compile
|
|
13
|
-
operator('??', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) ?? b(ctx)));
|
package/feature/op/optional.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Optional chaining operators
|
|
2
|
+
* Optional chaining operators - parse half
|
|
3
3
|
*
|
|
4
4
|
* a?.b → optional member access
|
|
5
5
|
* a?.[x] → optional computed access
|
|
6
6
|
* a?.() → optional call
|
|
7
|
-
*
|
|
8
|
-
* Common in: JS, TS, Swift, Kotlin, C#
|
|
9
7
|
*/
|
|
10
|
-
import { token, expr, skip, space
|
|
11
|
-
import { unsafe } from '../access.js';
|
|
8
|
+
import { token, expr, skip, space } from '../../parse.js';
|
|
12
9
|
|
|
13
10
|
const ACCESS = 170;
|
|
14
11
|
|
|
@@ -23,39 +20,3 @@ token('?.', ACCESS, (a, b) => {
|
|
|
23
20
|
b = expr(ACCESS);
|
|
24
21
|
return b ? ['?.', a, b] : void 0;
|
|
25
22
|
});
|
|
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
|
-
});
|
package/feature/op/pow.js
CHANGED
|
@@ -1,19 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Exponentiation operator
|
|
2
|
+
* Exponentiation operator - parse half
|
|
3
3
|
*
|
|
4
4
|
* ** **=
|
|
5
|
-
*
|
|
6
|
-
* ES2016+, not in classic JS/C
|
|
7
5
|
*/
|
|
8
|
-
import { binary
|
|
9
|
-
import { isLval, prop } from '../access.js';
|
|
6
|
+
import { binary } from '../../parse.js';
|
|
10
7
|
|
|
11
8
|
const EXP = 130, ASSIGN = 20;
|
|
12
9
|
|
|
13
10
|
binary('**', EXP, true);
|
|
14
11
|
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))));
|