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.
Files changed (83) hide show
  1. package/README.md +115 -169
  2. package/feature/access.js +67 -7
  3. package/feature/accessor.js +49 -0
  4. package/feature/asi.js +15 -0
  5. package/feature/async.js +45 -0
  6. package/feature/block.js +41 -0
  7. package/feature/class.js +69 -0
  8. package/feature/collection.js +40 -0
  9. package/feature/comment.js +25 -5
  10. package/feature/destruct.js +33 -0
  11. package/feature/function.js +44 -0
  12. package/feature/group.js +39 -9
  13. package/feature/if.js +23 -38
  14. package/feature/literal.js +13 -0
  15. package/feature/loop.js +107 -106
  16. package/feature/module.js +42 -0
  17. package/feature/number.js +41 -38
  18. package/feature/op/arithmetic.js +29 -0
  19. package/feature/op/arrow.js +33 -0
  20. package/feature/op/assign-logical.js +33 -0
  21. package/feature/op/assignment.js +47 -0
  22. package/feature/op/bitwise-unsigned.js +17 -0
  23. package/feature/op/bitwise.js +29 -0
  24. package/feature/op/comparison.js +19 -0
  25. package/feature/op/defer.js +15 -0
  26. package/feature/op/equality.js +16 -0
  27. package/feature/op/identity.js +15 -0
  28. package/feature/op/increment.js +23 -0
  29. package/feature/op/logical.js +21 -0
  30. package/feature/op/membership.js +17 -0
  31. package/feature/op/nullish.js +13 -0
  32. package/feature/op/optional.js +61 -0
  33. package/feature/op/pow.js +19 -0
  34. package/feature/op/range.js +26 -0
  35. package/feature/op/spread.js +15 -0
  36. package/feature/op/ternary.js +15 -0
  37. package/feature/op/type.js +18 -0
  38. package/feature/op/unary.js +41 -0
  39. package/feature/prop.js +34 -0
  40. package/feature/regex.js +31 -0
  41. package/feature/seq.js +21 -0
  42. package/feature/string.js +24 -17
  43. package/feature/switch.js +48 -0
  44. package/feature/template.js +39 -0
  45. package/feature/try.js +57 -0
  46. package/feature/unit.js +35 -0
  47. package/feature/var.js +51 -41
  48. package/jessie.js +31 -0
  49. package/jessie.min.js +8 -0
  50. package/justin.js +39 -48
  51. package/justin.min.js +8 -4
  52. package/package.json +15 -16
  53. package/parse.js +153 -0
  54. package/subscript.d.ts +45 -5
  55. package/subscript.js +62 -22
  56. package/subscript.min.js +5 -4
  57. package/util/bundle.js +507 -0
  58. package/util/stringify.js +172 -0
  59. package/feature/add.js +0 -22
  60. package/feature/array.js +0 -11
  61. package/feature/arrow.js +0 -23
  62. package/feature/assign.js +0 -11
  63. package/feature/bitwise.js +0 -11
  64. package/feature/bool.js +0 -5
  65. package/feature/call.js +0 -15
  66. package/feature/compare.js +0 -11
  67. package/feature/control.js +0 -142
  68. package/feature/increment.js +0 -11
  69. package/feature/logic.js +0 -11
  70. package/feature/mult.js +0 -25
  71. package/feature/object.js +0 -17
  72. package/feature/optional.js +0 -23
  73. package/feature/pow.js +0 -5
  74. package/feature/shift.js +0 -12
  75. package/feature/spread.js +0 -6
  76. package/feature/ternary.js +0 -10
  77. package/src/compile.d.ts +0 -17
  78. package/src/compile.js +0 -28
  79. package/src/const.js +0 -45
  80. package/src/parse.d.ts +0 -22
  81. package/src/parse.js +0 -113
  82. package/src/stringify.js +0 -27
  83. /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
- ))
@@ -1,11 +0,0 @@
1
- import { PREC_OR, PREC_AND, PREC_SHIFT, PREC_XOR, PREC_PREFIX } from "../src/const.js"
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
- unary('~', PREC_PREFIX), operator('~', (a, b) => !b && (a = compile(a), ctx => ~a(ctx)))
6
-
7
- binary('|', PREC_OR), operator('|', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) | b(ctx)))
8
-
9
- binary('&', PREC_AND), operator('&', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) & b(ctx)))
10
-
11
- binary('^', PREC_XOR), operator('^', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) ^ b(ctx)))
package/feature/bool.js DELETED
@@ -1,5 +0,0 @@
1
- import { token } from "../src/parse.js"
2
- import { PREC_TOKEN } from "../src/const.js"
3
-
4
- token('true', PREC_TOKEN, a => a ? err() : [, true])
5
- token('false', PREC_TOKEN, a => a ? err() : [, false])
package/feature/call.js DELETED
@@ -1,15 +0,0 @@
1
- import { access } from '../src/parse.js'
2
- import { operator, compile, prop } from '../src/compile.js'
3
- import { PREC_ACCESS } from '../src/const.js'
4
-
5
- // a(b,c,d), a()
6
- access('()', PREC_ACCESS)
7
- operator('()', (a, b, args) => b !== undefined && (
8
- args = !b ? () => [] : // a()
9
- b[0] === ',' ? (b = b.slice(1).map(b => !b ? err() : compile(b)), ctx => b.map(arg => arg(ctx))) : // a(b,c)
10
- (b = compile(b), ctx => [b(ctx)]), // a(b)
11
-
12
- // a(...args), a.b(...args), a[b](...args)
13
- prop(a, (obj, path, ctx) => obj[path](...args(ctx)), true)
14
- )
15
- )
@@ -1,11 +0,0 @@
1
- import { PREC_EQ, PREC_COMP } from '../src/const.js'
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
-
6
- binary('==', PREC_EQ), operator('==', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) == b(ctx)))
7
- binary('!=', PREC_EQ), operator('!=', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) != b(ctx)))
8
- binary('>', PREC_COMP), operator('>', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) > b(ctx)))
9
- binary('<', PREC_COMP), operator('<', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) < b(ctx)))
10
- binary('>=', PREC_COMP), operator('>=', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) >= b(ctx)))
11
- binary('<=', PREC_COMP), operator('<=', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) <= b(ctx)))
@@ -1,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
- })
@@ -1,11 +0,0 @@
1
- import { token, expr } from "../src/parse.js"
2
- import { operator, compile, prop } from "../src/compile.js"
3
- import { PREC_POSTFIX } from "../src/const.js"
4
-
5
- token('++', PREC_POSTFIX, a => a ? ['++', a, null,] : ['++', expr(PREC_POSTFIX - 1)])
6
- // ++a, ++((a)), ++a.b, ++a[b]
7
- operator('++', (a,b) => prop(a, b === null ? (obj, path) => obj[path]++ : (obj, path) => ++obj[path]))
8
-
9
- token('--', PREC_POSTFIX, a => a ? ['--', a, null,] : ['--', expr(PREC_POSTFIX - 1)])
10
- // --a, --a.b, --a[b]
11
- operator('--', (a, b) => prop(a, b === null ? (obj, path) => obj[path]-- : (obj, path) => --obj[path]))
package/feature/logic.js DELETED
@@ -1,11 +0,0 @@
1
- import { PREC_LOR, PREC_LAND, PREC_PREFIX, PREC_ASSIGN } from '../src/const.js';
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
- unary('!', PREC_PREFIX), operator('!', (a, b) => !b && (a = compile(a), ctx => !a(ctx)))
6
-
7
- binary('||', PREC_LOR)
8
- operator('||', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) || b(ctx)))
9
-
10
- binary('&&', PREC_LAND)
11
- operator('&&', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) && b(ctx)))
package/feature/mult.js DELETED
@@ -1,25 +0,0 @@
1
- import { binary } from '../src/parse.js'
2
- import { operator, compile, prop } from '../src/compile.js'
3
- import { PREC_MULT, PREC_ASSIGN } from '../src/const.js'
4
-
5
- binary('*', PREC_MULT), operator('*', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) * b(ctx)))
6
- binary('/', PREC_MULT), operator('/', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) / b(ctx)))
7
- binary('%', PREC_MULT), operator('%', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) % b(ctx)))
8
-
9
- binary('*=', PREC_ASSIGN, true)
10
- operator('*=', (a, b) => (
11
- b = compile(b),
12
- prop(a, (container, path, ctx) => container[path] *= b(ctx))
13
- ))
14
-
15
- binary('/=', PREC_ASSIGN, true)
16
- operator('/=', (a, b) => (
17
- b = compile(b),
18
- prop(a, (container, path, ctx) => container[path] /= b(ctx))
19
- ))
20
-
21
- binary('%=', PREC_ASSIGN, true)
22
- operator('%=', (a, b) => (
23
- b = compile(b),
24
- prop(a, (container, path, ctx) => container[path] %= b(ctx))
25
- ))
package/feature/object.js DELETED
@@ -1,17 +0,0 @@
1
- import { token, expr, group, binary } from '../src/parse.js'
2
- import { operator, compile } from '../src/compile.js'
3
- import { PREC_ASSIGN, PREC_SEQ, PREC_TOKEN } from '../src/const.js'
4
-
5
-
6
- // {a:1, b:2, c:3}
7
- group('{}', PREC_TOKEN)
8
- operator('{}', (a, b) => b === undefined && (
9
- // {}, {a:b}, {a}, {a, b}
10
- a = (!a ? [] : a[0] !== ',' ? [a] : a.slice(1)),
11
- a = a.map(p => compile(typeof p === 'string' ? [':', p, p] : p)),
12
- ctx => Object.fromEntries(a.flatMap(frag => frag(ctx)))
13
- ))
14
-
15
- binary(':', PREC_ASSIGN - 1, true)
16
- // "a": a, a: a
17
- operator(':', (a, b) => (b = compile(b), Array.isArray(a) ? (a = compile(a), ctx => [[a(ctx), b(ctx)]]) : ctx => [[a, b(ctx)]]))
@@ -1,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
@@ -1,5 +0,0 @@
1
- import { binary } from "../src/parse.js";
2
- import { compile, operator } from "../src/compile.js";
3
- import { PREC_EXP } from "../src/const.js";
4
-
5
- binary('**', PREC_EXP, true), operator('**', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) ** b(ctx)))
package/feature/shift.js DELETED
@@ -1,12 +0,0 @@
1
- import { PREC_OR, PREC_AND, PREC_SHIFT, PREC_XOR, PREC_PREFIX, PREC_ASSIGN } from "../src/const.js"
2
- import { unary, binary } from "../src/parse.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
-
6
- binary('>>', PREC_SHIFT), operator('>>', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) >> b(ctx)))
7
- binary('<<', PREC_SHIFT), operator('<<', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) << b(ctx)))
8
-
9
- binary('>>=', PREC_ASSIGN, true)
10
- operator('>>=', (a, b) => (b = compile(b), prop(a, (obj, path, ctx) => (obj[path] >>= b(ctx)))))
11
- binary('<<=', PREC_ASSIGN, true)
12
- operator('<<=', (a, b) => (b = compile(b), prop(a, (obj, path, ctx) => (obj[path] <<= b(ctx)))))
package/feature/spread.js DELETED
@@ -1,6 +0,0 @@
1
- import { unary } from "../src/parse.js"
2
- import { PREC_PREFIX } from "../src/const.js"
3
- import { operator, compile } from "../src/compile.js"
4
-
5
- unary('...', PREC_PREFIX)
6
- operator('...', (a) => (a = compile(a), ctx => Object.entries(a(ctx))))
@@ -1,10 +0,0 @@
1
- import { token, expr, next } from '../src/parse.js'
2
- import { operator, compile } from '../src/compile.js'
3
- import { PREC_ASSIGN, COLON } from '../src/const.js'
4
-
5
- // ?:
6
- // token('?', PREC_ASSIGN, (a, b, c) => a && (b = expr(PREC_ASSIGN - 1, COLON)) && (c = expr(PREC_ASSIGN - 1), ['?', a, b, c]))
7
- // ALT: not throwing
8
- token('?', PREC_ASSIGN, (a, b, c) => a && (b = expr(PREC_ASSIGN - 1)) && next(c => c === COLON) && (c = expr(PREC_ASSIGN - 1), ['?', a, b, c]))
9
-
10
- operator('?', (a, b, c) => (a = compile(a), b = compile(b), c = compile(c), ctx => a(ctx) ? b(ctx) : c(ctx)))
package/src/compile.d.ts DELETED
@@ -1,17 +0,0 @@
1
- export type OperatorFunction = (...args: any[]) => any;
2
- export type OperatorMap = {
3
- [key: string]: OperatorFunction;
4
- };
5
- export type Node = string | [string | undefined, ...Node[]];
6
- export function compile(node: Node): ((ctx?: any) => any) | OperatorFunction;
7
- export const operators: OperatorMap;
8
- export function operator(op: string, fn: OperatorFunction): void;
9
-
10
- type AccessorFunction = (ctx: any) => any;
11
- export function access(
12
- a: [string, ...any[]] | string,
13
- fn: Function,
14
- generic: boolean
15
- ): AccessorFunction;
16
-
17
- export default compile;
package/src/compile.js DELETED
@@ -1,28 +0,0 @@
1
- import { err } from "./parse.js"
2
-
3
- // build optimized evaluator for the tree
4
- export const compile = (node) => !Array.isArray(node) ? compile.id(node) : !node[0] ? () => node[1] : operators[node[0]].call(...node),
5
- // compile id getter
6
- id = compile.id = name => ctx => ctx?.[name],
7
-
8
- // registered operators
9
- operators = {},
10
-
11
- // register an operator
12
- operator = (op, fn, prev = operators[op]) => (operators[op] = (...args) => fn(...args) || prev?.(...args)),
13
-
14
- // takes node and returns evaluator depending on the case with passed params (container, path, ctx) =>
15
- prop = (a, fn, generic, obj, path) => (
16
- // (((x))) => x
17
- a[0] === '()' && a.length == 2 ? prop(a[1], fn, generic) :
18
- // (_, name, ctx) => ctx[path]
19
- typeof a === 'string' ? ctx => fn(ctx, a, ctx) :
20
- // (container, path, ctx) => container(ctx)[path]
21
- a[0] === '.' ? (obj = compile(a[1]), path = a[2], ctx => fn(obj(ctx), path, ctx)) :
22
- // (container, path, ctx) => container(ctx)[path(ctx)]
23
- a[0] === '[]' && a.length === 3 ? (obj = compile(a[1]), path = compile(a[2]), ctx => fn(obj(ctx), path(ctx), ctx)) :
24
- // (src, _, ctx) => src(ctx)
25
- generic ? (a = compile(a), ctx => fn([a(ctx)], 0, ctx)) : () => err('Bad left value')
26
- )
27
-
28
- export default compile
package/src/const.js DELETED
@@ -1,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
- }
File without changes