subscript 6.3.1 → 6.4.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/justin.js CHANGED
@@ -1,184 +1,22 @@
1
- const SPACE=32;
2
-
3
- // current string, index and collected ids
4
- let idx, cur, args,
5
-
6
- // no handling tagged literals since easily done on user side with cache, if needed
7
- parse = (s, fn) => (
8
- idx=0, args=[], cur=s.trim(),
9
- !(s = cur ? expr() : ctx=>fn) || cur[idx] ? err() :
10
- fn = ctx=>s(ctx||{}), fn.args = args, fn
11
- ),
12
-
13
- isId = c =>
14
- (c >= 48 && c <= 57) || // 0..9
15
- (c >= 65 && c <= 90) || // A...Z
16
- (c >= 97 && c <= 122) || // a...z
17
- c == 36 || c == 95 || // $, _,
18
- (c >= 192 && c != 215 && c != 247), // any non-ASCII
19
-
20
- err = (msg='Bad syntax',c=cur[idx]) => { throw SyntaxError(msg + ' `' + c + '` at ' + idx) },
21
-
22
- skip = (is=1, from=idx, l) => {
23
- if (typeof is == 'number') idx += is;
24
- else while (is(cur.charCodeAt(idx))) idx++;
25
- return cur.slice(from, idx)
26
- },
27
-
28
- // a + b - c
29
- expr = (prec=0, end, cc, token, newNode, fn) => {
30
- // chunk/token parser
31
- while (
32
- ( cc=space() ) && // till not end
33
- // FIXME: extra work is happening here, when lookup bails out due to lower precedence -
34
- // it makes extra `space` call for parent exprs on the same character to check precedence again
35
- ( newNode =
36
- (fn=lookup[cc]) && fn(token, prec) || // if operator with higher precedence isn't found
37
- (!token && id()) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
38
- )
39
- ) token = newNode;
40
-
41
- // check end character
42
- // FIXME: can't show "Unclose paren", because can be unknown operator within group as well
43
- if (end) cc==end?idx++:err();
44
-
45
- return token
46
- },
47
-
48
- // skip space chars, return first non-space character
49
- space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
50
-
51
- // variable identifier
52
- id = (name=skip(isId), fn) => name ? (fn=ctx => ctx[name], args.push(name), fn.id=()=>name, fn) : 0,
53
-
54
- // operator/token lookup table
55
- lookup = [],
56
-
57
- // create operator checker/mapper (see examples)
58
- set = parse.set = (
59
- op,
60
- opPrec, fn=SPACE, // if opPrec & fn come in reverse order - consider them raw parse fn case, still precedence possible
61
- c=op.charCodeAt(0),
62
- l=op.length,
63
- prev=lookup[c],
64
- arity=fn.length || ([fn,opPrec]=[opPrec,fn], 0),
65
- word=op.toUpperCase()!==op, // make sure word boundary comes after word operator
66
- map=
67
- // binary
68
- arity>1 ? (a,b) => a && (b=expr(opPrec)) && (
69
- !a.length && !b.length ? (a=fn(a(),b()), ()=>a) : // static pre-eval like `"a"+"b"`
70
- ctx => fn(a(ctx),b(ctx),a.id?.(ctx),b.id?.(ctx))
71
- ) :
72
- // unary prefix (0 args)
73
- arity ? a => !a && (a=expr(opPrec-1)) && (ctx => fn(a(ctx))) :
74
- fn // custom parser
75
- ) =>
76
- 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));
77
-
78
- const PERIOD=46, CPAREN=41, CBRACK$1=93, DQUOTE$1=34, _0=48, _9=57,
79
- PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR$1=6, PREC_XOR=7, PREC_AND=8,
80
- PREC_EQ$1=9, PREC_COMP$1=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_UNARY$1=15, PREC_CALL=18;
81
-
82
- let list$1, op$1, prec$1, fn$1,
83
- isNum = c => c>=_0 && c<=_9,
84
- // 1.2e+3, .5
85
- num = n => (
86
- n&&err('Unexpected number'),
87
- n = skip(c=>c == PERIOD || isNum(c)),
88
- (cur.charCodeAt(idx) == 69 || cur.charCodeAt(idx) == 101) && (n += skip(2) + skip(isNum)),
89
- n=+n, n!=n ? err('Bad number') : () => n // 0 args means token is static
90
- ),
91
-
92
- inc = (a,fn) => ctx => fn(a.of?a.of(ctx):ctx, a.id(ctx));
93
-
94
- // numbers
95
- for (op$1=_0;op$1<=_9;) lookup[op$1++] = num;
96
-
97
- // operators
98
- for (list$1=[
99
- // "a"
100
- '"', a => (a=a?err('Unexpected string'):skip(c => c-DQUOTE$1), skip()||err('Bad string'), ()=>a),,
101
-
102
- // a.b
103
- '.', (a,id) => (space(), id=skip(isId)||err(), fn$1=ctx=>a(ctx)[id], fn$1.id=()=>id, fn$1.of=a, fn$1), PREC_CALL,
104
-
105
- // .2
106
- // FIXME: .123 is not operator, so we skip back, but mb reorganizing num would be better
107
- '.', a => !a && num(skip(-1)),,
108
-
109
- // a[b]
110
- '[', (a,b,fn) => a && (b=expr(0,CBRACK$1)||err(), fn=ctx=>a(ctx)[b(ctx)], fn.id=b, fn.of=a, fn), PREC_CALL,
111
-
112
- // a(), a(b), (a,b), (a+b)
113
- '(', (a,b,fn) => (
114
- b=expr(0,CPAREN),
115
- // a(), a(b), a(b,c,d)
116
- a ? ctx => a(ctx).apply(a.of?.(ctx), b ? b.all ? b.all(ctx) : [b(ctx)] : []) :
117
- // (a+b)
118
- b || err()
119
- ), PREC_CALL,
120
-
121
- // [a,b,c] or (a,b,c)
122
- ',', (a,prec,b=expr(PREC_SEQ),fn=ctx => (a(ctx), b(ctx))) => (
123
- b ? (fn.all = a.all ? ctx => [...a.all(ctx),b(ctx)] : ctx => [a(ctx),b(ctx)]) : err('Skipped argument',),
124
- fn
125
- ), PREC_SEQ,
126
-
127
- '|', PREC_OR$1, (a,b)=>a|b,
128
- '||', PREC_SOME, (a,b)=>a||b,
129
-
130
- '&', PREC_AND, (a,b)=>a&b,
131
- '&&', PREC_EVERY, (a,b)=>a&&b,
132
-
133
- '^', PREC_XOR, (a,b)=>a^b,
134
-
135
- // ==, !=
136
- '==', PREC_EQ$1, (a,b)=>a==b,
137
- '!=', PREC_EQ$1, (a,b)=>a!=b,
138
-
139
- // > >= >> >>>, < <= <<
140
- '>', PREC_COMP$1, (a,b)=>a>b,
141
- '>=', PREC_COMP$1, (a,b)=>a>=b,
142
- '>>', PREC_SHIFT, (a,b)=>a>>b,
143
- '>>>', PREC_SHIFT, (a,b)=>a>>>b,
144
- '<', PREC_COMP$1, (a,b)=>a<b,
145
- '<=', PREC_COMP$1, (a,b)=>a<=b,
146
- '<<', PREC_SHIFT, (a,b)=>a<<b,
147
-
148
- // + ++ - --
149
- '+', PREC_SUM, (a,b)=>a+b,
150
- '+', PREC_UNARY$1, (a)=>+a,
151
- '++', a => inc(a||expr(PREC_UNARY$1-1), a ? (a,b)=>a[b]++ : (a,b)=>++a[b]), PREC_UNARY$1,
152
-
153
- '-', PREC_SUM, (a,b)=>a-b,
154
- '-', PREC_UNARY$1, (a)=>-a,
155
- '--', a => inc(a||expr(PREC_UNARY$1-1), a ? (a,b)=>a[b]-- : (a,b)=>--a[b]), PREC_UNARY$1,
156
-
157
- // ! ~
158
- '!', PREC_UNARY$1, (a)=>!a,
159
-
160
- // * / %
161
- '*', PREC_MULT, (a,b)=>a*b,
162
- '/', PREC_MULT, (a,b)=>a/b,
163
- '%', PREC_MULT, (a,b)=>a%b
164
- ]; [op$1,prec$1,fn$1,...list$1]=list$1, op$1;) set(op$1,prec$1,fn$1);
165
-
166
1
  // justin lang https://github.com/endojs/Jessie/issues/66
2
+ import {set, lookup, skip, cur, idx, err, expr, isId, space, args} from './parser.js'
3
+ export { default } from './subscript.js'
167
4
 
168
- const CBRACK=93, DQUOTE=34, QUOTE=39, BSLASH=92,
169
- PREC_OR=6, PREC_EQ=9, PREC_COMP=10, PREC_EXP=14, PREC_UNARY=15;
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
+ PREC_SEQ=1, PREC_COND=3, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
7
+ PREC_EQ=9, PREC_COMP=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_EXP=14, PREC_UNARY=15, PREC_POSTFIX=16, PREC_CALL=18, PREC_GROUP=19
170
8
 
171
9
 
172
- let list, op, prec, fn,
10
+ let u, list, op, prec, fn,
173
11
  escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'},
174
12
  string = q => (qc, c, str='') => {
175
- qc&&err('Unexpected string'); // must not follow another token
13
+ qc&&err('Unexpected string') // must not follow another token
176
14
  while (c=cur.charCodeAt(idx), c-q) {
177
- if (c === BSLASH) skip(), c=skip(), str += escape[c] || c;
178
- else str += skip();
15
+ if (c === BSLASH) skip(), c=skip(), str += escape[c] || c
16
+ else str += skip()
179
17
  }
180
18
  return skip()||err('Bad string'), () => str
181
- };
19
+ }
182
20
 
183
21
  // operators
184
22
  for (list=[
@@ -233,6 +71,4 @@ for (list=[
233
71
  // for JSON case we should not collect arg (different evaluator than ternary)
234
72
  ':', (a, prec, b) => (b=expr(1.1)||err(), a.id&&args.pop(), ctx => [(a.id||a)(ctx), b(ctx)]), 1.1
235
73
 
236
- ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn);
237
-
238
- export { parse as default };
74
+ ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- let e,t,r,l,a,n,d,o=(l,a)=>(e=0,r=[],t=l.trim(),!(l=t?c():e=>a)||t[e]?f():a=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)},p=(r=1,l=e,a)=>{if("number"==typeof r)e+=r;else for(;r(t.charCodeAt(e));)e++;return t.slice(l,e)},c=(t=0,r,l,a,n,d)=>{for(;(l=s())&&(n=(d=h[l])&&d(a,t)||!a&&u());)a=n;return r&&(l==r?e++:f()),a},s=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},u=(e=p(i),t)=>e?(t=t=>t[e],r.push(e),t.id=()=>e,t):0,h=[],g=o.set=(r,l,a=32,n=r.charCodeAt(0),d=r.length,o=h[n],f=a.length||([a,l]=[l,a],0),p=r.toUpperCase()!==r,s=(f>1?(e,t)=>e&&(t=c(l))&&(e.length||t.length?r=>a(e(r),t(r),e.id?.(r),t.id?.(r)):(e=a(e(),t()),()=>e)):f?e=>!e&&(e=c(l-1))&&(t=>a(e(t))):a))=>h[n]=(a,n,f=e)=>n<l&&(d<2||t.substr(e,d)==r)&&(!p||!i(t.charCodeAt(e+d)))&&(e+=d,s(a,n))||(e=f,o&&o(a,n)),x=e=>e>=48&&e<=57,C=r=>(r&&f("Unexpected number"),r=p((e=>46==e||x(e))),(69==t.charCodeAt(e)||101==t.charCodeAt(e))&&(r+=p(2)+p(x)),(r=+r)!=r?f("Bad number"):()=>r),A=(e,t)=>r=>t(e.of?e.of(r):r,e.id(r));for(a=48;a<=57;)h[a++]=C;for(l=['"',e=>(e=e?f("Unexpected string"):p((e=>e-34)),p()||f("Bad string"),()=>e),,".",(e,t)=>(s(),t=p(i)||f(),d=r=>e(r)[t],d.id=()=>t,d.of=e,d),18,".",e=>!e&&C(p(-1)),,"[",(e,t,r)=>e&&(t=c(0,93)||f(),(r=r=>e(r)[t(r)]).id=t,r.of=e,r),18,"(",(e,t,r)=>(t=c(0,41),e?r=>e(r).apply(e.of?.(r),t?t.all?t.all(r):[t(r)]:[]):t||f()),18,",",(e,t,r=c(1),l=(t=>(e(t),r(t))))=>(r?l.all=e.all?t=>[...e.all(t),r(t)]:t=>[e(t),r(t)]:f("Skipped argument"),l),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||c(14),e?(e,t)=>e[t]++:(e,t)=>++e[t]),15,"-",12,(e,t)=>e-t,"-",15,e=>-e,"--",e=>A(e||c(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;)g(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?(p(),a=p(),n+=B[a]||a):n+=p();return p()||f("Bad string"),()=>n};for((U=['"',v(34),,"'",v(39),,"/*",(r,l)=>(p((r=>42!==r&&47!==t.charCodeAt(e+1))),p(2),r||c(l)),,"//",(e,t)=>(p((e=>e>=32)),e||c(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=>c()||(()=>{}),,"===",9,(e,t)=>e===t,"!==",9,(e,t)=>e!==t,"~",15,e=>~e,"**",(e,t,r=c(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=p(i))&&(r=>e(r)?.[t])),,"in",10,(e,t)=>e in t,"[",e=>!e&&((e=c(0,93))?e.all?t=>e.all(t):t=>[e(t)]:e=>[]),,"{",(e,t)=>!e&&((e=c(0,125))?r=>(t=(e.all||e)(r),Object.fromEntries(e.all?t:[t])):e=>({})),,":",(e,t,l)=>(l=c(1.1)||f(),e.id&&r.pop(),t=>[(e.id||e)(t),l(t)]),1.1]);[b,m,y,...U]=U,b;)g(b,m,y);export{o as default};
1
+ let e,t,r,l,a,n,d,o=(l,a)=>(e=0,r=[],t=l.trim(),!(l=t?c():e=>{})||t[e]?f():a=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)},p=(r=1,l=e,a)=>{if("number"==typeof r)e+=r;else for(;r(t.charCodeAt(e));)e++;return t.slice(l,e)},c=(t=0,r,l,a,n,d)=>{for(;(l=s())&&(n=(d=h[l])&&d(a,t)||!a&&u());)a=n;return r&&(l==r?e++:f()),a},s=r=>{for(;(r=t.charCodeAt(e))<=32;)e++;return r},u=(e=p(i),t)=>e?(t=t=>t[e],r.push(e),t.id=()=>e,t):0,h=[],g=o.set=(r,l,a=32,n=r.charCodeAt(0),d=r.length,o=h[n],f=a.length||([a,l]=[l,a],0),p=r.toUpperCase()!==r,s=(f>1?(e,t)=>e&&(t=c(l))&&(e.length||t.length?r=>a(e(r),t(r),e.id?.(r),t.id?.(r)):(e=a(e(),t()),()=>e)):f?e=>!e&&(e=c(l-1))&&(t=>a(e(t))):a))=>h[n]=(a,n,f=e)=>n<l&&(d<2||t.substr(e,d)==r)&&(!p||!i(t.charCodeAt(e+d)))&&(e+=d,s(a,n))||(e=f,o&&o(a,n)),x=e=>e>=48&&e<=57,C=r=>(r&&f("Unexpected number"),r=p((e=>46==e||x(e))),(69==t.charCodeAt(e)||101==t.charCodeAt(e))&&(r+=p(2)+p(x)),(r=+r)!=r?f("Bad number"):()=>r),A=(e,t)=>r=>t(e.of?e.of(r):r,e.id(r));for(a=48;a<=57;)h[a++]=C;for(l=['"',e=>(e=e?f("Unexpected string"):p((e=>e-34)),p()||f("Bad string"),()=>e),,".",(e,t)=>(s(),t=p(i)||f(),d=r=>e(r)[t],d.id=()=>t,d.of=e,d),18,".",e=>!e&&C(p(-1)),,"[",(e,t,r)=>e&&(t=c(0,93)||f(),(r=r=>e(r)[t(r)]).id=t,r.of=e,r),18,"(",(e,t,r)=>(t=c(0,41),e?r=>e(r).apply(e.of?.(r),t?t.all?t.all(r):[t(r)]:[]):t||f()),18,",",(e,t,r=c(1),l=(t=>(e(t),r(t))))=>(r?l.all=e.all?t=>[...e.all(t),r(t)]:t=>[e(t),r(t)]:f("Skipped argument"),l),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||c(14),e?(e,t)=>e[t]++:(e,t)=>++e[t]),15,"-",12,(e,t)=>e-t,"-",15,e=>-e,"--",e=>A(e||c(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;)g(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?(p(),a=p(),n+=B[a]||a):n+=p();return p()||f("Bad string"),()=>n};for((U=['"',v(34),,"'",v(39),,"/*",(r,l)=>(p((r=>42!==r&&47!==t.charCodeAt(e+1))),p(2),r||c(l)),,"//",(e,t)=>(p((e=>e>=32)),e||c(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=>c()||(()=>{}),,"===",9,(e,t)=>e===t,"!==",9,(e,t)=>e!==t,"~",15,e=>~e,"**",(e,t,r=c(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=p(i))&&(r=>e(r)?.[t])),,"in",10,(e,t)=>e in t,"[",e=>!e&&((e=c(0,93))?e.all?t=>e.all(t):t=>[e(t)]:e=>[]),,"{",(e,t)=>!e&&((e=c(0,125))?r=>(t=(e.all||e)(r),Object.fromEntries(e.all?t:[t])):e=>({})),,":",(e,t,l)=>(l=c(1.1)||f(),e.id&&r.pop(),t=>[(e.id||e)(t),l(t)]),1.1]);[b,m,y,...U]=U,b;)g(b,m,y);export{o as default};
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "6.3.1",
3
+ "version": "6.4.0",
4
4
  "description": "Fast and tiny expression evaluator with common syntax microlanguage.",
5
- "main": "src/subscript.js",
6
- "module": "src/subscript.js",
5
+ "main": "subscript.js",
6
+ "module": "subscript.js",
7
7
  "browser": "subscript.js",
8
8
  "type": "module",
9
9
  "files": [
10
- "src",
10
+ "parser.js",
11
11
  "subscript.js",
12
12
  "subscript.min.js",
13
13
  "justin.js",
@@ -19,12 +19,13 @@
19
19
  "test": "test"
20
20
  },
21
21
  "scripts": {
22
- "build": "npm run build-subscript && npm run minify-subscript && npm run build-justin && npm run minify-justin",
23
- "build-subscript": "rollup src/subscript.js --file subscript.js --format esm --name \"Subscript\"",
24
- "minify-subscript": "terser subscript.js -o subscript.min.js --module -c passes=3 -m",
25
- "build-justin": "rollup src/justin.js --file justin.js --format esm --name \"Justin\"",
26
- "minify-justin": "terser justin.js -o justin.min.js --module -c passes=3 -m",
27
- "test": "node test"
22
+ "build": "npm run build-subscript && npm run build-justin",
23
+ "minify": "npm run minify-subscript && npm run minify-justin",
24
+ "build-subscript": "rollup subscript.js --file subscript.min.js --format esm --name \"Subscript\"",
25
+ "minify-subscript": "terser subscript.min.js -o subscript.min.js --module -c passes=3 -m",
26
+ "build-justin": "rollup justin.js --file justin.min.js --format esm --name \"Justin\"",
27
+ "minify-justin": "terser justin.min.js -o justin.min.js --module -c passes=3 -m",
28
+ "test": "node test && node test/jsep && node test/perf"
28
29
  },
29
30
  "repository": {
30
31
  "type": "git",
File without changes
package/subscript.js CHANGED
@@ -1,85 +1,10 @@
1
- const SPACE=32;
2
-
3
- // current string, index and collected ids
4
- let idx, cur, args,
5
-
6
- // no handling tagged literals since easily done on user side with cache, if needed
7
- parse = (s, fn) => (
8
- idx=0, args=[], cur=s.trim(),
9
- !(s = cur ? expr() : ctx=>fn) || cur[idx] ? err() :
10
- fn = ctx=>s(ctx||{}), fn.args = args, fn
11
- ),
12
-
13
- isId = c =>
14
- (c >= 48 && c <= 57) || // 0..9
15
- (c >= 65 && c <= 90) || // A...Z
16
- (c >= 97 && c <= 122) || // a...z
17
- c == 36 || c == 95 || // $, _,
18
- (c >= 192 && c != 215 && c != 247), // any non-ASCII
19
-
20
- err = (msg='Bad syntax',c=cur[idx]) => { throw SyntaxError(msg + ' `' + c + '` at ' + idx) },
21
-
22
- skip = (is=1, from=idx, l) => {
23
- if (typeof is == 'number') idx += is;
24
- else while (is(cur.charCodeAt(idx))) idx++;
25
- return cur.slice(from, idx)
26
- },
27
-
28
- // a + b - c
29
- expr = (prec=0, end, cc, token, newNode, fn) => {
30
- // chunk/token parser
31
- while (
32
- ( cc=space() ) && // till not end
33
- // FIXME: extra work is happening here, when lookup bails out due to lower precedence -
34
- // it makes extra `space` call for parent exprs on the same character to check precedence again
35
- ( newNode =
36
- (fn=lookup[cc]) && fn(token, prec) || // if operator with higher precedence isn't found
37
- (!token && id()) // parse literal or quit. token seqs are forbidden: `a b`, `a "b"`, `1.32 a`
38
- )
39
- ) token = newNode;
40
-
41
- // check end character
42
- // FIXME: can't show "Unclose paren", because can be unknown operator within group as well
43
- if (end) cc==end?idx++:err();
44
-
45
- return token
46
- },
47
-
48
- // skip space chars, return first non-space character
49
- space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
50
-
51
- // variable identifier
52
- id = (name=skip(isId), fn) => name ? (fn=ctx => ctx[name], args.push(name), fn.id=()=>name, fn) : 0,
53
-
54
- // operator/token lookup table
55
- lookup = [],
56
-
57
- // create operator checker/mapper (see examples)
58
- set = parse.set = (
59
- op,
60
- opPrec, fn=SPACE, // if opPrec & fn come in reverse order - consider them raw parse fn case, still precedence possible
61
- c=op.charCodeAt(0),
62
- l=op.length,
63
- prev=lookup[c],
64
- arity=fn.length || ([fn,opPrec]=[opPrec,fn], 0),
65
- word=op.toUpperCase()!==op, // make sure word boundary comes after word operator
66
- map=
67
- // binary
68
- arity>1 ? (a,b) => a && (b=expr(opPrec)) && (
69
- !a.length && !b.length ? (a=fn(a(),b()), ()=>a) : // static pre-eval like `"a"+"b"`
70
- ctx => fn(a(ctx),b(ctx),a.id?.(ctx),b.id?.(ctx))
71
- ) :
72
- // unary prefix (0 args)
73
- arity ? a => !a && (a=expr(opPrec-1)) && (ctx => fn(a(ctx))) :
74
- fn // custom parser
75
- ) =>
76
- 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));
77
-
78
- const PERIOD=46, CPAREN=41, CBRACK=93, DQUOTE=34, _0=48, _9=57,
1
+ import {parse, set, lookup, skip, cur, idx, err, expr, isId, args, space} from './parser.js'
2
+
3
+ const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, _0=48, _9=57,
79
4
  PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
80
- PREC_EQ=9, PREC_COMP=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_UNARY=15, PREC_CALL=18;
5
+ 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
81
6
 
82
- let list, op, prec, fn,
7
+ let u, list, op, prec, fn,
83
8
  isNum = c => c>=_0 && c<=_9,
84
9
  // 1.2e+3, .5
85
10
  num = n => (
@@ -89,10 +14,10 @@ let list, op, prec, fn,
89
14
  n=+n, n!=n ? err('Bad number') : () => n // 0 args means token is static
90
15
  ),
91
16
 
92
- inc = (a,fn) => ctx => fn(a.of?a.of(ctx):ctx, a.id(ctx));
17
+ inc = (a,fn) => ctx => fn(a.of?a.of(ctx):ctx, a.id(ctx))
93
18
 
94
19
  // numbers
95
- for (op=_0;op<=_9;) lookup[op++] = num;
20
+ for (op=_0;op<=_9;) lookup[op++] = num
96
21
 
97
22
  // operators
98
23
  for (list=[
@@ -161,6 +86,6 @@ for (list=[
161
86
  '*', PREC_MULT, (a,b)=>a*b,
162
87
  '/', PREC_MULT, (a,b)=>a/b,
163
88
  '%', PREC_MULT, (a,b)=>a%b
164
- ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn);
165
-
166
- export { parse as default };
89
+ ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
90
+
91
+ export default parse
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- let e,r,t,a,o,d,l,n=(a,o)=>(e=0,t=[],r=a.trim(),!(a=r?s():e=>o)||r[e]?h():o=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)},i=(t=1,a=e,o)=>{if("number"==typeof t)e+=t;else for(;t(r.charCodeAt(e));)e++;return r.slice(a,e)},s=(r=0,t,a,o,d,l)=>{for(;(a=p())&&(d=(l=c[a])&&l(o,r)||!o&&u());)o=d;return t&&(a==t?e++:h()),o},p=t=>{for(;(t=r.charCodeAt(e))<=32;)e++;return t},u=(e=i(f),r)=>e?(r=r=>r[e],t.push(e),r.id=()=>e,r):0,c=[],g=n.set=(t,a,o=32,d=t.charCodeAt(0),l=t.length,n=c[d],h=o.length||([o,a]=[a,o],0),i=t.toUpperCase()!==t,p=(h>1?(e,r)=>e&&(r=s(a))&&(e.length||r.length?t=>o(e(t),r(t),e.id?.(t),r.id?.(t)):(e=o(e(),r()),()=>e)):h?e=>!e&&(e=s(a-1))&&(r=>o(e(r))):o))=>c[d]=(o,d,h=e)=>d<a&&(l<2||r.substr(e,l)==t)&&(!i||!f(r.charCodeAt(e+l)))&&(e+=l,p(o,d))||(e=h,n&&n(o,d)),C=e=>e>=48&&e<=57,A=t=>(t&&h("Unexpected number"),t=i((e=>46==e||C(e))),(69==r.charCodeAt(e)||101==r.charCodeAt(e))&&(t+=i(2)+i(C)),(t=+t)!=t?h("Bad number"):()=>t),m=(e,r)=>t=>r(e.of?e.of(t):t,e.id(t));for(o=48;o<=57;)c[o++]=A;for(a=['"',e=>(e=e?h("Unexpected string"):i((e=>e-34)),i()||h("Bad string"),()=>e),,".",(e,r)=>(p(),r=i(f)||h(),l=t=>e(t)[r],l.id=()=>r,l.of=e,l),18,".",e=>!e&&A(i(-1)),,"[",(e,r,t)=>e&&(r=s(0,93)||h(),(t=t=>e(t)[r(t)]).id=r,t.of=e,t),18,"(",(e,r,t)=>(r=s(0,41),e?t=>e(t).apply(e.of?.(t),r?r.all?r.all(t):[r(t)]:[]):r||h()),18,",",(e,r,t=s(1),a=(r=>(e(r),t(r))))=>(t?a.all=e.all?r=>[...e.all(r),t(r)]:r=>[e(r),t(r)]:h("Skipped argument"),a),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=>m(e||s(14),e?(e,r)=>e[r]++:(e,r)=>++e[r]),15,"-",12,(e,r)=>e-r,"-",15,e=>-e,"--",e=>m(e||s(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,d,l,...a]=a,o;)g(o,d,l);export{n as default};
1
+ let e,r,t,a,o,d,l,n=(a,o)=>(e=0,t=[],r=a.trim(),!(a=r?s():e=>{})||r[e]?h():o=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)},i=(t=1,a=e,o)=>{if("number"==typeof t)e+=t;else for(;t(r.charCodeAt(e));)e++;return r.slice(a,e)},s=(r=0,t,a,o,d,l)=>{for(;(a=p())&&(d=(l=c[a])&&l(o,r)||!o&&u());)o=d;return t&&(a==t?e++:h()),o},p=t=>{for(;(t=r.charCodeAt(e))<=32;)e++;return t},u=(e=i(f),r)=>e?(r=r=>r[e],t.push(e),r.id=()=>e,r):0,c=[],g=n.set=(t,a,o=32,d=t.charCodeAt(0),l=t.length,n=c[d],h=o.length||([o,a]=[a,o],0),i=t.toUpperCase()!==t,p=(h>1?(e,r)=>e&&(r=s(a))&&(e.length||r.length?t=>o(e(t),r(t),e.id?.(t),r.id?.(t)):(e=o(e(),r()),()=>e)):h?e=>!e&&(e=s(a-1))&&(r=>o(e(r))):o))=>c[d]=(o,d,h=e)=>d<a&&(l<2||r.substr(e,l)==t)&&(!i||!f(r.charCodeAt(e+l)))&&(e+=l,p(o,d))||(e=h,n&&n(o,d)),C=e=>e>=48&&e<=57,A=t=>(t&&h("Unexpected number"),t=i((e=>46==e||C(e))),(69==r.charCodeAt(e)||101==r.charCodeAt(e))&&(t+=i(2)+i(C)),(t=+t)!=t?h("Bad number"):()=>t),m=(e,r)=>t=>r(e.of?e.of(t):t,e.id(t));for(o=48;o<=57;)c[o++]=A;for(a=['"',e=>(e=e?h("Unexpected string"):i((e=>e-34)),i()||h("Bad string"),()=>e),,".",(e,r)=>(p(),r=i(f)||h(),l=t=>e(t)[r],l.id=()=>r,l.of=e,l),18,".",e=>!e&&A(i(-1)),,"[",(e,r,t)=>e&&(r=s(0,93)||h(),(t=t=>e(t)[r(t)]).id=r,t.of=e,t),18,"(",(e,r,t)=>(r=s(0,41),e?t=>e(t).apply(e.of?.(t),r?r.all?r.all(t):[r(t)]:[]):r||h()),18,",",(e,r,t=s(1),a=(r=>(e(r),t(r))))=>(t?a.all=e.all?r=>[...e.all(r),t(r)]:r=>[e(r),t(r)]:h("Skipped argument"),a),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=>m(e||s(14),e?(e,r)=>e[r]++:(e,r)=>++e[r]),15,"-",12,(e,r)=>e-r,"-",15,e=>-e,"--",e=>m(e||s(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,d,l,...a]=a,o;)g(o,d,l);export{n as default};
package/src/justin.js DELETED
@@ -1,74 +0,0 @@
1
- // justin lang https://github.com/endojs/Jessie/issues/66
2
- import {set, lookup, skip, cur, idx, err, expr, isId, space, args} from './index.js'
3
- export { default } from './subscript.js'
4
-
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
- PREC_SEQ=1, PREC_COND=3, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
7
- PREC_EQ=9, PREC_COMP=10, PREC_SHIFT=11, PREC_SUM=12, PREC_MULT=13, PREC_EXP=14, PREC_UNARY=15, PREC_POSTFIX=16, PREC_CALL=18, PREC_GROUP=19
8
-
9
-
10
- let u, list, op, prec, fn,
11
- escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'},
12
- string = q => (qc, c, str='') => {
13
- qc&&err('Unexpected string') // must not follow another token
14
- while (c=cur.charCodeAt(idx), c-q) {
15
- if (c === BSLASH) skip(), c=skip(), str += escape[c] || c
16
- else str += skip()
17
- }
18
- return skip()||err('Bad string'), () => str
19
- }
20
-
21
- // operators
22
- for (list=[
23
- // "' with /
24
- '"', string(DQUOTE),,
25
- "'", string(QUOTE),,
26
-
27
- // /**/, //
28
- '/*', (a, prec) => (skip(c => c !== 42 && cur.charCodeAt(idx+1) !== 47), skip(2), a||expr(prec)),,
29
- '//', (a, prec) => (skip(c => c >= 32), a||expr(prec)),,
30
-
31
- // literals
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
-
37
- ';', a => expr()||(()=>{}),,
38
-
39
- // operators
40
- '===', PREC_EQ, (a,b) => a===b,
41
- '!==', PREC_EQ, (a,b) => a!==b,
42
- '~', PREC_UNARY, (a) => ~a,
43
-
44
- // right order
45
- '**', (a,prec,b=expr(PREC_EXP-1)) => ctx=>a(ctx)**b(ctx), PREC_EXP,
46
-
47
- // ?:
48
- ':', 3.1, (a,b) => [a,b],
49
- '?', 3, (a,b) => a ? b[0] : b[1],
50
-
51
- '??', PREC_OR, (a,b) => a??b,
52
-
53
- // a?.[, a?.( - postfix operator
54
- '?.', a => a && (ctx => a(ctx)||(()=>{})),,//(a) => a||(()=>{}),
55
- // a?.b - optional chain operator
56
- '?.', (a,id) => (space(), id=skip(isId)) && (ctx => a(ctx)?.[id]),,
57
-
58
- 'in', PREC_COMP, (a,b) => a in b,
59
-
60
- // [a,b,c]
61
- '[', (a) => !a && (
62
- a=expr(0,CBRACK),
63
- !a ? ctx => [] : a.all ? ctx => a.all(ctx) : ctx => [a(ctx)]
64
- ),,
65
-
66
- // {a:1, b:2, c:3}
67
- '{', (a, entries) => !a && (
68
- a=expr(0,125),
69
- !a ? ctx => ({}) : ctx => (entries=(a.all||a)(ctx), Object.fromEntries(a.all?entries:[entries]))
70
- ),,
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
73
-
74
- ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
package/src/subscript.js DELETED
@@ -1,91 +0,0 @@
1
- import {parse, set, lookup, skip, cur, idx, err, expr, isId, args, space} from './index.js'
2
-
3
- const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, _0=48, _9=57,
4
- PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
5
- 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
6
-
7
- let u, list, op, prec, fn,
8
- isNum = c => c>=_0 && c<=_9,
9
- // 1.2e+3, .5
10
- num = n => (
11
- n&&err('Unexpected number'),
12
- n = skip(c=>c == PERIOD || isNum(c)),
13
- (cur.charCodeAt(idx) == 69 || cur.charCodeAt(idx) == 101) && (n += skip(2) + skip(isNum)),
14
- n=+n, n!=n ? err('Bad number') : () => n // 0 args means token is static
15
- ),
16
-
17
- inc = (a,fn) => ctx => fn(a.of?a.of(ctx):ctx, a.id(ctx))
18
-
19
- // numbers
20
- for (op=_0;op<=_9;) lookup[op++] = num
21
-
22
- // operators
23
- for (list=[
24
- // "a"
25
- '"', a => (a=a?err('Unexpected string'):skip(c => c-DQUOTE), skip()||err('Bad string'), ()=>a),,
26
-
27
- // a.b
28
- '.', (a,id) => (space(), id=skip(isId)||err(), fn=ctx=>a(ctx)[id], fn.id=()=>id, fn.of=a, fn), PREC_CALL,
29
-
30
- // .2
31
- // FIXME: .123 is not operator, so we skip back, but mb reorganizing num would be better
32
- '.', a => !a && num(skip(-1)),,
33
-
34
- // a[b]
35
- '[', (a,b,fn) => a && (b=expr(0,CBRACK)||err(), fn=ctx=>a(ctx)[b(ctx)], fn.id=b, fn.of=a, fn), PREC_CALL,
36
-
37
- // a(), a(b), (a,b), (a+b)
38
- '(', (a,b,fn) => (
39
- b=expr(0,CPAREN),
40
- // a(), a(b), a(b,c,d)
41
- a ? ctx => a(ctx).apply(a.of?.(ctx), b ? b.all ? b.all(ctx) : [b(ctx)] : []) :
42
- // (a+b)
43
- b || err()
44
- ), PREC_CALL,
45
-
46
- // [a,b,c] or (a,b,c)
47
- ',', (a,prec,b=expr(PREC_SEQ),fn=ctx => (a(ctx), b(ctx))) => (
48
- b ? (fn.all = a.all ? ctx => [...a.all(ctx),b(ctx)] : ctx => [a(ctx),b(ctx)]) : err('Skipped argument',),
49
- fn
50
- ), PREC_SEQ,
51
-
52
- '|', PREC_OR, (a,b)=>a|b,
53
- '||', PREC_SOME, (a,b)=>a||b,
54
-
55
- '&', PREC_AND, (a,b)=>a&b,
56
- '&&', PREC_EVERY, (a,b)=>a&&b,
57
-
58
- '^', PREC_XOR, (a,b)=>a^b,
59
-
60
- // ==, !=
61
- '==', PREC_EQ, (a,b)=>a==b,
62
- '!=', PREC_EQ, (a,b)=>a!=b,
63
-
64
- // > >= >> >>>, < <= <<
65
- '>', PREC_COMP, (a,b)=>a>b,
66
- '>=', PREC_COMP, (a,b)=>a>=b,
67
- '>>', PREC_SHIFT, (a,b)=>a>>b,
68
- '>>>', PREC_SHIFT, (a,b)=>a>>>b,
69
- '<', PREC_COMP, (a,b)=>a<b,
70
- '<=', PREC_COMP, (a,b)=>a<=b,
71
- '<<', PREC_SHIFT, (a,b)=>a<<b,
72
-
73
- // + ++ - --
74
- '+', PREC_SUM, (a,b)=>a+b,
75
- '+', PREC_UNARY, (a)=>+a,
76
- '++', a => inc(a||expr(PREC_UNARY-1), a ? (a,b)=>a[b]++ : (a,b)=>++a[b]), PREC_UNARY,
77
-
78
- '-', PREC_SUM, (a,b)=>a-b,
79
- '-', PREC_UNARY, (a)=>-a,
80
- '--', a => inc(a||expr(PREC_UNARY-1), a ? (a,b)=>a[b]-- : (a,b)=>--a[b]), PREC_UNARY,
81
-
82
- // ! ~
83
- '!', PREC_UNARY, (a)=>!a,
84
-
85
- // * / %
86
- '*', PREC_MULT, (a,b)=>a*b,
87
- '/', PREC_MULT, (a,b)=>a/b,
88
- '%', PREC_MULT, (a,b)=>a%b
89
- ]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
90
-
91
- export default parse