subscript 7.4.6 → 7.5.1

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
@@ -11,10 +11,10 @@ _Subscript_ is expression evaluator / microlanguage with [common syntax](https:/
11
11
  import subscript, { parse, compile } from './subscript.js'
12
12
 
13
13
  // create expression evaluator
14
- let fn = subscript('a.b + c(d - 1)')
15
- fn({ a: { b:1 }, c: x => x * 2, d: 3 }) // 5
14
+ let fn = subscript('a.b + Math.sqrt(c - 1)')
15
+ fn({ a: { b:1 }, c: 5, Math }) // 3
16
16
 
17
- // or
17
+ // --- or ---
18
18
  // parse expression
19
19
  let tree = parse('a.b + c')
20
20
  tree // ['+', ['.', 'a', 'b'], 'c']
@@ -28,12 +28,12 @@ fn({a:{b:1}, c:2}) // 3
28
28
 
29
29
  _Subscript_ is designed to be useful for:
30
30
 
31
- * templates (perfect match with [template parts](https://github.com/github/template-parts), see [templize](https://github.com/spectjs/templize))
31
+ * templates (eg. [sprae](https://github.com/dy/sprae), [templize](https://github.com/dy/templize))
32
32
  * expressions evaluators, calculators
33
- * configurable subsets of languages (eg. [justin](#justin))
34
- * pluggable/mock language features (eg. pipe operator)
33
+ * subsets of languages (eg. [justin](#justin))
34
+ * pluggable/configurable/mock language features (eg. pipe operator)
35
35
  * sandboxes, playgrounds, safe eval
36
- * custom DSL (see [lino](https://github.com/dy/lino)) <!-- uneural -->
36
+ * custom DSL (see [mell](https://github.com/dy/lino)) <!-- uneural -->
37
37
  * preprocessors (see [prepr](https://github.com/dy/prepr))
38
38
 
39
39
  _Subscript_ has [3.5kb](https://npmfs.com/package/subscript/7.4.3/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.
@@ -105,16 +105,16 @@ import script, { operator, unary, binary, token } from './subscript.js'
105
105
 
106
106
  // add ~ unary operator with precedence 15
107
107
  unary('~', 15)
108
- operator('~', a => ~a)
108
+ operator('~', a => ctx => ~a)
109
109
 
110
110
  // add === binary operator with precedence 9
111
111
  binary('===', 9)
112
- operator('===', (a, b) => a===b)
112
+ operator('===', (a, b) => ctx => ctx[a]===ctx[b])
113
113
 
114
114
  // add boolean literals
115
115
  token('true', 20, prev => ['',true])
116
116
  token('false', 20, prev => ['',false])
117
- operator('', boolNode => ctx => boolNode[1]])
117
+ operator('', boolNode => ctx => boolNode[1])
118
118
  ```
119
119
 
120
120
  See [subscript.js](subscript.js) or [justin.js](./justin.js) for examples.
@@ -331,5 +331,6 @@ math-parser: -
331
331
  * [math-parser](https://www.npmjs.com/package/math-parser)
332
332
  * [math.js](https://mathjs.org/docs/expressions/parsing.html)
333
333
  * [nx-compile](https://github.com/nx-js/compiler-util)
334
+ * [built-in-math-eval](https://github.com/mauriciopoppe/built-in-math-eval)
334
335
 
335
336
  <p align=center><a href="https://github.com/krsnzd/license/">🕉</a></p>
package/justin.js CHANGED
@@ -1,94 +1,94 @@
1
1
  // justin lang https://github.com/endojs/Jessie/issues/66
2
- import { skip, cur, idx, err, expr } from './parse.js'
3
- import compile from './compile.js'
2
+ import { skip, cur, idx, err, expr, lookup, token } from './parse.js'
3
+ import compile, { operator } from './compile.js'
4
4
  import subscript, { set } from './subscript.js'
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,
7
- PREC_SEQ=1, PREC_COND=3, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
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
6
+ const PERIOD = 46, OPAREN = 40, CPAREN = 41, OBRACK = 91, CBRACK = 93, SPACE = 32, DQUOTE = 34, QUOTE = 39, _0 = 48, _9 = 57, BSLASH = 92,
7
+ PREC_SEQ = 1, PREC_COND = 3, PREC_SOME = 4, PREC_EVERY = 5, PREC_OR = 6, PREC_XOR = 7, PREC_AND = 8,
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
9
9
 
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
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
13
  skip()
14
- while (c=cur.charCodeAt(idx), c-q) {
15
- if (c === BSLASH) skip(), c=skip(), str += escape[c] || c
14
+ while (c = cur.charCodeAt(idx), c - q) {
15
+ if (c === BSLASH) skip(), c = skip(), str += escape[c] || c
16
16
  else str += skip()
17
17
  }
18
18
  skip()
19
19
  return ['', str]
20
- },
21
-
22
- list = [
23
- // operators
24
- '===', PREC_EQ, (a,b) => a===b,
25
- '!==', PREC_EQ, (a,b) => a!==b,
26
- '~', PREC_UNARY, (a) => ~a,
27
-
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
- ],
33
-
34
- '??', PREC_OR, (a,b) => a ?? b,
35
-
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
- ],
43
-
44
- 'in', PREC_COMP , (a,b) => a in b,
45
-
46
- // "' with /
47
- '"', , [string(DQUOTE)],
48
- "'", , [string(QUOTE)],
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))],
53
-
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]],
59
-
60
- // FIXME: make sure that is right
61
- ';', -20, (...args) => { for (let i = args.length; i--; ) if (args[i] != null) return args[i] },
62
-
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,
66
-
67
- // [a,b,c]
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
- )],
75
-
76
- // {a:1, b:2, c:3}
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];) set(...list.splice(0,3))
20
+ }
21
+
22
+ // operators
23
+ set('===', PREC_EQ, (a, b) => a === b)
24
+ set('!==', PREC_EQ, (a, b) => a !== b)
25
+ set('~', PREC_UNARY, (a) => ~a)
26
+
27
+ // ?:
28
+ token('?', PREC_COND, (a, b, c) => a && (b = expr(2, 58)) && (c = expr(3), ['?', a, b, c]))
29
+ operator('?', (a, b, c) => (a = compile(a), b = compile(b), c = compile(c), ctx => a(ctx) ? b(ctx) : c(ctx)))
30
+
31
+ set('??', PREC_OR, (a, b) => a ?? b)
32
+
33
+ // a?.[, a?.( - postfix operator
34
+ token('?.', PREC_CALL, a => a && ['?.', a])
35
+ operator('?.', a => (a = compile(a), ctx => a(ctx) || (() => { })))
36
+
37
+ // a?.b - optional chain operator
38
+ token('?.', PREC_CALL, (a, b) => a && (b = expr(PREC_CALL), !b?.map) && ['?.', a, b])
39
+ operator('?.', (a, b) => b && (a = compile(a), ctx => a(ctx)?.[b]))
40
+
41
+ // a?.x() - keep context
42
+ operator('(', (a, b, path, args) => b != null && a[0] === '?.' && (
43
+ args = b == '' ? () => [] : // a()
44
+ b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(a => a(ctx))) : // a(b,c)
45
+ (b = compile(b), ctx => [b(ctx)]), // a(b)
46
+ path = a[2], a = compile(a[1]), ctx => a(ctx)?.[path](...args(ctx))
47
+ ))
48
+
49
+ // a in b
50
+ set('in', PREC_COMP, (a, b) => a in b)
51
+
52
+ // "' with /
53
+ lookup[DQUOTE] = string(DQUOTE)
54
+ lookup[QUOTE] = string(QUOTE)
55
+
56
+ // /**/, //
57
+ token('/*', 20, (a, prec) => (skip(c => c !== 42 && cur.charCodeAt(idx + 1) !== 47), skip(2), a || expr(prec) || ['']))
58
+ token('//', 20, (a, prec) => (skip(c => c >= 32), a || expr(prec) || ['']))
59
+
60
+ // literals
61
+ token('null', 20, a => a ? err() : ['', null])
62
+ token('true', 20, a => a ? err() : ['', true])
63
+ token('false', 20, a => a ? err() : ['', false])
64
+ token('undefined', 20, a => a ? err() : ['', undefined])
65
+
66
+ // FIXME: make sure that is right
67
+ set(';', -20, (...args) => { for (let i = args.length; i--;) if (args[i] != null) return args[i] })
68
+
69
+ // right order
70
+ // '**', (a,prec,b=expr(PREC_EXP-1)) => ctx=>a(ctx)**b(ctx), PREC_EXP,
71
+ set('**', -PREC_EXP, (a, b) => a ** b)
72
+
73
+ // [a,b,c]
74
+ token('[', 20, (a) => !a && ['[', expr(0, 93) || ''])
75
+ operator('[', (a, b) => !b && (
76
+ !a ? () => [] : // []
77
+ a[0] === ',' ? (a = a.slice(1).map(compile), ctx => a.map(a => a(ctx))) : // [a,b,c]
78
+ (a = compile(a), ctx => [a(ctx)]) // [a]
79
+ ))
80
+
81
+ // {a:1, b:2, c:3}
82
+ token('{', 20, a => !a && (['{', expr(0, 125) || '']))
83
+ operator('{', (a, b) => (
84
+ !a ? ctx => ({}) : // {}
85
+ a[0] === ',' ? (a = a.slice(1).map(compile), ctx => Object.fromEntries(a.map(a => a(ctx)))) : // {a:1,b:2}
86
+ a[0] === ':' ? (a = compile(a), ctx => Object.fromEntries([a(ctx)])) : // {a:1}
87
+ (b = compile(a), ctx => ({ [a]: b(ctx) }))
88
+ ))
89
+
90
+ token(':', 1.1, (a, b) => (b = expr(1.1) || err(), [':', a, b]))
91
+ operator(':', (a, b) => (b = compile(b), a = Array.isArray(a) ? compile(a) : (a => a).bind(0, a), ctx => [a(ctx), b(ctx)]))
92
92
 
93
93
  export default subscript
94
94
  export * from './subscript.js'
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- let e,t,r=r=>(e=0,t=r,r=s(),t[e]?l():r||""),l=(r="Bad syntax",l=t[e],n=t.slice(0,e).split("\n"),a=n.pop())=>{throw SyntaxError(`${r} ${l?`\`${l}\` `:""}at ${n.length}:${a.length}`,n.length)},n=(r="Bad syntax",l=t[e],n=t.slice(0,e).split("\n"),a=n.pop())=>{let s=t.slice(e-10,e).split("\n").pop(),i=t.slice(e+1,e+10).split("\n").shift(),h=n.length+":"+a.length;throw EvalError(`${r} at ${h} \`${s+l+i}\`\n${" ".repeat(18+r.length+h.length+s.length+1)}^`)},a=(r=1,l=e,n)=>{if("number"==typeof r)e+=r;else for(;n=r(t.charCodeAt(e));)e+=n;return t.slice(l,e)},s=(t=0,n,a,s,i,h)=>{for(;(a=r.space())&&(i=((h=o[a])&&h(s,t))??(!s&&r.id()));)s=i;return n&&(a==n?e++:l()),s},i=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,h=r.space=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},p=r.id=e=>a(i),o=[],c=(r,l=32,n,a=r.charCodeAt(0),s=r.length,h=o[a],p=r.toUpperCase()!==r)=>o[a]=(a,o,c=e)=>o<l&&(s<2||t.substr(e,s)==r)&&(!p||!i(t.charCodeAt(e+s)))&&(e+=s,n(a,o))||(e=c,h?.(a,o)),f=(e,t,r=0)=>c(e,t,((l,n)=>l&&(n=s(t-r/2))&&[e,l,n])),g=(e,t,r)=>c(e,t,(l=>r?l&&[e,l]:!l&&(l=s(t-.5))&&[e,l])),d=(e,t,r)=>{c(e,t,((l,n)=>(l||r)&&((n=s(t))||r)&&((!l||l[0]!==e)&&(l=[e,l]),(n||r)&&l.push(n),l)))};const u=e=>Array.isArray(e)?m[e[0]](...e.slice(1)):t=>t?.[e],m={},A=(e,t,r=m[e])=>m[e]=(...e)=>t(...e)||r&&r(...e),b=e=>(e=r(e),t=>(e.call?e:e=u(e))(t)),y=(e,t,r)=>r[0]||r[1]?(t?c(e,t,r[0]):o[e.charCodeAt(0)||1]=r[0],A(e,r[1])):r.length?r.length>1?(f(e,Math.abs(t),t<0),A(e,((e,t)=>t&&(e=u(e),t=u(t),e.length||t.length?l=>r(e(l),t(l)):(e=r(e(),t()),()=>e))))):(g(e,t),A(e,((e,t)=>!t&&((e=u(e)).length?t=>r(e(t)):(e=r(e()),()=>e))))):(d(e,Math.abs(t),t<0),A(e,((...e)=>(e=e.map(u),t=>r(...e.map((e=>e(t)))))))),$=e=>e?l():["",(e=+a((e=>46===e||e>=48&&e<=57||(69===e||101===e?2:0))))!=e?l():e],C=(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=u(e[1]),l=>r(e(l),t)):"["===e[0]?([,e,t]=e,e=u(e),t=u(t),l=>r(e(l),t(l))):t=>r(t,e)]],x=["",,[,e=>()=>e],'"',,[e=>e?l():["",(a()+a((e=>e-34?1:0))+(a()||l("Bad string"))).slice(1,-1)]],".",,[e=>!e&&$()],...Array(10).fill(0).flatMap(((e,t)=>[""+t,0,[$]])),",",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,...C("++",15,((e,t)=>++e[t])),...C("--",15,((e,t)=>--e[t])),"[",18,[e=>e&&["[",e,s(0,93)||l()],(e,t)=>t&&(e=u(e),t=u(t),r=>e(r)[t(r)])],".",18,[(e,t)=>e&&(t=s(18))&&[".",e,t],(e,t)=>(e=u(e),t=t[0]?t:t[1],r=>e(r)[t])],"(",18,[e=>!e&&["(",s(0,41)||l()],u],"(",18,[(e,t)=>e&&((t=s(0,41))?["(",e,t]:["(",e,""]),(e,t,r,l)=>null!=t&&(l=""==t?()=>[]:","===t[0]?(t=t.slice(1).map(u),e=>t.map((t=>t(e)))):(t=u(t),e=>[t(e)]),"."===e[0]?(r=e[2],e=u(e[1]),t=>e(t)[r](...l(t))):"["===e[0]?(r=u(e[2]),e=u(e[1]),t=>e(t)[r(t)](...l(t))):(e=u(e),t=>e(t)(...l(t))))]];for(;x[2];)y(...x.splice(0,3));let E={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},v=r=>(n,s,i="")=>{for(n&&l("Unexpected string"),a();(s=t.charCodeAt(e))-r;)92===s?(a(),s=a(),i+=E[s]||s):i+=a();return a(),["",i]},B=["===",9,(e,t)=>e===t,"!==",9,(e,t)=>e!==t,"~",15,e=>~e,"?",3,[(e,t,r)=>e&&(t=s(2,58))&&["?",e,t,s(3)],(e,t,r)=>(e=u(e),t=u(t),r=u(r),l=>e(l)?t(l):r(l))],"??",6,(e,t)=>e??t,"?.",18,[e=>e&&["?.",e],e=>(e=u(e),t=>e(t)||(()=>{}))],"?.",18,[(e,t)=>e&&!(t=s(18))?.map&&["?.",e,t],(e,t)=>t&&(e=u(e),r=>e(r)?.[t])],"in",10,(e,t)=>e in t,'"',,[v(34)],"'",,[v(39)],"/*",20,[(r,l)=>(a((r=>42!==r&&47!==t.charCodeAt(e+1))),a(2),r||s(l))],"//",20,[(e,t)=>(a((e=>e>=32)),e||s(t))],"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)=>{for(let t=e.length;t--;)if(null!=e[t])return e[t]},"**",-14,(e,t)=>e**t,"[",20,[e=>!e&&["[",s(0,93)||""],(e,t)=>!t&&(e?","===e[0]?(e=e.slice(1).map(u),t=>e.map((e=>e(t)))):(e=u(e),t=>[e(t)]):()=>[])],"{",20,[e=>!e&&["{",s(0,125)||""],(e,t)=>e?","===e[0]?(e=e.slice(1).map(u),t=>Object.fromEntries(e.map((e=>e(t))))):":"===e[0]?(e=u(e),t=>Object.fromEntries([e(t)])):(t=u(e),r=>({[e]:t(r)})):e=>({})],":",1.1,[(e,t)=>[":",e,s(1.1)||l()],(e,t)=>(t=u(t),e=Array.isArray(e)?u(e):(e=>e).bind(0,e),r=>[e(r),t(r)])]];for(;B[2];)y(...B.splice(0,3));export{f as binary,u as compile,t as cur,b as default,l as err,s as expr,p as id,e as idx,i as isId,n as longErr,o as lookup,d as nary,A as operator,m as operators,r as parse,y as set,a as skip,h as space,c as token,g as unary};
1
+ let e,t,r=r=>(e=0,t=r,r=s(),t[e]?l():r||""),l=(r="Bad syntax",l=t[e],n=t.slice(0,e).split("\n"),a=n.pop())=>{throw SyntaxError(`${r} ${l?`\`${l}\` `:""}at ${n.length}:${a.length}`,n.length)},n=(r="Bad syntax",l=t[e],n=t.slice(0,e).split("\n"),a=n.pop())=>{let s=t.slice(e-10,e).split("\n").pop(),i=t.slice(e+1,e+10).split("\n").shift(),h=n.length+":"+a.length;throw EvalError(`${r} at ${h} \`${s+l+i}\`\n${" ".repeat(18+r.length+h.length+s.length+1)}^`)},a=(r=1,l=e,n)=>{if("number"==typeof r)e+=r;else for(;n=r(t.charCodeAt(e));)e+=n;return t.slice(l,e)},s=(t=0,n,a,s,i,h)=>{for(;(a=r.space())&&(i=((h=o[a])&&h(s,t))??(!s&&r.id()));)s=i;return n&&(a==n?e++:l()),s},i=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,h=r.space=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},p=r.id=e=>a(i),o=[],c=(r,l=32,n,a=r.charCodeAt(0),s=r.length,h=o[a],p=r.toUpperCase()!==r)=>o[a]=(a,o,c=e)=>o<l&&(s<2||t.substr(e,s)==r)&&(!p||!i(t.charCodeAt(e+s)))&&(e+=s,n(a,o))||(e=c,h?.(a,o)),g=(e,t,r=0)=>c(e,t,((l,n)=>l&&(n=s(t-r/2))&&[e,l,n])),f=(e,t,r)=>c(e,t,(l=>r?l&&[e,l]:!l&&(l=s(t-.5))&&[e,l])),u=(e,t,r)=>{c(e,t,((l,n)=>(l||r)&&((n=s(t))||r)&&((!l||l[0]!==e)&&(l=[e,l]),(n||r)&&l.push(n),l)))};const d=e=>Array.isArray(e)?m[e[0]](...e.slice(1)):t=>t?.[e],m={},A=(e,t,r=m[e])=>m[e]=(...e)=>t(...e)||r&&r(...e),b=e=>(e=r(e),t=>(e.call?e:e=d(e))(t)),$=(e,t,r)=>r.length?r.length>1?(g(e,Math.abs(t),t<0),A(e,((e,t)=>t&&(e=d(e),t=d(t),e.length||t.length?l=>r(e(l),t(l)):(e=r(e(),t()),()=>e))))):(f(e,t),A(e,((e,t)=>!t&&((e=d(e)).length?t=>r(e(t)):(e=r(e()),()=>e))))):(u(e,Math.abs(t),t<0),A(e,((...e)=>(e=e.map(d),t=>r(...e.map((e=>e(t)))))))),y=e=>e?l():["",(e=+a((e=>46===e||e>=48&&e<=57||(69===e||101===e?2:0))))!=e?l():e],C=(e,t,r,l)=>(c(e,t,(r=>r?["++"===e?"-":"+",[e,r],["",1]]:[e,s(t-1)])),A(e,l=(e,t)=>"("===e[0]?l(e[1]):"."===e[0]?(t=e[2],e=d(e[1]),l=>r(e(l),t)):"["===e[0]?([,e,t]=e,e=d(e),t=d(t),l=>r(e(l),t(l))):t=>r(t,e)));A("",(e=>()=>e)),o[34]=e=>e?l():["",(a()+a((e=>e-34?1:0))+(a()||l("Bad string"))).slice(1,-1)],o[46]=e=>!e&&y();for(let e=0;e<9;e++)o[48+e]=y;$(",",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)),C("++",15,((e,t)=>++e[t])),C("--",15,((e,t)=>--e[t])),c("[",18,(e=>e&&["[",e,s(0,93)||l()])),A("[",((e,t)=>t&&(e=d(e),t=d(t),r=>e(r)[t(r)]))),c(".",18,((e,t)=>e&&(t=s(18))&&[".",e,t])),A(".",((e,t)=>(e=d(e),t=t[0]?t:t[1],r=>e(r)[t]))),c("(",18,(e=>!e&&["(",s(0,41)||l()])),c("(",18,((e,t)=>e&&((t=s(0,41))?["(",e,t]:["(",e,""]))),A("(",((e,t,r,l)=>null==t?d(e):(l=""==t?()=>[]:","===t[0]?(t=t.slice(1).map(d),e=>t.map((t=>t(e)))):(t=d(t),e=>[t(e)]),"."===e[0]?(r=e[2],e=d(e[1]),t=>e(t)[r](...l(t))):"["===e[0]?(r=d(e[2]),e=d(e[1]),t=>e(t)[r(t)](...l(t))):(e=d(e),t=>e(t)(...l(t))))));let x={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},E=r=>(n,s,i="")=>{for(n&&l("Unexpected string"),a();(s=t.charCodeAt(e))-r;)92===s?(a(),s=a(),i+=x[s]||s):i+=a();return a(),["",i]};$("===",9,((e,t)=>e===t)),$("!==",9,((e,t)=>e!==t)),$("~",15,(e=>~e)),c("?",3,((e,t,r)=>e&&(t=s(2,58))&&["?",e,t,s(3)])),A("?",((e,t,r)=>(e=d(e),t=d(t),r=d(r),l=>e(l)?t(l):r(l)))),$("??",6,((e,t)=>e??t)),c("?.",18,(e=>e&&["?.",e])),A("?.",(e=>(e=d(e),t=>e(t)||(()=>{})))),c("?.",18,((e,t)=>e&&!(t=s(18))?.map&&["?.",e,t])),A("?.",((e,t)=>t&&(e=d(e),r=>e(r)?.[t]))),A("(",((e,t,r,l)=>null!=t&&"?."===e[0]&&(l=""==t?()=>[]:","===t[0]?(t=t.slice(1).map(d),e=>t.map((t=>t(e)))):(t=d(t),e=>[t(e)]),r=e[2],e=d(e[1]),t=>e(t)?.[r](...l(t))))),$("in",10,((e,t)=>e in t)),o[34]=E(34),o[39]=E(39),c("/*",20,((r,l)=>(a((r=>42!==r&&47!==t.charCodeAt(e+1))),a(2),r||s(l)||[""]))),c("//",20,((e,t)=>(a((e=>e>=32)),e||s(t)||[""]))),c("null",20,(e=>e?l():["",null])),c("true",20,(e=>e?l():["",!0])),c("false",20,(e=>e?l():["",!1])),c("undefined",20,(e=>e?l():["",void 0])),$(";",-20,((...e)=>{for(let t=e.length;t--;)if(null!=e[t])return e[t]})),$("**",-14,((e,t)=>e**t)),c("[",20,(e=>!e&&["[",s(0,93)||""])),A("[",((e,t)=>!t&&(e?","===e[0]?(e=e.slice(1).map(d),t=>e.map((e=>e(t)))):(e=d(e),t=>[e(t)]):()=>[]))),c("{",20,(e=>!e&&["{",s(0,125)||""])),A("{",((e,t)=>e?","===e[0]?(e=e.slice(1).map(d),t=>Object.fromEntries(e.map((e=>e(t))))):":"===e[0]?(e=d(e),t=>Object.fromEntries([e(t)])):(t=d(e),r=>({[e]:t(r)})):e=>({}))),c(":",1.1,((e,t)=>[":",e,s(1.1)||l()])),A(":",((e,t)=>(t=d(t),e=Array.isArray(e)?d(e):(e=>e).bind(0,e),r=>[e(r),t(r)])));export{g as binary,d as compile,t as cur,b as default,l as err,s as expr,p as id,e as idx,i as isId,n as longErr,o as lookup,u as nary,A as operator,m as operators,r as parse,$ as set,a as skip,h as space,c as token,f as unary};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "7.4.6",
3
+ "version": "7.5.1",
4
4
  "description": "Fast and tiny expression evaluator with minimal syntax.",
5
5
  "main": "subscript.js",
6
6
  "module": "subscript.js",
package/parse.js CHANGED
@@ -1,95 +1,95 @@
1
- const SPACE=32
1
+ const SPACE = 32
2
2
 
3
3
  // current string, index and collected ids
4
4
  export let idx, cur,
5
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
- err = (msg='Bad syntax', frag=cur[idx], prev=cur.slice(0,idx).split('\n'), last=prev.pop()) => {
10
- throw SyntaxError(`${msg} ${frag ? `\`${frag}\` ` : ''}at ${prev.length}:${last.length}`, prev.length)
11
- },
12
-
13
- longErr = (msg='Bad syntax',
14
- frag=cur[idx],
15
- lines=cur.slice(0,idx).split('\n'),
16
- last=lines.pop()
17
- ) => {
18
- let before = cur.slice(idx-10,idx).split('\n').pop()
19
- let after = cur.slice(idx+1, idx+10).split('\n').shift()
20
- let location = lines.length + ':' + last.length
21
- throw EvalError(`${msg} at ${location} \`${before+frag+after}\`\n${' '.repeat(18 + msg.length + location.length + before.length + 1)}^`)
22
- },
23
-
24
- skip = (is=1, from=idx, l) => {
25
- if (typeof is == 'number') idx += is
26
- else while (l=is(cur.charCodeAt(idx))) idx+=l
27
- return cur.slice(from, idx)
28
- },
29
-
30
- // a + b - c
31
- expr = (prec=0, end, cc, token, newNode, fn) => {
32
- // chunk/token parser
33
- while (
34
- ( cc=parse.space() ) && // till not end
35
- // FIXME: extra work is happening here, when lookup bails out due to lower precedence -
36
- // it makes extra `space` call for parent exprs on the same character to check precedence again
37
- (newNode =
38
- ((fn=lookup[cc]) && fn(token, prec)) ?? // if operator with higher precedence isn't found
39
- (!token && parse.id()) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
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
+ err = (msg = 'Bad syntax', frag = cur[idx], prev = cur.slice(0, idx).split('\n'), last = prev.pop()) => {
10
+ throw SyntaxError(`${msg} ${frag ? `\`${frag}\` ` : ''}at ${prev.length}:${last.length}`, prev.length)
11
+ },
12
+
13
+ longErr = (msg = 'Bad syntax',
14
+ frag = cur[idx],
15
+ lines = cur.slice(0, idx).split('\n'),
16
+ last = lines.pop()
17
+ ) => {
18
+ let before = cur.slice(idx - 10, idx).split('\n').pop()
19
+ let after = cur.slice(idx + 1, idx + 10).split('\n').shift()
20
+ let location = lines.length + ':' + last.length
21
+ throw EvalError(`${msg} at ${location} \`${before + frag + after}\`\n${' '.repeat(18 + msg.length + location.length + before.length + 1)}^`)
22
+ },
23
+
24
+ skip = (is = 1, from = idx, l) => {
25
+ if (typeof is == 'number') idx += is
26
+ else while (l = is(cur.charCodeAt(idx))) idx += l
27
+ return cur.slice(from, idx)
28
+ },
29
+
30
+ // a + b - c
31
+ expr = (prec = 0, end, cc, token, newNode, fn) => {
32
+ // chunk/token parser
33
+ while (
34
+ (cc = parse.space()) && // till not end
35
+ // FIXME: extra work is happening here, when lookup bails out due to lower precedence -
36
+ // it makes extra `space` call for parent exprs on the same character to check precedence again
37
+ (newNode =
38
+ ((fn = lookup[cc]) && fn(token, prec)) ?? // if operator with higher precedence isn't found
39
+ (!token && parse.id()) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
40
+ )
41
+ ) token = newNode;
42
+
43
+ // check end character
44
+ // FIXME: can't show "Unclosed paren", because can be unknown operator within group as well
45
+ if (end) cc == end ? idx++ : err()
46
+
47
+ return token
48
+ },
49
+
50
+ isId = c =>
51
+ (c >= 48 && c <= 57) || // 0..9
52
+ (c >= 65 && c <= 90) || // A...Z
53
+ (c >= 97 && c <= 122) || // a...z
54
+ c == 36 || c == 95 || // $, _,
55
+ (c >= 192 && c != 215 && c != 247), // any non-ASCII
56
+
57
+ // skip space chars, return first non-space character
58
+ space = parse.space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
59
+
60
+ id = parse.id = n => skip(isId),
61
+
62
+ // operator/token lookup table
63
+ // lookup[0] is id parser to let configs redefine it
64
+ lookup = [],
65
+
66
+
67
+ // create operator checker/mapper (see examples)
68
+ token = (
69
+ op,
70
+ prec = SPACE,
71
+ map,
72
+ c = op.charCodeAt(0),
73
+ l = op.length,
74
+ prev = lookup[c],
75
+ word = op.toUpperCase() !== op // make sure word boundary comes after word operator
76
+ ) => lookup[c] = (a, curPrec, from = idx) =>
77
+ (curPrec < prec && (l < 2 || cur.substr(idx, l) == op) && (!word || !isId(cur.charCodeAt(idx + l))) && (idx += l, map(a, curPrec))) ||
78
+ (idx = from, prev?.(a, curPrec)),
79
+
80
+ // right assoc is indicated by negative precedence (meaning go from right to left)
81
+ binary = (op, prec, right = 0) => token(op, prec, (a, b) => a && (b = expr(prec - right / 2)) && [op, a, b]),
82
+ unary = (op, prec, post) => token(op, prec, a => post ? (a && [op, a]) : (!a && (a = expr(prec - .5)) && [op, a])),
83
+ nary = (op, prec, skips) => {
84
+ token(op, prec, (a, b) => (
85
+ (a || skips) && // if lhs exists or we're ok to skip
86
+ (b = expr(prec), b || skips) && // either rhs exists or we're ok to skip rhs
87
+ (
88
+ (!a || a[0] !== op) && (a = [op, a]), // if beginning of sequence - init node
89
+ (b || skips) && a.push(b),
90
+ a
91
+ ))
40
92
  )
41
- ) token = newNode;
42
-
43
- // check end character
44
- // FIXME: can't show "Unclose paren", because can be unknown operator within group as well
45
- if (end) cc==end?idx++:err()
46
-
47
- return token
48
- },
49
-
50
- isId = c =>
51
- (c >= 48 && c <= 57) || // 0..9
52
- (c >= 65 && c <= 90) || // A...Z
53
- (c >= 97 && c <= 122) || // a...z
54
- c == 36 || c == 95 || // $, _,
55
- (c >= 192 && c != 215 && c != 247), // any non-ASCII
56
-
57
- // skip space chars, return first non-space character
58
- space = parse.space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
59
-
60
- id = parse.id = n => skip(isId),
61
-
62
- // operator/token lookup table
63
- // lookup[0] is id parser to let configs redefine it
64
- lookup = [],
65
-
66
-
67
- // create operator checker/mapper (see examples)
68
- token = (
69
- op,
70
- prec=SPACE,
71
- map,
72
- c=op.charCodeAt(0),
73
- l=op.length,
74
- prev=lookup[c],
75
- word=op.toUpperCase()!==op // make sure word boundary comes after word operator
76
- ) => lookup[c] = (a, curPrec, from=idx) =>
77
- (curPrec<prec && (l<2||cur.substr(idx,l)==op) && (!word||!isId(cur.charCodeAt(idx+l))) && (idx+=l, map(a, curPrec))) ||
78
- (idx=from, prev?.(a, curPrec)),
79
-
80
- // right assoc is indicated by negative precedence (meaning go from right to left)
81
- binary = (op, prec, right=0) => token(op, prec, (a, b) => a && (b=expr(prec-right/2)) && [op,a,b] ),
82
- unary = (op, prec, post) => token(op, prec, a => post ? (a && [op, a]) : (!a && (a=expr(prec-.5)) && [op, a])),
83
- nary = (op, prec, skips) => {
84
- token(op, prec, (a, b) => (
85
- (a || skips) && // if lhs exists or we're ok to skip
86
- (b=expr(prec), b||skips) && // either rhs exists or we're ok to skip rhs
87
- (
88
- (!a || a[0] !== op) && (a = [op,a]), // if beginning of sequence - init node
89
- (b || skips) && a.push(b),
90
- a
91
- ))
92
- )
93
- }
93
+ }
94
94
 
95
95
  export default parse
package/subscript.js CHANGED
@@ -1,128 +1,116 @@
1
1
  import parse, { lookup, nary, binary, unary, token, skip, err, expr } from './parse.js'
2
2
  import compile, { operator } from './compile.js'
3
3
 
4
- const OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, PERIOD=46, _0=48, _9=57,
5
- PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
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 = (op, prec, fn) =>
13
- (fn[0]||fn[1]) ? (prec ? token(op,prec,fn[0]) : (lookup[op.charCodeAt(0)||1]=fn[0]), operator(op, fn[1])) : (
14
- !fn.length ? (
15
- nary(op, Math.abs(prec), prec<0),
16
- operator(op, (...args) => (args=args.map(compile), ctx => fn(...args.map(arg=>arg(ctx)))))
17
- ) :
18
- fn.length > 1 ? (
19
- binary(op, Math.abs(prec), prec<0),
20
- operator(op,
21
- (a,b) => b && (a=compile(a),b=compile(b), !a.length&&!b.length ? (a=fn(a(),b()),()=>a) : ctx => fn(a(ctx),b(ctx)))
22
- )
23
- ) :
24
- (
25
- unary(op, prec),
26
- operator(op, (a,b) => !b && (a=compile(a), !a.length ? (a=fn(a()),()=>a) : ctx => fn(a(ctx))))
4
+ const OPAREN = 40, CPAREN = 41, OBRACK = 91, CBRACK = 93, SPACE = 32, DQUOTE = 34, PERIOD = 46, _0 = 48, _9 = 57,
5
+ PREC_SEQ = 1, PREC_SOME = 4, PREC_EVERY = 5, PREC_OR = 6, PREC_XOR = 7, PREC_AND = 8,
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 = (op, prec, fn) => (
13
+ !fn.length ? (
14
+ nary(op, Math.abs(prec), prec < 0),
15
+ operator(op, (...args) => (args = args.map(compile), ctx => fn(...args.map(arg => arg(ctx)))))
16
+ ) :
17
+ fn.length > 1 ? (
18
+ binary(op, Math.abs(prec), prec < 0),
19
+ operator(op,
20
+ (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
+ )
22
+ ) :
23
+ (
24
+ unary(op, prec),
25
+ operator(op, (a, b) => !b && (a = compile(a), !a.length ? (a = fn(a()), () => a) : ctx => fn(a(ctx))))
26
+ )
27
+ ),
28
+
29
+ num = a => a ? err() : ['', (a = +skip(c => c === PERIOD || (c >= _0 && c <= _9) || (c === 69 || c === 101 ? 2 : 0))) != a ? err() : a],
30
+
31
+ // create increment-assign pair from fn
32
+ inc = (op, prec, fn, ev) => (
33
+ token(op, prec, a => a ? [op === '++' ? '-' : '+', [op, a], ['', 1]] : [op, expr(prec - 1)]), // ++a → [++, a], a++ → [-,[++,a],1]
34
+ operator(op, ev = (a, b) => (
35
+ a[0] === '(' ? ev(a[1]) : // ++(((a)))
36
+ a[0] === '.' ? (b = a[2], a = compile(a[1]), ctx => fn(a(ctx), b)) : // ++a.b
37
+ a[0] === '[' ? ([, a, b] = a, a = compile(a), b = compile(b), ctx => fn(a(ctx), b(ctx))) : // ++a[b]
38
+ (ctx => fn(ctx, a)) // ++a
39
+ ))
27
40
  )
28
- ),
29
-
30
- num = a => a ? err() : ['', (a=+skip(c => c === PERIOD || (c>=_0 && c<=_9) || (c===69||c===101?2:0)))!=a?err():a],
31
- // create increment-assign pair from fn
32
- inc = (op, prec, fn, ev) => [op, prec, [
33
- a => a ? [op==='++'?'-':'+',[op,a],['',1]] : [op,expr(prec-1)], // ++a → [++, a], a++ → [-,[++,a],1]
34
- ev = (a,b) => (
35
- a[0] === '(' ? ev(a[1]) : // ++(((a)))
36
- a[0] === '.' ? (b=a[2], a=compile(a[1]), ctx => fn(a(ctx), b)) : // ++a.b
37
- a[0] === '[' ? ([,a,b]=a, a=compile(a),b=compile(b), ctx => fn(a(ctx),b(ctx))) : // ++a[b]
38
- (ctx => fn(ctx,a)) // ++a
39
- )
40
- ]],
41
-
42
- list = [
43
- // literals
44
- // null operator returns first value (needed for direct literals)
45
- '',, [,v => () => v],
46
-
47
- '"',, [
48
- (a) => a ? err() : ['', (skip() + skip(c => c - DQUOTE ? 1 : 0) + (skip()||err('Bad string'))).slice(1,-1)],
49
- ],
50
-
51
- // .1
52
- '.',, [a=>!a && num()],
53
-
54
- // 0-9
55
- ...Array(10).fill(0).flatMap((_,i)=>[''+i,0,[num]]),
56
-
57
- // sequences
58
- ',', PREC_SEQ, (...args) => args[args.length-1],
59
- '||', PREC_SOME, (...args) => { let i=0, v; for (; !v && i < args.length; ) v = args[i++]; return v },
60
- '&&', PREC_EVERY, (...args) => { let i=0, v=true; for (; v && i < args.length; ) v = args[i++]; return v },
61
-
62
- // binaries
63
- '+', PREC_SUM, (a,b)=>a+b,
64
- '-', PREC_SUM, (a,b)=>a-b,
65
- '*', PREC_MULT, (a,b)=>a*b,
66
- '/', PREC_MULT, (a,b)=>a/b,
67
- '%', PREC_MULT, (a,b)=>a%b,
68
- '|', PREC_OR, (a,b)=>a|b,
69
- '&', PREC_AND, (a,b)=>a&b,
70
- '^', PREC_XOR, (a,b)=>a^b,
71
- '==', PREC_EQ, (a,b)=>a==b,
72
- '!=', PREC_EQ, (a,b)=>a!=b,
73
- '>', PREC_COMP, (a,b)=>a>b,
74
- '>=', PREC_COMP, (a,b)=>a>=b,
75
- '<', PREC_COMP, (a,b)=>a<b,
76
- '<=', PREC_COMP, (a,b)=>a<=b,
77
- '>>', PREC_SHIFT, (a,b)=>a>>b,
78
- '>>>', PREC_SHIFT, (a,b)=>a>>>b,
79
- '<<', PREC_SHIFT, (a,b)=>a<<b,
80
-
81
- // unaries
82
- '+', PREC_UNARY, a => +a,
83
- '-', PREC_UNARY, a => -a,
84
- '!', PREC_UNARY, a => !a,
85
-
86
- // increments
87
- ...inc('++', PREC_UNARY, (a,b) => ++a[b]),
88
- ...inc('--', PREC_UNARY, (a,b) => --a[b]),
89
-
90
- // a[b]
91
- '[', PREC_CALL, [
92
- a => a && ['[', a, expr(0,CBRACK)||err()],
93
- (a,b) => b && (a=compile(a), b=compile(b), ctx => a(ctx)[b(ctx)])
94
- ],
95
-
96
- // a.b
97
- '.', PREC_CALL, [
98
- (a,b) => a && (b=expr(PREC_CALL)) && ['.',a,b],
99
- (a,b) => (a=compile(a),b=!b[0]?b[1]:b, ctx => a(ctx)[b]) // a.true, a.1 → needs to work fine
100
- ],
101
-
102
- // (a,b,c), (a)
103
- '(', PREC_CALL, [
104
- a => !a && ['(', expr(0,CPAREN)||err()],
105
- compile
106
- ],
107
-
108
- // a(b,c,d), a()
109
- '(', PREC_CALL, [
110
- (a,b) => a && (b = expr(0,CPAREN), b ? ['(', a, b] : ['(', a, '']),
111
- (a,b,path,args) => b!=null && (
112
- args = b=='' ? () => [] : // a()
113
- b[0] === ',' ? (b=b.slice(1).map(compile), ctx => b.map(a=>a(ctx))) : // a(b,c)
114
- (b=compile(b), ctx => [b(ctx)]), // a(b)
115
-
116
- a[0] === '.' ? (path=a[2], a=compile(a[1]), ctx => a(ctx)[path](...args(ctx))) : // a.b(...args)
117
- a[0] === '[' ? (path=compile(a[2]), a=compile(a[1]), ctx => a(ctx)[path(ctx)](...args(ctx))) : // a[b](...args)
118
- (a=compile(a), ctx => a(ctx)(...args(ctx))) // a(...args)
119
- )
120
- ]
121
- ]
122
-
123
- for (;list[2];) set(...list.splice(0,3))
41
+
42
+
43
+ // literals
44
+ // null operator returns first value (needed for direct literals)
45
+ operator('', v => () => v)
46
+
47
+ // "a"
48
+ lookup[DQUOTE] = (a) => a ? err() : ['', (skip() + skip(c => c - DQUOTE ? 1 : 0) + (skip() || err('Bad string'))).slice(1, -1)]
49
+
50
+ // .1
51
+ lookup[PERIOD] = a => !a && num()
52
+
53
+ // 0-9
54
+ for (let i = 0; i < 9; i++) lookup[_0 + i] = num
55
+
56
+ // sequences
57
+ set(',', PREC_SEQ, (...args) => args[args.length - 1])
58
+ set('||', PREC_SOME, (...args) => { let i = 0, v; for (; !v && i < args.length;) v = args[i++]; return v })
59
+ set('&&', PREC_EVERY, (...args) => { let i = 0, v = true; for (; v && i < args.length;) v = args[i++]; return v })
60
+
61
+ // binaries
62
+ set('+', PREC_SUM, (a, b) => a + b)
63
+ set('-', PREC_SUM, (a, b) => a - b)
64
+ set('*', PREC_MULT, (a, b) => a * b)
65
+ set('/', PREC_MULT, (a, b) => a / b)
66
+ set('%', PREC_MULT, (a, b) => a % b)
67
+ set('|', PREC_OR, (a, b) => a | b)
68
+ set('&', PREC_AND, (a, b) => a & b)
69
+ set('^', PREC_XOR, (a, b) => a ^ b)
70
+ set('==', PREC_EQ, (a, b) => a == b)
71
+ set('!=', PREC_EQ, (a, b) => a != b)
72
+ set('>', PREC_COMP, (a, b) => a > b)
73
+ set('>=', PREC_COMP, (a, b) => a >= b)
74
+ set('<', PREC_COMP, (a, b) => a < b)
75
+ set('<=', PREC_COMP, (a, b) => a <= b)
76
+ set('>>', PREC_SHIFT, (a, b) => a >> b)
77
+ set('>>>', PREC_SHIFT, (a, b) => a >>> b)
78
+ set('<<', PREC_SHIFT, (a, b) => a << b)
79
+
80
+ // unaries
81
+ set('+', PREC_UNARY, a => +a)
82
+ set('-', PREC_UNARY, a => -a)
83
+ set('!', PREC_UNARY, a => !a)
84
+
85
+ // increments
86
+ inc('++', PREC_UNARY, (a, b) => ++a[b])
87
+ inc('--', PREC_UNARY, (a, b) => --a[b])
88
+
89
+ // a[b]
90
+ token('[', PREC_CALL, a => a && ['[', a, expr(0, CBRACK) || err()])
91
+ operator('[', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx)[b(ctx)]))
92
+
93
+ // a.b
94
+ token('.', PREC_CALL, (a, b) => a && (b = expr(PREC_CALL)) && ['.', a, b])
95
+ operator('.', (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
+ // (a,b,c), (a)
98
+ token('(', PREC_CALL, a => !a && ['(', expr(0, CPAREN) || err()])
99
+
100
+ // a(b,c,d), a()
101
+ token('(', PREC_CALL, (a, b) => a && (b = expr(0, CPAREN), b ? ['(', a, b] : ['(', a, '']))
102
+ operator('(', (a, b, path, args) => b == null ? compile(a, b) : (
103
+ args = b == '' ? () => [] : // a()
104
+ b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(a => a(ctx))) : // a(b,c)
105
+ (b = compile(b), ctx => [b(ctx)]), // a(b)
106
+
107
+ a[0] === '.' ? (path = a[2], a = compile(a[1]), ctx => a(ctx)[path](...args(ctx))) : // a.b(...args)
108
+ a[0] === '[' ? (path = compile(a[2]), a = compile(a[1]), ctx => a(ctx)[path(ctx)](...args(ctx))) : // a[b](...args)
109
+ (a = compile(a), ctx => a(ctx)(...args(ctx))) // a(...args)
110
+ )
111
+ )
124
112
 
125
113
  export default subscript
126
- export {set}
114
+ export { set }
127
115
  export * from './parse.js'
128
116
  export * from './compile.js'
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- let t,e,l=l=>(t=0,e=l,l=s(),e[t]?r():l||""),r=(l="Bad syntax",r=e[t],a=e.slice(0,t).split("\n"),n=a.pop())=>{throw SyntaxError(`${l} ${r?`\`${r}\` `:""}at ${a.length}:${n.length}`,a.length)},a=(l="Bad syntax",r=e[t],a=e.slice(0,t).split("\n"),n=a.pop())=>{let s=e.slice(t-10,t).split("\n").pop(),h=e.slice(t+1,t+10).split("\n").shift(),p=a.length+":"+n.length;throw EvalError(`${l} at ${p} \`${s+r+h}\`\n${" ".repeat(18+l.length+p.length+s.length+1)}^`)},n=(l=1,r=t,a)=>{if("number"==typeof l)t+=l;else for(;a=l(e.charCodeAt(t));)t+=a;return e.slice(r,t)},s=(e=0,a,n,s,h,p)=>{for(;(n=l.space())&&(h=((p=i[n])&&p(s,e))??(!s&&l.id()));)s=h;return a&&(n==a?t++:r()),s},h=t=>t>=48&&t<=57||t>=65&&t<=90||t>=97&&t<=122||36==t||95==t||t>=192&&215!=t&&247!=t,p=l.space=l=>{for(;(l=e.charCodeAt(t))<=32;)t++;return l},o=l.id=t=>n(h),i=[],c=(l,r=32,a,n=l.charCodeAt(0),s=l.length,p=i[n],o=l.toUpperCase()!==l)=>i[n]=(n,i,c=t)=>i<r&&(s<2||e.substr(t,s)==l)&&(!o||!h(e.charCodeAt(t+s)))&&(t+=s,a(n,i))||(t=c,p?.(n,i)),g=(t,e,l=0)=>c(t,e,((r,a)=>r&&(a=s(e-l/2))&&[t,r,a])),f=(t,e,l)=>c(t,e,(r=>l?r&&[t,r]:!r&&(r=s(e-.5))&&[t,r])),d=(t,e,l)=>{c(t,e,((r,a)=>(r||l)&&((a=s(e))||l)&&((!r||r[0]!==t)&&(r=[t,r]),(a||l)&&r.push(a),r)))};const u=t=>Array.isArray(t)?$[t[0]](...t.slice(1)):e=>e?.[t],$={},A=(t,e,l=$[t])=>$[t]=(...t)=>e(...t)||l&&l(...t),y=t=>(t=l(t),e=>(t.call?t:t=u(t))(e)),C=(t,e,l)=>l[0]||l[1]?(e?c(t,e,l[0]):i[t.charCodeAt(0)||1]=l[0],A(t,l[1])):l.length?l.length>1?(g(t,Math.abs(e),e<0),A(t,((t,e)=>e&&(t=u(t),e=u(e),t.length||e.length?r=>l(t(r),e(r)):(t=l(t(),e()),()=>t))))):(f(t,e),A(t,((t,e)=>!e&&((t=u(t)).length?e=>l(t(e)):(t=l(t()),()=>t))))):(d(t,Math.abs(e),e<0),A(t,((...t)=>(t=t.map(u),e=>l(...t.map((t=>t(e)))))))),m=t=>t?r():["",(t=+n((t=>46===t||t>=48&&t<=57||(69===t||101===t?2:0))))!=t?r():t],b=(t,e,l,r)=>[t,e,[l=>l?["++"===t?"-":"+",[t,l],["",1]]:[t,s(e-1)],r=(t,e)=>"("===t[0]?r(t[1]):"."===t[0]?(e=t[2],t=u(t[1]),r=>l(t(r),e)):"["===t[0]?([,t,e]=t,t=u(t),e=u(e),r=>l(t(r),e(r))):e=>l(e,t)]],x=["",,[,t=>()=>t],'"',,[t=>t?r():["",(n()+n((t=>t-34?1:0))+(n()||r("Bad string"))).slice(1,-1)]],".",,[t=>!t&&m()],...Array(10).fill(0).flatMap(((t,e)=>[""+e,0,[m]])),",",1,(...t)=>t[t.length-1],"||",4,(...t)=>{let e,l=0;for(;!e&&l<t.length;)e=t[l++];return e},"&&",5,(...t)=>{let e=0,l=!0;for(;l&&e<t.length;)l=t[e++];return l},"+",12,(t,e)=>t+e,"-",12,(t,e)=>t-e,"*",13,(t,e)=>t*e,"/",13,(t,e)=>t/e,"%",13,(t,e)=>t%e,"|",6,(t,e)=>t|e,"&",8,(t,e)=>t&e,"^",7,(t,e)=>t^e,"==",9,(t,e)=>t==e,"!=",9,(t,e)=>t!=e,">",10,(t,e)=>t>e,">=",10,(t,e)=>t>=e,"<",10,(t,e)=>t<e,"<=",10,(t,e)=>t<=e,">>",11,(t,e)=>t>>e,">>>",11,(t,e)=>t>>>e,"<<",11,(t,e)=>t<<e,"+",15,t=>+t,"-",15,t=>-t,"!",15,t=>!t,...b("++",15,((t,e)=>++t[e])),...b("--",15,((t,e)=>--t[e])),"[",18,[t=>t&&["[",t,s(0,93)||r()],(t,e)=>e&&(t=u(t),e=u(e),l=>t(l)[e(l)])],".",18,[(t,e)=>t&&(e=s(18))&&[".",t,e],(t,e)=>(t=u(t),e=e[0]?e:e[1],l=>t(l)[e])],"(",18,[t=>!t&&["(",s(0,41)||r()],u],"(",18,[(t,e)=>t&&((e=s(0,41))?["(",t,e]:["(",t,""]),(t,e,l,r)=>null!=e&&(r=""==e?()=>[]:","===e[0]?(e=e.slice(1).map(u),t=>e.map((e=>e(t)))):(e=u(e),t=>[e(t)]),"."===t[0]?(l=t[2],t=u(t[1]),e=>t(e)[l](...r(e))):"["===t[0]?(l=u(t[2]),t=u(t[1]),e=>t(e)[l(e)](...r(e))):(t=u(t),e=>t(e)(...r(e))))]];for(;x[2];)C(...x.splice(0,3));export{g as binary,u as compile,e as cur,y as default,r as err,s as expr,o as id,t as idx,h as isId,a as longErr,i as lookup,d as nary,A as operator,$ as operators,l as parse,C as set,n as skip,p as space,c as token,f as unary};
1
+ let t,e,l=l=>(t=0,e=l,l=s(),e[t]?r():l||""),r=(l="Bad syntax",r=e[t],n=e.slice(0,t).split("\n"),a=n.pop())=>{throw SyntaxError(`${l} ${r?`\`${r}\` `:""}at ${n.length}:${a.length}`,n.length)},n=(l="Bad syntax",r=e[t],n=e.slice(0,t).split("\n"),a=n.pop())=>{let s=e.slice(t-10,t).split("\n").pop(),h=e.slice(t+1,t+10).split("\n").shift(),p=n.length+":"+a.length;throw EvalError(`${l} at ${p} \`${s+r+h}\`\n${" ".repeat(18+l.length+p.length+s.length+1)}^`)},a=(l=1,r=t,n)=>{if("number"==typeof l)t+=l;else for(;n=l(e.charCodeAt(t));)t+=n;return e.slice(r,t)},s=(e=0,n,a,s,h,p)=>{for(;(a=l.space())&&(h=((p=g[a])&&p(s,e))??(!s&&l.id()));)s=h;return n&&(a==n?t++:r()),s},h=t=>t>=48&&t<=57||t>=65&&t<=90||t>=97&&t<=122||36==t||95==t||t>=192&&215!=t&&247!=t,p=l.space=l=>{for(;(l=e.charCodeAt(t))<=32;)t++;return l},o=l.id=t=>a(h),g=[],i=(l,r=32,n,a=l.charCodeAt(0),s=l.length,p=g[a],o=l.toUpperCase()!==l)=>g[a]=(a,g,i=t)=>g<r&&(s<2||e.substr(t,s)==l)&&(!o||!h(e.charCodeAt(t+s)))&&(t+=s,n(a,g))||(t=i,p?.(a,g)),c=(t,e,l=0)=>i(t,e,((r,n)=>r&&(n=s(e-l/2))&&[t,r,n])),d=(t,e,l)=>i(t,e,(r=>l?r&&[t,r]:!r&&(r=s(e-.5))&&[t,r])),f=(t,e,l)=>{i(t,e,((r,n)=>(r||l)&&((n=s(e))||l)&&((!r||r[0]!==t)&&(r=[t,r]),(n||l)&&r.push(n),r)))};const u=t=>Array.isArray(t)?$[t[0]](...t.slice(1)):e=>e?.[t],$={},y=(t,e,l=$[t])=>$[t]=(...t)=>e(...t)||l&&l(...t),A=t=>(t=l(t),e=>(t.call?t:t=u(t))(e)),m=(t,e,l)=>l.length?l.length>1?(c(t,Math.abs(e),e<0),y(t,((t,e)=>e&&(t=u(t),e=u(e),t.length||e.length?r=>l(t(r),e(r)):(t=l(t(),e()),()=>t))))):(d(t,e),y(t,((t,e)=>!e&&((t=u(t)).length?e=>l(t(e)):(t=l(t()),()=>t))))):(f(t,Math.abs(e),e<0),y(t,((...t)=>(t=t.map(u),e=>l(...t.map((t=>t(e)))))))),C=t=>t?r():["",(t=+a((t=>46===t||t>=48&&t<=57||(69===t||101===t?2:0))))!=t?r():t],b=(t,e,l,r)=>(i(t,e,(l=>l?["++"===t?"-":"+",[t,l],["",1]]:[t,s(e-1)])),y(t,r=(t,e)=>"("===t[0]?r(t[1]):"."===t[0]?(e=t[2],t=u(t[1]),r=>l(t(r),e)):"["===t[0]?([,t,e]=t,t=u(t),e=u(e),r=>l(t(r),e(r))):e=>l(e,t)));y("",(t=>()=>t)),g[34]=t=>t?r():["",(a()+a((t=>t-34?1:0))+(a()||r("Bad string"))).slice(1,-1)],g[46]=t=>!t&&C();for(let t=0;t<9;t++)g[48+t]=C;m(",",1,((...t)=>t[t.length-1])),m("||",4,((...t)=>{let e,l=0;for(;!e&&l<t.length;)e=t[l++];return e})),m("&&",5,((...t)=>{let e=0,l=!0;for(;l&&e<t.length;)l=t[e++];return l})),m("+",12,((t,e)=>t+e)),m("-",12,((t,e)=>t-e)),m("*",13,((t,e)=>t*e)),m("/",13,((t,e)=>t/e)),m("%",13,((t,e)=>t%e)),m("|",6,((t,e)=>t|e)),m("&",8,((t,e)=>t&e)),m("^",7,((t,e)=>t^e)),m("==",9,((t,e)=>t==e)),m("!=",9,((t,e)=>t!=e)),m(">",10,((t,e)=>t>e)),m(">=",10,((t,e)=>t>=e)),m("<",10,((t,e)=>t<e)),m("<=",10,((t,e)=>t<=e)),m(">>",11,((t,e)=>t>>e)),m(">>>",11,((t,e)=>t>>>e)),m("<<",11,((t,e)=>t<<e)),m("+",15,(t=>+t)),m("-",15,(t=>-t)),m("!",15,(t=>!t)),b("++",15,((t,e)=>++t[e])),b("--",15,((t,e)=>--t[e])),i("[",18,(t=>t&&["[",t,s(0,93)||r()])),y("[",((t,e)=>e&&(t=u(t),e=u(e),l=>t(l)[e(l)]))),i(".",18,((t,e)=>t&&(e=s(18))&&[".",t,e])),y(".",((t,e)=>(t=u(t),e=e[0]?e:e[1],l=>t(l)[e]))),i("(",18,(t=>!t&&["(",s(0,41)||r()])),i("(",18,((t,e)=>t&&((e=s(0,41))?["(",t,e]:["(",t,""]))),y("(",((t,e,l,r)=>null==e?u(t):(r=""==e?()=>[]:","===e[0]?(e=e.slice(1).map(u),t=>e.map((e=>e(t)))):(e=u(e),t=>[e(t)]),"."===t[0]?(l=t[2],t=u(t[1]),e=>t(e)[l](...r(e))):"["===t[0]?(l=u(t[2]),t=u(t[1]),e=>t(e)[l(e)](...r(e))):(t=u(t),e=>t(e)(...r(e))))));export{c as binary,u as compile,e as cur,A as default,r as err,s as expr,o as id,t as idx,h as isId,n as longErr,g as lookup,f as nary,y as operator,$ as operators,l as parse,m as set,a as skip,p as space,i as token,d as unary};