subscript 6.4.0 → 7.0.3
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 +51 -20
- package/compile.js +9 -0
- package/justin.js +73 -53
- package/justin.min.js +1 -1
- package/package.json +10 -2
- package/{parser.js → parse.js} +23 -34
- package/subscript.js +106 -75
- package/subscript.min.js +1 -1
package/README.md
CHANGED
|
@@ -1,32 +1,41 @@
|
|
|
1
1
|
# <img alt="subscript" src="/subscript2.svg" height=28/> <!--sub͘<em>script</em>--> <!--<sub>SUB͘<em>SCRIPT</em></sub>--> <a href="https://github.com/spectjs/subscript/actions/workflows/node.js.yml"><img src="https://github.com/spectjs/subscript/actions/workflows/node.js.yml/badge.svg"/></a> <a href="http://npmjs.org/subscript"><img src="https://img.shields.io/npm/v/subscript"/></a> <a href="http://microjs.com/#subscript"><img src="https://img.shields.io/badge/microjs-subscript-blue?color=darkslateblue"/></a>
|
|
2
2
|
|
|
3
|
-
_Subscript_ is expression evaluator / microlanguage with
|
|
3
|
+
_Subscript_ is expression evaluator / microlanguage with [common syntax](https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(syntax)).<br/>
|
|
4
4
|
|
|
5
|
-
* Any fragment can be copy-pasted to any language: C++, JS, Java, Python, Go, Rust etc.
|
|
5
|
+
* Any fragment can be copy-pasted to any language: C++, JS, Java, Python, Go, Rust etc.
|
|
6
6
|
* Tiny size <sub><a href="https://bundlephobia.com/package/subscript@6.0.0"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip"/></a></sub>
|
|
7
7
|
* :rocket: Fast [performance](#performance)
|
|
8
8
|
* Configurable & extensible
|
|
9
9
|
* Trivial to use
|
|
10
10
|
|
|
11
11
|
```js
|
|
12
|
-
import script from './subscript.js'
|
|
13
|
-
|
|
12
|
+
import script, { parse, compile } from './subscript.js'
|
|
13
|
+
|
|
14
|
+
// create expression evaluator
|
|
15
|
+
let fn = script('a.b + c(d - 1)')
|
|
14
16
|
fn({ a: { b:1 }, c: x => x * 2, d: 3 }) // 5
|
|
15
|
-
|
|
17
|
+
|
|
18
|
+
// or
|
|
19
|
+
// parse expression tree
|
|
20
|
+
let tree = parse('a.b + c')
|
|
21
|
+
tree // ['+', ['.', 'a', 'b'], 'c']
|
|
22
|
+
|
|
23
|
+
// compile tree to evaluable function
|
|
24
|
+
let evaluate = compile(tree)
|
|
16
25
|
```
|
|
17
26
|
|
|
18
27
|
## Motivation
|
|
19
28
|
|
|
20
29
|
_Subscript_ is designed to be useful for:
|
|
21
30
|
|
|
22
|
-
* templates (perfect match with [template parts](https://github.com/github/template-parts), [templize](https://github.com/spectjs/templize))
|
|
31
|
+
* templates (perfect match with [template parts](https://github.com/github/template-parts), see [templize](https://github.com/spectjs/templize))
|
|
23
32
|
* expressions evaluators, calculators
|
|
24
|
-
* configurable subsets of languages (eg. [justin](#justin))
|
|
33
|
+
* configurable subsets of languages (eg. [justin](#justin))
|
|
25
34
|
* pluggable/mock language features (eg. pipe operator)
|
|
26
35
|
* sandboxes, playgrounds, safe eval
|
|
27
|
-
* custom DSL
|
|
36
|
+
* custom DSL <!-- see sonr, mineural -->
|
|
28
37
|
|
|
29
|
-
_Subscript_ has [
|
|
38
|
+
_Subscript_ has [2.8kb](https://npmfs.com/package/subscript/7.0.0/subscript.min.js) footprint, compared to [11.4kb](https://npmfs.com/package/jsep/1.2.0/dist/jsep.min.js) _jsep_ + [4.5kb](https://npmfs.com/package/expression-eval/5.0.0/dist/expression-eval.module.js) _expression-eval_, with better test coverage and better performance.
|
|
30
39
|
|
|
31
40
|
|
|
32
41
|
## Design
|
|
@@ -54,26 +63,47 @@ Default literals:
|
|
|
54
63
|
* `"abc"` strings
|
|
55
64
|
* `1.2e+3` numbers
|
|
56
65
|
|
|
57
|
-
Everything else can be extended via `
|
|
66
|
+
Everything else can be extended via `subscript.set(str, prec, fn)` for unary, binary or n-ary operators (detected by number of arguments in `fn`), or via `subscript.set(str, prec, [parse, compile])` for custom tokens.
|
|
58
67
|
|
|
59
68
|
```js
|
|
60
|
-
import script from './subscript.js'
|
|
69
|
+
import script, { compile } from './subscript.js'
|
|
61
70
|
|
|
62
71
|
// add ~ unary operator with precedence 15
|
|
63
72
|
script.set('~', 15, a => ~a)
|
|
64
73
|
|
|
65
|
-
// add === binary operator
|
|
74
|
+
// add === binary operator with precedence 9
|
|
66
75
|
script.set('===', 9, (a, b) => a===b)
|
|
67
76
|
|
|
68
77
|
// add literals
|
|
69
|
-
script.set('true', a =>
|
|
70
|
-
script.set('false', a =>
|
|
78
|
+
script.set('true', 20, [a => ['',true], a => ctx => a[1]])
|
|
79
|
+
script.set('false', 20, [a => ['',false], a => ctx => a[1]])
|
|
71
80
|
|
|
72
|
-
script`true === false`() // false
|
|
81
|
+
script(`true === false`)() // false
|
|
73
82
|
```
|
|
74
83
|
|
|
75
84
|
See [subscript.js](subscript.js) or [justin.js](./justin.js) for examples.
|
|
76
85
|
|
|
86
|
+
|
|
87
|
+
## Parser & Compiler
|
|
88
|
+
|
|
89
|
+
Subscript exposes separate `./parse.js` and `./compile.js` entries. Parser builds AST, compiler converts it to evaluable function.
|
|
90
|
+
|
|
91
|
+
AST has simplified lispy calltree structure (inspired by [frisk](https://ghub.io/frisk)), opposed to [ESTree](https://github.com/estree/estree):
|
|
92
|
+
|
|
93
|
+
* is not limited to particular language, can be cross-compiled;
|
|
94
|
+
* reflects execution sequence, rather than code layout;
|
|
95
|
+
* has minimal possible overhead, better fits for directly mapping to operators;
|
|
96
|
+
* simplifies manual evaluation and debugging;
|
|
97
|
+
* has conventional form and one-liner docs:
|
|
98
|
+
|
|
99
|
+
```js
|
|
100
|
+
import { compile } from 'subscript.js'
|
|
101
|
+
|
|
102
|
+
const fn = compile(['+', ['*', 'min', ['',60]], ['','sec']])
|
|
103
|
+
|
|
104
|
+
fn({min: 5}) // min*60 + "sec" == "300sec"
|
|
105
|
+
```
|
|
106
|
+
|
|
77
107
|
<!--
|
|
78
108
|
Operators can be extended via .
|
|
79
109
|
|
|
@@ -286,8 +316,9 @@ Subscript shows relatively good performance within other evaluators:
|
|
|
286
316
|
Parse 30k times:
|
|
287
317
|
|
|
288
318
|
```
|
|
289
|
-
|
|
290
|
-
|
|
319
|
+
es-module-lexer: 50ms 🥇
|
|
320
|
+
subscript: ~150 ms 🥈
|
|
321
|
+
justin: ~183 ms
|
|
291
322
|
jsep: ~270 ms 🥉
|
|
292
323
|
jexpr: ~297 ms
|
|
293
324
|
mr-parser: ~420 ms
|
|
@@ -302,8 +333,8 @@ new Function: ~1154 ms
|
|
|
302
333
|
Eval 30k times:
|
|
303
334
|
```
|
|
304
335
|
new Function: ~7 ms 🥇
|
|
305
|
-
subscript: ~
|
|
306
|
-
justin: ~17 ms
|
|
336
|
+
subscript: ~15 ms 🥈
|
|
337
|
+
justin: ~17 ms
|
|
307
338
|
jexpr: ~23 ms 🥉
|
|
308
339
|
jsep (expression-eval): ~30 ms
|
|
309
340
|
math-expression-evaluator: ~50ms
|
|
@@ -328,7 +359,7 @@ math-parser: -
|
|
|
328
359
|
* [math-parser](https://www.npmjs.com/package/math-parser)
|
|
329
360
|
* [math.js](https://mathjs.org/docs/expressions/parsing.html)
|
|
330
361
|
|
|
331
|
-
##
|
|
362
|
+
## JS engines
|
|
332
363
|
|
|
333
364
|
* [engine262](https://github.com/engine262/engine262)
|
|
334
365
|
* [Jessie](https://github.com/endojs/Jessie)
|
package/compile.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// build optimized evaluator for the tree
|
|
2
|
+
export const compile = (node) => !Array.isArray(node) ? ctx => ctx?.[node] : operator[node[0]](...node.slice(1)),
|
|
3
|
+
|
|
4
|
+
set = compile.set = (op, fn, prev=operator[op]) => operator[op] = (...args) => fn(...args) || prev && prev(...args),
|
|
5
|
+
|
|
6
|
+
operator = {}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export default compile
|
package/justin.js
CHANGED
|
@@ -1,74 +1,94 @@
|
|
|
1
1
|
// justin lang https://github.com/endojs/Jessie/issues/66
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import { skip, cur, idx, err, expr } from './parse.js'
|
|
3
|
+
import compile from './compile.js'
|
|
4
|
+
import subscript from './subscript.js'
|
|
4
5
|
|
|
5
6
|
const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, QUOTE=39, _0=48, _9=57, BSLASH=92,
|
|
6
7
|
PREC_SEQ=1, PREC_COND=3, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
|
|
7
8
|
PREC_EQ=9, PREC_COMP=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_EXP=14, PREC_UNARY=15, PREC_POSTFIX=16, PREC_CALL=18, PREC_GROUP=19
|
|
8
9
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
else str += skip()
|
|
17
|
-
}
|
|
18
|
-
return skip()||err('Bad string'), () => str
|
|
10
|
+
let escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'},
|
|
11
|
+
string = q => (qc, c, str='') => {
|
|
12
|
+
qc&&err('Unexpected string') // must not follow another token
|
|
13
|
+
skip()
|
|
14
|
+
while (c=cur.charCodeAt(idx), c-q) {
|
|
15
|
+
if (c === BSLASH) skip(), c=skip(), str += escape[c] || c
|
|
16
|
+
else str += skip()
|
|
19
17
|
}
|
|
18
|
+
skip()
|
|
19
|
+
return ['', str]
|
|
20
|
+
},
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
'
|
|
25
|
-
|
|
22
|
+
list = [
|
|
23
|
+
// operators
|
|
24
|
+
'===', PREC_EQ, (a,b) => a===b,
|
|
25
|
+
'!==', PREC_EQ, (a,b) => a!==b,
|
|
26
|
+
'~', PREC_UNARY, (a) => ~a,
|
|
26
27
|
|
|
27
|
-
//
|
|
28
|
-
'
|
|
29
|
-
|
|
28
|
+
// ?:
|
|
29
|
+
'?', PREC_COND, [
|
|
30
|
+
(a, b, c) => a && (b=expr(2,58)) && (c=expr(3), ['?', a, b, c]),
|
|
31
|
+
(a, b, c) => (a=compile(a),b=compile(b),c=compile(c), ctx => a(ctx) ? b(ctx) : c(ctx))
|
|
32
|
+
],
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
'null', a => a ? err('Unexpected literal') : ()=>null,,
|
|
33
|
-
'true', a => a ? err('Unexpected literal') : ()=>true,,
|
|
34
|
-
'false', a => a ? err('Unexpected literal') : ()=>false,,
|
|
35
|
-
'undefined', a => a ? err('Unexpected literal') : ()=>undefined,,
|
|
34
|
+
'??', PREC_OR, (a,b) => a ?? b,
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
// a?.[, a?.( - postfix operator
|
|
37
|
+
'?.', PREC_CALL, [a => a && ['?.', a], a => (a=compile(a), ctx => a(ctx)||(()=>{})) ],
|
|
38
|
+
// a?.b - optional chain operator
|
|
39
|
+
'?.', PREC_CALL, [
|
|
40
|
+
(a,b) => a && (b=expr(PREC_CALL),!b?.map) && ['?.',a,b],
|
|
41
|
+
(a,b) => b && (a=compile(a), ctx => a(ctx)?.[b])
|
|
42
|
+
],
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
'===', PREC_EQ, (a,b) => a===b,
|
|
41
|
-
'!==', PREC_EQ, (a,b) => a!==b,
|
|
42
|
-
'~', PREC_UNARY, (a) => ~a,
|
|
44
|
+
'in', PREC_COMP , (a,b) => a in b,
|
|
43
45
|
|
|
44
|
-
//
|
|
45
|
-
'
|
|
46
|
+
// "' with /
|
|
47
|
+
'"', , [string(DQUOTE)],
|
|
48
|
+
"'", , [string(QUOTE)],
|
|
46
49
|
|
|
47
|
-
//
|
|
48
|
-
'
|
|
49
|
-
'
|
|
50
|
+
// /**/, //
|
|
51
|
+
'/*', 20, [(a, prec) => (skip(c => c !== 42 && cur.charCodeAt(idx+1) !== 47), skip(2), a||expr(prec))],
|
|
52
|
+
'//', 20, [(a, prec) => (skip(c => c >= 32), a||expr(prec))],
|
|
50
53
|
|
|
51
|
-
|
|
54
|
+
// literals
|
|
55
|
+
'null', 20, [a => a ? err() : ['',null]],
|
|
56
|
+
'true', 20, [a => a ? err() : ['',true]],
|
|
57
|
+
'false', 20, [a => a ? err() : ['',false]],
|
|
58
|
+
'undefined', 20, [a => a ? err() : ['',undefined]],
|
|
52
59
|
|
|
53
|
-
//
|
|
54
|
-
'
|
|
55
|
-
// a?.b - optional chain operator
|
|
56
|
-
'?.', (a,id) => (space(), id=skip(isId)) && (ctx => a(ctx)?.[id]),,
|
|
60
|
+
// FIXME: make sure that is right
|
|
61
|
+
';', 20, [a => expr()||['']],
|
|
57
62
|
|
|
58
|
-
|
|
63
|
+
// right order
|
|
64
|
+
// '**', (a,prec,b=expr(PREC_EXP-1)) => ctx=>a(ctx)**b(ctx), PREC_EXP,
|
|
65
|
+
'**', -PREC_EXP, (a,b)=>a**b,
|
|
59
66
|
|
|
60
67
|
// [a,b,c]
|
|
61
|
-
'[',
|
|
62
|
-
a
|
|
63
|
-
|
|
64
|
-
|
|
68
|
+
'[', 20, [
|
|
69
|
+
(a) => !a && ['[', expr(0,93)||''],
|
|
70
|
+
(a,b) => !b && (
|
|
71
|
+
!a ? () => [] : // []
|
|
72
|
+
a[0] === ',' ? (a=a.slice(1).map(compile), ctx => a.map(a=>a(ctx))) : // [a,b,c]
|
|
73
|
+
(a=compile(a), ctx => [a(ctx)]) // [a]
|
|
74
|
+
)],
|
|
65
75
|
|
|
66
76
|
// {a:1, b:2, c:3}
|
|
67
|
-
'{',
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
'{', 20, [
|
|
78
|
+
a => !a && (['{', expr(0,125)||'']),
|
|
79
|
+
(a,b) => (
|
|
80
|
+
!a ? ctx => ({}) : // {}
|
|
81
|
+
a[0] === ',' ? (a=a.slice(1).map(compile), ctx=>Object.fromEntries(a.map(a=>a(ctx)))) : // {a:1,b:2}
|
|
82
|
+
a[0] === ':' ? (a=compile(a), ctx => Object.fromEntries([a(ctx)])) : // {a:1}
|
|
83
|
+
(b=compile(a), ctx=>({[a]:b(ctx)}))
|
|
84
|
+
)
|
|
85
|
+
],
|
|
86
|
+
':', 1.1, [
|
|
87
|
+
(a, b) => (b=expr(1.1)||err(), [':',a,b]),
|
|
88
|
+
(a,b) => (b=compile(b),a=Array.isArray(a)?compile(a):(a=>a).bind(0,a), ctx=>[a(ctx),b(ctx)])
|
|
89
|
+
]
|
|
90
|
+
]
|
|
91
|
+
for (;list[2];) subscript.set(...list.splice(0,3))
|
|
92
|
+
|
|
93
|
+
export default subscript
|
|
94
|
+
export * from './subscript.js'
|
package/justin.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let e,
|
|
1
|
+
let e,r,t=t=>(e=0,r=t,t=a(),r[e]?l():t||""),l=(t="Bad syntax",l=r[e])=>{throw SyntaxError(t+" `"+l+"` at "+e)},n=(t=1,l=e,n)=>{if("number"==typeof t)e+=t;else for(;n=t(r.charCodeAt(e));)e+=n;return r.slice(l,e)},a=(r=0,t,n,a,o,i)=>{for(;(n=s())&&(o=(i=c[n])&&i(a,r)||!a&&c[0]());)a=o;return t&&(n==t?e++:l()),a},s=t=>{for(;(t=r.charCodeAt(e))<=32;)e++;return t},o=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,c=[e=>n(o)];t.set=(t,l=32,n,a=t.charCodeAt(0),s=t.length,i=c[a],f=t.toUpperCase()!==t)=>c[a]=(a,c,p=e)=>c<l&&(s<2||r.substr(e,s)==t)&&(!f||!o(r.charCodeAt(e+s)))&&(e+=s,n(a,c))||(e=p,i&&i(a,c));const i=e=>Array.isArray(e)?f[e[0]](...e.slice(1)):r=>r?.[e];i.set=(e,r,t=f[e])=>f[e]=(...e)=>r(...e)||t&&t(...e);const f={},p=e=>(e=t(e),r=>(e.call?e:e=i(e))(r)),h=p.set=(e,r,l,n=r<0,s=l[0],o=l[1],f=!s&&l.length)=>(s||=f?f>1?(t,l)=>t&&(l=a(r-n))&&[e,t,l]:t=>!t&&(t=a(r-1))&&[e,t]:(t,l)=>t&&(l=a(r))&&(t[0]===e&&t[2]?(t.push(l),t):[e,t,l]),o||=f?f>1?(e,r)=>r&&(e=i(e),r=i(r),e.length||r.length?t=>l(e(t),r(t)):(e=l(e(),r()),()=>e)):(e,r)=>!r&&((e=i(e)).length?r=>l(e(r)):(e=l(e()),()=>e)):(...e)=>(e=e.map(i),r=>l(...e.map((e=>e(r))))),(r=n?-r:r)?t.set(e,r,s):c[e.charCodeAt(0)||1]=s,i.set(e,o)),d=e=>e?l():["",(e=+n((e=>46===e||e>=48&&e<=57||(69===e||101===e?2:0))))!=e?l():e],u=(e,r,t,l)=>[e,r,[t=>t?["++"===e?"-":"+",[e,t],["",1]]:[e,a(r-1)],l=(e,r)=>"("===e[0]?l(e[1]):"."===e[0]?(r=e[2],e=i(e[1]),l=>t(e(l),r)):"["===e[0]?([,e,r]=e,e=i(e),r=i(r),l=>t(e(l),r(l))):r=>t(r,e)]],m=["",,[,e=>()=>e],'"',,[e=>e?l():["",(n()+n((e=>e-34?1:0))+(n()||l("Bad string"))).slice(1,-1)]],".",,[e=>!e&&d()],...Array(10).fill(0).flatMap(((e,r)=>[""+r,0,[d]])),",",1,(...e)=>e[e.length-1],"||",4,(...e)=>{let r,t=0;for(;!r&&t<e.length;)r=e[t++];return r},"&&",5,(...e)=>{let r=0,t=!0;for(;t&&r<e.length;)t=e[r++];return t},"+",12,(e,r)=>e+r,"-",12,(e,r)=>e-r,"*",13,(e,r)=>e*r,"/",13,(e,r)=>e/r,"%",13,(e,r)=>e%r,"|",6,(e,r)=>e|r,"&",8,(e,r)=>e&r,"^",7,(e,r)=>e^r,"==",9,(e,r)=>e==r,"!=",9,(e,r)=>e!=r,">",10,(e,r)=>e>r,">=",10,(e,r)=>e>=r,"<",10,(e,r)=>e<r,"<=",10,(e,r)=>e<=r,">>",11,(e,r)=>e>>r,">>>",11,(e,r)=>e>>>r,"<<",11,(e,r)=>e<<r,"+",15,e=>+e,"-",15,e=>-e,"!",15,e=>!e,...u("++",15,((e,r)=>++e[r])),...u("--",15,((e,r)=>--e[r])),"[",18,[e=>e&&["[",e,a(0,93)||l()],(e,r)=>r&&(e=i(e),r=i(r),t=>e(t)[r(t)])],".",18,[(e,r)=>e&&(r=a(18))&&[".",e,r],(e,r)=>(e=i(e),r=r[0]?r:r[1],t=>e(t)[r])],"(",18,[e=>!e&&["(",a(0,41)||l()],i],"(",18,[e=>e&&["(",e,a(0,41)||""],(e,r,t,l)=>null!=r&&(l=""==r?()=>[]:","===r[0]?(r=r.slice(1).map(i),e=>r.map((r=>r(e)))):(r=i(r),e=>[r(e)]),"."===e[0]?(t=e[2],e=i(e[1]),r=>e(r)[t](...l(r))):"["===e[0]?(t=i(e[2]),e=i(e[1]),r=>e(r)[t(r)](...l(r))):(e=i(e),r=>e(r)(...l(r))))]];for(;m[2];)h(...m.splice(0,3));let A={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},g=t=>(a,s,o="")=>{for(a&&l("Unexpected string"),n();(s=r.charCodeAt(e))-t;)92===s?(n(),s=n(),o+=A[s]||s):o+=n();return n(),["",o]},y=["===",9,(e,r)=>e===r,"!==",9,(e,r)=>e!==r,"~",15,e=>~e,"?",3,[(e,r,t)=>e&&(r=a(2,58))&&["?",e,r,a(3)],(e,r,t)=>(e=i(e),r=i(r),t=i(t),l=>e(l)?r(l):t(l))],"??",6,(e,r)=>e??r,"?.",18,[e=>e&&["?.",e],e=>(e=i(e),r=>e(r)||(()=>{}))],"?.",18,[(e,r)=>e&&!(r=a(18))?.map&&["?.",e,r],(e,r)=>r&&(e=i(e),t=>e(t)?.[r])],"in",10,(e,r)=>e in r,'"',,[g(34)],"'",,[g(39)],"/*",20,[(t,l)=>(n((t=>42!==t&&47!==r.charCodeAt(e+1))),n(2),t||a(l))],"//",20,[(e,r)=>(n((e=>e>=32)),e||a(r))],"null",20,[e=>e?l():["",null]],"true",20,[e=>e?l():["",!0]],"false",20,[e=>e?l():["",!1]],"undefined",20,[e=>e?l():["",void 0]],";",20,[e=>a()||[""]],"**",-14,(e,r)=>e**r,"[",20,[e=>!e&&["[",a(0,93)||""],(e,r)=>!r&&(e?","===e[0]?(e=e.slice(1).map(i),r=>e.map((e=>e(r)))):(e=i(e),r=>[e(r)]):()=>[])],"{",20,[e=>!e&&["{",a(0,125)||""],(e,r)=>e?","===e[0]?(e=e.slice(1).map(i),r=>Object.fromEntries(e.map((e=>e(r))))):":"===e[0]?(e=i(e),r=>Object.fromEntries([e(r)])):(r=i(e),t=>({[e]:r(t)})):e=>({})],":",1.1,[(e,r)=>[":",e,a(1.1)||l()],(e,r)=>(r=i(r),e=Array.isArray(e)?i(e):(e=>e).bind(0,e),t=>[e(t),r(t)])]];for(;y[2];)p.set(...y.splice(0,3));export{i as compile,p as default,t as parse};
|
package/package.json
CHANGED
|
@@ -1,13 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subscript",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "7.0.3",
|
|
4
4
|
"description": "Fast and tiny expression evaluator with common syntax microlanguage.",
|
|
5
5
|
"main": "subscript.js",
|
|
6
6
|
"module": "subscript.js",
|
|
7
7
|
"browser": "subscript.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./subscript.js",
|
|
10
|
+
"./parse.js": "./parse.js",
|
|
11
|
+
"./compile.js": "./compile.js",
|
|
12
|
+
"./subscript.js": "./subscript.js",
|
|
13
|
+
"./justin.js": "./justin.js"
|
|
14
|
+
},
|
|
8
15
|
"type": "module",
|
|
9
16
|
"files": [
|
|
10
|
-
"
|
|
17
|
+
"parse.js",
|
|
18
|
+
"compile.js",
|
|
11
19
|
"subscript.js",
|
|
12
20
|
"subscript.min.js",
|
|
13
21
|
"justin.js",
|
package/{parser.js → parse.js}
RENAMED
|
@@ -1,40 +1,30 @@
|
|
|
1
|
-
const SPACE=32
|
|
1
|
+
const SPACE=32
|
|
2
2
|
|
|
3
3
|
// current string, index and collected ids
|
|
4
|
-
export let idx, cur,
|
|
4
|
+
export let idx, cur,
|
|
5
5
|
|
|
6
6
|
// no handling tagged literals since easily done on user side with cache, if needed
|
|
7
|
-
parse = (s,
|
|
8
|
-
idx=0, args=[], cur=s.trim(),
|
|
9
|
-
!(s = cur ? expr() : ctx=>{}) || cur[idx] ? err() :
|
|
10
|
-
fn = ctx=>s(ctx||{}), fn.args = args, fn
|
|
11
|
-
),
|
|
12
|
-
|
|
13
|
-
isId = c =>
|
|
14
|
-
(c >= 48 && c <= 57) || // 0..9
|
|
15
|
-
(c >= 65 && c <= 90) || // A...Z
|
|
16
|
-
(c >= 97 && c <= 122) || // a...z
|
|
17
|
-
c == 36 || c == 95 || // $, _,
|
|
18
|
-
(c >= 192 && c != 215 && c != 247), // any non-ASCII
|
|
7
|
+
parse = s => (idx=0, cur=s, s = expr(), cur[idx] ? err() : s || ''),
|
|
19
8
|
|
|
20
9
|
err = (msg='Bad syntax',c=cur[idx]) => { throw SyntaxError(msg + ' `' + c + '` at ' + idx) },
|
|
21
10
|
|
|
22
11
|
skip = (is=1, from=idx, l) => {
|
|
23
12
|
if (typeof is == 'number') idx += is
|
|
24
|
-
else while (is(cur.charCodeAt(idx))) idx
|
|
13
|
+
else while (l=is(cur.charCodeAt(idx))) idx+=l
|
|
25
14
|
return cur.slice(from, idx)
|
|
26
15
|
},
|
|
27
16
|
|
|
28
17
|
// a + b - c
|
|
29
18
|
expr = (prec=0, end, cc, token, newNode, fn) => {
|
|
19
|
+
|
|
30
20
|
// chunk/token parser
|
|
31
21
|
while (
|
|
32
22
|
( cc=space() ) && // till not end
|
|
33
23
|
// FIXME: extra work is happening here, when lookup bails out due to lower precedence -
|
|
34
24
|
// it makes extra `space` call for parent exprs on the same character to check precedence again
|
|
35
|
-
(
|
|
25
|
+
(newNode =
|
|
36
26
|
(fn=lookup[cc]) && fn(token, prec) || // if operator with higher precedence isn't found
|
|
37
|
-
(!token &&
|
|
27
|
+
(!token && lookup[0]()) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
|
|
38
28
|
)
|
|
39
29
|
) token = newNode;
|
|
40
30
|
|
|
@@ -48,29 +38,28 @@ expr = (prec=0, end, cc, token, newNode, fn) => {
|
|
|
48
38
|
// skip space chars, return first non-space character
|
|
49
39
|
space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
|
|
50
40
|
|
|
51
|
-
|
|
52
|
-
|
|
41
|
+
isId = c =>
|
|
42
|
+
(c >= 48 && c <= 57) || // 0..9
|
|
43
|
+
(c >= 65 && c <= 90) || // A...Z
|
|
44
|
+
(c >= 97 && c <= 122) || // a...z
|
|
45
|
+
c == 36 || c == 95 || // $, _,
|
|
46
|
+
(c >= 192 && c != 215 && c != 247), // any non-ASCII
|
|
53
47
|
|
|
54
48
|
// operator/token lookup table
|
|
55
|
-
lookup
|
|
49
|
+
// lookup[0] is id parser to let configs redefine it
|
|
50
|
+
lookup = [n=>skip(isId)],
|
|
56
51
|
|
|
57
52
|
// create operator checker/mapper (see examples)
|
|
58
53
|
set = parse.set = (
|
|
59
54
|
op,
|
|
60
|
-
|
|
55
|
+
prec=SPACE,
|
|
56
|
+
map,
|
|
61
57
|
c=op.charCodeAt(0),
|
|
62
58
|
l=op.length,
|
|
63
59
|
prev=lookup[c],
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
map
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
ctx => fn(a(ctx),b(ctx),a.id?.(ctx),b.id?.(ctx))
|
|
71
|
-
) :
|
|
72
|
-
// unary prefix (0 args)
|
|
73
|
-
arity ? a => !a && (a=expr(opPrec-1)) && (ctx => fn(a(ctx))) :
|
|
74
|
-
fn // custom parser
|
|
75
|
-
) =>
|
|
76
|
-
lookup[c] = (a, curPrec, from=idx) => curPrec<opPrec && (l<2||cur.substr(idx,l)==op) && (!word||!isId(cur.charCodeAt(idx+l))) && (idx+=l, map(a, curPrec)) || (idx=from, prev&&prev(a, curPrec))
|
|
60
|
+
word=op.toUpperCase()!==op // make sure word boundary comes after word operator
|
|
61
|
+
) => lookup[c] = (a, curPrec, from=idx) =>
|
|
62
|
+
curPrec<prec && (l<2||cur.substr(idx,l)==op) && (!word||!isId(cur.charCodeAt(idx+l))) && (idx+=l, map(a, curPrec)) ||
|
|
63
|
+
(idx=from, prev&&prev(a, curPrec))
|
|
64
|
+
|
|
65
|
+
export default parse
|
package/subscript.js
CHANGED
|
@@ -1,91 +1,122 @@
|
|
|
1
|
-
import
|
|
1
|
+
import parse, { lookup, skip, cur, idx, err, expr } from './parse.js'
|
|
2
|
+
import compile from './compile.js'
|
|
2
3
|
|
|
3
|
-
const
|
|
4
|
+
const OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, PERIOD=46, _0=48, _9=57,
|
|
4
5
|
PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
|
|
5
|
-
PREC_EQ=9, PREC_COMP=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_UNARY=15, PREC_POSTFIX=16, PREC_CALL=18
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
),
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
'
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
),
|
|
51
|
-
|
|
6
|
+
PREC_EQ=9, PREC_COMP=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_UNARY=15, PREC_POSTFIX=16, PREC_CALL=18
|
|
7
|
+
|
|
8
|
+
const subscript = s => (s=parse(s), ctx => (s.call?s:(s=compile(s)))(ctx)),
|
|
9
|
+
|
|
10
|
+
// set any operator
|
|
11
|
+
// right assoc is indicated by negative precedence (meaning go from right to left)
|
|
12
|
+
set = subscript.set = (op, prec, fn, right=prec<0, parseFn=fn[0], evalFn=fn[1], arity=!parseFn&&fn.length) => (
|
|
13
|
+
parseFn ||=
|
|
14
|
+
!arity ? (a, b) => a && (b=expr(prec)) && (a[0] === op && a[2] ? (a.push(b), a) : [op,a,b]) :
|
|
15
|
+
arity > 1 ? (a, b) => a && (b=expr(prec-right)) && [op,a,b] :
|
|
16
|
+
a => !a && (a=expr(prec-1)) && [op, a]
|
|
17
|
+
,
|
|
18
|
+
evalFn ||=
|
|
19
|
+
!arity ? (...args) => (args=args.map(compile), ctx => fn(...args.map(arg=>arg(ctx)))) :
|
|
20
|
+
arity > 1 ? (a,b) => b && (a=compile(a),b=compile(b), !a.length&&!b.length ? (a=fn(a(),b()),()=>a) : ctx => fn(a(ctx),b(ctx))) :
|
|
21
|
+
(a,b) => !b && (a=compile(a), !a.length ? (a=fn(a()),()=>a) : ctx => fn(a(ctx)))
|
|
22
|
+
,
|
|
23
|
+
(prec=right?-prec:prec) ? parse.set(op,prec,parseFn) : (lookup[op.charCodeAt(0)||1]=parseFn),
|
|
24
|
+
compile.set(op, evalFn)
|
|
25
|
+
),
|
|
26
|
+
|
|
27
|
+
// create increment-assign pair from fn
|
|
28
|
+
num = a => a ? err() : ['', (a=+skip(c => c === PERIOD || (c>=_0 && c<=_9) || (c===69||c===101?2:0)))!=a?err():a],
|
|
29
|
+
inc = (op, prec, fn, ev) => [op, prec, [
|
|
30
|
+
a => a ? [op==='++'?'-':'+',[op,a],['',1]] : [op,expr(prec-1)], // ++a → [++, a], a++ → [-,[++,a],1]
|
|
31
|
+
ev = (a,b) => (
|
|
32
|
+
a[0] === '(' ? ev(a[1]) : // ++(((a)))
|
|
33
|
+
a[0] === '.' ? (b=a[2], a=compile(a[1]), ctx => fn(a(ctx), b)) : // ++a.b
|
|
34
|
+
a[0] === '[' ? ([,a,b]=a, a=compile(a),b=compile(b), ctx => fn(a(ctx),b(ctx))) : // ++a[b]
|
|
35
|
+
(ctx => fn(ctx,a)) // ++a
|
|
36
|
+
)
|
|
37
|
+
]],
|
|
38
|
+
list = [
|
|
39
|
+
// literals
|
|
40
|
+
// null operator returns first value (needed for direct literals)
|
|
41
|
+
'',, [,v => () => v],
|
|
42
|
+
|
|
43
|
+
'"',, [
|
|
44
|
+
(a) => a ? err() : ['', (skip() + skip(c => c - DQUOTE ? 1 : 0) + (skip()||err('Bad string'))).slice(1,-1)],
|
|
45
|
+
],
|
|
46
|
+
|
|
47
|
+
// .1
|
|
48
|
+
'.',, [a=>!a && num()],
|
|
49
|
+
|
|
50
|
+
// 0-9
|
|
51
|
+
...Array(10).fill(0).flatMap((_,i)=>[''+i,0,[num]]),
|
|
52
|
+
|
|
53
|
+
// sequences
|
|
54
|
+
',', PREC_SEQ, (...args) => args[args.length-1],
|
|
55
|
+
'||', PREC_SOME, (...args) => { let i=0, v; for (; !v && i < args.length; ) v = args[i++]; return v },
|
|
56
|
+
'&&', PREC_EVERY, (...args) => { let i=0, v=true; for (; v && i < args.length; ) v = args[i++]; return v },
|
|
57
|
+
|
|
58
|
+
// binaries
|
|
59
|
+
'+', PREC_SUM, (a,b)=>a+b,
|
|
60
|
+
'-', PREC_SUM, (a,b)=>a-b,
|
|
61
|
+
'*', PREC_MULT, (a,b)=>a*b,
|
|
62
|
+
'/', PREC_MULT, (a,b)=>a/b,
|
|
63
|
+
'%', PREC_MULT, (a,b)=>a%b,
|
|
52
64
|
'|', PREC_OR, (a,b)=>a|b,
|
|
53
|
-
'||', PREC_SOME, (a,b)=>a||b,
|
|
54
|
-
|
|
55
65
|
'&', PREC_AND, (a,b)=>a&b,
|
|
56
|
-
'&&', PREC_EVERY, (a,b)=>a&&b,
|
|
57
|
-
|
|
58
66
|
'^', PREC_XOR, (a,b)=>a^b,
|
|
59
|
-
|
|
60
|
-
// ==, !=
|
|
61
67
|
'==', PREC_EQ, (a,b)=>a==b,
|
|
62
68
|
'!=', PREC_EQ, (a,b)=>a!=b,
|
|
63
|
-
|
|
64
|
-
// > >= >> >>>, < <= <<
|
|
65
69
|
'>', PREC_COMP, (a,b)=>a>b,
|
|
66
70
|
'>=', PREC_COMP, (a,b)=>a>=b,
|
|
67
|
-
'>>', PREC_SHIFT, (a,b)=>a>>b,
|
|
68
|
-
'>>>', PREC_SHIFT, (a,b)=>a>>>b,
|
|
69
71
|
'<', PREC_COMP, (a,b)=>a<b,
|
|
70
72
|
'<=', PREC_COMP, (a,b)=>a<=b,
|
|
73
|
+
'>>', PREC_SHIFT, (a,b)=>a>>b,
|
|
74
|
+
'>>>', PREC_SHIFT, (a,b)=>a>>>b,
|
|
71
75
|
'<<', PREC_SHIFT, (a,b)=>a<<b,
|
|
72
76
|
|
|
73
|
-
//
|
|
74
|
-
'+',
|
|
75
|
-
'
|
|
76
|
-
'
|
|
77
|
-
|
|
78
|
-
'-', PREC_SUM, (a,b)=>a-b,
|
|
79
|
-
'-', PREC_UNARY, (a)=>-a,
|
|
80
|
-
'--', a => inc(a||expr(PREC_UNARY-1), a ? (a,b)=>a[b]-- : (a,b)=>--a[b]), PREC_UNARY,
|
|
77
|
+
// unaries
|
|
78
|
+
'+', PREC_UNARY, a => +a,
|
|
79
|
+
'-', PREC_UNARY, a => -a,
|
|
80
|
+
'!', PREC_UNARY, a => !a,
|
|
81
81
|
|
|
82
|
-
//
|
|
83
|
-
'
|
|
82
|
+
// increments
|
|
83
|
+
...inc('++', PREC_UNARY, (a,b) => ++a[b]),
|
|
84
|
+
...inc('--', PREC_UNARY, (a,b) => --a[b]),
|
|
84
85
|
|
|
85
|
-
//
|
|
86
|
-
'
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
]
|
|
86
|
+
// a[b]
|
|
87
|
+
'[', PREC_CALL, [
|
|
88
|
+
a => a && ['[', a, expr(0,CBRACK)||err()],
|
|
89
|
+
(a,b) => b && (a=compile(a), b=compile(b), ctx => a(ctx)[b(ctx)])
|
|
90
|
+
],
|
|
90
91
|
|
|
91
|
-
|
|
92
|
+
// a.b
|
|
93
|
+
'.', PREC_CALL, [
|
|
94
|
+
(a,b) => a && (b=expr(PREC_CALL)) && ['.',a,b],
|
|
95
|
+
(a,b) => (a=compile(a),b=!b[0]?b[1]:b, ctx => a(ctx)[b]) // a.true, a.1 → needs to work fine
|
|
96
|
+
],
|
|
97
|
+
|
|
98
|
+
// (a,b,c), (a)
|
|
99
|
+
'(', PREC_CALL, [
|
|
100
|
+
a => !a && ['(', expr(0,CPAREN)||err()],
|
|
101
|
+
compile
|
|
102
|
+
],
|
|
103
|
+
|
|
104
|
+
// a(b,c,d), a()
|
|
105
|
+
'(', PREC_CALL, [
|
|
106
|
+
a => a && ['(', a, expr(0,CPAREN)||''],
|
|
107
|
+
(a,b,path,args) => b!=null && (
|
|
108
|
+
args = b=='' ? () => [] : // a()
|
|
109
|
+
b[0] === ',' ? (b=b.slice(1).map(compile), ctx => b.map(a=>a(ctx))) : // a(b,c)
|
|
110
|
+
(b=compile(b), ctx => [b(ctx)]), // a(b)
|
|
111
|
+
|
|
112
|
+
a[0] === '.' ? (path=a[2], a=compile(a[1]), ctx => a(ctx)[path](...args(ctx))) : // a.b(...args)
|
|
113
|
+
a[0] === '[' ? (path=compile(a[2]), a=compile(a[1]), ctx => a(ctx)[path(ctx)](...args(ctx))) : // a[b](...args)
|
|
114
|
+
(a=compile(a), ctx => a(ctx)(...args(ctx))) // a(...args)
|
|
115
|
+
)
|
|
116
|
+
]
|
|
117
|
+
]
|
|
118
|
+
|
|
119
|
+
for (;list[2];) set(...list.splice(0,3))
|
|
120
|
+
|
|
121
|
+
export default subscript
|
|
122
|
+
export {compile, parse}
|
package/subscript.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let e,
|
|
1
|
+
let e,t,r=r=>(e=0,t=r,r=s(),t[e]?l():r||""),l=(r="Bad syntax",l=t[e])=>{throw SyntaxError(r+" `"+l+"` at "+e)},a=(r=1,l=e,a)=>{if("number"==typeof r)e+=r;else for(;a=r(t.charCodeAt(e));)e+=a;return t.slice(l,e)},s=(t=0,r,a,s,o,c)=>{for(;(a=n())&&(o=(c=h[a])&&c(s,t)||!s&&h[0]());)s=o;return r&&(a==r?e++:l()),s},n=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},o=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,h=[e=>a(o)];r.set=(r,l=32,a,s=r.charCodeAt(0),n=r.length,c=h[s],f=r.toUpperCase()!==r)=>h[s]=(s,h,p=e)=>h<l&&(n<2||t.substr(e,n)==r)&&(!f||!o(t.charCodeAt(e+n)))&&(e+=n,a(s,h))||(e=p,c&&c(s,h));const c=e=>Array.isArray(e)?f[e[0]](...e.slice(1)):t=>t?.[e];c.set=(e,t,r=f[e])=>f[e]=(...e)=>t(...e)||r&&r(...e);const f={},p=e=>(e=r(e),t=>(e.call?e:e=c(e))(t)),u=p.set=(e,t,l,a=t<0,n=l[0],o=l[1],f=!n&&l.length)=>(n||=f?f>1?(r,l)=>r&&(l=s(t-a))&&[e,r,l]:r=>!r&&(r=s(t-1))&&[e,r]:(r,l)=>r&&(l=s(t))&&(r[0]===e&&r[2]?(r.push(l),r):[e,r,l]),o||=f?f>1?(e,t)=>t&&(e=c(e),t=c(t),e.length||t.length?r=>l(e(r),t(r)):(e=l(e(),t()),()=>e)):(e,t)=>!t&&((e=c(e)).length?t=>l(e(t)):(e=l(e()),()=>e)):(...e)=>(e=e.map(c),t=>l(...e.map((e=>e(t))))),(t=a?-t:t)?r.set(e,t,n):h[e.charCodeAt(0)||1]=n,c.set(e,o)),g=e=>e?l():["",(e=+a((e=>46===e||e>=48&&e<=57||(69===e||101===e?2:0))))!=e?l():e],i=(e,t,r,l)=>[e,t,[r=>r?["++"===e?"-":"+",[e,r],["",1]]:[e,s(t-1)],l=(e,t)=>"("===e[0]?l(e[1]):"."===e[0]?(t=e[2],e=c(e[1]),l=>r(e(l),t)):"["===e[0]?([,e,t]=e,e=c(e),t=c(t),l=>r(e(l),t(l))):t=>r(t,e)]],d=["",,[,e=>()=>e],'"',,[e=>e?l():["",(a()+a((e=>e-34?1:0))+(a()||l("Bad string"))).slice(1,-1)]],".",,[e=>!e&&g()],...Array(10).fill(0).flatMap(((e,t)=>[""+t,0,[g]])),",",1,(...e)=>e[e.length-1],"||",4,(...e)=>{let t,r=0;for(;!t&&r<e.length;)t=e[r++];return t},"&&",5,(...e)=>{let t=0,r=!0;for(;r&&t<e.length;)r=e[t++];return r},"+",12,(e,t)=>e+t,"-",12,(e,t)=>e-t,"*",13,(e,t)=>e*t,"/",13,(e,t)=>e/t,"%",13,(e,t)=>e%t,"|",6,(e,t)=>e|t,"&",8,(e,t)=>e&t,"^",7,(e,t)=>e^t,"==",9,(e,t)=>e==t,"!=",9,(e,t)=>e!=t,">",10,(e,t)=>e>t,">=",10,(e,t)=>e>=t,"<",10,(e,t)=>e<t,"<=",10,(e,t)=>e<=t,">>",11,(e,t)=>e>>t,">>>",11,(e,t)=>e>>>t,"<<",11,(e,t)=>e<<t,"+",15,e=>+e,"-",15,e=>-e,"!",15,e=>!e,...i("++",15,((e,t)=>++e[t])),...i("--",15,((e,t)=>--e[t])),"[",18,[e=>e&&["[",e,s(0,93)||l()],(e,t)=>t&&(e=c(e),t=c(t),r=>e(r)[t(r)])],".",18,[(e,t)=>e&&(t=s(18))&&[".",e,t],(e,t)=>(e=c(e),t=t[0]?t:t[1],r=>e(r)[t])],"(",18,[e=>!e&&["(",s(0,41)||l()],c],"(",18,[e=>e&&["(",e,s(0,41)||""],(e,t,r,l)=>null!=t&&(l=""==t?()=>[]:","===t[0]?(t=t.slice(1).map(c),e=>t.map((t=>t(e)))):(t=c(t),e=>[t(e)]),"."===e[0]?(r=e[2],e=c(e[1]),t=>e(t)[r](...l(t))):"["===e[0]?(r=c(e[2]),e=c(e[1]),t=>e(t)[r(t)](...l(t))):(e=c(e),t=>e(t)(...l(t))))]];for(;d[2];)u(...d.splice(0,3));export{c as compile,p as default,r as parse};
|