subscript 6.0.1 → 6.1.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
@@ -1,21 +1,18 @@
1
- # <img alt="subscript" src="/subscript2.svg" height=42/> <!--sub͘<em>script</em>--> <!--<sub>SUB͘<em>SCRIPT</em></sub>-->
2
- <a href="https://github.com/spectjs/subscript/actions/workflows/node.js.yml"><img src="https://github.com/spectjs/subscript/actions/workflows/node.js.yml/badge.svg"/></a>
3
- <a href="http://npmjs.org/subscript"><img src="https://img.shields.io/npm/v/subscript?color=indianred"/></a>
4
- <a href="http://microjs.com/#subscript"><img src="https://img.shields.io/badge/microjs-subscript-blue?color=darkslateblue"/></a>
1
+ # <img alt="subscript" src="/subscript2.svg" height=28/> <!--sub͘<em>script</em>--> <!--<sub>SUB͘<em>SCRIPT</em></sub>--> <a href="https://github.com/spectjs/subscript/actions/workflows/node.js.yml"><img src="https://github.com/spectjs/subscript/actions/workflows/node.js.yml/badge.svg"/></a> <a href="http://npmjs.org/subscript"><img src="https://img.shields.io/npm/v/subscript"/></a> <a href="http://microjs.com/#subscript"><img src="https://img.shields.io/badge/microjs-subscript-blue?color=darkslateblue"/></a>
5
2
 
6
- _Subscript_ is micro-language with common syntax subset of C++, JS, Java, Python, Go, Rust etc.<br/>
3
+ _Subscript_ is expression evaluator with standard syntax<br/>
7
4
 
8
- * Standard conventional syntax
9
- * Any fragment can be copy-pasted to any target language
5
+ * Any fragment can be copy-pasted to any language: C++, JS, Java, Python, Go, Rust etc.
10
6
  * Tiny size <sub><a href="https://bundlephobia.com/package/subscript@6.0.0"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip"/></a></sub>
11
- * :rocket: fast ([performance](#performance))
7
+ * :rocket: Fast [performance](#performance)
12
8
  * Configurable & extensible
13
9
  * Trivial to use
14
10
 
15
11
  ```js
16
- import script from 'subscript.js'
12
+ import script from './subscript.js'
17
13
  let fn = script`a.b + c(d - 1)`
18
14
  fn({ a: { b:1 }, c: x => x * 2, d: 3 }) // 5
15
+ fn.args // ['a', 'c', 'd']
19
16
  ```
20
17
 
21
18
  ## Motivation
@@ -34,29 +31,46 @@ _Subscript_ has [2kb](https://npmfs.com/package/subscript/6.0.0/subscript.min.js
34
31
 
35
32
  ## Design
36
33
 
37
- Default operators (same as JS precedence order):
34
+ Default operators are (same as JS precedence order):
38
35
 
39
36
  * `( a, b, c )`
40
- * `a . b`, `a [ b ]`, `a ( b, c )`
37
+ * `a.b`, `a[b]`, `a(b, c)`
41
38
  * `a++`, `a--` unary postfix
42
39
  * `!a`, `+a`, `-a`, `++a`, `--a` unary prefix
43
40
  * `a * b`, `a / b`, `a % b`
44
41
  * `a + b`, `a - b`
45
- * `a << b`, `a >>b`, `a >>>b`
46
- * `a < b`, `a <= b`, `a >b`, `a >=b`
42
+ * `a << b`, `a >> b`, `a >>> b`
43
+ * `a < b`, `a <= b`, `a > b`, `a >= b`
47
44
  * `a == b`, `a != b`
48
45
  * `a & b`
49
46
  * `a ^ b`
50
47
  * `a | b`
51
48
  * `a && b`
52
49
  * `a || b`
50
+ * `a , b`
53
51
 
54
52
  Default literals:
55
53
 
56
54
  * `"abc"` strings
57
55
  * `1.2e+3` numbers
58
56
 
59
- Everything else can be extended via `parse.set(operator, precedence, fn)` for unary or binary operators (detected by number of arguments in `fn`), or via `parse.set(operator, parser, precedence)` for custom tokens.
57
+ Everything else can be extended via `parse.set(token, precedence, operator)` for unary or binary operators (detected by number of arguments in `operator`), or via `parse.set(token, parse, precedence)` for custom tokens.
58
+
59
+ ```js
60
+ import script from './subscript.js'
61
+
62
+ // add ~ unary operator with precedence 15
63
+ script.set('~', 15, a => ~a)
64
+
65
+ // add === binary operator
66
+ script.set('===', 9, (a, b) => a===b)
67
+
68
+ // add literals
69
+ script.set('true', a => ()=>true)
70
+ script.set('false', a => ()=>false)
71
+
72
+ script`true === false`() // false
73
+ ```
60
74
 
61
75
  See [subscript.js](subscript.js) or [justin.js](./justin.js) for examples.
62
76
 
@@ -107,6 +121,7 @@ It extends _subscript_ with:
107
121
  + `'` strings
108
122
  + `?:` ternary operator
109
123
  + `?.` optional chain operator
124
+ + `??` nullish coalesce operator
110
125
  + `[...]` Array literal
111
126
  + `{...}` Object literal
112
127
  + `in` binary
@@ -271,12 +286,14 @@ Subscript shows relatively good performance within other evaluators:
271
286
  Parse 30k times:
272
287
 
273
288
  ```
274
- subscript: ~170 ms
275
- justin: ~183 ms
276
- jsep: ~250 ms
289
+ subscript: ~170 ms 🥇
290
+ justin: ~183 ms 🥈
291
+ jsep: ~270 ms 🥉
292
+ jexpr: ~297 ms
277
293
  mr-parser: ~420 ms
278
294
  expr-eval: ~480 ms
279
295
  math-parser: ~570 ms
296
+ math-expression-evaluator: ~900ms
280
297
  jexl: ~1056 ms
281
298
  mathjs: ~1200 ms
282
299
  new Function: ~1154 ms
@@ -284,19 +301,22 @@ new Function: ~1154 ms
284
301
 
285
302
  Eval 30k times:
286
303
  ```
287
- subscript: ~15 ms
288
- justin: ~15 ms
304
+ new Function: ~7 ms 🥇
305
+ subscript: ~17 ms 🥈
306
+ justin: ~17 ms 🥈
307
+ jexpr: ~23 ms 🥉
289
308
  jsep (expression-eval): ~30 ms
290
- mr-parser: -
309
+ math-expression-evaluator: ~50ms
291
310
  expr-eval: ~72 ms
292
- math-parser: -
293
311
  jexl: ~110 ms
294
312
  mathjs: ~119 ms
295
- new Function: ~5 ms
313
+ mr-parser: -
314
+ math-parser: -
296
315
  ```
297
316
 
298
317
  ## Alternatives
299
318
 
319
+ * [jexpr](https://github.com/justinfagnani/jexpr)
300
320
  * [jexl](https://github.com/TomFrost/Jexl)
301
321
  * [mozjexl](https://github.com/mozilla/mozjexl)
302
322
  * [expr-eval](https://github.com/silentmatt/expr-eval)
package/index.js ADDED
@@ -0,0 +1,72 @@
1
+ const SPACE=32, CPAREN=41
2
+
3
+ // current string, index and collected ids
4
+ export let idx, cur, args,
5
+
6
+ // no handling tagged literals since easily done on user side with cache, if needed
7
+ parse = (s, fn= !(cur=s, idx=0, args=[], s=expr()) || cur[idx] ? err() : ctx=>s(ctx||{})) => (fn.args = args, fn),
8
+
9
+ isId = c =>
10
+ (c >= 48 && c <= 57) || // 0..9
11
+ (c >= 65 && c <= 90) || // A...Z
12
+ (c >= 97 && c <= 122) || // a...z
13
+ c == 36 || c == 95 || // $, _,
14
+ (c >= 192 && c != 215 && c != 247), // any non-ASCII
15
+
16
+ err = (msg='Bad syntax',c=cur[idx]) => { throw SyntaxError(msg + ' `' + c + '` at ' + idx) },
17
+
18
+ skip = (is=1, from=idx, l) => {
19
+ if (typeof is == 'number') idx += is
20
+ else while (is(cur.charCodeAt(idx))) idx++
21
+ return cur.slice(from, idx)
22
+ },
23
+
24
+ // a + b - c
25
+ expr = (prec=0, end, cc, token, newNode, fn) => {
26
+ // chunk/token parser
27
+ while (
28
+ ( cc=space() ) && // till not end
29
+ // FIXME: extra work is happening here, when lookup bails out due to lower precedence -
30
+ // it makes extra `space` call for parent exprs on the same character to check precedence again
31
+ ( newNode =
32
+ (fn=lookup[cc]) && fn(token, prec) || // if operator with higher precedence isn't found
33
+ (!token && id()) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
34
+ )
35
+ ) token = newNode;
36
+
37
+ // check end character
38
+ // FIXME: can't show "Unclose paren", because can be unknown operator within group as well
39
+ if (end) cc==end?idx++:err()
40
+
41
+ return token
42
+ },
43
+
44
+ // skip space chars, return first non-space character
45
+ space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
46
+
47
+ // variable identifier
48
+ id = (name=skip(isId), fn) => name ? (fn=ctx => ctx[name], args.push(name), fn.id=()=>name, fn) : 0,
49
+
50
+ // operator/token lookup table
51
+ lookup = [],
52
+
53
+ // create operator checker/mapper (see examples)
54
+ set = parse.set = (
55
+ op,
56
+ opPrec, fn=SPACE, // if opPrec & fn come in reverse order - consider them raw parse fn case, still precedence possible
57
+ c=op.charCodeAt(0),
58
+ l=op.length,
59
+ prev=lookup[c],
60
+ arity=fn.length || ([fn,opPrec]=[opPrec,fn], 0),
61
+ word=op.toUpperCase()!==op, // make sure word boundary comes after word operator
62
+ map=
63
+ // binary
64
+ arity>1 ? (a,b) => a && (b=expr(opPrec)) && (
65
+ !a.length && !b.length ? (a=fn(a(),b()), ()=>a) : // static pre-eval like `"a"+"b"`
66
+ ctx => fn(a(ctx),b(ctx))
67
+ ) :
68
+ // unary prefix (0 args)
69
+ arity ? a => !a && (a=expr(opPrec-1)) && (ctx => fn(a(ctx))) :
70
+ fn // custom parser
71
+ ) =>
72
+ lookup[c] = (a, curPrec, from=idx) => curPrec<opPrec && (l<2||cur.substr(idx,l)==op) && (!word||!isId(cur.charCodeAt(idx+l))) && (idx+=l, map(a, curPrec)) || (idx=from, prev&&prev(a, curPrec))
package/justin.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // justin lang https://github.com/endojs/Jessie/issues/66
2
- import {parse, set, lookup, skip, cur, idx, err, expr, isId, space} from './index.js'
3
- import './subscript.js'
2
+ import {set, lookup, skip, cur, idx, err, expr, isId, space, args} from './index.js'
3
+ export { default } from './subscript.js'
4
4
 
5
5
  const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, QUOTE=39, _0=48, _9=57, BSLASH=92,
6
6
  PREC_SEQ=1, PREC_COND=3, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
@@ -10,7 +10,7 @@ PREC_EQ=9, PREC_COMP=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_EXP=14,
10
10
  let u, list, op, prec, fn,
11
11
  escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'},
12
12
  string = q => (qc, c, str='') => {
13
- qc&&err() // must not follow another token
13
+ qc&&err('Unexpected string') // must not follow another token
14
14
  while (c=cur.charCodeAt(idx), c-q) {
15
15
  if (c === BSLASH) skip(), c=skip(), str += escape[c] || c
16
16
  else str += skip()
@@ -29,10 +29,10 @@ for (list=[
29
29
  '//', (a, prec) => (skip(c => c >= 32), a||expr(prec)),,
30
30
 
31
31
  // literals
32
- 'null', a => a ? err() : ()=>null,,
33
- 'true', a => a ? err() : ()=>true,,
34
- 'false', a => a ? err() : ()=>false,,
35
- 'undefined', a => a ? err() : ()=>undefined,,
32
+ 'null', a => a ? err('Unexpected literal') : ()=>null,,
33
+ 'true', a => a ? err('Unexpected literal') : ()=>true,,
34
+ 'false', a => a ? err('Unexpected literal') : ()=>false,,
35
+ 'undefined', a => a ? err('Unexpected literal') : ()=>undefined,,
36
36
 
37
37
  ';', a => expr()||(()=>{}),,
38
38
 
@@ -46,7 +46,9 @@ for (list=[
46
46
 
47
47
  // ?:
48
48
  ':', 3.1, (a,b) => [a,b],
49
- '?', 3, (a,b) => a ? b[2] : b[1],
49
+ '?', 3, (a,b) => a ? b[0] : b[1],
50
+
51
+ '??', PREC_OR, (a,b) => a??b,
50
52
 
51
53
  // a?.[, a?.( - postfix operator
52
54
  '?.', a => a && (ctx => a(ctx)||(()=>{})),,//(a) => a||(()=>{}),
@@ -56,18 +58,17 @@ for (list=[
56
58
  'in', PREC_COMP, (a,b) => a in b,
57
59
 
58
60
  // [a,b,c]
59
- '[', (a, args) => !a && (
61
+ '[', (a) => !a && (
60
62
  a=expr(0,CBRACK),
61
63
  !a ? ctx => [] : a.all ? ctx => a.all(ctx) : ctx => [a(ctx)]
62
64
  ),,
63
65
 
64
66
  // {a:1, b:2, c:3}
65
- '{', (a, args) => !a && (
67
+ '{', (a, entries) => !a && (
66
68
  a=expr(0,125),
67
- !a ? ctx => ({}) : ctx => (args=(a.all||a)(ctx), Object.fromEntries(a.all?args:[args]))
69
+ !a ? ctx => ({}) : ctx => (entries=(a.all||a)(ctx), Object.fromEntries(a.all?entries:[entries]))
68
70
  ),,
69
- ':', (a, prec, b) => (b=expr(3.1)||err(), ctx => [(a.id||a)(ctx), b(ctx), a(ctx)]), 3.1
71
+ // for JSON case we should not collect arg (different evaluator than ternary)
72
+ ':', (a, prec, b) => (b=expr(1.1)||err(), a.id&&args.pop(), ctx => [(a.id||a)(ctx), b(ctx)]), 1.1
70
73
 
71
74
  ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
72
-
73
- export default parse
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- let r,e,t,l,a,o,n=(t,...l)=>(e=t.raw?String.raw(t,...l):t,r=0,!(t=i())||e[r]?f():r=>t(r||{})),d=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r,f=(t="Bad syntax",l=e[r])=>{throw Error(t+" `"+l+"` at "+r)},h=(t=1,l=r,a)=>{if("number"==typeof t)r+=t;else for(;t(e.charCodeAt(r));)r++;return e.slice(l,r)},i=(e=0,t,l,a,o,n)=>{for(;(l=s())&&(o=(n=c[l])&&n(a,e)||!a&&u());)a=o;return t&&(l==t?r++:f("Unclosed")),a},s=t=>{for(;(t=e.charCodeAt(r))<=32;)r++;return t},u=(r=h(d),e)=>r?((e=e=>e[r]).id=()=>r,e):0,c=[],C=n.set=(t,l,a=32,o=t.charCodeAt(0),n=t.length,f=c[o],h=a.length||([a,l]=[l,a],0),s=t.toUpperCase()!==t,u=(h>1?(r,e)=>r&&(e=i(l))&&(r.length||e.length?t=>a(r(t),e(t)):(r=a(r(),e()),()=>r)):h?r=>!r&&(r=i(l-1))&&(e=>a(r(e))):a))=>c[o]=(a,o,h=r)=>o<l&&(n<2||e.substr(r,n)==t)&&(!s||!d(e.charCodeAt(r+n)))&&(r+=n,u(a,o))||(r=h,f&&f(a,o)),A=r=>r>=48&&r<=57,g=t=>(t&&f(),t=h((r=>46==r||A(r))),(69==e.charCodeAt(r)||101==e.charCodeAt(r))&&(t+=h(2)+h(A)),(t=+t)!=t?f("Bad number"):()=>t),p=(r,e,t=r.of)=>l=>e(t?t(l):l,r.id());for(l=48;l<=57;)c[l++]=g;for(t=['"',r=>(r=r?f():h((r=>r-34)),h()||f("Bad string"),()=>r),,".",(r,e,t)=>r?(s(),e=h(d)||f(),(t=t=>r(t)[e]).id=()=>e,t.of=r,t):g(h(-1)),18,"[",(r,e,t)=>r&&(e=i(0,93)||f(),(t=t=>r(t)[e(t)]).id=e,t.of=r,t),18,"(",(r,e,t)=>(e=i(0,41),r?t=>r(t).apply(r.of?.(t),e?e.all?e.all(t):[e(t)]:[]):e||f()),18,",",(r,e,t=i(1))=>(t.all=r.all?(e,l,a=r.all(e))=>a.push(t(e))&&a:e=>[r(e),t(e)],t),1,"|",6,(r,e)=>r|e,"||",4,(r,e)=>r||e,"&",8,(r,e)=>r&e,"&&",5,(r,e)=>r&&e,"^",7,(r,e)=>r^e,"==",9,(r,e)=>r==e,"!=",9,(r,e)=>r!=e,">",10,(r,e)=>r>e,">=",10,(r,e)=>r>=e,">>",11,(r,e)=>r>>e,">>>",11,(r,e)=>r>>>e,"<",10,(r,e)=>r<e,"<=",10,(r,e)=>r<=e,"<<",11,(r,e)=>r<<e,"+",12,(r,e)=>r+e,"+",15,r=>+r,"++",r=>p(r||i(14),r?(r,e)=>r[e]++:(r,e)=>++r[e]),15,"-",12,(r,e)=>r-e,"-",15,r=>-r,"--",r=>p(r||i(14),r?(r,e)=>r[e]--:(r,e)=>--r[e]),15,"!",15,r=>!r,"*",13,(r,e)=>r*e,"/",13,(r,e)=>r/e,"%",13,(r,e)=>r%e];[l,a,o,...t]=t,l;)C(l,a,o);let b,B,m,w,y={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},v=t=>(l,a,o="")=>{for(l&&f();(a=e.charCodeAt(r))-t;)92===a?(h(),a=h(),o+=y[a]||a):o+=h();return h()||f("Bad string"),()=>o};for((b=['"',v(34),,"'",v(39),,"/*",(t,l)=>(h((t=>42!==t&&47!==e.charCodeAt(r+1))),h(2),t||i(l)),,"//",(r,e)=>(h((r=>r>=32)),r||i(e)),,"null",r=>r?f():()=>null,,"true",r=>r?f():()=>!0,,"false",r=>r?f():()=>!1,,"undefined",r=>r?f():()=>{},,";",r=>i()||(()=>{}),,"===",9,(r,e)=>r===e,"!==",9,(r,e)=>r!==e,"~",15,r=>~r,"**",(r,e,t=i(13))=>e=>r(e)**t(e),14,":",3.1,(r,e)=>[r,e],"?",3,(r,e)=>r?e[2]:e[1],"?.",r=>r&&(e=>r(e)||(()=>{})),,"?.",(r,e)=>(s(),(e=h(d))&&(t=>r(t)?.[e])),,"in",10,(r,e)=>r in e,"[",(r,e)=>!r&&((r=i(0,93))?r.all?e=>r.all(e):e=>[r(e)]:r=>[]),,"{",(r,e)=>!r&&((r=i(0,125))?t=>(e=(r.all||r)(t),Object.fromEntries(r.all?e:[e])):r=>({})),,":",(r,e,t)=>(t=i(3.1)||f(),e=>[(r.id||r)(e),t(e),r(e)]),3.1]);[B,m,w,...b]=b,B;)C(B,m,w);export{n as default};
1
+ let e,t,r,l,a,n,d,o=(l,a=(t=l,e=0,r=[],!(l=p())||t[e]?f():e=>l(e||{})))=>(a.args=r,a),i=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,f=(r="Bad syntax",l=t[e])=>{throw SyntaxError(r+" `"+l+"` at "+e)},c=(r=1,l=e,a)=>{if("number"==typeof r)e+=r;else for(;r(t.charCodeAt(e));)e++;return t.slice(l,e)},p=(t=0,r,l,a,n,d)=>{for(;(l=s())&&(n=(d=u[l])&&d(a,t)||!a&&h());)a=n;return r&&(l==r?e++:f()),a},s=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},h=(e=c(i),t)=>e?(t=t=>t[e],r.push(e),t.id=()=>e,t):0,u=[],x=o.set=(r,l,a=32,n=r.charCodeAt(0),d=r.length,o=u[n],f=a.length||([a,l]=[l,a],0),c=r.toUpperCase()!==r,s=(f>1?(e,t)=>e&&(t=p(l))&&(e.length||t.length?r=>a(e(r),t(r)):(e=a(e(),t()),()=>e)):f?e=>!e&&(e=p(l-1))&&(t=>a(e(t))):a))=>u[n]=(a,n,f=e)=>n<l&&(d<2||t.substr(e,d)==r)&&(!c||!i(t.charCodeAt(e+d)))&&(e+=d,s(a,n))||(e=f,o&&o(a,n)),g=e=>e>=48&&e<=57,C=r=>(r&&f("Unexpected number"),r=c((e=>46==e||g(e))),(69==t.charCodeAt(e)||101==t.charCodeAt(e))&&(r+=c(2)+c(g)),(r=+r)!=r?f("Bad number"):()=>r),A=(e,t,r=e.of)=>l=>t(r?r(l):l,e.id());for(a=48;a<=57;)u[a++]=C;for(l=['"',e=>(e=e?f("Unexpected string"):c((e=>e-34)),c()||f("Bad string"),()=>e),,".",(e,t,r)=>e?(s(),t=c(i)||f(),(r=r=>e(r)[t]).id=()=>t,r.of=e,r):C(c(-1)),18,"[",(e,t,r)=>e&&(t=p(0,93)||f(),(r=r=>e(r)[t(r)]).id=t,r.of=e,r),18,"(",(e,t,r)=>(t=p(0,41),e?r=>e(r).apply(e.of?.(r),t?t.all?t.all(r):[t(r)]:[]):t||f()),18,",",(e,t,r=p(1))=>(r.all=e.all?t=>[...e.all(t),r(t)]:t=>[e(t),r(t)],r),1,"|",6,(e,t)=>e|t,"||",4,(e,t)=>e||t,"&",8,(e,t)=>e&t,"&&",5,(e,t)=>e&&t,"^",7,(e,t)=>e^t,"==",9,(e,t)=>e==t,"!=",9,(e,t)=>e!=t,">",10,(e,t)=>e>t,">=",10,(e,t)=>e>=t,">>",11,(e,t)=>e>>t,">>>",11,(e,t)=>e>>>t,"<",10,(e,t)=>e<t,"<=",10,(e,t)=>e<=t,"<<",11,(e,t)=>e<<t,"+",12,(e,t)=>e+t,"+",15,e=>+e,"++",e=>A(e||p(14),e?(e,t)=>e[t]++:(e,t)=>++e[t]),15,"-",12,(e,t)=>e-t,"-",15,e=>-e,"--",e=>A(e||p(14),e?(e,t)=>e[t]--:(e,t)=>--e[t]),15,"!",15,e=>!e,"*",13,(e,t)=>e*t,"/",13,(e,t)=>e/t,"%",13,(e,t)=>e%t];[a,n,d,...l]=l,a;)x(a,n,d);let U,b,m,y,B={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},v=r=>(l,a,n="")=>{for(l&&f("Unexpected string");(a=t.charCodeAt(e))-r;)92===a?(c(),a=c(),n+=B[a]||a):n+=c();return c()||f("Bad string"),()=>n};for((U=['"',v(34),,"'",v(39),,"/*",(r,l)=>(c((r=>42!==r&&47!==t.charCodeAt(e+1))),c(2),r||p(l)),,"//",(e,t)=>(c((e=>e>=32)),e||p(t)),,"null",e=>e?f("Unexpected literal"):()=>null,,"true",e=>e?f("Unexpected literal"):()=>!0,,"false",e=>e?f("Unexpected literal"):()=>!1,,"undefined",e=>e?f("Unexpected literal"):()=>{},,";",e=>p()||(()=>{}),,"===",9,(e,t)=>e===t,"!==",9,(e,t)=>e!==t,"~",15,e=>~e,"**",(e,t,r=p(13))=>t=>e(t)**r(t),14,":",3.1,(e,t)=>[e,t],"?",3,(e,t)=>e?t[0]:t[1],"??",6,(e,t)=>e??t,"?.",e=>e&&(t=>e(t)||(()=>{})),,"?.",(e,t)=>(s(),(t=c(i))&&(r=>e(r)?.[t])),,"in",10,(e,t)=>e in t,"[",e=>!e&&((e=p(0,93))?e.all?t=>e.all(t):t=>[e(t)]:e=>[]),,"{",(e,t)=>!e&&((e=p(0,125))?r=>(t=(e.all||e)(r),Object.fromEntries(e.all?t:[t])):e=>({})),,":",(e,t,l)=>(l=p(1.1)||f(),e.id&&r.pop(),t=>[(e.id||e)(t),l(t)]),1.1]);[b,m,y,...U]=U,b;)x(b,m,y);export{o as default};
package/package.json CHANGED
@@ -1,12 +1,11 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "6.0.1",
4
- "description": "Microlanguage with common syntax for JS/C++/Python/Rust",
3
+ "version": "6.1.0",
4
+ "description": "Fast and tiny expression evaluator with common syntax microlanguage.",
5
5
  "main": "subscript.js",
6
6
  "type": "module",
7
7
  "files": [
8
- "parse.js",
9
- "evaluate.js",
8
+ "index.js",
10
9
  "subscript.js",
11
10
  "subscript.min.js",
12
11
  "justin.js",
@@ -32,11 +31,17 @@
32
31
  "jexl",
33
32
  "jsep",
34
33
  "expression",
34
+ "evaluator",
35
+ "parser",
35
36
  "evaluation",
36
37
  "math",
37
38
  "arithmetic",
38
- "evaluator",
39
39
  "justin",
40
+ "eval",
41
+ "math-eval",
42
+ "math-evaluator",
43
+ "math-expression-evaluator",
44
+ "calculation",
40
45
  "jessie",
41
46
  "jessica",
42
47
  "eval",
@@ -44,11 +49,13 @@
44
49
  "json",
45
50
  "calculator",
46
51
  "calc",
47
- "lisp",
48
- "frisk",
49
52
  "math.js",
53
+ "mathjs",
50
54
  "math-codegen",
51
- "math-parser"
55
+ "math-parser",
56
+ "formula",
57
+ "operator",
58
+ "overload"
52
59
  ],
53
60
  "author": "Dmitry Iv.",
54
61
  "license": "ISC",
package/subscript.js CHANGED
@@ -1,4 +1,4 @@
1
- import {parse, set, lookup, skip, cur, idx, err, expr, isId, space} from './index.js'
1
+ import {parse, set, lookup, skip, cur, idx, err, expr, isId, args, space} from './index.js'
2
2
 
3
3
  const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, _0=48, _9=57,
4
4
  PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
@@ -8,8 +8,8 @@ let u, list, op, prec, fn,
8
8
  isNum = c => c>=_0 && c<=_9,
9
9
  // 1.2e+3, .5
10
10
  num = n => (
11
- n&&err(),
12
- n = skip(c=>c==PERIOD || isNum(c)),
11
+ n&&err('Unexpected number'),
12
+ n = skip(c=>c == PERIOD || isNum(c)),
13
13
  (cur.charCodeAt(idx) == 69 || cur.charCodeAt(idx) == 101) && (n += skip(2) + skip(isNum)),
14
14
  n=+n, n!=n ? err('Bad number') : () => n // 0 args means token is static
15
15
  ),
@@ -22,7 +22,7 @@ for (op=_0;op<=_9;) lookup[op++] = num
22
22
  // operators
23
23
  for (list=[
24
24
  // "a"
25
- '"', a => (a=a?err():skip(c => c-DQUOTE), skip()||err('Bad string'), ()=>a),,
25
+ '"', a => (a=a?err('Unexpected string'):skip(c => c-DQUOTE), skip()||err('Bad string'), ()=>a),,
26
26
 
27
27
  // a.b, .2, 1.2 parser in one
28
28
  '.', (a,id,fn) => !a ? num(skip(-1)) : // FIXME: .123 is not operator, so we skip back, but mb reorganizing num would be better
@@ -42,7 +42,7 @@ for (list=[
42
42
 
43
43
  // [a,b,c] or (a,b,c)
44
44
  ',', (a,prec,b=expr(PREC_SEQ)) => (
45
- b.all = a.all ? (ctx,prec,arr=a.all(ctx)) => arr.push(b(ctx)) && arr : ctx => [a(ctx),b(ctx)],
45
+ b.all = a.all ? ctx => [...a.all(ctx), b(ctx)] : ctx => [a(ctx),b(ctx)],
46
46
  b
47
47
  ), PREC_SEQ,
48
48
 
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- let r,e,t,a,o,l,d=(t,...a)=>(e=t.raw?String.raw(t,...a):t,r=0,!(t=s())||e[r]?f():r=>t(r||{})),n=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r,f=(t="Bad syntax",a=e[r])=>{throw Error(t+" `"+a+"` at "+r)},h=(t=1,a=r,o)=>{if("number"==typeof t)r+=t;else for(;t(e.charCodeAt(r));)r++;return e.slice(a,r)},s=(e=0,t,a,o,l,d)=>{for(;(a=c())&&(l=(d=u[a])&&d(o,e)||!o&&i());)o=l;return t&&(a==t?r++:f("Unclosed")),o},c=t=>{for(;(t=e.charCodeAt(r))<=32;)r++;return t},i=(r=h(n),e)=>r?((e=e=>e[r]).id=()=>r,e):0,u=[],p=d.set=(t,a,o=32,l=t.charCodeAt(0),d=t.length,f=u[l],h=o.length||([o,a]=[a,o],0),c=t.toUpperCase()!==t,i=(h>1?(r,e)=>r&&(e=s(a))&&(r.length||e.length?t=>o(r(t),e(t)):(r=o(r(),e()),()=>r)):h?r=>!r&&(r=s(a-1))&&(e=>o(r(e))):o))=>u[l]=(o,l,h=r)=>l<a&&(d<2||e.substr(r,d)==t)&&(!c||!n(e.charCodeAt(r+d)))&&(r+=d,i(o,l))||(r=h,f&&f(o,l)),C=r=>r>=48&&r<=57,g=t=>(t&&f(),t=h((r=>46==r||C(r))),(69==e.charCodeAt(r)||101==e.charCodeAt(r))&&(t+=h(2)+h(C)),(t=+t)!=t?f("Bad number"):()=>t),A=(r,e,t=r.of)=>a=>e(t?t(a):a,r.id());for(a=48;a<=57;)u[a++]=g;for(t=['"',r=>(r=r?f():h((r=>r-34)),h()||f("Bad string"),()=>r),,".",(r,e,t)=>r?(c(),e=h(n)||f(),(t=t=>r(t)[e]).id=()=>e,t.of=r,t):g(h(-1)),18,"[",(r,e,t)=>r&&(e=s(0,93)||f(),(t=t=>r(t)[e(t)]).id=e,t.of=r,t),18,"(",(r,e,t)=>(e=s(0,41),r?t=>r(t).apply(r.of?.(t),e?e.all?e.all(t):[e(t)]:[]):e||f()),18,",",(r,e,t=s(1))=>(t.all=r.all?(e,a,o=r.all(e))=>o.push(t(e))&&o:e=>[r(e),t(e)],t),1,"|",6,(r,e)=>r|e,"||",4,(r,e)=>r||e,"&",8,(r,e)=>r&e,"&&",5,(r,e)=>r&&e,"^",7,(r,e)=>r^e,"==",9,(r,e)=>r==e,"!=",9,(r,e)=>r!=e,">",10,(r,e)=>r>e,">=",10,(r,e)=>r>=e,">>",11,(r,e)=>r>>e,">>>",11,(r,e)=>r>>>e,"<",10,(r,e)=>r<e,"<=",10,(r,e)=>r<=e,"<<",11,(r,e)=>r<<e,"+",12,(r,e)=>r+e,"+",15,r=>+r,"++",r=>A(r||s(14),r?(r,e)=>r[e]++:(r,e)=>++r[e]),15,"-",12,(r,e)=>r-e,"-",15,r=>-r,"--",r=>A(r||s(14),r?(r,e)=>r[e]--:(r,e)=>--r[e]),15,"!",15,r=>!r,"*",13,(r,e)=>r*e,"/",13,(r,e)=>r/e,"%",13,(r,e)=>r%e];[a,o,l,...t]=t,a;)p(a,o,l);export{d as default};
1
+ let e,r,t,a,o,l,d,n=(a,o=(r=a,e=0,t=[],!(a=c())||r[e]?h():e=>a(e||{})))=>(o.args=t,o),f=e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e,h=(t="Bad syntax",a=r[e])=>{throw SyntaxError(t+" `"+a+"` at "+e)},s=(t=1,a=e,o)=>{if("number"==typeof t)e+=t;else for(;t(r.charCodeAt(e));)e++;return r.slice(a,e)},c=(r=0,t,a,o,l,d)=>{for(;(a=p())&&(l=(d=i[a])&&d(o,r)||!o&&u());)o=l;return t&&(a==t?e++:h()),o},p=t=>{for(;(t=r.charCodeAt(e))<=32;)e++;return t},u=(e=s(f),r)=>e?(r=r=>r[e],t.push(e),r.id=()=>e,r):0,i=[],g=n.set=(t,a,o=32,l=t.charCodeAt(0),d=t.length,n=i[l],h=o.length||([o,a]=[a,o],0),s=t.toUpperCase()!==t,p=(h>1?(e,r)=>e&&(r=c(a))&&(e.length||r.length?t=>o(e(t),r(t)):(e=o(e(),r()),()=>e)):h?e=>!e&&(e=c(a-1))&&(r=>o(e(r))):o))=>i[l]=(o,l,h=e)=>l<a&&(d<2||r.substr(e,d)==t)&&(!s||!f(r.charCodeAt(e+d)))&&(e+=d,p(o,l))||(e=h,n&&n(o,l)),C=e=>e>=48&&e<=57,A=t=>(t&&h("Unexpected number"),t=s((e=>46==e||C(e))),(69==r.charCodeAt(e)||101==r.charCodeAt(e))&&(t+=s(2)+s(C)),(t=+t)!=t?h("Bad number"):()=>t),x=(e,r,t=e.of)=>a=>r(t?t(a):a,e.id());for(o=48;o<=57;)i[o++]=A;for(a=['"',e=>(e=e?h("Unexpected string"):s((e=>e-34)),s()||h("Bad string"),()=>e),,".",(e,r,t)=>e?(p(),r=s(f)||h(),(t=t=>e(t)[r]).id=()=>r,t.of=e,t):A(s(-1)),18,"[",(e,r,t)=>e&&(r=c(0,93)||h(),(t=t=>e(t)[r(t)]).id=r,t.of=e,t),18,"(",(e,r,t)=>(r=c(0,41),e?t=>e(t).apply(e.of?.(t),r?r.all?r.all(t):[r(t)]:[]):r||h()),18,",",(e,r,t=c(1))=>(t.all=e.all?r=>[...e.all(r),t(r)]:r=>[e(r),t(r)],t),1,"|",6,(e,r)=>e|r,"||",4,(e,r)=>e||r,"&",8,(e,r)=>e&r,"&&",5,(e,r)=>e&&r,"^",7,(e,r)=>e^r,"==",9,(e,r)=>e==r,"!=",9,(e,r)=>e!=r,">",10,(e,r)=>e>r,">=",10,(e,r)=>e>=r,">>",11,(e,r)=>e>>r,">>>",11,(e,r)=>e>>>r,"<",10,(e,r)=>e<r,"<=",10,(e,r)=>e<=r,"<<",11,(e,r)=>e<<r,"+",12,(e,r)=>e+r,"+",15,e=>+e,"++",e=>x(e||c(14),e?(e,r)=>e[r]++:(e,r)=>++e[r]),15,"-",12,(e,r)=>e-r,"-",15,e=>-e,"--",e=>x(e||c(14),e?(e,r)=>e[r]--:(e,r)=>--e[r]),15,"!",15,e=>!e,"*",13,(e,r)=>e*r,"/",13,(e,r)=>e/r,"%",13,(e,r)=>e%r];[o,l,d,...a]=a,o;)g(o,l,d);export{n as default};