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 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 standard syntax<br/>
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
- let fn = script`a.b + c(d - 1)`
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
- fn.args // ['a', 'c', 'd']
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)) <!-- see sonr, mineural -->
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 [2kb](https://npmfs.com/package/subscript/6.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.
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 `parse.set(token, precedence, operator)` for unary or binary operators (detected by number of arguments in `operator`), or via `parse.set(token, parse, precedence)` for custom tokens.
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 => ()=>true)
70
- script.set('false', a => ()=>false)
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
- subscript: ~170 ms 🥇
290
- justin: ~183 ms 🥈
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: ~17 ms 🥈
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
- ## Next door
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 {set, lookup, skip, cur, idx, err, expr, isId, space, args} from './parser.js'
3
- export { default } from './subscript.js'
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
- let u, list, op, prec, fn,
11
- escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'},
12
- string = q => (qc, c, str='') => {
13
- qc&&err('Unexpected string') // must not follow another token
14
- while (c=cur.charCodeAt(idx), c-q) {
15
- if (c === BSLASH) skip(), c=skip(), str += escape[c] || c
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
- // operators
22
- for (list=[
23
- // "' with /
24
- '"', string(DQUOTE),,
25
- "'", string(QUOTE),,
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
- '/*', (a, prec) => (skip(c => c !== 42 && cur.charCodeAt(idx+1) !== 47), skip(2), a||expr(prec)),,
29
- '//', (a, prec) => (skip(c => c >= 32), a||expr(prec)),,
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
- // literals
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
- ';', a => expr()||(()=>{}),,
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
- // operators
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
- // right order
45
- '**', (a,prec,b=expr(PREC_EXP-1)) => ctx=>a(ctx)**b(ctx), PREC_EXP,
46
+ // "' with /
47
+ '"', , [string(DQUOTE)],
48
+ "'", , [string(QUOTE)],
46
49
 
47
- // ?:
48
- ':', 3.1, (a,b) => [a,b],
49
- '?', 3, (a,b) => a ? b[0] : b[1],
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
- '??', PREC_OR, (a,b) => a??b,
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
- // a?.[, a?.( - postfix operator
54
- '?.', a => a && (ctx => a(ctx)||(()=>{})),,//(a) => a||(()=>{}),
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
- 'in', PREC_COMP, (a,b) => a in b,
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
- '[', (a) => !a && (
62
- a=expr(0,CBRACK),
63
- !a ? ctx => [] : a.all ? ctx => a.all(ctx) : ctx => [a(ctx)]
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
- '{', (a, entries) => !a && (
68
- a=expr(0,125),
69
- !a ? ctx => ({}) : ctx => (entries=(a.all||a)(ctx), Object.fromEntries(a.all?entries:[entries]))
70
- ),,
71
- // for JSON case we should not collect arg (different evaluator than ternary)
72
- ':', (a, prec, b) => (b=expr(1.1)||err(), a.id&&args.pop(), ctx => [(a.id||a)(ctx), b(ctx)]), 1.1
73
-
74
- ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
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,t,r,l,a,n,d,o=(l,a)=>(e=0,r=[],t=l.trim(),!(l=t?c():e=>{})||t[e]?f():a=e=>l(e||{}),a.args=r,a),i=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,f=(r="Bad syntax",l=t[e])=>{throw SyntaxError(r+" `"+l+"` at "+e)},p=(r=1,l=e,a)=>{if("number"==typeof r)e+=r;else for(;r(t.charCodeAt(e));)e++;return t.slice(l,e)},c=(t=0,r,l,a,n,d)=>{for(;(l=s())&&(n=(d=h[l])&&d(a,t)||!a&&u());)a=n;return r&&(l==r?e++:f()),a},s=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},u=(e=p(i),t)=>e?(t=t=>t[e],r.push(e),t.id=()=>e,t):0,h=[],g=o.set=(r,l,a=32,n=r.charCodeAt(0),d=r.length,o=h[n],f=a.length||([a,l]=[l,a],0),p=r.toUpperCase()!==r,s=(f>1?(e,t)=>e&&(t=c(l))&&(e.length||t.length?r=>a(e(r),t(r),e.id?.(r),t.id?.(r)):(e=a(e(),t()),()=>e)):f?e=>!e&&(e=c(l-1))&&(t=>a(e(t))):a))=>h[n]=(a,n,f=e)=>n<l&&(d<2||t.substr(e,d)==r)&&(!p||!i(t.charCodeAt(e+d)))&&(e+=d,s(a,n))||(e=f,o&&o(a,n)),x=e=>e>=48&&e<=57,C=r=>(r&&f("Unexpected number"),r=p((e=>46==e||x(e))),(69==t.charCodeAt(e)||101==t.charCodeAt(e))&&(r+=p(2)+p(x)),(r=+r)!=r?f("Bad number"):()=>r),A=(e,t)=>r=>t(e.of?e.of(r):r,e.id(r));for(a=48;a<=57;)h[a++]=C;for(l=['"',e=>(e=e?f("Unexpected string"):p((e=>e-34)),p()||f("Bad string"),()=>e),,".",(e,t)=>(s(),t=p(i)||f(),d=r=>e(r)[t],d.id=()=>t,d.of=e,d),18,".",e=>!e&&C(p(-1)),,"[",(e,t,r)=>e&&(t=c(0,93)||f(),(r=r=>e(r)[t(r)]).id=t,r.of=e,r),18,"(",(e,t,r)=>(t=c(0,41),e?r=>e(r).apply(e.of?.(r),t?t.all?t.all(r):[t(r)]:[]):t||f()),18,",",(e,t,r=c(1),l=(t=>(e(t),r(t))))=>(r?l.all=e.all?t=>[...e.all(t),r(t)]:t=>[e(t),r(t)]:f("Skipped argument"),l),1,"|",6,(e,t)=>e|t,"||",4,(e,t)=>e||t,"&",8,(e,t)=>e&t,"&&",5,(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,">>",11,(e,t)=>e>>t,">>>",11,(e,t)=>e>>>t,"<",10,(e,t)=>e<t,"<=",10,(e,t)=>e<=t,"<<",11,(e,t)=>e<<t,"+",12,(e,t)=>e+t,"+",15,e=>+e,"++",e=>A(e||c(14),e?(e,t)=>e[t]++:(e,t)=>++e[t]),15,"-",12,(e,t)=>e-t,"-",15,e=>-e,"--",e=>A(e||c(14),e?(e,t)=>e[t]--:(e,t)=>--e[t]),15,"!",15,e=>!e,"*",13,(e,t)=>e*t,"/",13,(e,t)=>e/t,"%",13,(e,t)=>e%t];[a,n,d,...l]=l,a;)g(a,n,d);let U,b,m,y,B={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},v=r=>(l,a,n="")=>{for(l&&f("Unexpected string");(a=t.charCodeAt(e))-r;)92===a?(p(),a=p(),n+=B[a]||a):n+=p();return p()||f("Bad string"),()=>n};for((U=['"',v(34),,"'",v(39),,"/*",(r,l)=>(p((r=>42!==r&&47!==t.charCodeAt(e+1))),p(2),r||c(l)),,"//",(e,t)=>(p((e=>e>=32)),e||c(t)),,"null",e=>e?f("Unexpected literal"):()=>null,,"true",e=>e?f("Unexpected literal"):()=>!0,,"false",e=>e?f("Unexpected literal"):()=>!1,,"undefined",e=>e?f("Unexpected literal"):()=>{},,";",e=>c()||(()=>{}),,"===",9,(e,t)=>e===t,"!==",9,(e,t)=>e!==t,"~",15,e=>~e,"**",(e,t,r=c(13))=>t=>e(t)**r(t),14,":",3.1,(e,t)=>[e,t],"?",3,(e,t)=>e?t[0]:t[1],"??",6,(e,t)=>e??t,"?.",e=>e&&(t=>e(t)||(()=>{})),,"?.",(e,t)=>(s(),(t=p(i))&&(r=>e(r)?.[t])),,"in",10,(e,t)=>e in t,"[",e=>!e&&((e=c(0,93))?e.all?t=>e.all(t):t=>[e(t)]:e=>[]),,"{",(e,t)=>!e&&((e=c(0,125))?r=>(t=(e.all||e)(r),Object.fromEntries(e.all?t:[t])):e=>({})),,":",(e,t,l)=>(l=c(1.1)||f(),e.id&&r.pop(),t=>[(e.id||e)(t),l(t)]),1.1]);[b,m,y,...U]=U,b;)g(b,m,y);export{o as default};
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": "6.4.0",
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
- "parser.js",
17
+ "parse.js",
18
+ "compile.js",
11
19
  "subscript.js",
12
20
  "subscript.min.js",
13
21
  "justin.js",
@@ -1,40 +1,30 @@
1
- const SPACE=32, CPAREN=41
1
+ const SPACE=32
2
2
 
3
3
  // current string, index and collected ids
4
- export let idx, cur, args,
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, fn) => (
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
- ( newNode =
25
+ (newNode =
36
26
  (fn=lookup[cc]) && fn(token, prec) || // if operator with higher precedence isn't found
37
- (!token && id()) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
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
- // variable identifier
52
- id = (name=skip(isId), fn) => name ? (fn=ctx => ctx[name], args.push(name), fn.id=()=>name, fn) : 0,
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
- opPrec, fn=SPACE, // if opPrec & fn come in reverse order - consider them raw parse fn case, still precedence possible
55
+ prec=SPACE,
56
+ map,
61
57
  c=op.charCodeAt(0),
62
58
  l=op.length,
63
59
  prev=lookup[c],
64
- arity=fn.length || ([fn,opPrec]=[opPrec,fn], 0),
65
- word=op.toUpperCase()!==op, // make sure word boundary comes after word operator
66
- map=
67
- // binary
68
- arity>1 ? (a,b) => a && (b=expr(opPrec)) && (
69
- !a.length && !b.length ? (a=fn(a(),b()), ()=>a) : // static pre-eval like `"a"+"b"`
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 {parse, set, lookup, skip, cur, idx, err, expr, isId, args, space} from './parser.js'
1
+ import parse, { lookup, skip, cur, idx, err, expr } from './parse.js'
2
+ import compile from './compile.js'
2
3
 
3
- const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, _0=48, _9=57,
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, PREC_GROUP=19
6
-
7
- let u, list, op, prec, fn,
8
- isNum = c => c>=_0 && c<=_9,
9
- // 1.2e+3, .5
10
- num = n => (
11
- n&&err('Unexpected number'),
12
- n = skip(c=>c == PERIOD || isNum(c)),
13
- (cur.charCodeAt(idx) == 69 || cur.charCodeAt(idx) == 101) && (n += skip(2) + skip(isNum)),
14
- n=+n, n!=n ? err('Bad number') : () => n // 0 args means token is static
15
- ),
16
-
17
- inc = (a,fn) => ctx => fn(a.of?a.of(ctx):ctx, a.id(ctx))
18
-
19
- // numbers
20
- for (op=_0;op<=_9;) lookup[op++] = num
21
-
22
- // operators
23
- for (list=[
24
- // "a"
25
- '"', a => (a=a?err('Unexpected string'):skip(c => c-DQUOTE), skip()||err('Bad string'), ()=>a),,
26
-
27
- // a.b
28
- '.', (a,id) => (space(), id=skip(isId)||err(), fn=ctx=>a(ctx)[id], fn.id=()=>id, fn.of=a, fn), PREC_CALL,
29
-
30
- // .2
31
- // FIXME: .123 is not operator, so we skip back, but mb reorganizing num would be better
32
- '.', a => !a && num(skip(-1)),,
33
-
34
- // a[b]
35
- '[', (a,b,fn) => a && (b=expr(0,CBRACK)||err(), fn=ctx=>a(ctx)[b(ctx)], fn.id=b, fn.of=a, fn), PREC_CALL,
36
-
37
- // a(), a(b), (a,b), (a+b)
38
- '(', (a,b,fn) => (
39
- b=expr(0,CPAREN),
40
- // a(), a(b), a(b,c,d)
41
- a ? ctx => a(ctx).apply(a.of?.(ctx), b ? b.all ? b.all(ctx) : [b(ctx)] : []) :
42
- // (a+b)
43
- b || err()
44
- ), PREC_CALL,
45
-
46
- // [a,b,c] or (a,b,c)
47
- ',', (a,prec,b=expr(PREC_SEQ),fn=ctx => (a(ctx), b(ctx))) => (
48
- b ? (fn.all = a.all ? ctx => [...a.all(ctx),b(ctx)] : ctx => [a(ctx),b(ctx)]) : err('Skipped argument',),
49
- fn
50
- ), PREC_SEQ,
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
- '+', PREC_SUM, (a,b)=>a+b,
75
- '+', PREC_UNARY, (a)=>+a,
76
- '++', a => inc(a||expr(PREC_UNARY-1), a ? (a,b)=>a[b]++ : (a,b)=>++a[b]), PREC_UNARY,
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
- '!', PREC_UNARY, (a)=>!a,
82
+ // increments
83
+ ...inc('++', PREC_UNARY, (a,b) => ++a[b]),
84
+ ...inc('--', PREC_UNARY, (a,b) => --a[b]),
84
85
 
85
- // * / %
86
- '*', PREC_MULT, (a,b)=>a*b,
87
- '/', PREC_MULT, (a,b)=>a/b,
88
- '%', PREC_MULT, (a,b)=>a%b
89
- ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
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
- export default parse
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,r,t,a,o,d,l,n=(a,o)=>(e=0,t=[],r=a.trim(),!(a=r?s():e=>{})||r[e]?h():o=e=>a(e||{}),o.args=t,o),f=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,h=(t="Bad syntax",a=r[e])=>{throw SyntaxError(t+" `"+a+"` at "+e)},i=(t=1,a=e,o)=>{if("number"==typeof t)e+=t;else for(;t(r.charCodeAt(e));)e++;return r.slice(a,e)},s=(r=0,t,a,o,d,l)=>{for(;(a=p())&&(d=(l=c[a])&&l(o,r)||!o&&u());)o=d;return t&&(a==t?e++:h()),o},p=t=>{for(;(t=r.charCodeAt(e))<=32;)e++;return t},u=(e=i(f),r)=>e?(r=r=>r[e],t.push(e),r.id=()=>e,r):0,c=[],g=n.set=(t,a,o=32,d=t.charCodeAt(0),l=t.length,n=c[d],h=o.length||([o,a]=[a,o],0),i=t.toUpperCase()!==t,p=(h>1?(e,r)=>e&&(r=s(a))&&(e.length||r.length?t=>o(e(t),r(t),e.id?.(t),r.id?.(t)):(e=o(e(),r()),()=>e)):h?e=>!e&&(e=s(a-1))&&(r=>o(e(r))):o))=>c[d]=(o,d,h=e)=>d<a&&(l<2||r.substr(e,l)==t)&&(!i||!f(r.charCodeAt(e+l)))&&(e+=l,p(o,d))||(e=h,n&&n(o,d)),C=e=>e>=48&&e<=57,A=t=>(t&&h("Unexpected number"),t=i((e=>46==e||C(e))),(69==r.charCodeAt(e)||101==r.charCodeAt(e))&&(t+=i(2)+i(C)),(t=+t)!=t?h("Bad number"):()=>t),m=(e,r)=>t=>r(e.of?e.of(t):t,e.id(t));for(o=48;o<=57;)c[o++]=A;for(a=['"',e=>(e=e?h("Unexpected string"):i((e=>e-34)),i()||h("Bad string"),()=>e),,".",(e,r)=>(p(),r=i(f)||h(),l=t=>e(t)[r],l.id=()=>r,l.of=e,l),18,".",e=>!e&&A(i(-1)),,"[",(e,r,t)=>e&&(r=s(0,93)||h(),(t=t=>e(t)[r(t)]).id=r,t.of=e,t),18,"(",(e,r,t)=>(r=s(0,41),e?t=>e(t).apply(e.of?.(t),r?r.all?r.all(t):[r(t)]:[]):r||h()),18,",",(e,r,t=s(1),a=(r=>(e(r),t(r))))=>(t?a.all=e.all?r=>[...e.all(r),t(r)]:r=>[e(r),t(r)]:h("Skipped argument"),a),1,"|",6,(e,r)=>e|r,"||",4,(e,r)=>e||r,"&",8,(e,r)=>e&r,"&&",5,(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,">>",11,(e,r)=>e>>r,">>>",11,(e,r)=>e>>>r,"<",10,(e,r)=>e<r,"<=",10,(e,r)=>e<=r,"<<",11,(e,r)=>e<<r,"+",12,(e,r)=>e+r,"+",15,e=>+e,"++",e=>m(e||s(14),e?(e,r)=>e[r]++:(e,r)=>++e[r]),15,"-",12,(e,r)=>e-r,"-",15,e=>-e,"--",e=>m(e||s(14),e?(e,r)=>e[r]--:(e,r)=>--e[r]),15,"!",15,e=>!e,"*",13,(e,r)=>e*r,"/",13,(e,r)=>e/r,"%",13,(e,r)=>e%r];[o,d,l,...a]=a,o;)g(o,d,l);export{n as default};
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};