subscript 5.2.0 → 5.3.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 +12 -7
- package/justin.js +40 -48
- package/justin.min.js +1 -1
- package/package.json +1 -1
- package/parse.js +19 -13
- package/subscript.js +7 -7
- package/subscript.min.js +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
# <img alt="subscript" src="/subscript2.svg" height=42/> <!--sub͘<em>script</em>--> <!--<sub>SUB͘<em>SCRIPT</em></sub>-->
|
|
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>
|
|
2
5
|
|
|
3
6
|
_Subscript_ is micro-language with common syntax subset of C++, JS, Java, Python, Go, Rust, Swift, Objective C, Kotlin etc.<br/>
|
|
4
7
|
|
|
@@ -21,13 +24,13 @@ _Subscript_ is designed to be useful for:
|
|
|
21
24
|
|
|
22
25
|
* templates (perfect match with [template parts](https://github.com/github/template-parts))
|
|
23
26
|
* expressions evaluators, calculators
|
|
24
|
-
* subsets of languages (eg. [justin](#justin)) <!-- see sonr, mineural -->
|
|
27
|
+
* configurable subsets of languages (eg. [justin](#justin)) <!-- see sonr, mineural -->
|
|
25
28
|
* mocking language features (eg. pipe operator)
|
|
26
29
|
* sandboxes, playgrounds, safe eval
|
|
27
30
|
* custom DSL
|
|
28
31
|
|
|
29
32
|
[_Jsep_](https://github.com/EricSmekens/jsep) is generally fine for the listed tasks, unless you need dependencies as small as possible.
|
|
30
|
-
_Subscript_ has [2.5kb](https://npmfs.com/package/subscript/5.
|
|
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_, with _jsep+_ test coverage and better performance.
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
## Evaluation
|
|
@@ -49,6 +52,8 @@ evaluate(['+', ['*', 'min', 60], '"sec"'], { min: 5 }) // min*60 + "sec" == "300
|
|
|
49
52
|
|
|
50
53
|
## Extending
|
|
51
54
|
|
|
55
|
+
### Operators
|
|
56
|
+
|
|
52
57
|
Default operators include common operators for the listed languages in the following precedence:
|
|
53
58
|
|
|
54
59
|
* `++ --` unary postfix
|
|
@@ -83,13 +88,13 @@ let tree = parse(`
|
|
|
83
88
|
evaluate(tree, { Math, map, take, interval, gaussian })
|
|
84
89
|
```
|
|
85
90
|
|
|
86
|
-
|
|
91
|
+
### Tokens
|
|
87
92
|
|
|
88
93
|
Default tokens include:
|
|
89
94
|
|
|
90
95
|
* `"abc"` strings
|
|
91
96
|
* `1.2e+3` floats
|
|
92
|
-
* identifiers
|
|
97
|
+
* `name` identifiers
|
|
93
98
|
|
|
94
99
|
Tokens are extensible via `parse.token` list, can be added support of _literals_, _regexes_, _strings_, _numbers_ and others.
|
|
95
100
|
|
|
@@ -102,7 +107,7 @@ parse.token.unshift(c => char(4) === 'this' ? ctx : null)
|
|
|
102
107
|
evaluate(parse(`this.x`)) // 1
|
|
103
108
|
```
|
|
104
109
|
|
|
105
|
-
|
|
110
|
+
### Spaces/comments
|
|
106
111
|
|
|
107
112
|
Comments can be added via extending `parse.space`. See [justin.js](./justin.js) for more examples.
|
|
108
113
|
|
|
@@ -280,7 +285,7 @@ Subscript shows relatively good performance within other evaluators:
|
|
|
280
285
|
// 1 + (a * b / c % d) - 2.0 + -3e-3 * +4.4e4 / f.g[0] - i.j(+k == 1)(0)
|
|
281
286
|
// parse 30k times
|
|
282
287
|
|
|
283
|
-
subscript: ~
|
|
288
|
+
subscript: ~230 ms
|
|
284
289
|
jsep: ~280 ms
|
|
285
290
|
expr-eval: ~480 ms
|
|
286
291
|
jexl: ~1200 ms
|
package/justin.js
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
// justin lang https://github.com/endojs/Jessie/issues/66
|
|
2
2
|
import {evaluate} from './evaluate.js'
|
|
3
|
-
import {parse, code, char, skip, expr, err} from './parse.js'
|
|
3
|
+
import {parse, code, char, skip, expr, err, val} from './parse.js'
|
|
4
4
|
|
|
5
5
|
const PERIOD=46, OPAREN=40, CPAREN=41, CBRACK=93, SPACE=32,
|
|
6
6
|
|
|
7
|
-
PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
|
|
8
|
-
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
|
|
7
|
+
PREC_SEQ=1, PREC_TERN=3, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
|
|
8
|
+
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,
|
|
9
|
+
PREC_EXP=14, PREC_TOKEN=20
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
// tokens
|
|
12
|
-
const v = v => ({valueOf:()=>v})
|
|
13
13
|
parse.token.push(
|
|
14
|
-
// TODO: better parser
|
|
15
14
|
// 1.2e+3, .5 - fast & small version, but consumes corrupted nums as well
|
|
16
15
|
(number) => (
|
|
17
16
|
(number = skip(c => (c > 47 && c < 58) || c == PERIOD)) && (
|
|
@@ -31,19 +30,6 @@ parse.token.push(
|
|
|
31
30
|
return skip(), qc + str + qc
|
|
32
31
|
},
|
|
33
32
|
|
|
34
|
-
// {}
|
|
35
|
-
(cc, node) => (
|
|
36
|
-
cc === 123 && (skip(), node = mapObj(['{', expr(0,125)]), skip(), node)
|
|
37
|
-
),
|
|
38
|
-
|
|
39
|
-
// literal
|
|
40
|
-
c =>
|
|
41
|
-
c === 116 && char(4) === 'true' && skip(4) ? v(true) :
|
|
42
|
-
c === 102 && char(5) === 'false' && skip(5) ? v(false) :
|
|
43
|
-
c === 110 && char(4) === 'null' && skip(4) ? v(null) :
|
|
44
|
-
c === 117 && char(9) === 'undefined' && skip(9) ? v(undefined) :
|
|
45
|
-
null,
|
|
46
|
-
|
|
47
33
|
// id
|
|
48
34
|
c => skip(c =>
|
|
49
35
|
(c >= 48 && c <= 57) || // 0..9
|
|
@@ -56,24 +42,17 @@ parse.token.push(
|
|
|
56
42
|
|
|
57
43
|
const escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'}
|
|
58
44
|
|
|
59
|
-
// {}
|
|
60
|
-
const mapObj = (n, args) => (
|
|
61
|
-
args = !n[1] ? [] :
|
|
62
|
-
(n[1][0]==':') ? [n[1]] :
|
|
63
|
-
(n[1][0]==',') ? n[1].slice(1) : args,
|
|
64
|
-
['{', ...args]
|
|
65
|
-
)
|
|
66
|
-
|
|
67
45
|
|
|
68
46
|
// /**/, //
|
|
69
47
|
parse.space = cc => {
|
|
70
|
-
while (cc = code(), cc <= 32) {
|
|
71
|
-
skip()
|
|
72
|
-
if (
|
|
48
|
+
while (cc = code(), cc <= 32 || cc === 47) {
|
|
49
|
+
if (cc <= 32) skip()
|
|
50
|
+
else if (cc === 47)
|
|
73
51
|
// /**/
|
|
74
52
|
if (code(1) === 42) skip(2), skip(c => c !== 42 && code(1) !== 47), skip(2)
|
|
75
53
|
// //
|
|
76
54
|
else if (code(1) === 47) skip(2), skip(c => c >= 32)
|
|
55
|
+
else break
|
|
77
56
|
}
|
|
78
57
|
return cc
|
|
79
58
|
}
|
|
@@ -86,7 +65,7 @@ const addOps = (add, stride=2, list) => {
|
|
|
86
65
|
|
|
87
66
|
addOps(parse.operator, 3, [
|
|
88
67
|
// subscript ones
|
|
89
|
-
// TODO: add ,, as node here
|
|
68
|
+
// TODO: add ,, as node here?
|
|
90
69
|
',', PREC_SEQ,,
|
|
91
70
|
|
|
92
71
|
'|', PREC_OR,,
|
|
@@ -132,24 +111,24 @@ addOps(parse.operator, 3, [
|
|
|
132
111
|
'.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
|
|
133
112
|
|
|
134
113
|
// a[b]
|
|
135
|
-
'[', PREC_CALL, (node) => (skip(), node = ['.', node, expr(0,CBRACK)
|
|
114
|
+
'[', PREC_CALL, (node) => (skip(), node = ['.', node, val(expr(0,CBRACK))], node),
|
|
136
115
|
']',,,
|
|
137
116
|
|
|
138
117
|
// a(b)
|
|
139
|
-
'(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN),
|
|
140
|
-
Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, b
|
|
118
|
+
'(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN),
|
|
119
|
+
Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, val(b)] : [node]
|
|
141
120
|
),
|
|
142
121
|
// (a+b)
|
|
143
|
-
'(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(),
|
|
122
|
+
'(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(), b),
|
|
144
123
|
')',,,
|
|
145
124
|
|
|
146
125
|
// justin extension
|
|
147
|
-
';',
|
|
148
|
-
'===',
|
|
149
|
-
'!==',
|
|
150
|
-
'**',
|
|
151
|
-
'~',
|
|
152
|
-
'?',
|
|
126
|
+
';', PREC_SEQ,,
|
|
127
|
+
'===', PREC_EQ,,
|
|
128
|
+
'!==', PREC_EQ,,
|
|
129
|
+
'**', PREC_EXP,,
|
|
130
|
+
'~', PREC_UNARY, -1,
|
|
131
|
+
'?', PREC_TERN, (node) => {
|
|
153
132
|
if (!node) err('Expected expression')
|
|
154
133
|
let a, b
|
|
155
134
|
skip(), parse.space(), a = expr()
|
|
@@ -158,13 +137,28 @@ addOps(parse.operator, 3, [
|
|
|
158
137
|
return ['?:', node, a, b]
|
|
159
138
|
},
|
|
160
139
|
'}',,,
|
|
161
|
-
':'
|
|
162
|
-
'in',
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
)
|
|
140
|
+
':',,,
|
|
141
|
+
'in', PREC_COMP, (node) => code(2) <= 32 && [skip(2), '"'+node+'"', expr(PREC_COMP)],
|
|
142
|
+
|
|
143
|
+
// as operator it's faster to lookup (no need to extra rule check), smaller and no conflict with word names
|
|
144
|
+
// [a,b,c]
|
|
145
|
+
'[', PREC_TOKEN, (node,arg) => !node && (
|
|
146
|
+
skip(), arg=expr(0,93),
|
|
147
|
+
!arg ? ['['] : arg[0] == ',' ? (arg[0]='[',arg) : ['[',arg]
|
|
148
|
+
),
|
|
149
|
+
|
|
150
|
+
// {a:0, b:1}
|
|
151
|
+
'{', PREC_TOKEN, (node,arg) => !node && (skip(), arg=expr(0,125),
|
|
152
|
+
!arg ? ['{'] : arg[0] == ':' ? ['{',arg] : arg[0] == ',' ? (arg[0]='{',arg) : ['{',arg])
|
|
153
|
+
,
|
|
154
|
+
|
|
155
|
+
// literals
|
|
156
|
+
'null', PREC_TOKEN, node=>!node&&(skip(4),v(null)),
|
|
157
|
+
'false', PREC_TOKEN, node=>!node&&(skip(5),v(false)),
|
|
158
|
+
'true', PREC_TOKEN, node=>!node&&(skip(4),v(true)),
|
|
159
|
+
'undefined', PREC_TOKEN, node=>!node&&(skip(9),v(undefined)),
|
|
167
160
|
])
|
|
161
|
+
const v = v => ({valueOf:()=>v})
|
|
168
162
|
|
|
169
163
|
addOps(evaluate.operator, 2, [
|
|
170
164
|
// subscript
|
|
@@ -206,9 +200,7 @@ addOps(evaluate.operator, 2, [
|
|
|
206
200
|
'?:', (a,b,c)=>a?b:c,
|
|
207
201
|
'in', (a,b)=>a in b,
|
|
208
202
|
|
|
209
|
-
// []
|
|
210
203
|
'[', (...args) => Array(...args),
|
|
211
|
-
// as operator it's faster to lookup (no need to call extra rule check), smaller and no conflict with word names
|
|
212
204
|
'{', (...args)=>Object.fromEntries(args),
|
|
213
205
|
':', (a,b)=>[a,b]
|
|
214
206
|
])
|
package/justin.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e,r,t=e=>Array.isArray(e)&&("string"==typeof e[0]||t(e[0])),a=(e,r={},o,
|
|
1
|
+
var e,r,t=e=>Array.isArray(e)&&("string"==typeof e[0]||t(e[0])),a=(e,r={},o,s)=>t(e)?("string"==typeof(o=e[0])&&(s=n[o]),"function"!=typeof(o=s||a(o,r))?o:o.call(...e.map((e=>a(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,n={},o=(a.operator=(e,r)=>n[e]=2==r.length?(...e)=>e.reduce(r):r,(t,a)=>(r=t,e=0,a=p(),e<r.length?s():d(a))),s=(t="Bad syntax")=>{throw Error(t+" `"+r[e]+"` at "+e)},f=(t=1,a=e)=>{if("number"==typeof t)e+=t;else for(;t(i());)e++;return r.slice(a,e)},i=(t=0)=>r.charCodeAt(e+t),l=(t=1)=>r.substr(e,t),p=(e=0,r,t,a,n=0,i,l)=>{for(;(t=o.space())&&(l=y[t]?.(a,e)||!a&&c(t));)a=l;return r&&(t!=r?s("Unclosed paren"):f()),a},u=(o.space=r=>{for(;(r=i())<=32;)e++;return r},o.token=[]),c=(e,r=0,t)=>{for(;r<u.length;)if(t=u[r++](e))return t},y=[],d=(o.operator=(r,t=0,a=0,n,u=r.charCodeAt(0),c=r.length,h=y[u],v=a<=0&&r.toUpperCase()!==r)=>(n=a?a>0?e=>e&&[f(c),d(e)]:a<0?e=>!e&&[f(c),d(p(t-1))]:a:a=>{a=[r,a||s()];do{e+=c,a.push(d(p(t)))}while(o.space()==u&&(c<2||l(c)==r)&&(!v||i(c)<=32));return a},y[u]=(e,a)=>a<t&&(c<2||l(c)==r)&&(!v||i(c)<=32)&&n(e)||h&&h(e,a)),e=>Array.isArray(e)?e:(e||s()).valueOf()),h=10,v=15,g=20;o.token.push((e=>(e=f((e=>e>47&&e<58||46==e)))&&((69==i()||101==i())&&(e+=f(2)+f((e=>e>=48&&e<=57))),isNaN(e=new Number(e))?s("Bad number"):e)),((e,r,t,a)=>{if(34===e||39===e){for(r=l(),f(),a="";(t=i())-e;)92===t?(f(),a+=A[l()]||l()):a+=l(),f();return f(),r+a+r}}),(e=>f((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))));var A={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};o.space=e=>{for(;(e=i())<=32||47===e;)if(e<=32)f();else if(47===e)if(42===i(1))f(2),f((e=>42!==e&&47!==i(1))),f(2);else{if(47!==i(1))break;f(2),f((e=>e>=32))}return e};var b=(e,r=2,t)=>{for(let a=0;a<t.length;a+=r)e(t[a],t[a+1],t[a+2])};b(o.operator,3,[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",h,,">=",h,,">>",11,,">>>",11,,"<",h,,"<=",h,,"<<",11,,"+",12,,"+",v,-1,"++",v,-1,"++",v,1,"-",12,,"-",v,-1,"--",v,-1,"--",v,1,"!",v,-1,"*",13,,"/",13,,"%",13,,".",18,(e,r)=>e&&[f(),e,"string"==typeof(r=p(18))?'"'+r+'"':r.valueOf()],"[",18,e=>(f(),[".",e,d(p(0,93))]),"]",,,"(",18,(e,r)=>(f(),r=p(0,41),Array.isArray(r)&&","===r[0]?(r[0]=e,r):r?[e,d(r)]:[e]),"(",19,(e,r)=>!e&&(f(),p(0,41)||s()),")",,,";",1,,"===",9,,"!==",9,,"**",14,,"~",v,-1,"?",3,e=>{let r,t;return e||s("Expected expression"),f(),o.space(),r=p(),58!==i()&&s("Expected :"),f(),o.space(),t=p(),["?:",e,r,t]},"}",,,":",,,"in",h,e=>i(2)<=32&&[f(2),'"'+e+'"',p(h)],"[",g,(e,r)=>!e&&(f(),(r=p(0,93))?","==r[0]?(r[0]="[",r):["[",r]:["["]),"{",g,(e,r)=>!e&&(f(),(r=p(0,125))?":"==r[0]?["{",r]:","==r[0]?(r[0]="{",r):["{",r]:["{"]),"null",g,e=>!e&&(f(4),m(null)),"false",g,e=>!e&&(f(5),m(!1)),"true",g,e=>!e&&(f(4),m(!0)),"undefined",g,e=>!e&&(f(9),m(void 0))]);var m=e=>({valueOf:()=>e});b(a.operator,2,["!",e=>!e,"++",e=>++e,"--",e=>--e,".",(e,r)=>e&&e[r],"%",(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 x=e=>(e="string"==typeof e?o(e):e,r=>a(e,r));export{x as default,a as evaluate,o as parse};
|
package/package.json
CHANGED
package/parse.js
CHANGED
|
@@ -3,7 +3,7 @@ const SPACE=32
|
|
|
3
3
|
// current string & index
|
|
4
4
|
let idx, cur
|
|
5
5
|
|
|
6
|
-
export const parse = (str, tree) => (cur=str, idx=0, tree=expr(), idx<cur.length ? err() : tree
|
|
6
|
+
export const parse = (str, tree) => (cur=str, idx=0, tree=expr(), idx<cur.length ? err() : val(tree)),
|
|
7
7
|
|
|
8
8
|
err = (msg='Bad syntax') => { throw Error(msg + ' `' + cur[idx] + '` at ' + idx) },
|
|
9
9
|
|
|
@@ -24,7 +24,8 @@ expr = (prec=0, end, cc, node, i=0, map, newNode) => {
|
|
|
24
24
|
(cc=parse.space()) && (newNode = lookup[cc]?.(node, prec) || (!node && token(cc)) )
|
|
25
25
|
) node = newNode;
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
// skip end character, if expected
|
|
28
|
+
if (end) cc != end ? err('Unclosed paren') : skip()
|
|
28
29
|
|
|
29
30
|
return node
|
|
30
31
|
},
|
|
@@ -43,22 +44,27 @@ lookup = [],
|
|
|
43
44
|
// @param op is operator string
|
|
44
45
|
// @param prec is operator precedenc to check
|
|
45
46
|
// @param map is either number +1 - postfix unary, -1 prefix unary, 0 binary, else - custom mapper function
|
|
46
|
-
operator = parse.operator =
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
|
51
|
+
) => (
|
|
51
52
|
map = !type ? node => { // binary, consume same-op group
|
|
52
53
|
node = [op, node || err()]
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
do { idx+=l, node.push(val(expr(prec))) }
|
|
55
|
+
while (parse.space()==c && (l<2||char(l)==op) && (!spaced||code(l)<=SPACE))
|
|
55
56
|
return node
|
|
56
57
|
} :
|
|
57
|
-
type > 0 ? node => node && [skip(l), node] : // postfix unary
|
|
58
|
-
type < 0 ? node => !node && [skip(l), (expr(prec-1)
|
|
58
|
+
type > 0 ? node => node && [skip(l), val(node)] : // postfix unary
|
|
59
|
+
type < 0 ? node => !node && [skip(l), val(expr(prec-1))] : // prefix unary
|
|
59
60
|
type,
|
|
60
61
|
|
|
61
|
-
lookup[c] = (node, curPrec) =>
|
|
62
|
-
)
|
|
62
|
+
lookup[c] = (node, curPrec) =>
|
|
63
|
+
curPrec < prec && (l<2||char(l)==op) && (!spaced||code(l)<=SPACE) &&
|
|
64
|
+
map(node) || (prev && prev(node, curPrec))
|
|
65
|
+
),
|
|
66
|
+
|
|
67
|
+
// in order to support literal tokens, we call valueOf any time we create or modify calltree node
|
|
68
|
+
val = node => Array.isArray(node) ? node : (node || err()).valueOf()
|
|
63
69
|
|
|
64
70
|
export default parse
|
package/subscript.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import parse, {skip, expr, code, tokens, operator as parseOp} from './parse.js'
|
|
1
|
+
import parse, {skip, expr, code, tokens, val, operator as parseOp} from './parse.js'
|
|
2
2
|
import evaluate, {operator as evalOp} from './evaluate.js'
|
|
3
3
|
|
|
4
4
|
const PERIOD=46, OPAREN=40, CPAREN=41, CBRACK=93, SPACE=32,
|
|
@@ -58,11 +58,11 @@ addOps(parseOp, 3, [
|
|
|
58
58
|
'+', PREC_SUM,,
|
|
59
59
|
'+', PREC_UNARY, -1,
|
|
60
60
|
'++', PREC_UNARY, -1,
|
|
61
|
-
'++',
|
|
61
|
+
'++', PREC_POSTFIX, +1,
|
|
62
62
|
'-', PREC_SUM,,
|
|
63
63
|
'-', PREC_UNARY, -1,
|
|
64
64
|
'--', PREC_UNARY, -1,
|
|
65
|
-
'--',
|
|
65
|
+
'--', PREC_POSTFIX, +1,
|
|
66
66
|
|
|
67
67
|
// ! ~
|
|
68
68
|
'!', PREC_UNARY, -1,
|
|
@@ -76,15 +76,15 @@ addOps(parseOp, 3, [
|
|
|
76
76
|
'.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
|
|
77
77
|
|
|
78
78
|
// a[b]
|
|
79
|
-
'[', PREC_CALL, (node) => (skip(), node = ['.', node, expr(0,CBRACK)
|
|
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),
|
|
84
|
-
Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, b
|
|
83
|
+
'(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN),
|
|
84
|
+
Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, val(b)] : [node]
|
|
85
85
|
),
|
|
86
86
|
// (a+b)
|
|
87
|
-
'(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(),
|
|
87
|
+
'(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(), b),
|
|
88
88
|
')',,,
|
|
89
89
|
])
|
|
90
90
|
|
package/subscript.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e,
|
|
1
|
+
var r,e,t=(t,o)=>(e=t,r=0,o=l(),r<e.length?a():y(o)),a=(t="Bad syntax")=>{throw Error(t+" `"+e[r]+"` at "+r)},o=(t=1,a=r)=>{if("number"==typeof t)r+=t;else for(;t(n());)r++;return e.slice(a,r)},n=(t=0)=>e.charCodeAt(r+t),s=(t=1)=>e.substr(r,t),l=(r=0,e,n,s,l=0,p,i)=>{for(;(n=t.space())&&(i=u[n]?.(s,r)||!s&&f(n));)s=i;return e&&(n!=e?a("Unclosed paren"):o()),s},p=(t.space=e=>{for(;(e=n())<=32;)r++;return e},t.token=[]),f=(r,e=0,t)=>{for(;e<p.length;)if(t=p[e++](r))return t},u=[],i=t.operator=(e,p=0,f=0,i,c=e.charCodeAt(0),h=e.length,g=u[c],d=f<=0&&e.toUpperCase()!==e)=>(i=f?f>0?r=>r&&[o(h),y(r)]:f<0?r=>!r&&[o(h),y(l(p-1))]:f:o=>{o=[e,o||a()];do{r+=h,o.push(y(l(p)))}while(t.space()==c&&(h<2||s(h)==e)&&(!d||n(h)<=32));return o},u[c]=(r,t)=>t<p&&(h<2||s(h)==e)&&(!d||n(h)<=32)&&i(r)||g&&g(r,t)),y=r=>Array.isArray(r)?r:(r||a()).valueOf(),c=t,h=r=>Array.isArray(r)&&("string"==typeof r[0]||h(r[0])),g=(r,e={},t,a)=>h(r)?("string"==typeof(t=r[0])&&(a=d[t]),"function"!=typeof(t=a||g(t,e))?t:t.call(...r.map((r=>g(r,e))))):r&&"string"==typeof r?'"'===r[0]?r.slice(1,-1):"@"===r[0]?r.slice(1):r in e?e[r]:r:r,d={},A=g.operator=(r,e)=>d[r]=2==e.length?(...r)=>r.reduce(e):e,v=g;p.push((r=>(r=o((r=>r>47&&r<58||46==r)))&&((69==n()||101==n())&&(r+=o(2)+o((r=>r>=48&&r<=57))),isNaN(r=new Number(r))?err("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))));var m=(r,e=2,t)=>{for(let a=0;a<t.length;a+=e)r(t[a],t[a+1],t[a+2])};m(i,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)||err()),")",,,]),m(A,2,["!",r=>!r,"++",r=>++r,"--",r=>--r,".",(r,e)=>r&&r[e],"%",(r,e)=>r%e,"/",(r,e)=>r/e,"*",(r,e)=>r*e,"+",(r,e)=>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 b=r=>(r="string"==typeof r?c(r):r,e=>v(r,e));export{b as default,v as evaluate,c as parse};
|