subscript 4.0.0 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -27,7 +27,7 @@ _Subscript_ is designed to be useful for:
27
27
  * custom DSL
28
28
 
29
29
  [_Jsep_](https://github.com/EricSmekens/jsep) is generally fine for the listed tasks, unless you need dependencies as small as possible.
30
- _Subscript_ has [2.5kb](https://npmfs.com/package/subscript/3.0.0/subscript.min.js) footprint vs [11.4kb](https://npmfs.com/package/jsep/1.2.0/dist/jsep.min.js) _jsep_, with better performance.
30
+ _Subscript_ has [2.5kb](https://npmfs.com/package/subscript/4.0.0/subscript.min.js) footprint vs [11.4kb](https://npmfs.com/package/jsep/1.2.0/dist/jsep.min.js) _jsep_, with better performance.
31
31
 
32
32
 
33
33
  ## Operators
@@ -279,7 +279,7 @@ Subscript shows relatively good performance within other evaluators:
279
279
  // 1 + (a * b / c % d) - 2.0 + -3e-3 * +4.4e4 / f.g[0] - i.j(+k == 1)(0)
280
280
  // parse 30k times
281
281
 
282
- subscript: ~220 ms
282
+ subscript: ~200 ms
283
283
  jsep: ~280 ms
284
284
  expr-eval: ~480 ms
285
285
  jexl: ~1200 ms
package/evaluate.js CHANGED
@@ -18,6 +18,8 @@ evaluate = (s, ctx={}, c, op) => {
18
18
  return s
19
19
  },
20
20
 
21
+ reducer=fn=>(...a)=>a.reduce(fn),
22
+
21
23
  // op evaluators
22
24
  // multiple args allows shortcuts, lisp compatible, easy manual eval, functions anyways take multiple arguments
23
25
  operator = evaluate.operator = {
@@ -25,13 +27,13 @@ operator = evaluate.operator = {
25
27
  '++':a=>++a,
26
28
  '--':a=>--a,
27
29
 
28
- '.':(...a)=>a.reduce((a,b)=>a?a[b]:a),
30
+ '.':reducer((a,b)=>a?a[b]:a),
29
31
 
30
- '%':(...a)=>a.reduce((a,b)=>a%b),
31
- '/':(...a)=>a.reduce((a,b)=>a/b),
32
- '*':(...a)=>a.reduce((a,b)=>a*b),
32
+ '%':reducer((a,b)=>a%b),
33
+ '/':reducer((a,b)=>a/b),
34
+ '*':reducer((a,b)=>a*b),
33
35
 
34
- '+':(...a)=>a.reduce((a,b)=>a+b),
36
+ '+':reducer((a,b)=>a+b),
35
37
  '-':(...a)=>a.length < 2 ? -a : a.reduce((a,b)=>a-b),
36
38
 
37
39
  '>>>':(a,b)=>a>>>b,
@@ -51,7 +53,7 @@ operator = evaluate.operator = {
51
53
  '|':(a,b)=>a|b,
52
54
  '&&':(...a)=>a.every(Boolean),
53
55
  '||':(...a)=>a.some(Boolean),
54
- ',':(...a)=>a.reduce((a,b)=>(a,b))
56
+ ',':reducer((a,b)=>(a,b))
55
57
  }
56
58
 
57
59
  export default evaluate
package/justin.js CHANGED
@@ -1,17 +1,22 @@
1
1
  // justin lang https://github.com/endojs/Jessie/issues/66
2
2
  import {evaluate} from './evaluate.js'
3
- import {parse, code, char, skip, expr, nil, binary, unary} from './parse.js'
3
+ import {parse, code, char, skip, expr, operator, err} from './parse.js'
4
4
 
5
5
  // ;
6
- parse.operator[0] = binary(c => c==44||c==59)
6
+ operator(';', 1)
7
+
8
+ // ===, !==
9
+ operator('===', 9)
10
+ operator('!==', 9)
7
11
 
8
12
  // undefined
9
- parse.token.splice(3,0, c =>
10
- c === 116 && char(4) === 'true' && skip(4) ? true :
11
- c === 102 && char(5) === 'false' && skip(5) ? false :
12
- c === 110 && char(4) === 'null' && skip(4) ? null :
13
- c === 117 && char(9) === 'undefined' && skip(9) ? undefined :
14
- undefined
13
+ const v = v => ({valueOf:()=>v})
14
+ parse.token.splice(2,0, c =>
15
+ c === 116 && char(4) === 'true' && skip(4) ? v(true) :
16
+ c === 102 && char(5) === 'false' && skip(5) ? v(false) :
17
+ c === 110 && char(4) === 'null' && skip(4) ? v(null) :
18
+ c === 117 && char(9) === 'undefined' && skip(9) ? v(undefined) :
19
+ null
15
20
  )
16
21
 
17
22
  // "' with /
@@ -28,27 +33,25 @@ const escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'}
28
33
 
29
34
  // **
30
35
  evaluate.operator['**'] = (...args)=>args.reduceRight((a,b)=>Math.pow(b,a))
31
- parse.operator.splice(parse.operator.length - 3, 0, binary(cc=>cc===42 && code(1) === cc && 2))
36
+ operator('**', 14)
32
37
 
33
38
  // ~
34
- parse.operator.splice(parse.operator.length-2, 0, unary(cc => cc === 126))
39
+ operator('~', 13, -1)
35
40
  evaluate.operator['~'] = a=>~a
36
41
 
37
42
  // TODO ...
38
- // // unary[1]['...']=true
39
-
40
43
 
41
44
  // ?:
42
45
  evaluate.operator['?:']=(a,b,c)=>a?b:c
43
- parse.operator.splice(1,0, (node,cc,prec,end) => {
46
+ operator('?', 3, (node) => {
47
+ if (!node) err('Expected expression')
44
48
  let a, b
45
- if (cc !== 63) return
46
- if (node===nil) err('Bad expression')
47
- skip(), parse.space(), a = expr(-1,58)
48
- if (code() !== 58) return
49
+ skip(), parse.space(), a = expr()
50
+ if (code() !== 58) err('Expected :')
49
51
  skip(), parse.space(), b = expr()
50
52
  return ['?:', node, a, b]
51
53
  })
54
+ // operator(':')
52
55
 
53
56
  // /**/, //
54
57
  parse.space = cc => {
@@ -65,29 +68,28 @@ parse.space = cc => {
65
68
 
66
69
  // in
67
70
  evaluate.operator['in'] = (a,b)=>a in b
68
- parse.operator.splice(6,0,(a,cc,prec,end) => (char(2) === 'in' && [skip(2), '"' + a + '"', expr(prec,end)]))
71
+ operator('in', 10, (node) => code(2) <= 32 && [skip(2), '"'+node+'"', expr(10)])
69
72
 
70
73
  // []
71
74
  evaluate.operator['['] = (...args) => Array(...args)
72
- parse.token.unshift((cc, node, arg) =>
73
- cc === 91 &&
74
- (
75
- skip(), arg=expr(0,93),
76
- node = arg===nil ? ['['] : arg[0] === ',' ? (arg[0]='[',arg) : ['[',arg],
77
- skip(), node
78
- )
79
- )
75
+ // as operator it's faster to lookup (no need to call extra rule check), smaller and no conflict with word names
76
+ operator('[', 20, (node,arg) => !node && (
77
+ skip(), arg=expr(0,93), skip(),
78
+ !arg ? ['['] : arg[0] === ',' ? (arg[0]='[',arg) : ['[',arg]
79
+ ))
80
80
 
81
81
  // {}
82
82
  parse.token.unshift((cc, node) => (
83
- cc === 123 ? (skip(), node = map(['{',expr(0,125)]), skip(), node) : null
83
+ cc === 123 && (skip(), node = map(['{', expr(0,125)]), skip(), node)
84
84
  ))
85
- parse.operator.splice(4,0, binary(cc=>cc===58))
85
+
86
+ operator('}')
87
+ operator(':', 0)
86
88
  evaluate.operator['{'] = (...args)=>Object.fromEntries(args)
87
89
  evaluate.operator[':'] = (a,b)=>[a,b]
88
90
 
89
91
  const map = (n, args) => {
90
- if (n[1]===nil) args = []
92
+ if (!n[1]) args = []
91
93
  else if (n[1][0]==':') args = [n[1]]
92
94
  else if (n[1][0]==',') args = n[1].slice(1)
93
95
  return ['{', ...args]
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- var e,r,o=e=>Array.isArray(e)&&("string"==typeof e[0]||o(e[0])),t=(e,r={},n,p)=>o(e)?("string"==typeof(n=e[0])&&(p=a[n]),"function"!=typeof(n=p||t(n,r))?n:n.call(...e.map((e=>t(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,a=t.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":(...e)=>e.reduce(((e,r)=>e&&e[r])),"%":(...e)=>e.reduce(((e,r)=>e%r)),"/":(...e)=>e.reduce(((e,r)=>e/r)),"*":(...e)=>e.reduce(((e,r)=>e*r)),"+":(...e)=>e.reduce(((e,r)=>e+r)),"-":(...e)=>e.length<2?-e:e.reduce(((e,r)=>e-r)),">>>":(e,r)=>e>>>r,">>":(e,r)=>e>>r,"<<":(e,r)=>e<<r,">=":(e,r)=>e>=r,">":(e,r)=>e>r,"<=":(e,r)=>e<=r,"<":(e,r)=>e<r,"!=":(e,r)=>e!=r,"==":(e,r)=>e==r,"&":(e,r)=>e&r,"^":(e,r)=>e^r,"|":(e,r)=>e|r,"&&":(...e)=>e.every(Boolean),"||":(...e)=>e.some(Boolean),",":(...e)=>e.reduce(((e,r)=>r))},n=(o,t)=>(r=o,e=0,t=u(),e<r.length?p():t),p=(o="Bad syntax")=>{throw Error(o+" `"+r[e]+"` at "+e)},s=(o=1,t=e)=>{if("number"==typeof o)e+=o;else for(;o(i());)e++;return r.slice(t,e)||c},i=(o=0)=>r.charCodeAt(e+o),l=(o=1)=>r.substr(e,o),c="",u=(r=0,o,t=n.space(),a,s=e,l=0,u)=>{for(;s===e&&l<n.token.length;)a=n.token[l++](t);for(l=Math.max(0|h[t=n.space()],r);l<n.operator.length&&!(t===o||l<r);)(u=n.operator[l++](a,t,l,o))&&(u.indexOf(c)>=0&&p("Bad expression"),a=u,l=Math.max(0|h[t=n.space()],r));return!r&&o&&i()!=o&&p("Unclosed paren"),a},f=(n.space=r=>{for(;(r=i())<=32;)e++;return r},n.token=[e=>(e=s((e=>e>47&&e<58||46===e)))?((69===i()||101===i())&&(e+=s(2)+s((e=>e>=48&&e<=57))),isNaN(e=parseFloat(e))?p("Bad number"):e):c,(e,r)=>34===e?s()+s((r=>r-e))+s():c,r=>40===r?(++e,r=u(0,41),++e,r===c?p():r):c,e=>s((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))],e=>(r,o,t,a,p,i,f)=>{if(r!==c&&(i=0|e(o))){p=[f=l(i),r];do{s(i),p.push(u(t,a))}while(n.space()==o&&l(i)==f);return p}}),d=(e,r=!1)=>r?(r,o,t,a,n)=>r!==c&&(n=0|e(o))&&[s(n),r]:(r,o,t,a,n)=>r===c&&(n=0|e(o))&&[s(n),u(t-1,a)],h=(n.operator=[f((e=>44==e)),f((e=>124==e&&i(1)==e&&2)),f((e=>38==e&&i(1)==e&&2)),f((e=>124==e)),f((e=>94==e)),f((e=>38==e)),f((e=>(61==e||33==e)&&61==i(1)&&(i(1)==i(2)?3:2))),f((e=>(62==e||60==e)&&e!=i(1))),f((e=>(60==e||62==e)&&e==i(1)&&(e==i(2)?3:2))),f((e=>(43==e||45==e)&&i(1)!=e)),f((e=>42==e&&42!=i(1)||47==e||37==e)),d((e=>(43==e||45==e)&&i(1)==e&&2),!0),d((e=>(43==e||45==e||33==e)&&(i(1)==e?2:1))),(r,o,t,a,n)=>46==o?[s(),r,"string"==typeof(n=u(t,a))?'"'+n+'"':n]:91==o?(e++,r=[".",r,u(0,93)],e++,r):40==o?(e++,n=u(0,41),e++,Array.isArray(n)&&","===n[0]?(n[0]=r,n):n===c?[r]:[r,n]):c],[]);h[44]=0,h[124]=1,h[38]=2,h[94]=4,h[61]=h[33]=6,h[60]=h[62]=7,h[43]=h[45]=9,h[42]=h[47]=h[37]=10,h[46]=h[91]=h[40]=13,n.operator[0]=f((e=>44==e||59==e)),n.token.splice(3,0,(e=>!(116!==e||"true"!==l(4)||!s(4))||(102!==e||"false"!==l(5)||!s(5))&&(110===e&&"null"===l(4)&&s(4)?null:void(117===e&&"undefined"===l(9)&&s(9))))),n.token[1]=(e,r,o,t)=>{if(34===e||39===e){for(r=l(),s(),t="";(o=i())-e;)92===o?(s(),t+=y[l()]||l()):t+=l(),s();return s(),r+t+r}};var y={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};t.operator["**"]=(...e)=>e.reduceRight(((e,r)=>Math.pow(r,e))),n.operator.splice(n.operator.length-3,0,f((e=>42===e&&i(1)===e&&2))),n.operator.splice(n.operator.length-2,0,d((e=>126===e))),t.operator["~"]=e=>~e,t.operator["?:"]=(e,r,o)=>e?r:o,n.operator.splice(1,0,((e,r,o,t)=>{let a,p;if(63===r&&(e===c&&err("Bad expression"),s(),n.space(),a=u(-1,58),58===i()))return s(),n.space(),p=u(),["?:",e,a,p]})),n.space=e=>{for(;(e=i())<=32;)s(),47===i()&&(42===i(1)?(s(2),s((e=>42!==e&&47!==i(1))),s(2)):47===i(1)&&(s(2),s((e=>e>=32))));return e},t.operator.in=(e,r)=>e in r,n.operator.splice(6,0,((e,r,o,t)=>"in"===l(2)&&[s(2),'"'+e+'"',u(o,t)])),t.operator["["]=(...e)=>Array(...e),n.token.unshift(((e,r,o)=>91===e&&(s(),r=(o=u(0,93))===c?["["]:","===o[0]?(o[0]="[",o):["[",o],s(),r))),n.token.unshift(((e,r)=>123===e?(s(),r=g(["{",u(0,125)]),s(),r):null)),n.operator.splice(4,0,f((e=>58===e))),t.operator["{"]=(...e)=>Object.fromEntries(e),t.operator[":"]=(e,r)=>[e,r];var g=(e,r)=>(e[1]===c?r=[]:":"==e[1][0]?r=[e[1]]:","==e[1][0]&&(r=e[1].slice(1)),["{",...r]),v=n;export{v as default,t as evaluate,n as parse};
1
+ var e,r,t=e=>Array.isArray(e)&&("string"==typeof e[0]||t(e[0])),a=(e,r={},o,l)=>t(e)?("string"==typeof(o=e[0])&&(l=n[o]),"function"!=typeof(o=l||a(o,r))?o:o.call(...e.map((e=>a(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,o=e=>(...r)=>r.reduce(e),n=a.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":o(((e,r)=>e&&e[r])),"%":o(((e,r)=>e%r)),"/":o(((e,r)=>e/r)),"*":o(((e,r)=>e*r)),"+":o(((e,r)=>e+r)),"-":(...e)=>e.length<2?-e:e.reduce(((e,r)=>e-r)),">>>":(e,r)=>e>>>r,">>":(e,r)=>e>>r,"<<":(e,r)=>e<<r,">=":(e,r)=>e>=r,">":(e,r)=>e>r,"<=":(e,r)=>e<=r,"<":(e,r)=>e<r,"!=":(e,r)=>e!=r,"==":(e,r)=>e==r,"&":(e,r)=>e&r,"^":(e,r)=>e^r,"|":(e,r)=>e|r,"&&":(...e)=>e.every(Boolean),"||":(...e)=>e.some(Boolean),",":o(((e,r)=>r))},l=15,s=(t,a)=>(r=t,e=0,a=c(),e<r.length?p():a.valueOf()),p=(t="Bad syntax")=>{throw Error(t+" `"+r[e]+"` at "+e)},u=(t=1,a=e)=>{if("number"==typeof t)e+=t;else for(;t(f());)e++;return r.slice(a,e)},f=(t=0)=>r.charCodeAt(e+t),i=(t=1)=>r.substr(e,t),c=(e=0,r,t,a,o=0,n,l)=>{for(;(t=s.space())&&(l=h[t]?.(a,e)||!a&&d(t));)a=l;return r&&t!==r&&p("Unclosed paren"),a},v=(s.space=r=>{for(;(r=f())<=32;)e++;return r},s.token=[e=>(e=u((e=>e>47&&e<58||46==e)))&&((69==f()||101==f())&&(e+=u(2)+u((e=>e>=48&&e<=57))),isNaN(e=new Number(e))?p("Bad number"):e),(e,r)=>34==e&&u()+u((r=>r-e))+u(),e=>u((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))]),d=(e,r=0,t)=>{for(;r<v.length;)if(t=v[r++](e))return t},h=[],y=(r,t=0,a=0,o,n=r.charCodeAt(0),l=r.length,v=h[n],d=r.toUpperCase()!==r,y)=>(y=l<2?d?e=>f(1)<=32:e=>1:d?e=>i(l)==r&&f(l)<=32:e=>i(l)==r,o=a?a>0?e=>e&&[u(l),e]:a<0?e=>!e&&[u(l),(c(t-1)||p()).valueOf()]:a:a=>{a=[r,a||p()];do{e+=l,a.push((c(t)||p()).valueOf())}while(s.space()==n&&y());return a},h[n]=(e,r)=>r<t&&y()&&o(e)||v&&v(e,r));for(let r=0,t=[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",10,,">=",10,,">>",11,,">>>",11,,"<",10,,"<=",10,,"<<",11,,"+",12,,"+",l,-1,"++",l,-1,"++",l,1,"-",12,,"-",l,-1,"--",l,-1,"--",l,1,"!",l,-1,"*",13,,"/",13,,"%",13,,".",18,(e,r)=>e&&[u(),e,"string"==typeof(r=c(18))?'"'+r+'"':r.valueOf()],"[",18,r=>(e++,r=[".",r,c(0,93).valueOf()],e++,r),"]",,,"(",18,(r,t)=>(e++,t=c(0,41),e++,Array.isArray(t)&&","===t[0]?(t[0]=r,t):t?[r,t.valueOf()]:[r]),"(",19,(r,t)=>!r&&(++e,t=c(0,41)||p(),++e,t),")",,,];r<t.length;)y(t[r++],t[r++],t[r++]);y(";",1),y("===",9),y("!==",9);var g=e=>({valueOf:()=>e});s.token.splice(2,0,(e=>116===e&&"true"===i(4)&&u(4)?g(!0):102===e&&"false"===i(5)&&u(5)?g(!1):110===e&&"null"===i(4)&&u(4)?g(null):117===e&&"undefined"===i(9)&&u(9)?g(void 0):null)),s.token[1]=(e,r,t,a)=>{if(34===e||39===e){for(r=i(),u(),a="";(t=f())-e;)92===t?(u(),a+=O[i()]||i()):a+=i(),u();return u(),r+a+r}};var O={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};a.operator["**"]=(...e)=>e.reduceRight(((e,r)=>Math.pow(r,e))),y("**",14),y("~",13,-1),a.operator["~"]=e=>~e,a.operator["?:"]=(e,r,t)=>e?r:t,y("?",3,(e=>{let r,t;return e||p("Expected expression"),u(),s.space(),r=c(),58!==f()&&p("Expected :"),u(),s.space(),t=c(),["?:",e,r,t]})),s.space=e=>{for(;(e=f())<=32;)u(),47===f()&&(42===f(1)?(u(2),u((e=>42!==e&&47!==f(1))),u(2)):47===f(1)&&(u(2),u((e=>e>=32))));return e},a.operator.in=(e,r)=>e in r,y("in",10,(e=>f(2)<=32&&[u(2),'"'+e+'"',c(10)])),a.operator["["]=(...e)=>Array(...e),y("[",20,((e,r)=>!e&&(u(),r=c(0,93),u(),r?","===r[0]?(r[0]="[",r):["[",r]:["["]))),s.token.unshift(((e,r)=>123===e&&(u(),r=b(["{",c(0,125)]),u(),r))),y("}"),y(":",0),a.operator["{"]=(...e)=>Object.fromEntries(e),a.operator[":"]=(e,r)=>[e,r];var b=(e,r)=>(e[1]?":"==e[1][0]?r=[e[1]]:","==e[1][0]&&(r=e[1].slice(1)):r=[],["{",...r]),A=s;export{A as default,a as evaluate,s as parse};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "4.0.0",
3
+ "version": "5.0.0",
4
4
  "description": "Microlanguage with common syntax for JS/C++/Python/Rust",
5
5
  "main": "subscript.js",
6
6
  "type": "module",
package/parse.js CHANGED
@@ -1,39 +1,34 @@
1
- // precedence-based parsing
2
- const GT=62, LT=60, EQ=61, PLUS=43, MINUS=45, AND=38, OR=124, HAT=94, MUL=42, DIV=47, MOD=37, PERIOD=46, OBRACK=91, CBRACK=93, OPAREN=40, CPAREN=41, COMMA=44, SPACE=32, EXCL=33
1
+ const PERIOD=46, OPAREN=40, CPAREN=41, CBRACK=93, SPACE=32,
2
+
3
+ PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
4
+ 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
5
+
3
6
 
4
7
  // current string & index
5
8
  let idx, cur
6
9
 
7
- export const parse = (str, tree) => (cur=str, idx=0, tree=expr(), idx<cur.length ? err() : tree),
10
+ export const parse = (str, tree) => (cur=str, idx=0, tree=expr(), idx<cur.length ? err() : tree.valueOf()),
8
11
 
9
12
  err = (msg='Bad syntax') => { throw Error(msg + ' `' + cur[idx] + '` at ' + idx) },
10
13
 
11
14
  skip = (is=1, from=idx) => {
12
15
  if (typeof is === 'number') idx += is
13
16
  else while (is(code())) idx++;
14
- return cur.slice(from, idx) || nil
17
+ return cur.slice(from, idx)
15
18
  },
16
19
 
17
20
  code = (i=0) => cur.charCodeAt(idx+i),
18
21
 
19
22
  char = (n=1) => cur.substr(idx, n),
20
23
 
21
- nil = '',
22
-
23
24
  // a + b - c
24
- expr = (prec=0, end, cc=parse.space(), node, from=idx, i=0, mapped) => {
25
- // prefix or token
26
- while (from===idx && i < parse.token.length) node = parse.token[i++](cc)
25
+ expr = (prec=0, end, cc, node, i=0, map, newNode) => {
26
+ // chunk/token parser
27
+ while (
28
+ (cc=parse.space()) && (newNode = lookup[cc]?.(node, prec) || (!node && token(cc)) )
29
+ ) node = newNode;
27
30
 
28
- // postfix or binary
29
- for (i = Math.max(lookup[cc=parse.space()]|0, prec); i < parse.operator.length;) {
30
- if (cc===end || i<prec) break // if lookup got prec lower than current - end group
31
- else if (mapped = parse.operator[i++](node, cc, i, end))
32
- mapped.indexOf(nil) >=0 && err('Bad expression'),
33
- node = mapped, i = Math.max(lookup[cc=parse.space()]|0, prec); // we pass i+1 as precision
34
- }
35
-
36
- if (!prec && end && code()!=end) err('Unclosed paren')
31
+ if (end && cc !== end) err('Unclosed paren')
37
32
 
38
33
  return node
39
34
  },
@@ -42,20 +37,17 @@ expr = (prec=0, end, cc=parse.space(), node, from=idx, i=0, mapped) => {
42
37
  space = parse.space = cc => { while (cc = code(), cc <= SPACE) idx++; return cc },
43
38
 
44
39
  // tokens
45
- token = parse.token = [
40
+ tokens = parse.token = [
46
41
  // 1.2e+3, .5 - fast & small version, but consumes corrupted nums as well
47
- (number) => {
48
- if (number = skip(c => (c > 47 && c < 58) || c === PERIOD)) {
49
- if (code() === 69 || code() === 101) number += skip(2) + skip(c => c >= 48 && c <= 57)
50
- return isNaN(number = parseFloat(number)) ? err('Bad number') : number
51
- }
52
- return nil
53
- },
42
+ (number) => (
43
+ (number = skip(c => (c > 47 && c < 58) || c == PERIOD)) && (
44
+ (code() == 69 || code() == 101) && (number += skip(2) + skip(c => c >= 48 && c <= 57)),
45
+ isNaN(number = new Number(number)) ? err('Bad number') : number
46
+ )
47
+ ),
54
48
  // "a"
55
- (q, qc) => q === 34 ? (skip() + skip(c => c-q) + skip()) : nil,
56
- // (...exp)
57
- c => c === OPAREN ? (++idx, c=expr(0,CPAREN), ++idx, c===nil?err():c) : nil,
58
- // var
49
+ (q, qc) => q == 34 && (skip() + skip(c => c-q) + skip()),
50
+ // id
59
51
  c => skip(c =>
60
52
  (c >= 48 && c <= 57) || // 0..9
61
53
  (c >= 65 && c <= 90) || // A...Z
@@ -65,70 +57,92 @@ token = parse.token = [
65
57
  )
66
58
  ],
67
59
 
68
- // create binary operator parser
69
- binary = (is) => (a,cc,prec,end, list,len,op) => {
70
- if (a!==nil && (len = is(cc)|0)) {
71
- // consume same-op group, do..while saves op lookups
72
- list = [op=char(len),a]
73
- do { skip(len), list.push(expr(prec,end)) } while (parse.space()==cc && char(len)==op)
74
- return list
75
- }
76
- },
77
- unary = (is, post=false) => post ?
78
- (a,cc,prec,end,l) => a!==nil && (l=is(cc)|0) && [skip(l), a] :
79
- (a,cc,prec,end,l) => a===nil && (l=is(cc)|0) && [skip(l), expr(prec-1,end)],
80
-
81
- operator = parse.operator = [
82
- // ','
83
- binary(c => c==COMMA),
84
- // '||' '&&'
85
- binary(c => c==OR && code(1)==c && 2),
86
- binary(c => c==AND && code(1)==c && 2),
87
- // '|' '^' '&'
88
- binary(c => c==OR),
89
- binary(c => c==HAT),
90
- binary(c => c==AND),
91
- // '==' '!='
92
- binary(c => (c==EQ || c==EXCL) && code(1)==EQ && (code(1)==code(2) ? 3 : 2)),
93
- // '<' '>' '<=' '>='
94
- binary(c => (c==GT || c==LT) && c!=code(1)),
95
- // '<<' '>>' '>>>'
96
- binary(c => (c==LT || c==GT) && c==code(1) && (c==code(2) ? 3 : 2)),
97
- // '+' '-'
98
- binary(c => (c==PLUS || c==MINUS) && code(1)!=c),
99
- // '*' '/' '%'
100
- binary(c => (c==MUL && code(1) != MUL) || c==DIV || c==MOD),
101
- // -- ++ unaries
102
- unary(c => (c==PLUS || c==MINUS) && code(1) == c && 2, true),
103
- // - + ! unaries
104
- unary(c => (c==PLUS || c==MINUS || c==EXCL) && (code(1)==c ? 2 : 1)),
105
- // '()', '[]', '.'
106
- (a,cc,prec,end,b) => (
107
- // a.b[c](d)
108
- cc==PERIOD ? [skip(), (a), typeof (b = (expr(prec,end))) === 'string' ? '"' + b + '"' : b] :
109
- cc==OBRACK ? (idx++, a = ['.', (a), (expr(0,CBRACK))], idx++, a) :
110
- cc==OPAREN ? (
111
- idx++, b=expr(0,CPAREN), idx++,
112
- Array.isArray(b) && b[0]===',' ? (b[0]=a, b) :
113
- b === nil ? [a] :
114
- [a, b]
115
- ) : nil
116
- )
117
- ],
118
-
119
- // fast operator lookup table
120
- lookup = []
121
-
122
- lookup[COMMA] = 0
123
- lookup[OR] = 1
124
- lookup[AND] = 2
125
- lookup[HAT] = 4
126
- lookup[EQ] = lookup[EXCL] = 6
127
- lookup[LT] = lookup[GT] = 7
128
- lookup[PLUS] = lookup[MINUS] = 9
129
- lookup[MUL] = lookup[DIV] = lookup[MOD] = 10
130
- lookup[PERIOD] = lookup[OBRACK] = lookup[OPAREN] = 13
131
-
60
+ token = (c,i=0,node) => { while(i<tokens.length) if (node = tokens[i++](c)) return node },
61
+
62
+ // operator lookup table
63
+ lookup = [],
64
+
65
+ // create operator checker/mapper (see examples)
66
+ // @param op is operator string
67
+ // @param prec is operator precedenc to check
68
+ // @param map is either number +1 - postfix unary, -1 prefix unary, 0 binary, else - custom mapper function
69
+ operator = (op, prec=0, type=0, map, c=op.charCodeAt(0), l=op.length, prev=lookup[c], word=op.toUpperCase()!==op, isop) => (
70
+ isop = l<2 ? // word operator must have space after
71
+ !word ? c=>1 : c=>code(1)<=SPACE :
72
+ !word ? c=>char(l)==op : c=>char(l)==op&&code(l)<=SPACE,
73
+
74
+ map = !type ? node => { // binary, consume same-op group
75
+ node = [op, node || err()]
76
+ // in order to support literal tokens, we call valueOf any time we create or modify calltree node
77
+ do { idx+=l, node.push((expr(prec) || err()).valueOf()) } while (parse.space()==c && isop())
78
+ return node
79
+ } :
80
+ type > 0 ? node => node && [skip(l), node] : // postfix unary
81
+ type < 0 ? node => !node && [skip(l), (expr(prec-1) || err()).valueOf()] : // prefix unary
82
+ type,
83
+
84
+ lookup[c] = (node, curPrec) => curPrec < prec && isop() && map(node) || (prev && prev(node, curPrec))
85
+ )
86
+
87
+ // ,
88
+ for (let i = 0, ops = [
89
+ // TODO: add ,, as node here
90
+ ',', PREC_SEQ,,
91
+
92
+ '|', PREC_OR,,
93
+ '||', PREC_SOME,,
94
+
95
+ '&', PREC_AND,,
96
+ '&&', PREC_EVERY,,
97
+
98
+ '^', PREC_XOR,,
99
+
100
+ // ==, !=
101
+ '==', PREC_EQ,,
102
+ '!=', PREC_EQ,,
103
+
104
+ // > >= >> >>>, < <= <<
105
+ '>', PREC_COMP,,
106
+ '>=', PREC_COMP,,
107
+ '>>', PREC_SHIFT,,
108
+ '>>>', PREC_SHIFT,,
109
+ '<', PREC_COMP,,
110
+ '<=', PREC_COMP,,
111
+ '<<', PREC_SHIFT,,
112
+
113
+ // + ++ - --
114
+ '+', PREC_SUM,,
115
+ '+', PREC_UNARY, -1,
116
+ '++', PREC_UNARY, -1,
117
+ '++', PREC_UNARY, +1,
118
+ '-', PREC_SUM,,
119
+ '-', PREC_UNARY, -1,
120
+ '--', PREC_UNARY, -1,
121
+ '--', PREC_UNARY, +1,
122
+
123
+ // ! ~
124
+ '!', PREC_UNARY, -1,
125
+
126
+ // * / %
127
+ '*', PREC_MULT,,
128
+ '/', PREC_MULT,,
129
+ '%', PREC_MULT,,
130
+
131
+ // a.b
132
+ '.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
133
+
134
+ // a[b]
135
+ '[', PREC_CALL, (node) => (idx++, node = ['.', node, expr(0,CBRACK).valueOf()], idx++, node),
136
+ ']',,,
137
+
138
+ // a(b)
139
+ '(', PREC_CALL, (node,b) => ( idx++, b=expr(0,CPAREN), idx++,
140
+ Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, b.valueOf()] : [node]
141
+ ),
142
+ // (a+b)
143
+ '(', PREC_GROUP, (node,b) => !node && (++idx, b=expr(0,CPAREN) || err(), ++idx, b),
144
+ ')',,,
145
+ ]; i < ops.length;) operator(ops[i++],ops[i++],ops[i++])
132
146
 
133
147
 
134
148
  export default parse
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- var e,r,a=(a,o)=>(r=a,e=0,o=c(),e<r.length?t():o),t=(a="Bad syntax")=>{throw Error(a+" `"+r[e]+"` at "+e)},o=(a=1,t=e)=>{if("number"==typeof a)e+=a;else for(;a(s());)e++;return r.slice(t,e)||p},s=(a=0)=>r.charCodeAt(e+a),n=(a=1)=>r.substr(e,a),p="",c=(r=0,o,n=a.space(),c,i=e,u=0,f)=>{for(;i===e&&u<a.token.length;)c=a.token[u++](n);for(u=Math.max(0|l[n=a.space()],r);u<a.operator.length&&!(n===o||u<r);)(f=a.operator[u++](c,n,u,o))&&(f.indexOf(p)>=0&&t("Bad expression"),c=f,u=Math.max(0|l[n=a.space()],r));return!r&&o&&s()!=o&&t("Unclosed paren"),c},i=(a.space=r=>{for(;(r=s())<=32;)e++;return r},a.token=[e=>(e=o((e=>e>47&&e<58||46===e)))?((69===s()||101===s())&&(e+=o(2)+o((e=>e>=48&&e<=57))),isNaN(e=parseFloat(e))?t("Bad number"):e):p,(e,r)=>34===e?o()+o((r=>r-e))+o():p,r=>40===r?(++e,r=c(0,41),++e,r===p?t():r):p,e=>o((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))],e=>(r,t,s,i,u,l,f)=>{if(r!==p&&(l=0|e(t))){u=[f=n(l),r];do{o(l),u.push(c(s,i))}while(a.space()==t&&n(l)==f);return u}}),u=(e,r=!1)=>r?(r,a,t,s,n)=>r!==p&&(n=0|e(a))&&[o(n),r]:(r,a,t,s,n)=>r===p&&(n=0|e(a))&&[o(n),c(t-1,s)],l=(a.operator=[i((e=>44==e)),i((e=>124==e&&s(1)==e&&2)),i((e=>38==e&&s(1)==e&&2)),i((e=>124==e)),i((e=>94==e)),i((e=>38==e)),i((e=>(61==e||33==e)&&61==s(1)&&(s(1)==s(2)?3:2))),i((e=>(62==e||60==e)&&e!=s(1))),i((e=>(60==e||62==e)&&e==s(1)&&(e==s(2)?3:2))),i((e=>(43==e||45==e)&&s(1)!=e)),i((e=>42==e&&42!=s(1)||47==e||37==e)),u((e=>(43==e||45==e)&&s(1)==e&&2),!0),u((e=>(43==e||45==e||33==e)&&(s(1)==e?2:1))),(r,a,t,s,n)=>46==a?[o(),r,"string"==typeof(n=c(t,s))?'"'+n+'"':n]:91==a?(e++,r=[".",r,c(0,93)],e++,r):40==a?(e++,n=c(0,41),e++,Array.isArray(n)&&","===n[0]?(n[0]=r,n):n===p?[r]:[r,n]):p],[]);l[44]=0,l[124]=1,l[38]=2,l[94]=4,l[61]=l[33]=6,l[60]=l[62]=7,l[43]=l[45]=9,l[42]=l[47]=l[37]=10,l[46]=l[91]=l[40]=13;var f=a,d=e=>Array.isArray(e)&&("string"==typeof e[0]||d(e[0])),y=(e,r={},a,t)=>d(e)?("string"==typeof(a=e[0])&&(t=h[a]),"function"!=typeof(a=t||y(a,r))?a:a.call(...e.map((e=>y(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,h=y.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":(...e)=>e.reduce(((e,r)=>e&&e[r])),"%":(...e)=>e.reduce(((e,r)=>e%r)),"/":(...e)=>e.reduce(((e,r)=>e/r)),"*":(...e)=>e.reduce(((e,r)=>e*r)),"+":(...e)=>e.reduce(((e,r)=>e+r)),"-":(...e)=>e.length<2?-e:e.reduce(((e,r)=>e-r)),">>>":(e,r)=>e>>>r,">>":(e,r)=>e>>r,"<<":(e,r)=>e<<r,">=":(e,r)=>e>=r,">":(e,r)=>e>r,"<=":(e,r)=>e<=r,"<":(e,r)=>e<r,"!=":(e,r)=>e!=r,"==":(e,r)=>e==r,"&":(e,r)=>e&r,"^":(e,r)=>e^r,"|":(e,r)=>e|r,"&&":(...e)=>e.every(Boolean),"||":(...e)=>e.some(Boolean),",":(...e)=>e.reduce(((e,r)=>r))},g=y,m=e=>(e="string"==typeof e?f(e):e,r=>g(e,r));export{m as default,g as evaluate,f as parse};
1
+ var e,r,a=15,t=(a,t)=>(r=a,e=0,t=f(),e<r.length?o():t.valueOf()),o=(a="Bad syntax")=>{throw Error(a+" `"+r[e]+"` at "+e)},n=(a=1,t=e)=>{if("number"==typeof a)e+=a;else for(;a(s());)e++;return r.slice(t,e)},s=(a=0)=>r.charCodeAt(e+a),l=(a=1)=>r.substr(e,a),f=(e=0,r,a,n,s=0,l,f)=>{for(;(a=t.space())&&(f=i[a]?.(n,e)||!n&&p(a));)n=f;return r&&a!==r&&o("Unclosed paren"),n},u=(t.space=r=>{for(;(r=s())<=32;)e++;return r},t.token=[e=>(e=n((e=>e>47&&e<58||46==e)))&&((69==s()||101==s())&&(e+=n(2)+n((e=>e>=48&&e<=57))),isNaN(e=new Number(e))?o("Bad number"):e),(e,r)=>34==e&&n()+n((r=>r-e))+n(),e=>n((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))]),p=(e,r=0,a)=>{for(;r<u.length;)if(a=u[r++](e))return a},i=[],c=(r,a=0,u=0,p,c=r.charCodeAt(0),y=r.length,g=i[c],h=r.toUpperCase()!==r,v)=>(v=y<2?h?e=>s(1)<=32:e=>1:h?e=>l(y)==r&&s(y)<=32:e=>l(y)==r,p=u?u>0?e=>e&&[n(y),e]:u<0?e=>!e&&[n(y),(f(a-1)||o()).valueOf()]:u:n=>{n=[r,n||o()];do{e+=y,n.push((f(a)||o()).valueOf())}while(t.space()==c&&v());return n},i[c]=(e,r)=>r<a&&v()&&p(e)||g&&g(e,r));for(let r=0,t=[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",10,,">=",10,,">>",11,,">>>",11,,"<",10,,"<=",10,,"<<",11,,"+",12,,"+",a,-1,"++",a,-1,"++",a,1,"-",12,,"-",a,-1,"--",a,-1,"--",a,1,"!",a,-1,"*",13,,"/",13,,"%",13,,".",18,(e,r)=>e&&[n(),e,"string"==typeof(r=f(18))?'"'+r+'"':r.valueOf()],"[",18,r=>(e++,r=[".",r,f(0,93).valueOf()],e++,r),"]",,,"(",18,(r,a)=>(e++,a=f(0,41),e++,Array.isArray(a)&&","===a[0]?(a[0]=r,a):a?[r,a.valueOf()]:[r]),"(",19,(r,a)=>!r&&(++e,a=f(0,41)||o(),++e,a),")",,,];r<t.length;)c(t[r++],t[r++],t[r++]);var y=t,g=e=>Array.isArray(e)&&("string"==typeof e[0]||g(e[0])),h=(e,r={},a,t)=>g(e)?("string"==typeof(a=e[0])&&(t=d[a]),"function"!=typeof(a=t||h(a,r))?a:a.call(...e.map((e=>h(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,v=e=>(...r)=>r.reduce(e),d=h.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":v(((e,r)=>e&&e[r])),"%":v(((e,r)=>e%r)),"/":v(((e,r)=>e/r)),"*":v(((e,r)=>e*r)),"+":v(((e,r)=>e+r)),"-":(...e)=>e.length<2?-e:e.reduce(((e,r)=>e-r)),">>>":(e,r)=>e>>>r,">>":(e,r)=>e>>r,"<<":(e,r)=>e<<r,">=":(e,r)=>e>=r,">":(e,r)=>e>r,"<=":(e,r)=>e<=r,"<":(e,r)=>e<r,"!=":(e,r)=>e!=r,"==":(e,r)=>e==r,"&":(e,r)=>e&r,"^":(e,r)=>e^r,"|":(e,r)=>e|r,"&&":(...e)=>e.every(Boolean),"||":(...e)=>e.some(Boolean),",":v(((e,r)=>r))},A=h,O=e=>(e="string"==typeof e?y(e):e,r=>A(e,r));export{O as default,A as evaluate,y as parse};