subscript 9.2.0 → 10.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +115 -169
- 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 -5
- package/feature/destruct.js +33 -0
- package/feature/function.js +44 -0
- package/feature/group.js +39 -9
- package/feature/if.js +23 -38
- package/feature/literal.js +13 -0
- package/feature/loop.js +107 -106
- package/feature/module.js +42 -0
- package/feature/number.js +41 -38
- 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 -17
- 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 +51 -41
- package/jessie.js +31 -0
- package/jessie.min.js +8 -0
- package/justin.js +39 -48
- package/justin.min.js +8 -4
- package/package.json +15 -16
- package/parse.js +153 -0
- package/subscript.d.ts +45 -5
- package/subscript.js +62 -22
- package/subscript.min.js +5 -4
- 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/control.js +0 -142
- 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 -23
- 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 -45
- package/src/parse.d.ts +0 -22
- package/src/parse.js +0 -113
- package/src/stringify.js +0 -27
- /package/{LICENSE → license} +0 -0
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/control.js
DELETED
|
@@ -1,142 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Control flow: if/else, while, for, break, continue, return, blocks
|
|
3
|
-
*
|
|
4
|
-
* AST:
|
|
5
|
-
* if (c) a else b → ['if', c, a, b?]
|
|
6
|
-
* while (c) a → ['while', c, a]
|
|
7
|
-
* for (i;c;s) a → ['for', i, c, s, a]
|
|
8
|
-
* { a; b } → ['block', [';', a, b]]
|
|
9
|
-
* break/continue → ['break'] / ['continue']
|
|
10
|
-
* return x → ['return', x?]
|
|
11
|
-
*/
|
|
12
|
-
import * as P from '../src/parse.js'
|
|
13
|
-
import { operator, compile } from '../src/compile.js'
|
|
14
|
-
import { PREC_STATEMENT, OPAREN, CPAREN, OBRACE, CBRACE, PREC_SEQ, PREC_TOKEN } from '../src/const.js'
|
|
15
|
-
|
|
16
|
-
const { token, expr, skip, space, err, parse, next } = P
|
|
17
|
-
const SEMI = 59
|
|
18
|
-
|
|
19
|
-
// Control signals
|
|
20
|
-
class Break {}
|
|
21
|
-
class Continue {}
|
|
22
|
-
class Return { constructor(v) { this.value = v } }
|
|
23
|
-
export const BREAK = new Break(), CONTINUE = new Continue()
|
|
24
|
-
|
|
25
|
-
// Shared loop body executor
|
|
26
|
-
const loop = (body, ctx) => {
|
|
27
|
-
try { return { val: body(ctx) } }
|
|
28
|
-
catch (e) {
|
|
29
|
-
if (e === BREAK) return { brk: 1 }
|
|
30
|
-
if (e === CONTINUE) return { cnt: 1 }
|
|
31
|
-
if (e instanceof Return) return { ret: 1, val: e.value }
|
|
32
|
-
throw e
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// if (cond) body [else alt]
|
|
37
|
-
token('if', PREC_STATEMENT, a => {
|
|
38
|
-
if (a) return
|
|
39
|
-
space() === OPAREN || err('Expected (')
|
|
40
|
-
skip()
|
|
41
|
-
const cond = expr(0, CPAREN), body = parseBody()
|
|
42
|
-
space()
|
|
43
|
-
// check 'else' — skip 4 chars via skip() since P.idx is read-only from module
|
|
44
|
-
const alt = P.cur.substr(P.idx, 4) === 'else' && !parse.id(P.cur.charCodeAt(P.idx + 4))
|
|
45
|
-
? (skip(), skip(), skip(), skip(), parseBody()) : undefined
|
|
46
|
-
return alt !== undefined ? ['if', cond, body, alt] : ['if', cond, body]
|
|
47
|
-
})
|
|
48
|
-
|
|
49
|
-
operator('if', (cond, body, alt) => {
|
|
50
|
-
cond = compile(cond); body = compile(body); alt = alt !== undefined ? compile(alt) : null
|
|
51
|
-
return ctx => cond(ctx) ? body(ctx) : alt?.(ctx)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
// while (cond) body
|
|
55
|
-
token('while', PREC_STATEMENT, a => {
|
|
56
|
-
if (a) return
|
|
57
|
-
space() === OPAREN || err('Expected (')
|
|
58
|
-
skip()
|
|
59
|
-
return ['while', expr(0, CPAREN), parseBody()]
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
operator('while', (cond, body) => {
|
|
63
|
-
cond = compile(cond); body = compile(body)
|
|
64
|
-
return ctx => {
|
|
65
|
-
let r, res
|
|
66
|
-
while (cond(ctx)) {
|
|
67
|
-
r = loop(body, ctx)
|
|
68
|
-
if (r.brk) break
|
|
69
|
-
if (r.cnt) continue
|
|
70
|
-
if (r.ret) return r.val
|
|
71
|
-
res = r.val
|
|
72
|
-
}
|
|
73
|
-
return res
|
|
74
|
-
}
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
// for (init; cond; step) body
|
|
78
|
-
token('for', PREC_STATEMENT, a => {
|
|
79
|
-
if (a) return
|
|
80
|
-
space() === OPAREN || err('Expected (')
|
|
81
|
-
skip()
|
|
82
|
-
const init = space() === SEMI ? null : expr(PREC_SEQ)
|
|
83
|
-
space() === SEMI ? skip() : err('Expected ;')
|
|
84
|
-
const cond = space() === SEMI ? null : expr(PREC_SEQ)
|
|
85
|
-
space() === SEMI ? skip() : err('Expected ;')
|
|
86
|
-
const step = space() === CPAREN ? null : expr(PREC_SEQ)
|
|
87
|
-
space() === CPAREN ? skip() : err('Expected )')
|
|
88
|
-
return ['for', init, cond, step, parseBody()]
|
|
89
|
-
})
|
|
90
|
-
|
|
91
|
-
operator('for', (init, cond, step, body) => {
|
|
92
|
-
init = init ? compile(init) : null
|
|
93
|
-
cond = cond ? compile(cond) : () => true
|
|
94
|
-
step = step ? compile(step) : null
|
|
95
|
-
body = compile(body)
|
|
96
|
-
return ctx => {
|
|
97
|
-
let r, res
|
|
98
|
-
for (init?.(ctx); cond(ctx); step?.(ctx)) {
|
|
99
|
-
r = loop(body, ctx)
|
|
100
|
-
if (r.brk) break
|
|
101
|
-
if (r.cnt) continue
|
|
102
|
-
if (r.ret) return r.val
|
|
103
|
-
res = r.val
|
|
104
|
-
}
|
|
105
|
-
return res
|
|
106
|
-
}
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
// Block parsing helper - only used by control structures
|
|
110
|
-
const parseBody = () => {
|
|
111
|
-
if (space() === OBRACE) {
|
|
112
|
-
skip() // consume {
|
|
113
|
-
return ['block', expr(0, CBRACE)]
|
|
114
|
-
}
|
|
115
|
-
return expr(0) // prec=0 to allow nested control structures
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
operator('block', body => {
|
|
119
|
-
if (body === undefined) return () => {}
|
|
120
|
-
body = compile(body)
|
|
121
|
-
return ctx => body(Object.create(ctx)) // new scope
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
// break / continue / return
|
|
125
|
-
token('break', PREC_TOKEN, a => a ? null : ['break'])
|
|
126
|
-
operator('break', () => () => { throw BREAK })
|
|
127
|
-
|
|
128
|
-
token('continue', PREC_TOKEN, a => a ? null : ['continue'])
|
|
129
|
-
operator('continue', () => () => { throw CONTINUE })
|
|
130
|
-
|
|
131
|
-
token('return', PREC_STATEMENT, a => {
|
|
132
|
-
if (a) return
|
|
133
|
-
space()
|
|
134
|
-
const c = P.cur.charCodeAt(P.idx)
|
|
135
|
-
if (!c || c === CBRACE || c === SEMI) return ['return']
|
|
136
|
-
return ['return', expr(PREC_STATEMENT)]
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
operator('return', val => {
|
|
140
|
-
val = val !== undefined ? compile(val) : null
|
|
141
|
-
return ctx => { throw new Return(val?.(ctx)) }
|
|
142
|
-
})
|
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,23 +0,0 @@
|
|
|
1
|
-
import { token, expr } from '../src/parse.js'
|
|
2
|
-
import { operator, compile } from '../src/compile.js'
|
|
3
|
-
import { PREC_ACCESS, unsafe } from '../src/const.js'
|
|
4
|
-
|
|
5
|
-
// a?.[, a?.( - postfix operator
|
|
6
|
-
token('?.', PREC_ACCESS, a => a && ['?.', a])
|
|
7
|
-
operator('?.', a => (a = compile(a), ctx => a(ctx) || (() => { })))
|
|
8
|
-
|
|
9
|
-
// a?.b, a?.() - optional chain operator
|
|
10
|
-
token('?.', PREC_ACCESS, (a, b) => a && (b = expr(PREC_ACCESS), !b?.map) && ['?.', a, b])
|
|
11
|
-
operator('?.', (a, b) => b && (a = compile(a), unsafe(b) ? () => undefined : ctx => a(ctx)?.[b]))
|
|
12
|
-
|
|
13
|
-
// a?.x() - keep context, but watch out a?.()
|
|
14
|
-
operator('()', (a, b, container, args, path, optional) => b !== undefined && (a[0] === '?.') && (a[2] || Array.isArray(a[1])) && (
|
|
15
|
-
args = !b ? () => [] :
|
|
16
|
-
b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(a => a(ctx))) :
|
|
17
|
-
(b = compile(b), ctx => [b(ctx)]),
|
|
18
|
-
!a[2] && (optional = true, a = a[1]),
|
|
19
|
-
a[0] === '[]' && a.length === 3 ? (path = compile(a[2])) : (path = () => a[2]),
|
|
20
|
-
container = compile(a[1]), optional ?
|
|
21
|
-
ctx => { const p = path(ctx); return unsafe(p) ? undefined : container(ctx)?.[p]?.(...args(ctx)) } :
|
|
22
|
-
ctx => { const p = path(ctx); return unsafe(p) ? undefined : container(ctx)?.[p](...args(ctx)) }
|
|
23
|
-
))
|
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,45 +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
|
|
43
|
-
|
|
44
|
-
// Block prototype chain attacks: constructor, prototype, __proto__, __defineGetter__, etc.
|
|
45
|
-
export const unsafe = k => k?.[0] === '_' && k[1] === '_' || k === 'constructor' || k === 'prototype'
|
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(): 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;
|
package/src/parse.js
DELETED
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
import { SPACE } from "./const.js"
|
|
2
|
-
|
|
3
|
-
// current string, index and collected ids
|
|
4
|
-
export let idx, cur,
|
|
5
|
-
|
|
6
|
-
// no handling tagged literals since easily done on user side with cache, if needed
|
|
7
|
-
parse = s => (idx = 0, cur = s, s = expr(), cur[idx] ? err() : s || ''),
|
|
8
|
-
|
|
9
|
-
// display error with context
|
|
10
|
-
err = (msg = 'Unexpected token',
|
|
11
|
-
lines = cur.slice(0, idx).split('\n'),
|
|
12
|
-
last = lines.pop(),
|
|
13
|
-
before = cur.slice(Math.max(0, idx - 40), idx),
|
|
14
|
-
after = cur.slice(idx, idx + 20)
|
|
15
|
-
) => {
|
|
16
|
-
throw SyntaxError(`${msg} at ${lines.length + 1}:${last.length + 1} — ${before}^${after}`)
|
|
17
|
-
},
|
|
18
|
-
|
|
19
|
-
// advance until condition meets
|
|
20
|
-
next = (is, from = idx, l) => {
|
|
21
|
-
while (l = is(cur.charCodeAt(idx))) idx += l
|
|
22
|
-
return cur.slice(from, idx)
|
|
23
|
-
},
|
|
24
|
-
|
|
25
|
-
// advance n characters
|
|
26
|
-
skip = () => cur[idx++],
|
|
27
|
-
|
|
28
|
-
// a + b - c
|
|
29
|
-
expr = (prec = 0, end) => {
|
|
30
|
-
let cc, token, newNode, fn
|
|
31
|
-
|
|
32
|
-
// chunk/token parser
|
|
33
|
-
while (
|
|
34
|
-
(cc = space()) && // till not end
|
|
35
|
-
// NOTE: when lookup bails on lower precedence, parent expr re-calls space() — acceptable overhead
|
|
36
|
-
(newNode =
|
|
37
|
-
((fn = lookup[cc]) && fn(token, prec)) ?? // if operator with higher precedence isn't found
|
|
38
|
-
(!token && next(parse.id)) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
|
|
39
|
-
)
|
|
40
|
-
) token = newNode;
|
|
41
|
-
|
|
42
|
-
// check end character
|
|
43
|
-
if (end) cc == end ? idx++ : err('Unclosed ' + String.fromCharCode(end - (end > 42 ? 2 : 1)))
|
|
44
|
-
|
|
45
|
-
return token
|
|
46
|
-
},
|
|
47
|
-
|
|
48
|
-
// skip space chars, return first non-space character
|
|
49
|
-
space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
|
|
50
|
-
|
|
51
|
-
// parse identifier (configurable)
|
|
52
|
-
id = parse.id = c =>
|
|
53
|
-
(c >= 48 && c <= 57) || // 0..9
|
|
54
|
-
(c >= 65 && c <= 90) || // A...Z
|
|
55
|
-
(c >= 97 && c <= 122) || // a...z
|
|
56
|
-
c == 36 || c == 95 || // $, _,
|
|
57
|
-
(c >= 192 && c != 215 && c != 247), // any non-ASCII
|
|
58
|
-
|
|
59
|
-
// operator/token lookup table
|
|
60
|
-
// lookup[0] is id parser to let configs redefine it
|
|
61
|
-
lookup = [],
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// create operator checker/mapper (see examples)
|
|
65
|
-
token = (
|
|
66
|
-
op,
|
|
67
|
-
prec = SPACE,
|
|
68
|
-
map,
|
|
69
|
-
c = op.charCodeAt(0),
|
|
70
|
-
l = op.length,
|
|
71
|
-
prev = lookup[c],
|
|
72
|
-
word = op.toUpperCase() !== op // make sure word boundary comes after word operator
|
|
73
|
-
) => lookup[c] = (a, curPrec, curOp, from = idx) =>
|
|
74
|
-
(
|
|
75
|
-
(curOp ?
|
|
76
|
-
op == curOp :
|
|
77
|
-
((l < 2 || cur.substr(idx, l) == op) && (curOp = op)) // save matched op to avoid mismatches like `|` as part of `||`
|
|
78
|
-
) &&
|
|
79
|
-
curPrec < prec && // matches precedence AFTER operator matched
|
|
80
|
-
!(word && parse.id(cur.charCodeAt(idx + l))) && // finished word, not part of bigger word
|
|
81
|
-
(idx += l, map(a) || (idx = from, !prev && err())) // throw if operator didn't detect usage pattern: (a;^b) etc
|
|
82
|
-
) ||
|
|
83
|
-
prev?.(a, curPrec, curOp),
|
|
84
|
-
|
|
85
|
-
// right assoc is indicated by negative precedence (meaning go from right to left)
|
|
86
|
-
binary = (op, prec, right = false) => token(op, prec, (a, b) => a && (b = expr(prec - (right ? .5 : 0))) && [op, a, b]),
|
|
87
|
-
|
|
88
|
-
// post indicates postfix rather than prefix operator
|
|
89
|
-
unary = (op, prec, post) => token(op, prec, a => post ? (a && [op, a]) : (!a && (a = expr(prec - .5)) && [op, a])),
|
|
90
|
-
|
|
91
|
-
// NOTE: allows ;;; (valid empty statements) and ,,, (debatable but harmless)
|
|
92
|
-
// right=true allows same-precedence tokens on RHS (like statements after semicolon)
|
|
93
|
-
nary = (op, prec, right) => {
|
|
94
|
-
token(op, prec,
|
|
95
|
-
(a, b) => (
|
|
96
|
-
b = expr(prec - (right ? .5 : 0)),
|
|
97
|
-
(
|
|
98
|
-
(a?.[0] !== op) && (a = [op, a || null]), // if beginning of sequence - init node
|
|
99
|
-
b?.[0] === op ? a.push(...b.slice(1)) : a.push(b || null), // comments can return same-token expr
|
|
100
|
-
a
|
|
101
|
-
))
|
|
102
|
-
)
|
|
103
|
-
},
|
|
104
|
-
|
|
105
|
-
// register (a), [b], {c} etc groups
|
|
106
|
-
group = (op, prec) => token(op[0], prec, a => (!a && [op, expr(0, op.charCodeAt(1))])),
|
|
107
|
-
|
|
108
|
-
// register a(b), a[b], a<b> etc,
|
|
109
|
-
// NOTE: we make sure `null` indicates placeholder
|
|
110
|
-
access = (op, prec) => token(op[0], prec, a => (a && [op, a, expr(0, op.charCodeAt(1)) || null]))
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
export default parse
|
package/src/stringify.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
// convert ast to code string (codegen)
|
|
2
|
-
|
|
3
|
-
// NOTE: possible enhancements — pairs via options, custom spacing/newlines, custom literals
|
|
4
|
-
export function stringify(node) {
|
|
5
|
-
if (!node) return ''
|
|
6
|
-
|
|
7
|
-
if (Array.isArray(node)) {
|
|
8
|
-
const [op, ...args] = node;
|
|
9
|
-
|
|
10
|
-
// 1, "x"
|
|
11
|
-
if (!op) return JSON.stringify(args[0])
|
|
12
|
-
|
|
13
|
-
// (a), a(b)
|
|
14
|
-
if (op == '[]' || op == '{}' || op == '()') return (args.length > 1 ? stringify(args.shift()) : '') + op[0] + (stringify(args[0])) + op[1]
|
|
15
|
-
|
|
16
|
-
// +a
|
|
17
|
-
if (args.length === 1) return op + stringify(args[0])
|
|
18
|
-
|
|
19
|
-
// a + b
|
|
20
|
-
if (args.length === 2) return stringify(args[0]) + (op === '.' ? op : (' ' + op + ' ')) + stringify(args[1])
|
|
21
|
-
|
|
22
|
-
// a; b; c
|
|
23
|
-
return args.filter(Boolean).map(a => stringify(a)).join(op + '\n')
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return node;
|
|
27
|
-
}
|
/package/{LICENSE → license}
RENAMED
|
File without changes
|