subscript 5.3.2 → 5.5.2

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
@@ -7,7 +7,7 @@ _Subscript_ is micro-language with common syntax subset of C++, JS, Java, Python
7
7
 
8
8
  * Well-known syntax
9
9
  * Any _subscript_ fragment can be copy-pasted to any target language
10
- * It's tiny <sub>![npm bundle size](https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip)</sub>
10
+ * It's tiny <sub><a href="https://bundlephobia.com/package/subscript@5.5.0"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip"/></a></sub>
11
11
  * It's :rocket: fast ([see performance](#performance))
12
12
  * Configurable & extensible
13
13
  * Trivial to use...
@@ -30,7 +30,7 @@ _Subscript_ is designed to be useful for:
30
30
  * custom DSL
31
31
 
32
32
  [_Jsep_](https://github.com/EricSmekens/jsep) is generally fine for the listed tasks, unless you need dependencies as small as possible.
33
- _Subscript_ has [2.5kb](https://npmfs.com/package/subscript/5.2.0/subscript.min.js) footprint vs [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 _jsep_ test coverage and better performance.
33
+ _Subscript_ has [2.4kb](https://npmfs.com/package/subscript/5.5.0/subscript.min.js) footprint vs [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 _jsep_ test coverage and better performance.
34
34
 
35
35
 
36
36
  ## Evaluation
@@ -47,7 +47,7 @@ _Subscript_ parser generates lispy calltree (compatible with [frisk](https://npm
47
47
  ```js
48
48
  import {evaluate} from 'subscript.js'
49
49
 
50
- evaluate(['+', ['*', 'min', 60], '"sec"'], { min: 5 }) // min*60 + "sec" == "300sec"
50
+ evaluate(['+', ['*', 'min', 60], '@sec'], { min: 5 }) // min*60 + "sec" == "300sec"
51
51
  ```
52
52
 
53
53
  ## Extending
@@ -69,7 +69,7 @@ Default operators include common operators for the listed languages in the follo
69
69
  * `&&`
70
70
  * `||`
71
71
 
72
- Operators can be extended via `parse.operator(str, prec, type)` and `evaluate.operator(str, fn)` functions for any unary/binary/postfix operators, calls, props, groups, arrays, objects etc.
72
+ Operators can be extended via `parse.operator(str, prec, type)` and `evaluate.operator(str, fn)` functions for any unary/binary/postfix operators, calls, prop chains, groups etc.
73
73
 
74
74
  ```js
75
75
  import { parse, evaluate } from 'subscript.js'
@@ -77,7 +77,7 @@ import { parse, evaluate } from 'subscript.js'
77
77
  parse.operator('=>', 10) // precedence=10, type=default (0 - binary, 1 - postfix, -1 - prefix)
78
78
 
79
79
  evaluate.operator('=>', ( args, body ) => evaluate(body, args))
80
- evaluate.operator('|', ( a, ...b ) => a.pipe(...b))
80
+ evaluate.operator('|', ( a, b ) => a.pipe(b))
81
81
 
82
82
  let tree = parse(`
83
83
  interval(350)
@@ -136,7 +136,7 @@ It adds support of:
136
136
  ```js
137
137
  import { parse, evaluate } from 'subscript/justin.js'
138
138
 
139
- let xy = parse('{ x: 1, "y": 2+2 }["x"]') // ['[', {x:1, y: ['+', 2, 2]}, '"x"']
139
+ let xy = parse('{ x: 1, "y": 2+2 }["x"]') // ['[', {x:1, y: ['+', 2, 2]}, '@x']
140
140
  evaluate(xy) // 1
141
141
  ```
142
142
 
package/evaluate.js CHANGED
@@ -1,17 +1,18 @@
1
- const cache = new WeakMap
2
-
3
1
  // calltree → result
4
- export const evaluate = (node, ctx={},x, fn) => {
5
- // if (fn=cache.get(node)) return fn(ctx)
6
-
2
+ export const evaluate = (node, ctx={}) => {
7
3
  if (typeof node === 'string')
8
- return node[0] === '"' ? node.slice(1,-1) : node[0]==='@' ? node.slice(1) : node in ctx ? ctx[node] : node
4
+ return node[0]==='@' ? node.slice(1) : ctx[node]
9
5
 
10
- if (Array.isArray(node) && (typeof node[0] === 'string' || Array.isArray(node[0]))) {
6
+ if (Array.isArray(node)) {
11
7
  // [[a,b], c] or ['+', a, b] or ['myfn', a, b], or
12
- let [c, ...args] = node, fn = typeof c === 'string' ? (lookup[c] || ctx[c]) : evaluate(c, ctx)
13
- args = args.map(a => evaluate(a, ctx))
14
- return fn.apply(c,args)
8
+ let c = node[0], l = node.length,
9
+ fn = Array.isArray(c) ? evaluate(c, ctx) : (lookup[c] || ctx[c] || c),
10
+ i=1, res=[]
11
+
12
+ if (fn.ab) { res=evaluate(node[i++],ctx); do { res = fn(res, evaluate(node[i++],ctx)) } while ( i < l ) }
13
+ else { while ( i < l ) res.push(evaluate(node[i++], ctx)); res = fn.apply(ctx,res) }
14
+
15
+ return res
15
16
  }
16
17
 
17
18
  return node
@@ -19,7 +20,8 @@ export const evaluate = (node, ctx={},x, fn) => {
19
20
  lookup = {},
20
21
 
21
22
  // op evaluators
22
- // multiple args allows shortcuts, lisp compatible, easy manual eval, functions anyways take multiple arguments
23
- operator = evaluate.operator = (op, fn) => lookup[op] = fn.length == 2 ? (...a)=>a.reduce(fn) : fn
23
+ // multiple args (fn.r=false) are caused by:
24
+ // ||&& shortcuts, lisp compatiblity, manual eval, functions multiple arguments, right precedence
25
+ operator = evaluate.operator = (op, fn) => (lookup[op] = fn).ab = fn.length==2
24
26
 
25
27
  export default evaluate
package/justin.js CHANGED
@@ -27,7 +27,7 @@ parse.token.push(
27
27
  if (c === 92) skip(), str += escape[char()] || char(); else str+=char()
28
28
  skip()
29
29
  }
30
- return skip(), qc + str + qc
30
+ return skip(), '@' + str
31
31
  },
32
32
 
33
33
  // id
@@ -65,8 +65,7 @@ const addOps = (add, stride=2, list) => {
65
65
 
66
66
  addOps(parse.operator, 3, [
67
67
  // subscript ones
68
- // TODO: add ,, as node here?
69
- ',', PREC_SEQ,,
68
+ ',', PREC_SEQ,,
70
69
 
71
70
  '|', PREC_OR,,
72
71
  '||', PREC_SOME,,
@@ -93,13 +92,13 @@ addOps(parse.operator, 3, [
93
92
  '+', PREC_SUM,,
94
93
  '+', PREC_UNARY, -1,
95
94
  '++', PREC_UNARY, -1,
96
- '++', PREC_UNARY, +1,
95
+ '++', PREC_POSTFIX, +1,
97
96
  '-', PREC_SUM,,
98
97
  '-', PREC_UNARY, -1,
99
98
  '--', PREC_UNARY, -1,
100
- '--', PREC_UNARY, +1,
99
+ '--', PREC_POSTFIX, +1,
101
100
 
102
- // !
101
+ // ! ~
103
102
  '!', PREC_UNARY, -1,
104
103
 
105
104
  // * / %
@@ -108,14 +107,14 @@ addOps(parse.operator, 3, [
108
107
  '%', PREC_MULT,,
109
108
 
110
109
  // a.b
111
- '.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
110
+ '.', PREC_CALL, (node,b) => node && [skip(), node, '@' + expr(PREC_CALL)],
112
111
 
113
112
  // a[b]
114
113
  '[', PREC_CALL, (node) => (skip(), node = ['.', node, val(expr(0,CBRACK))], node),
115
114
  ']',,,
116
115
 
117
116
  // a(b)
118
- '(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN),
117
+ '(', PREC_CALL, (node,b) => (skip(), b=expr(0,CPAREN),
119
118
  Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, val(b)] : [node]
120
119
  ),
121
120
  // (a+b)
@@ -134,9 +133,8 @@ addOps(parse.operator, 3, [
134
133
  skip(), parse.space(), a = expr()
135
134
  return ['?:', node, a[1], a[2]]
136
135
  },
137
- '}',,,
138
- ':',2,,
139
- 'in', PREC_COMP, (node) => code(2) <= 32 && [skip(2), '"'+node+'"', expr(PREC_COMP)],
136
+ ':', PREC_COMP,,
137
+ 'in', PREC_COMP, (node) => code(2)<=32 && [skip(2), '@'+node, expr(PREC_COMP)],
140
138
 
141
139
  // as operator it's faster to lookup (no need to extra rule check), smaller and no conflict with word names
142
140
  // [a,b,c]
@@ -147,8 +145,9 @@ addOps(parse.operator, 3, [
147
145
 
148
146
  // {a:0, b:1}
149
147
  '{', PREC_TOKEN, (node,arg) => !node && (skip(), arg=expr(0,125),
150
- !arg ? ['{'] : arg[0] == ':' ? ['{',arg] : arg[0] == ',' ? (arg[0]='{',arg) : ['{',arg])
151
- ,
148
+ !arg ? ['{'] : arg[0] == ':' ? ['{',strkey(arg)] : arg[0] == ',' ? (arg[0]='{',arg.map(strkey)) : ['{',arg]),
149
+ '}',,,
150
+
152
151
 
153
152
  // literals
154
153
  'null', PREC_TOKEN, node=>!node&&(skip(4),v(null)),
@@ -156,6 +155,7 @@ addOps(parse.operator, 3, [
156
155
  'true', PREC_TOKEN, node=>!node&&(skip(4),v(true)),
157
156
  'undefined', PREC_TOKEN, node=>!node&&(skip(9),v(undefined)),
158
157
  ])
158
+ const strkey = a => Array.isArray(a) ? (a[1]=(a[1][0]==='@'?'':'@')+a[1],a) : a
159
159
  const v = v => ({valueOf:()=>v})
160
160
 
161
161
  addOps(evaluate.operator, 2, [
@@ -170,8 +170,8 @@ addOps(evaluate.operator, 2, [
170
170
  '/', (a,b)=>a/b,
171
171
  '*', (a,b)=>a*b,
172
172
 
173
- '+', (a,b)=>a+b,
174
- '-', (...a)=>a.length < 2 ? -a : a.reduce((a,b)=>a-b),
173
+ '+', (a,b)=>a+(b||0),
174
+ '-', (a,b)=>b==null ? -a : a-b,
175
175
 
176
176
  '>>>', (a,b)=>a>>>b,
177
177
  '>>', (a,b)=>a>>b,
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- const e=(t,n={},o,s)=>{if("string"==typeof t)return'"'===t[0]?t.slice(1,-1):"@"===t[0]?t.slice(1):t in n?n[t]:t;if(Array.isArray(t)&&("string"==typeof t[0]||Array.isArray(t[0]))){let[o,...s]=t,a="string"==typeof o?r[o]||n[o]:e(o,n);return s=s.map((r=>e(r,n))),a.apply(o,s)}return t},r={};let t,n;e.operator=(e,t)=>r[e]=2==t.length?(...e)=>e.reduce(t):t;const o=(e,r)=>(n=e,t=0,r=l(),t<n.length?s():y(r)),s=(e="Bad syntax")=>{throw Error(e+" `"+n[t]+"` at "+t)},a=(e=1,r=t)=>{if("number"==typeof e)t+=e;else for(;e(i());)t++;return n.slice(r,t)},i=(e=0)=>n.charCodeAt(t+e),f=(e=1)=>n.substr(t,e),l=(e=0,r,n,a,i=0,f,l)=>{for(;(n=o.space())&&(l=c[n]?.(a,e)||!a&&p(n));)a=l;return r&&(n!=r?s("Unclosed paren"):t++),a};o.space=e=>{for(;(e=i())<=32;)t++;return e};const u=o.token=[],p=(e,r=0,t)=>{for(;r<u.length;)if(t=u[r++](e))return t},c=[];o.operator=(e,r=0,n=0,s,u=e.charCodeAt(0),p=e.length,d=c[u],h=n<=0&&e.toUpperCase()!==e)=>(s=n?n>0?e=>e&&[a(p),y(e)]:n<0?e=>!e&&[a(p),y(l(r-1))]:n:n=>{n=[e,y(n)];do{t+=p,n.push(y(l(r)))}while(o.space()==u&&(p<2||f(p)==e)&&(!h||i(p)<=32));return n},c[u]=(t,n)=>n<r&&(p<2||f(p)==e)&&(!h||i(p)<=32)&&s(t)||d&&d(t,n));const y=e=>Array.isArray(e)?e:(e||s()).valueOf();o.token.push((e=>(e=a((e=>e>47&&e<58||46==e)))&&((69==i()||101==i())&&(e+=a(2)+a((e=>e>=48&&e<=57))),isNaN(e=new Number(e))?s("Bad number"):e)),((e,r,t,n)=>{if(34===e||39===e){for(r=f(),a(),n="";(t=i())-e;)92===t?(a(),n+=d[f()]||f()):n+=f(),a();return a(),r+n+r}}),(e=>a((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))));const d={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};o.space=e=>{for(;(e=i())<=32||47===e;)if(e<=32)a();else if(47===e)if(42===i(1))a(2),a((e=>42!==e&&47!==i(1))),a(2);else{if(47!==i(1))break;a(2),a((e=>e>=32))}return e};const h=(e,r=2,t)=>{for(let n=0;n<t.length;n+=r)e(t[n],t[n+1],t[n+2])};h(o.operator,3,[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",10,,">=",10,,">>",11,,">>>",11,,"<",10,,"<=",10,,"<<",11,,"+",12,,"+",15,-1,"++",15,-1,"++",15,1,"-",12,,"-",15,-1,"--",15,-1,"--",15,1,"!",15,-1,"*",13,,"/",13,,"%",13,,".",18,(e,r)=>e&&[a(),e,"string"==typeof(r=l(18))?'"'+r+'"':r.valueOf()],"[",18,e=>(a(),[".",e,y(l(0,93))]),"]",,,"(",18,(e,r)=>(a(),r=l(0,41),Array.isArray(r)&&","===r[0]?(r[0]=e,r):r?[e,y(r)]:[e]),"(",19,(e,r)=>!e&&(a(),l(0,41)||s()),")",,,";",1,,"===",9,,"!==",9,,"**",14,,"~",15,-1,"?",3,e=>{let r;return e||s("Expected expression"),a(),o.space(),r=l(),["?:",e,r[1],r[2]]},"}",,,":",2,,"in",10,e=>i(2)<=32&&[a(2),'"'+e+'"',l(10)],"[",20,(e,r)=>!e&&(a(),(r=l(0,93))?","==r[0]?(r[0]="[",r):["[",r]:["["]),"{",20,(e,r)=>!e&&(a(),(r=l(0,125))?":"==r[0]?["{",r]:","==r[0]?(r[0]="{",r):["{",r]:["{"]),"null",20,e=>!e&&(a(4),g(null)),"false",20,e=>!e&&(a(5),g(!1)),"true",20,e=>!e&&(a(4),g(!0)),"undefined",20,e=>!e&&(a(9),g(void 0))]);const g=e=>({valueOf:()=>e});h(e.operator,2,["!",e=>!e,"++",e=>++e,"--",e=>--e,".",(e,r)=>e?e[r]:e,"%",(e,r)=>e%r,"/",(e,r)=>e/r,"*",(e,r)=>e*r,"+",(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,r)=>r,"**",(...e)=>e.reduceRight(((e,r)=>Math.pow(r,e))),"~",e=>~e,"?:",(e,r,t)=>e?r:t,"in",(e,r)=>e in r,"[",(...e)=>Array(...e),"{",(...e)=>Object.fromEntries(e),":",(e,r)=>[e,r]]);var A=r=>(r="string"==typeof r?o(r):r,t=>e(r,t));export{A as default,e as evaluate,o as parse};
1
+ const r=(t,n={})=>{if("string"==typeof t)return"@"===t[0]?t.slice(1):n[t];if(Array.isArray(t)){let o=t[0],a=t.length,s=Array.isArray(o)?r(o,n):e[o]||n[o]||o,l=1,i=[];if(s.ab){i=r(t[l++],n);do{i=s(i,r(t[l++],n))}while(l<a)}else{for(;l<a;)i.push(r(t[l++],n));i=s.apply(o,i)}return i}return t},e={};let t,n;r.operator=(r,t)=>(e[r]=t,t.ab=2==t.length);const o=(r,e)=>(n=r,t=0,e=f(),t<n.length?a():y(e)),a=(r="Bad syntax")=>{throw Error(r+" `"+n[t]+"` at "+t)},s=(r=1,e=t)=>{if("number"==typeof r)t+=r;else for(;r(l());)t++;return n.slice(e,t)},l=(r=0)=>n.charCodeAt(t+r),i=(r=1)=>n.substr(t,r),f=(r=0,e,n,s,l=0,i,f)=>{for(;(n=o.space())&&(i=(f=c[n])&&f(s,r)||!s&&p(n));)s=i;return e&&(n!=e?a("Unclosed paren"):t++),s};o.space=r=>{for(;(r=l())<=32;)t++;return r};const u=o.token=[],p=(r,e=0,t)=>{for(;e<u.length;)if(t=u[e++](r))return t},c=[];o.operator=(r,e=0,n=0,a,l=r.charCodeAt(0),u=r.length,p=c[l])=>(a=n?n>0?r=>r&&[s(u),y(r)]:n<0?r=>!r&&[s(u),y(f(e-1))]:n:n=>{n=[r,y(n)];do{t+=u,n.push(y(f(e)))}while(o.space()==l&&(u<2||i(u)==r));return n},c[l]=(t,n)=>n<e&&(u<2||i(u)==r)&&a(t)||p&&p(t,n));const y=r=>Array.isArray(r)?r:(r||a()).valueOf();o.token.push((r=>(r=s((r=>r>47&&r<58||46==r)))&&((69==l()||101==l())&&(r+=s(2)+s((r=>r>=48&&r<=57))),isNaN(r=new Number(r))?a("Bad number"):r)),((r,e,t,n)=>{if(34===r||39===r){for(i(),s(),n="";(t=l())-r;)92===t?(s(),n+=h[i()]||i()):n+=i(),s();return s(),"@"+n}}),(r=>s((r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r))));const h={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};o.space=r=>{for(;(r=l())<=32||47===r;)if(r<=32)s();else if(47===r)if(42===l(1))s(2),s((r=>42!==r&&47!==l(1))),s(2);else{if(47!==l(1))break;s(2),s((r=>r>=32))}return r};const d=(r,e=2,t)=>{for(let n=0;n<t.length;n+=e)r(t[n],t[n+1],t[n+2])};d(o.operator,3,[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",10,,">=",10,,">>",11,,">>>",11,,"<",10,,"<=",10,,"<<",11,,"+",12,,"+",15,-1,"++",15,-1,"++",16,1,"-",12,,"-",15,-1,"--",15,-1,"--",16,1,"!",15,-1,"*",13,,"/",13,,"%",13,,".",18,(r,e)=>r&&[s(),r,"@"+f(18)],"[",18,r=>(s(),[".",r,y(f(0,93))]),"]",,,"(",18,(r,e)=>(s(),e=f(0,41),Array.isArray(e)&&","===e[0]?(e[0]=r,e):e?[r,y(e)]:[r]),"(",19,(r,e)=>!r&&(s(),f(0,41)||a()),")",,,";",1,,"===",9,,"!==",9,,"**",14,,"~",15,-1,"?",3,r=>{let e;return r||a("Expected expression"),s(),o.space(),e=f(),["?:",r,e[1],e[2]]},":",10,,"in",10,r=>l(2)<=32&&[s(2),"@"+r,f(10)],"[",20,(r,e)=>!r&&(s(),(e=f(0,93))?","==e[0]?(e[0]="[",e):["[",e]:["["]),"{",20,(r,e)=>!r&&(s(),(e=f(0,125))?":"==e[0]?["{",A(e)]:","==e[0]?(e[0]="{",e.map(A)):["{",e]:["{"]),"}",,,"null",20,r=>!r&&(s(4),b(null)),"false",20,r=>!r&&(s(5),b(!1)),"true",20,r=>!r&&(s(4),b(!0)),"undefined",20,r=>!r&&(s(9),b(void 0))]);const A=r=>Array.isArray(r)?(r[1]=("@"===r[1][0]?"":"@")+r[1],r):r,b=r=>({valueOf:()=>r});d(r.operator,2,["!",r=>!r,"++",r=>++r,"--",r=>--r,".",(r,e)=>r?r[e]:r,"%",(r,e)=>r%e,"/",(r,e)=>r/e,"*",(r,e)=>r*e,"+",(r,e)=>r+(e||0),"-",(r,e)=>null==e?-r: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)=>r.every(Boolean),"||",(...r)=>r.some(Boolean),",",(r,e)=>e,"**",(...r)=>r.reduceRight(((r,e)=>Math.pow(e,r))),"~",r=>~r,"?:",(r,e,t)=>r?e:t,"in",(r,e)=>r in e,"[",(...r)=>Array(...r),"{",(...r)=>Object.fromEntries(r),":",(r,e)=>[r,e]]);var g=e=>(e="string"==typeof e?o(e):e,t=>r(e,t));export{g as default,r as evaluate,o as parse};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "5.3.2",
3
+ "version": "5.5.2",
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
@@ -18,10 +18,10 @@ code = (i=0) => cur.charCodeAt(idx+i),
18
18
  char = (n=1) => cur.substr(idx, n),
19
19
 
20
20
  // a + b - c
21
- expr = (prec=0, end, cc, node, i=0, map, newNode) => {
21
+ expr = (prec=0, end, cc, node, i=0, newNode, op) => {
22
22
  // chunk/token parser
23
23
  while (
24
- (cc=parse.space()) && (newNode = lookup[cc]?.(node, prec) || (!node && token(cc)) )
24
+ (cc=parse.space()) && (newNode = (op=lookup[cc]) && op(node, prec) || (!node && token(cc)) )
25
25
  ) node = newNode;
26
26
 
27
27
  // skip end character, if expected
@@ -45,14 +45,12 @@ lookup = [],
45
45
  // @param prec is operator precedenc to check
46
46
  // @param map is either number +1 - postfix unary, -1 prefix unary, 0 binary, else - custom mapper function
47
47
  operator = parse.operator = (
48
- op, prec=0, type=0, map, c=op.charCodeAt(0), l=op.length,
49
- prev=lookup[c],
50
- spaced=type<=0&&op.toUpperCase()!==op // non-postfix word operator must have space after
48
+ op, prec=0, type=0, map, c=op.charCodeAt(0), l=op.length, prev=lookup[c]
51
49
  ) => (
52
- map = !type ? node => { // binary, consume same-op group
50
+ map = !type ? node => { // binary
53
51
  node = [op, val(node)]
54
- do { idx+=l, node.push(val(expr(prec))) }
55
- while (parse.space()==c && (l<2||char(l)==op) && (!spaced||code(l)<=SPACE))
52
+ do { idx+=l, node.push(val(expr(prec))) } // consume same-op group
53
+ while (parse.space()==c && (l<2||char(l)==op))
56
54
  return node
57
55
  } :
58
56
  type > 0 ? node => node && [skip(l), val(node)] : // postfix unary
@@ -60,8 +58,7 @@ operator = parse.operator = (
60
58
  type,
61
59
 
62
60
  lookup[c] = (node, curPrec) =>
63
- curPrec < prec && (l<2||char(l)==op) && (!spaced||code(l)<=SPACE) &&
64
- map(node) || (prev && prev(node, curPrec))
61
+ curPrec < prec && (l<2||char(l)==op) && map(node) || (prev && prev(node, curPrec))
65
62
  ),
66
63
 
67
64
  // in order to support literal tokens, we call valueOf any time we create or modify calltree node
package/subscript.js CHANGED
@@ -15,7 +15,7 @@ tokens.push(
15
15
  )
16
16
  ),
17
17
  // "a"
18
- (q, qc) => q == 34 && (skip() + skip(c => c-q) + skip()),
18
+ (q, qc, v) => q == 34 && (skip(), v=skip(c => c-q), skip(), '@'+v),
19
19
  // id
20
20
  c => skip(c =>
21
21
  (c >= 48 && c <= 57) || // 0..9
@@ -73,14 +73,14 @@ addOps(parseOp, 3, [
73
73
  '%', PREC_MULT,,
74
74
 
75
75
  // a.b
76
- '.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
76
+ '.', PREC_CALL, (node,b) => node && [skip(), node, '@' + expr(PREC_CALL)],
77
77
 
78
78
  // a[b]
79
79
  '[', PREC_CALL, (node) => (skip(), node = ['.', node, val(expr(0,CBRACK))], node),
80
80
  ']',,,
81
81
 
82
82
  // a(b)
83
- '(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN),
83
+ '(', PREC_CALL, (node,b) => (skip(), b=expr(0,CPAREN),
84
84
  Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, val(b)] : [node]
85
85
  ),
86
86
  // (a+b)
@@ -101,8 +101,8 @@ addOps(evalOp, 2, [
101
101
  '/', (a,b)=>a/b,
102
102
  '*', (a,b)=>a*b,
103
103
 
104
- '+', (a,b=0)=>a+b,
105
- '-', (...a)=>a.length < 2 ? -a : a.reduce((a,b)=>a-b),
104
+ '+', (a,b)=>a+(b||0),
105
+ '-', (a,b)=>b==null ? -a : a-b,
106
106
 
107
107
  '>>>', (a,b)=>a>>>b,
108
108
  '>>', (a,b)=>a>>b,
@@ -119,8 +119,8 @@ addOps(evalOp, 2, [
119
119
  '&', (a,b)=>a&b,
120
120
  '^', (a,b)=>a^b,
121
121
  '|', (a,b)=>a|b,
122
- '&&', (...a)=>a.every(Boolean),
123
- '||', (...a)=>a.some(Boolean),
122
+ '&&', (a,b)=>a&&b,
123
+ '||', (a,b)=>a||b,
124
124
  ',', (a,b)=>(a,b)
125
125
  ])
126
126
 
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- let r,e;const t=(t,o)=>(e=t,r=0,o=l(),r<e.length?n():y(o)),n=(t="Bad syntax")=>{throw Error(t+" `"+e[r]+"` at "+r)},o=(t=1,n=r)=>{if("number"==typeof t)r+=t;else for(;t(a());)r++;return e.slice(n,r)},a=(t=0)=>e.charCodeAt(r+t),s=(t=1)=>e.substr(r,t),l=(e=0,o,a,s,l=0,p,f)=>{for(;(a=t.space())&&(f=u[a]?.(s,e)||!s&&i(a));)s=f;return o&&(a!=o?n("Unclosed paren"):r++),s};t.space=e=>{for(;(e=a())<=32;)r++;return e};const p=t.token=[],i=(r,e=0,t)=>{for(;e<p.length;)if(t=p[e++](r))return t},u=[],f=t.operator=(e,n=0,p=0,i,f=e.charCodeAt(0),c=e.length,h=u[f],g=p<=0&&e.toUpperCase()!==e)=>(i=p?p>0?r=>r&&[o(c),y(r)]:p<0?r=>!r&&[o(c),y(l(n-1))]:p:o=>{o=[e,y(o)];do{r+=c,o.push(y(l(n)))}while(t.space()==f&&(c<2||s(c)==e)&&(!g||a(c)<=32));return o},u[f]=(r,t)=>t<n&&(c<2||s(c)==e)&&(!g||a(c)<=32)&&i(r)||h&&h(r,t)),y=r=>Array.isArray(r)?r:(r||n()).valueOf(),c=(r,e={},t,n)=>{if("string"==typeof r)return'"'===r[0]?r.slice(1,-1):"@"===r[0]?r.slice(1):r in e?e[r]:r;if(Array.isArray(r)&&("string"==typeof r[0]||Array.isArray(r[0]))){let[t,...n]=r,o="string"==typeof t?h[t]||e[t]:c(t,e);return n=n.map((r=>c(r,e))),o.apply(t,n)}return r},h={},g=c.operator=(r,e)=>h[r]=2==e.length?(...r)=>r.reduce(e):e;p.push((r=>(r=o((r=>r>47&&r<58||46==r)))&&((69==a()||101==a())&&(r+=o(2)+o((r=>r>=48&&r<=57))),isNaN(r=new Number(r))?n("Bad number"):r)),((r,e)=>34==r&&o()+o((e=>e-r))+o()),(r=>o((r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192))));const A=(r,e=2,t)=>{for(let n=0;n<t.length;n+=e)r(t[n],t[n+1],t[n+2])};A(f,3,[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",10,,">=",10,,">>",11,,">>>",11,,"<",10,,"<=",10,,"<<",11,,"+",12,,"+",15,-1,"++",15,-1,"++",16,1,"-",12,,"-",15,-1,"--",15,-1,"--",16,1,"!",15,-1,"*",13,,"/",13,,"%",13,,".",18,(r,e)=>r&&[o(),r,"string"==typeof(e=l(18))?'"'+e+'"':e.valueOf()],"[",18,r=>(o(),[".",r,y(l(0,93))]),"]",,,"(",18,(r,e)=>(o(),e=l(0,41),Array.isArray(e)&&","===e[0]?(e[0]=r,e):e?[r,y(e)]:[r]),"(",19,(r,e)=>!r&&(o(),l(0,41)||n()),")",,,]),A(g,2,["!",r=>!r,"++",r=>++r,"--",r=>--r,".",(r,e)=>r?r[e]:r,"%",(r,e)=>r%e,"/",(r,e)=>r/e,"*",(r,e)=>r*e,"+",(r,e=0)=>r+e,"-",(...r)=>r.length<2?-r:r.reduce(((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,"&&",(...r)=>r.every(Boolean),"||",(...r)=>r.some(Boolean),",",(r,e)=>e]);var d=r=>(r="string"==typeof r?t(r):r,e=>c(r,e));export{d as default,c as evaluate,t as parse};
1
+ let r,e;const t=(t,n)=>(e=t,r=0,n=l(),r<e.length?a():h(n)),a=(t="Bad syntax")=>{throw Error(t+" `"+e[r]+"` at "+r)},n=(t=1,a=r)=>{if("number"==typeof t)r+=t;else for(;t(o());)r++;return e.slice(a,r)},o=(t=0)=>e.charCodeAt(r+t),s=(t=1)=>e.substr(r,t),l=(e=0,n,o,s,l=0,u,p)=>{for(;(o=t.space())&&(u=(p=i[o])&&p(s,e)||!s&&f(o));)s=u;return n&&(o!=n?a("Unclosed paren"):r++),s};t.space=e=>{for(;(e=o())<=32;)r++;return e};const u=t.token=[],f=(r,e=0,t)=>{for(;e<u.length;)if(t=u[e++](r))return t},i=[],p=t.operator=(e,a=0,o=0,u,f=e.charCodeAt(0),p=e.length,y=i[f])=>(u=o?o>0?r=>r&&[n(p),h(r)]:o<0?r=>!r&&[n(p),h(l(a-1))]:o:n=>{n=[e,h(n)];do{r+=p,n.push(h(l(a)))}while(t.space()==f&&(p<2||s(p)==e));return n},i[f]=(r,t)=>t<a&&(p<2||s(p)==e)&&u(r)||y&&y(r,t)),h=r=>Array.isArray(r)?r:(r||a()).valueOf(),y=(r,e={})=>{if("string"==typeof r)return"@"===r[0]?r.slice(1):e[r];if(Array.isArray(r)){let t=r[0],a=r.length,n=Array.isArray(t)?y(t,e):c[t]||e[t]||t,o=1,s=[];if(n.ab){s=y(r[o++],e);do{s=n(s,y(r[o++],e))}while(o<a)}else{for(;o<a;)s.push(y(r[o++],e));s=n.apply(e,s)}return s}return r},c={},A=y.operator=(r,e)=>(c[r]=e).ab=2==e.length;u.push((r=>(r=n((r=>r>47&&r<58||46==r)))&&((69==o()||101==o())&&(r+=n(2)+n((r=>r>=48&&r<=57))),isNaN(r=new Number(r))?a("Bad number"):r)),((r,e,t)=>34==r&&(n(),t=n((e=>e-r)),n(),"@"+t)),(r=>n((r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192))));const d=(r,e=2,t)=>{for(let a=0;a<t.length;a+=e)r(t[a],t[a+1],t[a+2])};d(p,3,[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",10,,">=",10,,">>",11,,">>>",11,,"<",10,,"<=",10,,"<<",11,,"+",12,,"+",15,-1,"++",15,-1,"++",16,1,"-",12,,"-",15,-1,"--",15,-1,"--",16,1,"!",15,-1,"*",13,,"/",13,,"%",13,,".",18,(r,e)=>r&&[n(),r,"@"+l(18)],"[",18,r=>(n(),[".",r,h(l(0,93))]),"]",,,"(",18,(r,e)=>(n(),e=l(0,41),Array.isArray(e)&&","===e[0]?(e[0]=r,e):e?[r,h(e)]:[r]),"(",19,(r,e)=>!r&&(n(),l(0,41)||a()),")",,,]),d(A,2,["!",r=>!r,"++",r=>++r,"--",r=>--r,".",(r,e)=>r?r[e]:r,"%",(r,e)=>r%e,"/",(r,e)=>r/e,"*",(r,e)=>r*e,"+",(r,e)=>r+(e||0),"-",(r,e)=>null==e?-r: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)=>r&&e,"||",(r,e)=>r||e,",",(r,e)=>e]);var g=r=>(r="string"==typeof r?t(r):r,e=>y(r,e));export{g as default,y as evaluate,t as parse};