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 +42 -22
- package/index.js +72 -0
- package/justin.js +15 -14
- package/justin.min.js +1 -1
- package/package.json +15 -8
- package/subscript.js +5 -5
- package/subscript.min.js +1 -1
package/README.md
CHANGED
|
@@ -1,21 +1,18 @@
|
|
|
1
|
-
# <img alt="subscript" src="/subscript2.svg" height=
|
|
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
|
|
3
|
+
_Subscript_ is expression evaluator with standard syntax<br/>
|
|
7
4
|
|
|
8
|
-
*
|
|
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:
|
|
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
|
|
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
|
|
46
|
-
* `a < b`, `a <= b`, `a
|
|
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(
|
|
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: ~
|
|
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
|
-
|
|
288
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 {
|
|
3
|
-
|
|
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[
|
|
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
|
|
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,
|
|
67
|
+
'{', (a, entries) => !a && (
|
|
66
68
|
a=expr(0,125),
|
|
67
|
-
!a ? ctx => ({}) : ctx => (
|
|
69
|
+
!a ? ctx => ({}) : ctx => (entries=(a.all||a)(ctx), Object.fromEntries(a.all?entries:[entries]))
|
|
68
70
|
),,
|
|
69
|
-
|
|
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
|
|
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
|
|
4
|
-
"description": "
|
|
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
|
-
"
|
|
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 ?
|
|
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,
|
|
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};
|