subscript 7.1.1 → 7.3.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
@@ -62,26 +62,37 @@ Default literals:
62
62
  * `"abc"` strings
63
63
  * `1.2e+3` numbers
64
64
 
65
- 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.
65
+ ## Extending
66
+
67
+ Operators/tokens can be extended via:
68
+
69
+ * `unary(str, prec, postfix=false)` − register unary operator, either prefix or postfix.
70
+ * `binary(str, prec, rightAssoc=false)` − register binary operator, optionally right-associative.
71
+ * `nary(str, prec, allowSkip=false)` − register n-ary (sequence) operator, optionally allowing skipping args.
72
+ * `token(str, prec, fn)` − register custom token or literal. `fn` takes last token as argument and returns calltree node.
73
+ * `operator(str, fn)` − register evaluator for operator. `fn` takes node arguments and returns evaluator function.
66
74
 
67
75
  ```js
68
- import script, { compile } from './subscript.js'
76
+ import script, { operator, unary, binary, token } from './subscript.js'
69
77
 
70
78
  // add ~ unary operator with precedence 15
71
- script.set('~', 15, a => ~a)
79
+ unary('~', 15)
80
+ operator('~', a => ~a)
72
81
 
73
82
  // add === binary operator with precedence 9
74
- script.set('===', 9, (a, b) => a===b)
83
+ binary('===', 9)
84
+ operator('===', (a, b) => a===b)
75
85
 
76
86
  // add literals
77
- script.set('true', 20, [a => ['',true], a => ctx => a[1]])
78
- script.set('false', 20, [a => ['',false], a => ctx => a[1]])
87
+ token('true', 20, a => ['',true])
88
+ token('false', 20, a => ['',false])
89
+ operator('', a => ctx => a[1]])
79
90
  ```
80
91
 
81
92
  See [subscript.js](subscript.js) or [justin.js](./justin.js) for examples.
82
93
 
83
94
 
84
- ## Parser & Compiler
95
+ ## Syntax tree
85
96
 
86
97
  Subscript exposes separate `./parse.js` and `./compile.js` entries. Parser builds AST, compiler converts it to evaluable function.
87
98
 
package/compile.js CHANGED
@@ -1,13 +1,8 @@
1
1
  // build optimized evaluator for the tree
2
- export const compile = (node) => !Array.isArray(node) ? ctx => ctx?.[node] : operator[node[0]](...node.slice(1))
2
+ export const compile = (node) => !Array.isArray(node) ? ctx => ctx?.[node] : operators[node[0]](...node.slice(1)),
3
3
 
4
- const operator = {}
4
+ operators = {},
5
5
 
6
- compile.set = (op, fn, prev=operator[op]) => operator[op] = (...args) => fn(...args) || prev && prev(...args)
7
- compile.binary = (op, fn) => compile.set(op,
8
- (a,b) => b && (a=compile(a),b=compile(b), !a.length&&!b.length ? (a=fn(a(),b()),()=>a) : ctx => fn(a(ctx),b(ctx)))
9
- )
10
- compile.unary = (op, fn) => compile.set(op, (a,b) => !b && (a=compile(a), !a.length ? (a=fn(a()),()=>a) : ctx => fn(a(ctx))))
11
- compile.nary = (op, fn) => compile.set(op, (...args) => (args=args.map(compile), ctx => fn(...args.map(arg=>arg(ctx)))))
6
+ operator = (op, fn, prev=operators[op]) => operators[op] = (...args) => fn(...args) || prev && prev(...args)
12
7
 
13
8
  export default compile
package/justin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // justin lang https://github.com/endojs/Jessie/issues/66
2
2
  import { skip, cur, idx, err, expr } from './parse.js'
3
3
  import compile from './compile.js'
4
- import subscript from './subscript.js'
4
+ import subscript, { set } from './subscript.js'
5
5
 
6
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
7
  PREC_SEQ=1, PREC_COND=3, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
@@ -88,7 +88,7 @@ list = [
88
88
  (a,b) => (b=compile(b),a=Array.isArray(a)?compile(a):(a=>a).bind(0,a), ctx=>[a(ctx),b(ctx)])
89
89
  ]
90
90
  ]
91
- for (;list[2];) subscript.set(...list.splice(0,3))
91
+ for (;list[2];) set(...list.splice(0,3))
92
92
 
93
93
  export default subscript
94
94
  export * from './subscript.js'
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- let e,r,t=t=>(e=0,r=t,t=s(),r[e]?n():t||""),n=(t="Bad syntax",n=r[e],a=r.slice(0,e).split("\n"),s=a.pop())=>{throw SyntaxError(`${t} \`${n}\` at ${a.length}:${s.length}`)},a=(t=1,n=e,a)=>{if("number"==typeof t)e+=t;else for(;a=t(r.charCodeAt(e));)e+=a;return r.slice(n,e)},s=(r=0,a,s,l,o,c)=>{for(;(s=t.space())&&(o=((c=i[s])&&c(l,r))??(!l&&t.id()));)l=o;return a&&(s==a?e++:n()),l},l=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e;t.space=t=>{for(;(t=r.charCodeAt(e))<=32;)e++;return t},t.id=e=>a(l);let i=[];t.set=(t,n=32,a,s=t.charCodeAt(0),o=t.length,c=i[s],p=t.toUpperCase()!==t)=>i[s]=(s,i,h=e)=>i<n&&(o<2||r.substr(e,o)==t)&&(!p||!l(r.charCodeAt(e+o)))&&(e+=o,a(s,i))||(e=h,c?.(s,i)),t.binary=(e,r,n)=>t.set(e,r,((t,a)=>t&&(a=s(r-!!n))&&[e,t,a])),t.unary=(e,r,n)=>t.set(e,r,(t=>!t&&(t=s(r-1))&&[e,t])),t.nary=(e,r)=>t.set(e,r,((t,n)=>t&&(n=s(r))&&(t[0]===e&&t[2]?(t.push(n),t):[e,t,n])));const o=e=>Array.isArray(e)?c[e[0]](...e.slice(1)):r=>r?.[e],c={};o.set=(e,r,t=c[e])=>c[e]=(...e)=>r(...e)||t&&t(...e),o.binary=(e,r)=>o.set(e,((e,t)=>t&&(e=o(e),t=o(t),e.length||t.length?n=>r(e(n),t(n)):(e=r(e(),t()),()=>e)))),o.unary=(e,r)=>o.set(e,((e,t)=>!t&&((e=o(e)).length?t=>r(e(t)):(e=r(e()),()=>e)))),o.nary=(e,r)=>o.set(e,((...e)=>(e=e.map(o),t=>r(...e.map((e=>e(t)))))));const p=e=>(e=t(e),r=>(e.call?e:e=o(e))(r)),h=p.set=(e,r,n)=>n[0]||n[1]?(r?t.set(e,r,n[0]):i[e.charCodeAt(0)||1]=n[0],o.set(e,n[1])):n.length?n.length>1?(t.binary(e,Math.abs(r),r<0),o.binary(e,n)):(t.unary(e,r),o.unary(e,n)):(t.nary(e,r),o.nary(e,n)),y=e=>e?n():["",(e=+a((e=>46===e||e>=48&&e<=57||(69===e||101===e?2:0))))!=e?n():e],f=(e,r,t,n)=>[e,r,[t=>t?["++"===e?"-":"+",[e,t],["",1]]:[e,s(r-1)],n=(e,r)=>"("===e[0]?n(e[1]):"."===e[0]?(r=e[2],e=o(e[1]),n=>t(e(n),r)):"["===e[0]?([,e,r]=e,e=o(e),r=o(r),n=>t(e(n),r(n))):r=>t(r,e)]],u=["",,[,e=>()=>e],'"',,[e=>e?n():["",(a()+a((e=>e-34?1:0))+(a()||n("Bad string"))).slice(1,-1)]],".",,[e=>!e&&y()],...Array(10).fill(0).flatMap(((e,r)=>[""+r,0,[y]])),",",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,...f("++",15,((e,r)=>++e[r])),...f("--",15,((e,r)=>--e[r])),"[",18,[e=>e&&["[",e,s(0,93)||n()],(e,r)=>r&&(e=o(e),r=o(r),t=>e(t)[r(t)])],".",18,[(e,r)=>e&&(r=s(18))&&[".",e,r],(e,r)=>(e=o(e),r=r[0]?r:r[1],t=>e(t)[r])],"(",18,[e=>!e&&["(",s(0,41)||n()],o],"(",18,[e=>e&&["(",e,s(0,41)||""],(e,r,t,n)=>null!=r&&(n=""==r?()=>[]:","===r[0]?(r=r.slice(1).map(o),e=>r.map((r=>r(e)))):(r=o(r),e=>[r(e)]),"."===e[0]?(t=e[2],e=o(e[1]),r=>e(r)[t](...n(r))):"["===e[0]?(t=o(e[2]),e=o(e[1]),r=>e(r)[t(r)](...n(r))):(e=o(e),r=>e(r)(...n(r))))]];for(;u[2];)h(...u.splice(0,3));let d={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},g=t=>(s,l,i="")=>{for(s&&n("Unexpected string"),a();(l=r.charCodeAt(e))-t;)92===l?(a(),l=a(),i+=d[l]||l):i+=a();return a(),["",i]},b=["===",9,(e,r)=>e===r,"!==",9,(e,r)=>e!==r,"~",15,e=>~e,"?",3,[(e,r,t)=>e&&(r=s(2,58))&&["?",e,r,s(3)],(e,r,t)=>(e=o(e),r=o(r),t=o(t),n=>e(n)?r(n):t(n))],"??",6,(e,r)=>e??r,"?.",18,[e=>e&&["?.",e],e=>(e=o(e),r=>e(r)||(()=>{}))],"?.",18,[(e,r)=>e&&!(r=s(18))?.map&&["?.",e,r],(e,r)=>r&&(e=o(e),t=>e(t)?.[r])],"in",10,(e,r)=>e in r,'"',,[g(34)],"'",,[g(39)],"/*",20,[(t,n)=>(a((t=>42!==t&&47!==r.charCodeAt(e+1))),a(2),t||s(n))],"//",20,[(e,r)=>(a((e=>e>=32)),e||s(r))],"null",20,[e=>e?n():["",null]],"true",20,[e=>e?n():["",!0]],"false",20,[e=>e?n():["",!1]],"undefined",20,[e=>e?n():["",void 0]],";",20,[e=>s()||[""]],"**",-14,(e,r)=>e**r,"[",20,[e=>!e&&["[",s(0,93)||""],(e,r)=>!r&&(e?","===e[0]?(e=e.slice(1).map(o),r=>e.map((e=>e(r)))):(e=o(e),r=>[e(r)]):()=>[])],"{",20,[e=>!e&&["{",s(0,125)||""],(e,r)=>e?","===e[0]?(e=e.slice(1).map(o),r=>Object.fromEntries(e.map((e=>e(r))))):":"===e[0]?(e=o(e),r=>Object.fromEntries([e(r)])):(r=o(e),t=>({[e]:r(t)})):e=>({})],":",1.1,[(e,r)=>[":",e,s(1.1)||n()],(e,r)=>(r=o(r),e=Array.isArray(e)?o(e):(e=>e).bind(0,e),t=>[e(t),r(t)])]];for(;b[2];)p.set(...b.splice(0,3));export{o as compile,p as default,t as parse};
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}\` at ${n.length}:${a.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(),p=n.length+":"+a.length;throw SyntaxError(`${r} at ${p} \`${s+l+i}\`\n${" ".repeat(18+r.length+p.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,p)=>{for(;(a=r.space())&&(i=((p=h[a])&&p(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,p=r.space=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},o=r.id=e=>a(i),h=[],c=(r,l=32,n,a=r.charCodeAt(0),s=r.length,p=h[a],o=r.toUpperCase()!==r)=>h[a]=(a,h,c=e)=>h<l&&(s<2||t.substr(e,s)==r)&&(!o||!i(t.charCodeAt(e+s)))&&(e+=s,n(a,h))||(e=c,p?.(a,h)),f=(e,t,r)=>c(e,t,((l,n)=>l&&(n=s(t-!!r))&&[e,l,n])),d=(e,t,r)=>c(e,t,(l=>r?l&&[e,l]:!l&&(l=s(t-1))&&[e,l])),g=(e,t,r)=>c(e,t,((l,n)=>l&&((n=s(t))||r)&&(l[0]===e&&l[2]?(l.push(n||null),l):[e,l,n])));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),y=e=>(e=r(e),t=>(e.call?e:e=u(e))(t)),b=(e,t,r)=>r[0]||r[1]?(t?c(e,t,r[0]):h[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))))):(d(e,t),A(e,((e,t)=>!t&&((e=u(e)).length?t=>r(e(t)):(e=r(e()),()=>e))))):(g(e,t),A(e,((...e)=>(e=e.map(u),t=>r(...e.map((e=>e(t)))))))),C=e=>e?l():["",(e=+a((e=>46===e||e>=48&&e<=57||(69===e||101===e?2:0))))!=e?l():e],$=(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&&C()],...Array(10).fill(0).flatMap(((e,t)=>[""+t,0,[C]])),",",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,...$("++",15,((e,t)=>++e[t])),...$("--",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=>e&&["(",e,s(0,41)||""],(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];)b(...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=>s()||[""]],"**",-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];)b(...B.splice(0,3));export{f as binary,u as compile,t as cur,y as default,l as err,s as expr,o as id,e as idx,i as isId,n as longErr,h as lookup,g as nary,A as operator,m as operators,r as parse,b as set,a as skip,p as space,c as token,d as unary};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "7.1.1",
3
+ "version": "7.3.1",
4
4
  "description": "Fast and tiny expression evaluator with common syntax microlanguage.",
5
5
  "main": "subscript.js",
6
6
  "module": "subscript.js",
package/parse.js CHANGED
@@ -10,6 +10,17 @@ err = (msg='Bad syntax', frag=cur[idx], prev=cur.slice(0,idx).split('\n'), last=
10
10
  throw SyntaxError(`${msg} \`${frag}\` at ${prev.length}:${last.length}`)
11
11
  },
12
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 SyntaxError(`${msg} at ${location} \`${before+frag+after}\`\n${' '.repeat(18 + msg.length + location.length + before.length + 1)}^`)
22
+ },
23
+
13
24
  skip = (is=1, from=idx, l) => {
14
25
  if (typeof is == 'number') idx += is
15
26
  else while (l=is(cur.charCodeAt(idx))) idx+=l
@@ -50,11 +61,11 @@ id = parse.id = n => skip(isId),
50
61
 
51
62
  // operator/token lookup table
52
63
  // lookup[0] is id parser to let configs redefine it
53
- lookup = []
64
+ lookup = [],
54
65
 
55
66
 
56
67
  // create operator checker/mapper (see examples)
57
- parse.set = (
68
+ token = (
58
69
  op,
59
70
  prec=SPACE,
60
71
  map,
@@ -64,12 +75,11 @@ parse.set = (
64
75
  word=op.toUpperCase()!==op // make sure word boundary comes after word operator
65
76
  ) => lookup[c] = (a, curPrec, from=idx) =>
66
77
  (curPrec<prec && (l<2||cur.substr(idx,l)==op) && (!word||!isId(cur.charCodeAt(idx+l))) && (idx+=l, map(a, curPrec))) ||
67
- (idx=from, prev?.(a, curPrec))
78
+ (idx=from, prev?.(a, curPrec)),
68
79
 
69
80
  // right assoc is indicated by negative precedence (meaning go from right to left)
70
- parse.binary = (op, prec, right) => parse.set(op, prec, (a, b) => a && (b=expr(prec-!!right)) && [op,a,b] )
71
- parse.unary = (op, prec, post) => parse.set(op, prec, a => !a && (a=expr(prec-1)) && [op, a])
72
- parse.nary = (op, prec) => parse.set(op, prec, (a, b) => a && (b=expr(prec)) && (a[0] === op && a[2] ? (a.push(b), a) : [op,a,b]))
73
-
81
+ binary = (op, prec, right) => token(op, prec, (a, b) => a && (b=expr(prec-!!right)) && [op,a,b] ),
82
+ unary = (op, prec, post) => token(op, prec, a => post ? (a && [op, a]) : (!a && (a=expr(prec-1)) && [op, a])),
83
+ nary = (op, prec, skips) => token(op, prec, (a, b) => a && (b=expr(prec),b||skips) && (a[0] === op && a[2] ? (a.push(b||null), a) : [op,a,b]))
74
84
 
75
85
  export default parse
package/subscript.js CHANGED
@@ -1,5 +1,5 @@
1
- import parse, { lookup, skip, cur, idx, err, expr } from './parse.js'
2
- import compile from './compile.js'
1
+ import parse, { lookup, nary, binary, unary, token, skip, err, expr } from './parse.js'
2
+ import compile, { operator } from './compile.js'
3
3
 
4
4
  const OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, PERIOD=46, _0=48, _9=57,
5
5
  PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
@@ -9,11 +9,22 @@ const subscript = s => (s=parse(s), ctx => (s.call?s:(s=compile(s)))(ctx)),
9
9
 
10
10
  // set any operator
11
11
  // right assoc is indicated by negative precedence (meaning go from right to left)
12
- set = subscript.set = (op, prec, fn) =>
13
- (fn[0]||fn[1]) ? (prec ? parse.set(op,prec,fn[0]) : (lookup[op.charCodeAt(0)||1]=fn[0]), compile.set(op, fn[1])) : (
14
- !fn.length ? (parse.nary(op, prec), compile.nary(op, fn)) :
15
- fn.length > 1 ? (parse.binary(op, Math.abs(prec), prec<0), compile.binary(op, fn)) :
16
- (parse.unary(op, prec), compile.unary(op, fn))
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, prec),
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))))
27
+ )
17
28
  ),
18
29
 
19
30
  num = a => a ? err() : ['', (a=+skip(c => c === PERIOD || (c>=_0 && c<=_9) || (c===69||c===101?2:0)))!=a?err():a],
@@ -27,6 +38,7 @@ inc = (op, prec, fn, ev) => [op, prec, [
27
38
  (ctx => fn(ctx,a)) // ++a
28
39
  )
29
40
  ]],
41
+
30
42
  list = [
31
43
  // literals
32
44
  // null operator returns first value (needed for direct literals)
@@ -111,4 +123,6 @@ list = [
111
123
  for (;list[2];) set(...list.splice(0,3))
112
124
 
113
125
  export default subscript
114
- export {compile, parse}
126
+ export {set}
127
+ export * from './parse.js'
128
+ export * from './compile.js'
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- let e,t,r=r=>(e=0,t=r,r=s(),t[e]?a():r||""),a=(r="Bad syntax",a=t[e],n=t.slice(0,e).split("\n"),s=n.pop())=>{throw SyntaxError(`${r} \`${a}\` at ${n.length}:${s.length}`)},n=(r=1,a=e,n)=>{if("number"==typeof r)e+=r;else for(;n=r(t.charCodeAt(e));)e+=n;return t.slice(a,e)},s=(t=0,n,s,l,o,y)=>{for(;(s=r.space())&&(o=((y=h[s])&&y(l,t))??(!l&&r.id()));)l=o;return n&&(s==n?e++:a()),l},l=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e;r.space=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},r.id=e=>n(l);let h=[];r.set=(r,a=32,n,s=r.charCodeAt(0),o=r.length,y=h[s],i=r.toUpperCase()!==r)=>h[s]=(s,h,c=e)=>h<a&&(o<2||t.substr(e,o)==r)&&(!i||!l(t.charCodeAt(e+o)))&&(e+=o,n(s,h))||(e=c,y?.(s,h)),r.binary=(e,t,a)=>r.set(e,t,((r,n)=>r&&(n=s(t-!!a))&&[e,r,n])),r.unary=(e,t,a)=>r.set(e,t,(r=>!r&&(r=s(t-1))&&[e,r])),r.nary=(e,t)=>r.set(e,t,((r,a)=>r&&(a=s(t))&&(r[0]===e&&r[2]?(r.push(a),r):[e,r,a])));const o=e=>Array.isArray(e)?y[e[0]](...e.slice(1)):t=>t?.[e],y={};o.set=(e,t,r=y[e])=>y[e]=(...e)=>t(...e)||r&&r(...e),o.binary=(e,t)=>o.set(e,((e,r)=>r&&(e=o(e),r=o(r),e.length||r.length?a=>t(e(a),r(a)):(e=t(e(),r()),()=>e)))),o.unary=(e,t)=>o.set(e,((e,r)=>!r&&((e=o(e)).length?r=>t(e(r)):(e=t(e()),()=>e)))),o.nary=(e,t)=>o.set(e,((...e)=>(e=e.map(o),r=>t(...e.map((e=>e(r)))))));const i=e=>(e=r(e),t=>(e.call?e:e=o(e))(t)),c=i.set=(e,t,a)=>a[0]||a[1]?(t?r.set(e,t,a[0]):h[e.charCodeAt(0)||1]=a[0],o.set(e,a[1])):a.length?a.length>1?(r.binary(e,Math.abs(t),t<0),o.binary(e,a)):(r.unary(e,t),o.unary(e,a)):(r.nary(e,t),o.nary(e,a)),p=e=>e?a():["",(e=+n((e=>46===e||e>=48&&e<=57||(69===e||101===e?2:0))))!=e?a():e],u=(e,t,r,a)=>[e,t,[r=>r?["++"===e?"-":"+",[e,r],["",1]]:[e,s(t-1)],a=(e,t)=>"("===e[0]?a(e[1]):"."===e[0]?(t=e[2],e=o(e[1]),a=>r(e(a),t)):"["===e[0]?([,e,t]=e,e=o(e),t=o(t),a=>r(e(a),t(a))):t=>r(t,e)]],g=["",,[,e=>()=>e],'"',,[e=>e?a():["",(n()+n((e=>e-34?1:0))+(n()||a("Bad string"))).slice(1,-1)]],".",,[e=>!e&&p()],...Array(10).fill(0).flatMap(((e,t)=>[""+t,0,[p]])),",",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,...u("++",15,((e,t)=>++e[t])),...u("--",15,((e,t)=>--e[t])),"[",18,[e=>e&&["[",e,s(0,93)||a()],(e,t)=>t&&(e=o(e),t=o(t),r=>e(r)[t(r)])],".",18,[(e,t)=>e&&(t=s(18))&&[".",e,t],(e,t)=>(e=o(e),t=t[0]?t:t[1],r=>e(r)[t])],"(",18,[e=>!e&&["(",s(0,41)||a()],o],"(",18,[e=>e&&["(",e,s(0,41)||""],(e,t,r,a)=>null!=t&&(a=""==t?()=>[]:","===t[0]?(t=t.slice(1).map(o),e=>t.map((t=>t(e)))):(t=o(t),e=>[t(e)]),"."===e[0]?(r=e[2],e=o(e[1]),t=>e(t)[r](...a(t))):"["===e[0]?(r=o(e[2]),e=o(e[1]),t=>e(t)[r(t)](...a(t))):(e=o(e),t=>e(t)(...a(t))))]];for(;g[2];)c(...g.splice(0,3));export{o as compile,i as default,r as parse};
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}\` at ${n.length}:${a.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 SyntaxError(`${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=i[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),i=[],c=(l,r=32,n,a=l.charCodeAt(0),s=l.length,p=i[a],o=l.toUpperCase()!==l)=>i[a]=(a,i,c=t)=>i<r&&(s<2||e.substr(t,s)==l)&&(!o||!h(e.charCodeAt(t+s)))&&(t+=s,n(a,i))||(t=c,p?.(a,i)),g=(t,e,l)=>c(t,e,((r,n)=>r&&(n=s(e-!!l))&&[t,r,n])),f=(t,e,l)=>c(t,e,(r=>l?r&&[t,r]:!r&&(r=s(e-1))&&[t,r])),d=(t,e,l)=>c(t,e,((r,n)=>r&&((n=s(e))||l)&&(r[0]===t&&r[2]?(r.push(n||null),r):[t,r,n])));const u=t=>Array.isArray(t)?y[t[0]](...t.slice(1)):e=>e?.[t],y={},A=(t,e,l=y[t])=>y[t]=(...t)=>e(...t)||l&&l(...t),$=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,e),A(t,((...t)=>(t=t.map(u),e=>l(...t.map((t=>t(e)))))))),m=t=>t?r():["",(t=+a((t=>46===t||t>=48&&t<=57||(69===t||101===t?2:0))))!=t?r():t],x=(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)]],b=["",,[,t=>()=>t],'"',,[t=>t?r():["",(a()+a((t=>t-34?1:0))+(a()||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,...x("++",15,((t,e)=>++t[e])),...x("--",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=>t&&["(",t,s(0,41)||""],(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(;b[2];)C(...b.splice(0,3));export{g as binary,u as compile,e as cur,$ as default,r as err,s as expr,o as id,t as idx,h as isId,n as longErr,i as lookup,d as nary,A as operator,y as operators,l as parse,C as set,a as skip,p as space,c as token,f as unary};