subscript 3.0.0 → 4.0.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,11 +1,11 @@
1
1
  # <!--<img alt="subscript" src="/subscript2.svg" height=42/>--> sub͘<em>script</em> <!--<sub>SUB͘<em>SCRIPT</em></sub>-->
2
2
 
3
- _Subscript_ is micro-language with common syntax subset of C++, JS, Java, Python, Go, Rust.<br/>
3
+ _Subscript_ is micro-language with common syntax subset of C++, JS, Java, Python, Go, Rust, Swift, Objective C, Kotlin etc.<br/>
4
4
 
5
5
  * Well-known syntax
6
6
  * Any _subscript_ fragment can be copy-pasted to any target language
7
7
  * It's tiny <sub>![npm bundle size](https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip)</sub>
8
- * It's very fast ([see performance](#performance))
8
+ * It's :rocket: fast ([see performance](#performance))
9
9
  * Configurable & extensible
10
10
  * Trivial to use...
11
11
 
@@ -15,7 +15,9 @@ let fn = subscript(`a.b + c(d - 1)`)
15
15
  fn({ a: { b:1 }, c: x => x * 2, d: 3 }) // 5
16
16
  ```
17
17
 
18
- ## Useful in:
18
+ ## Motivation
19
+
20
+ _Subscript_ is designed to be useful for:
19
21
 
20
22
  * templates (perfect match with [template parts](https://github.com/github/template-parts))
21
23
  * expressions evaluators, calculators
@@ -24,12 +26,9 @@ fn({ a: { b:1 }, c: x => x * 2, d: 3 }) // 5
24
26
  * sandboxes, playgrounds, safe eval
25
27
  * custom DSL
26
28
 
27
- ```html
28
- <!-- template-parts proposal -->
29
- <template id="timer">
30
- <time datetime="{{ date.toUTCString() }}">{{ date.toLocaleTimeString() }}</time>
31
- </template>
32
- ```
29
+ [_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/3.0.0/subscript.min.js) footprint vs [11.4kb](https://npmfs.com/package/jsep/1.2.0/dist/jsep.min.js) _jsep_, with better performance.
31
+
33
32
 
34
33
  ## Operators
35
34
 
@@ -48,17 +47,53 @@ Default operators include common operators for the listed languages in the follo
48
47
  * `&&`
49
48
  * `||`
50
49
 
51
- All other operators can be extended via `parse.binary`, `parse.unary` and `evaluate.operator`.
50
+ All other operators can be extended, see [extension](#extension).
51
+
52
+ ## Evaluation
53
+
54
+ _Subscript_ parser generates lispy calltree (compatible with [frisk](https://npmjs.com/frisk)), which is compared to esprima AST has:
55
+
56
+ + minimal possible overhead
57
+ + clear precedence
58
+ + overloading by context
59
+ + manual evaluation and debugging
60
+ + conventional form
61
+ + one-liner docs:
62
+
63
+ ```js
64
+ import {evaluate} from 'subscript.js'
65
+
66
+ evaluate(['+', ['*', 'min', 60], '"sec"'], { min: 5 }) // min*60 + "sec" == "300sec"
67
+ ```
68
+
69
+ ## Extension
70
+
71
+ Tokens are extensible via `parse.token` list, can be added support of _regex_, _array_, _object_, _interpolated string_ and others.
72
+ Default tokens include:
73
+
74
+ * `"abc"` strings
75
+ * `1.2e+3` floats
76
+ * `()` expression groups or fn calls
77
+ * `.`, `[]` property access
78
+
79
+ Operators can be extended via `parse.operator` to add support for any unary/binary/postfix operators, calls, props or chains.
52
80
 
81
+ Comments can be added via extending `parse.space`.
82
+
83
+ For now see justin extension how things can be done.
84
+
85
+ <!--
53
86
  ```js
54
87
  import { parse, evaluate } from 'subscript.js'
55
88
 
56
89
  // add precedences
57
- parse.binary['=>'] = 10
90
+ // TODO
91
+ // parse.operator['=>'] = 10
58
92
 
59
93
  // define evaluators
60
- evaluate.operator['=>'] = ( args, body ) => evaluate(body, args)
61
- evaluate.operator['|'] = ( a, ...b ) => a.pipe(...b)
94
+ // TODO
95
+ // evaluate.operator['=>'] = ( args, body ) => evaluate(body, args)
96
+ // evaluate.operator['|'] = ( a, ...b ) => a.pipe(...b)
62
97
 
63
98
  let tree = parse(`
64
99
  interval(350)
@@ -68,28 +103,13 @@ let tree = parse(`
68
103
  `)
69
104
  evaluate(tree, { Math, map, take, interval, gaussian })
70
105
  ```
71
-
72
- ## Extending
73
-
74
- By default subscript detects the following tokens:
75
-
76
- * `"` strings
77
- * `1.2e+3` floats
78
- * `true`, `false`, `null` literals
79
- * `()` expression groups or fn calls
80
- * `.`, `[]` property access
81
-
82
- Literals can be extended via `parse.literal` dict.
83
-
84
- Token parsers are extensible via `parse.token` dict, can be added support of _regex_, _array_, _object_, _interpolated string_ and others.
85
-
86
- Postfix parsers are applied to parsed tokens and can be used to provide _property chains_, _function calls_, _postfix operators_, _token mapping_, _ternary operators_ and so on. They're extensible via `parse.postfix`.
106
+ -->
87
107
 
88
108
 
89
109
  ## Justin
90
110
 
91
111
  _Justin_ extension (original [thread](https://github.com/endojs/Jessie/issues/66)) is minimal JS subset − JSON with JS expressions.<br/>
92
- It adds support for:
112
+ It adds support of:
93
113
 
94
114
  + `**` binary operator
95
115
  + `~` unary operator
@@ -99,8 +119,10 @@ It adds support for:
99
119
  + `{...}` Object literal
100
120
  + `in` binary operator
101
121
  + `;` expression separator
102
- <!-- + `//, /* */` comments -->
103
- <!-- + `undefined` literal -->
122
+ + unary word operators
123
+ + `//`, `/* */` comments
124
+ + `true`, `false`, `null`, `undefined` literals
125
+ <!-- + `===`, `!==` operators -->
104
126
  <!-- + `?` chaining operator -->
105
127
  <!-- + `...x` unary operator -->
106
128
  <!-- + strings interpolation -->
@@ -117,6 +139,14 @@ evaluate(xy) // 1
117
139
 
118
140
  These are custom DSL operators snippets for your inspiration:
119
141
 
142
+
143
+ ```html
144
+ template-parts proposal
145
+ <template id="timer">
146
+ <time datetime="{{ date.toUTCString() }}">{{ date.toLocaleTimeString() }}</time>
147
+ </template>
148
+ ```
149
+
120
150
  // a.b.c
121
151
  // (node, c) => c === PERIOD ? (index++, space(), ['.', node, '"'+id()+'"']) : node,
122
152
 
@@ -249,7 +279,7 @@ Subscript shows relatively good performance within other evaluators:
249
279
  // 1 + (a * b / c % d) - 2.0 + -3e-3 * +4.4e4 / f.g[0] - i.j(+k == 1)(0)
250
280
  // parse 30k times
251
281
 
252
- subscript: ~270 ms
282
+ subscript: ~220 ms
253
283
  jsep: ~280 ms
254
284
  expr-eval: ~480 ms
255
285
  jexl: ~1200 ms
@@ -265,6 +295,6 @@ new Function: ~1400 ms
265
295
  * [expression-eval](https://github.com/donmccurdy/expression-eval)
266
296
  * [jsep](https://github.com/EricSmekens/jsep)
267
297
  * [string-math](https://github.com/devrafalko/string-math)
268
-
298
+ * [nerdamer](https://github.com/jiggzson/nerdamer)
269
299
 
270
300
  <p align=center>🕉</p>
@@ -12,8 +12,8 @@ evaluate = (s, ctx={}, c, op) => {
12
12
  }
13
13
  if (s && typeof s === 'string')
14
14
  return s[0] === '"' ? s.slice(1,-1)
15
- : s[0]==='@' ? s.slice(1)
16
- : s in ctx ? ctx[s] : s
15
+ : s[0]==='@' ? s.slice(1)
16
+ : s in ctx ? ctx[s] : s
17
17
 
18
18
  return s
19
19
  },
package/justin.js CHANGED
@@ -1,73 +1,99 @@
1
1
  // justin lang https://github.com/endojs/Jessie/issues/66
2
- import {evaluate, operator} from './src/evaluate.js'
3
- import {parse, binary, unary, postfix, token, literal,
4
- code, char, next, space, expr} from './src/parse.js'
2
+ import {evaluate} from './evaluate.js'
3
+ import {parse, code, char, skip, expr, nil, binary, unary} from './parse.js'
4
+
5
+ // ;
6
+ parse.operator[0] = binary(c => c==44||c==59)
5
7
 
6
8
  // undefined
7
- literal['undefined'] = undefined
9
+ parse.token.splice(3,0, c =>
10
+ c === 116 && char(4) === 'true' && skip(4) ? true :
11
+ c === 102 && char(5) === 'false' && skip(5) ? false :
12
+ c === 110 && char(4) === 'null' && skip(4) ? null :
13
+ c === 117 && char(9) === 'undefined' && skip(9) ? undefined :
14
+ undefined
15
+ )
8
16
 
9
- // '
10
- token.push((q, qc) => q === 39 ? (qc = char(), index++, qc) + next(c => c !== q) + (index++, qc) : null)
17
+ // "' with /
18
+ parse.token[1] = (q, qc, c, str) => {
19
+ if (q !== 34 && q !== 39) return
20
+ qc = char(), skip(), str = ''
21
+ while (c=code(), c-q) {
22
+ if (c === 92) skip(), str += escape[char()] || char(); else str+=char()
23
+ skip()
24
+ }
25
+ return skip(), qc + str + qc
26
+ }
27
+ const escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'}
11
28
 
12
29
  // **
13
- binary['**'] = 16
14
- operator['**'] = (...args)=>args.reduceRight((a,b)=>Math.pow(b,a))
30
+ evaluate.operator['**'] = (...args)=>args.reduceRight((a,b)=>Math.pow(b,a))
31
+ parse.operator.splice(parse.operator.length - 3, 0, binary(cc=>cc===42 && code(1) === cc && 2))
15
32
 
16
33
  // ~
17
- unary['~'] = 17
18
- operator['~'] = a=>~a
34
+ parse.operator.splice(parse.operator.length-2, 0, unary(cc => cc === 126))
35
+ evaluate.operator['~'] = a=>~a
19
36
 
20
- // ...
21
- // unary[1]['...']=true
37
+ // TODO ...
38
+ // // unary[1]['...']=true
22
39
 
23
- // ;
24
- binary[';'] = 1
25
40
 
26
41
  // ?:
27
- operator['?:']=(a,b,c)=>a?b:c
28
- postfix.push(node => {
42
+ evaluate.operator['?:']=(a,b,c)=>a?b:c
43
+ parse.operator.splice(1,0, (node,cc,prec,end) => {
29
44
  let a, b
30
- if (code() !== 63) return node
31
- next(), space(), a = expr(58)
32
- if (code() !== 58) return node
33
- next(), space(), b = expr()
34
- return ['?:',node, a, b]
45
+ if (cc !== 63) return
46
+ if (node===nil) err('Bad expression')
47
+ skip(), parse.space(), a = expr(-1,58)
48
+ if (code() !== 58) return
49
+ skip(), parse.space(), b = expr()
50
+ return ['?:', node, a, b]
35
51
  })
36
52
 
37
53
  // /**/, //
38
- // comments['/*']='*/'
39
- // comments['//']='\n'
54
+ parse.space = cc => {
55
+ while (cc = code(), cc <= 32) {
56
+ skip()
57
+ if (code() === 47)
58
+ // /**/
59
+ if (code(1) === 42) skip(2), skip(c => c !== 42 && code(1) !== 47), skip(2)
60
+ // //
61
+ else if (code(1) === 47) skip(2), skip(c => c >= 32)
62
+ }
63
+ return cc
64
+ }
40
65
 
41
66
  // in
42
67
  evaluate.operator['in'] = (a,b)=>a in b
43
- parse.postfix.unshift(node => (char(2) === 'in' ? (next(2), ['in', '"' + node + '"', expr()]) : node))
68
+ parse.operator.splice(6,0,(a,cc,prec,end) => (char(2) === 'in' && [skip(2), '"' + a + '"', expr(prec,end)]))
44
69
 
45
70
  // []
46
- operator['['] = (...args) => Array(...args)
47
- token.push((node, arg) =>
48
- code() === 91 ?
71
+ evaluate.operator['['] = (...args) => Array(...args)
72
+ parse.token.unshift((cc, node, arg) =>
73
+ cc === 91 &&
49
74
  (
50
- next(), arg=expr(93),
51
- node = arg==null ? ['['] : arg[0] === ',' ? (arg[0]='[',arg) : ['[',arg],
52
- next(), node
53
- ) : null
75
+ skip(), arg=expr(0,93),
76
+ node = arg===nil ? ['['] : arg[0] === ',' ? (arg[0]='[',arg) : ['[',arg],
77
+ skip(), node
78
+ )
54
79
  )
55
80
 
56
81
  // {}
57
- binary[':'] = 2
58
- token.unshift((node) => code() === 123 ? (next(), node = map(['{',expr(125)]), next(), node) : null)
59
- operator['{'] = (...args)=>Object.fromEntries(args)
60
- operator[':'] = (a,b)=>[a,b]
82
+ parse.token.unshift((cc, node) => (
83
+ cc === 123 ? (skip(), node = map(['{',expr(0,125)]), skip(), node) : null
84
+ ))
85
+ parse.operator.splice(4,0, binary(cc=>cc===58))
86
+ evaluate.operator['{'] = (...args)=>Object.fromEntries(args)
87
+ evaluate.operator[':'] = (a,b)=>[a,b]
61
88
 
62
89
  const map = (n, args) => {
63
- if (n[1]==null) args = []
90
+ if (n[1]===nil) args = []
64
91
  else if (n[1][0]==':') args = [n[1]]
65
92
  else if (n[1][0]==',') args = n[1].slice(1)
66
93
  return ['{', ...args]
67
94
  }
68
95
 
69
-
70
96
  // TODO: strings interpolation
71
97
 
72
- export { default } from './subscript.js';
98
+ export default parse
73
99
  export { parse, evaluate }
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- var e,r,n,t=e=>Array.isArray(e)&&("string"==typeof e[0]||t(e[0])),l=(e,r={},n,i)=>t(e)?("string"==typeof(n=e[0])&&(i=u[n]),"function"!=typeof(n=i||l(n,r))?n:n.call(...e.map((e=>l(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,u=l.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":(...e)=>e.reduce(((e,r)=>e&&e[r])),"%":(...e)=>e.reduce(((e,r)=>e%r)),"/":(...e)=>e.reduce(((e,r)=>e/r)),"*":(...e)=>e.reduce(((e,r)=>e*r)),"+":(...e)=>e.reduce(((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)=>e.reduce(((e,r)=>r))},i=l,o=t=>(r=t,e=n=0,f()),a=()=>{for(;d()<=32;)e++},s=(r,t,l,u=3)=>{if(e&&n&&n[3]===e)return n;for(;u;)if(null!=(l=r[t=c(u--)]))return n=[t,l,t.length,e]},f=(r,n=-1)=>{a();let t,l,u,i=d(),o=0,p=e;if(i!==r){for(;p===e&&o<g.length;)l=g[o++](i);if(p===e)(t=s(v))&&(e+=t[2],l=[t[0],f(r,t[1])]);else{if(a(),i=d(),i===r)return l;for(o=0;o<x.length;)(u=x[o](l,i))!==l?(l=u,o=0,a(),i=d()):o++}for(a();(i=d())&&i!==r&&(t=s(b))&&t[1]>n;){l=[t[0],l];do{e+=t[2],l.push(f(r,t[1]))}while(c(t[2])===t[0]);a()}return l}},p=e=>(e=y((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192)))&&A.hasOwnProperty(e)?A[e]:e,d=()=>r.charCodeAt(e),c=(n=1)=>r.substr(e,n),h=r=>{throw Error(r+" at "+e)},y=(n=1,t=e)=>{if("number"==typeof n)e+=n;else for(;n(d());)++e>r.length&&h("Unexpected end "+n);return e>t?r.slice(t,e):null},g=o.token=[(r,n)=>40===r?(e++,n=f(41),e++,n):null,(r,n,t)=>{if(r=y(t=e=>e>=48&&e<=57)||"",46===d()&&(e++,r+="."+y(t)),r)return(69===(n=d())||101===n)&&(e++,r+="e",(43===(n=d())||45===n)&&(r+=c(),e++),r+=y(t)),parseFloat(r)},(r,n)=>34===r?(n=c(),e++,n+y((e=>e!==r))+(e++,n)):null,p],A=o.literal={true:!0,false:!1,null:null},x=o.postfix=[(r,n,t)=>(46===n?(e++,a(),r=[".",r,'"'+p()+'"']):91===n?(e++,r=[".",r,f(93)],e++):40===n&&(e++,t=f(41),r=Array.isArray(t)&&","===t[0]?(t[0]=r,t):null==t?[r]:[r,t],e++),r),(n,t)=>43!==t&&45!==t||r.charCodeAt(e+1)!==t?n:[y(2),n]],v=o.unary={"-":17,"!":17,"+":17,"++":17,"--":17},b=o.binary={",":1,"||":6,"&&":7,"|":8,"^":9,"&":10,"==":11,"!=":11,"<":12,">":12,"<=":12,">=":12,"<<":13,">>":13,">>>":13,"+":14,"-":14,"*":15,"/":15,"%":15},m=o,w=e=>(e="string"==typeof e?m(e):e,r=>i(e,r));A.undefined=void 0,g.push(((e,r)=>39===e?(r=c(),index++,r+y((r=>r!==e))+(index++,r)):null)),b["**"]=16,u["**"]=(...e)=>e.reduceRight(((e,r)=>Math.pow(r,e))),v["~"]=17,u["~"]=e=>~e,b[";"]=1,u["?:"]=(e,r,n)=>e?r:n,x.push((e=>{let r,n;return 63!==d()||(y(),a(),r=f(58),58!==d())?e:(y(),a(),n=f(),["?:",e,r,n])})),l.operator.in=(e,r)=>e in r,o.postfix.unshift((e=>"in"===c(2)?(y(2),["in",'"'+e+'"',f()]):e)),u["["]=(...e)=>Array(...e),g.push(((e,r)=>91===d()?(y(),e=null==(r=f(93))?["["]:","===r[0]?(r[0]="[",r):["[",r],y(),e):null)),b[":"]=2,g.unshift((e=>123===d()?(y(),e=B(["{",f(125)]),y(),e):null)),u["{"]=(...e)=>Object.fromEntries(e),u[":"]=(e,r)=>[e,r];var B=(e,r)=>(null==e[1]?r=[]:":"==e[1][0]?r=[e[1]]:","==e[1][0]&&(r=e[1].slice(1)),["{",...r]);export{w as default,l as evaluate,o as parse};
1
+ var e,r,o=e=>Array.isArray(e)&&("string"==typeof e[0]||o(e[0])),t=(e,r={},n,p)=>o(e)?("string"==typeof(n=e[0])&&(p=a[n]),"function"!=typeof(n=p||t(n,r))?n:n.call(...e.map((e=>t(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,a=t.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":(...e)=>e.reduce(((e,r)=>e&&e[r])),"%":(...e)=>e.reduce(((e,r)=>e%r)),"/":(...e)=>e.reduce(((e,r)=>e/r)),"*":(...e)=>e.reduce(((e,r)=>e*r)),"+":(...e)=>e.reduce(((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)=>e.reduce(((e,r)=>r))},n=(o,t)=>(r=o,e=0,t=u(),e<r.length?p():t),p=(o="Bad syntax")=>{throw Error(o+" `"+r[e]+"` at "+e)},s=(o=1,t=e)=>{if("number"==typeof o)e+=o;else for(;o(i());)e++;return r.slice(t,e)||c},i=(o=0)=>r.charCodeAt(e+o),l=(o=1)=>r.substr(e,o),c="",u=(r=0,o,t=n.space(),a,s=e,l=0,u)=>{for(;s===e&&l<n.token.length;)a=n.token[l++](t);for(l=Math.max(0|h[t=n.space()],r);l<n.operator.length&&!(t===o||l<r);)(u=n.operator[l++](a,t,l,o))&&(u.indexOf(c)>=0&&p("Bad expression"),a=u,l=Math.max(0|h[t=n.space()],r));return!r&&o&&i()!=o&&p("Unclosed paren"),a},f=(n.space=r=>{for(;(r=i())<=32;)e++;return r},n.token=[e=>(e=s((e=>e>47&&e<58||46===e)))?((69===i()||101===i())&&(e+=s(2)+s((e=>e>=48&&e<=57))),isNaN(e=parseFloat(e))?p("Bad number"):e):c,(e,r)=>34===e?s()+s((r=>r-e))+s():c,r=>40===r?(++e,r=u(0,41),++e,r===c?p():r):c,e=>s((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))],e=>(r,o,t,a,p,i,f)=>{if(r!==c&&(i=0|e(o))){p=[f=l(i),r];do{s(i),p.push(u(t,a))}while(n.space()==o&&l(i)==f);return p}}),d=(e,r=!1)=>r?(r,o,t,a,n)=>r!==c&&(n=0|e(o))&&[s(n),r]:(r,o,t,a,n)=>r===c&&(n=0|e(o))&&[s(n),u(t-1,a)],h=(n.operator=[f((e=>44==e)),f((e=>124==e&&i(1)==e&&2)),f((e=>38==e&&i(1)==e&&2)),f((e=>124==e)),f((e=>94==e)),f((e=>38==e)),f((e=>(61==e||33==e)&&61==i(1)&&(i(1)==i(2)?3:2))),f((e=>(62==e||60==e)&&e!=i(1))),f((e=>(60==e||62==e)&&e==i(1)&&(e==i(2)?3:2))),f((e=>(43==e||45==e)&&i(1)!=e)),f((e=>42==e&&42!=i(1)||47==e||37==e)),d((e=>(43==e||45==e)&&i(1)==e&&2),!0),d((e=>(43==e||45==e||33==e)&&(i(1)==e?2:1))),(r,o,t,a,n)=>46==o?[s(),r,"string"==typeof(n=u(t,a))?'"'+n+'"':n]:91==o?(e++,r=[".",r,u(0,93)],e++,r):40==o?(e++,n=u(0,41),e++,Array.isArray(n)&&","===n[0]?(n[0]=r,n):n===c?[r]:[r,n]):c],[]);h[44]=0,h[124]=1,h[38]=2,h[94]=4,h[61]=h[33]=6,h[60]=h[62]=7,h[43]=h[45]=9,h[42]=h[47]=h[37]=10,h[46]=h[91]=h[40]=13,n.operator[0]=f((e=>44==e||59==e)),n.token.splice(3,0,(e=>!(116!==e||"true"!==l(4)||!s(4))||(102!==e||"false"!==l(5)||!s(5))&&(110===e&&"null"===l(4)&&s(4)?null:void(117===e&&"undefined"===l(9)&&s(9))))),n.token[1]=(e,r,o,t)=>{if(34===e||39===e){for(r=l(),s(),t="";(o=i())-e;)92===o?(s(),t+=y[l()]||l()):t+=l(),s();return s(),r+t+r}};var y={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};t.operator["**"]=(...e)=>e.reduceRight(((e,r)=>Math.pow(r,e))),n.operator.splice(n.operator.length-3,0,f((e=>42===e&&i(1)===e&&2))),n.operator.splice(n.operator.length-2,0,d((e=>126===e))),t.operator["~"]=e=>~e,t.operator["?:"]=(e,r,o)=>e?r:o,n.operator.splice(1,0,((e,r,o,t)=>{let a,p;if(63===r&&(e===c&&err("Bad expression"),s(),n.space(),a=u(-1,58),58===i()))return s(),n.space(),p=u(),["?:",e,a,p]})),n.space=e=>{for(;(e=i())<=32;)s(),47===i()&&(42===i(1)?(s(2),s((e=>42!==e&&47!==i(1))),s(2)):47===i(1)&&(s(2),s((e=>e>=32))));return e},t.operator.in=(e,r)=>e in r,n.operator.splice(6,0,((e,r,o,t)=>"in"===l(2)&&[s(2),'"'+e+'"',u(o,t)])),t.operator["["]=(...e)=>Array(...e),n.token.unshift(((e,r,o)=>91===e&&(s(),r=(o=u(0,93))===c?["["]:","===o[0]?(o[0]="[",o):["[",o],s(),r))),n.token.unshift(((e,r)=>123===e?(s(),r=g(["{",u(0,125)]),s(),r):null)),n.operator.splice(4,0,f((e=>58===e))),t.operator["{"]=(...e)=>Object.fromEntries(e),t.operator[":"]=(e,r)=>[e,r];var g=(e,r)=>(e[1]===c?r=[]:":"==e[1][0]?r=[e[1]]:","==e[1][0]&&(r=e[1].slice(1)),["{",...r]),v=n;export{v as default,t as evaluate,n as parse};
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "Microlanguage with common syntax for JS/C++/Python/Rust",
5
5
  "main": "subscript.js",
6
6
  "type": "module",
7
7
  "files": [
8
- "src/*",
8
+ "parse.js",
9
+ "evaluate.js",
9
10
  "subscript.js",
10
11
  "subscript.min.js",
11
12
  "justin.js",
package/parse.js ADDED
@@ -0,0 +1,134 @@
1
+ // precedence-based parsing
2
+ const GT=62, LT=60, EQ=61, PLUS=43, MINUS=45, AND=38, OR=124, HAT=94, MUL=42, DIV=47, MOD=37, PERIOD=46, OBRACK=91, CBRACK=93, OPAREN=40, CPAREN=41, COMMA=44, SPACE=32, EXCL=33
3
+
4
+ // current string & index
5
+ let idx, cur
6
+
7
+ export const parse = (str, tree) => (cur=str, idx=0, tree=expr(), idx<cur.length ? err() : tree),
8
+
9
+ err = (msg='Bad syntax') => { throw Error(msg + ' `' + cur[idx] + '` at ' + idx) },
10
+
11
+ skip = (is=1, from=idx) => {
12
+ if (typeof is === 'number') idx += is
13
+ else while (is(code())) idx++;
14
+ return cur.slice(from, idx) || nil
15
+ },
16
+
17
+ code = (i=0) => cur.charCodeAt(idx+i),
18
+
19
+ char = (n=1) => cur.substr(idx, n),
20
+
21
+ nil = '',
22
+
23
+ // a + b - c
24
+ expr = (prec=0, end, cc=parse.space(), node, from=idx, i=0, mapped) => {
25
+ // prefix or token
26
+ while (from===idx && i < parse.token.length) node = parse.token[i++](cc)
27
+
28
+ // postfix or binary
29
+ for (i = Math.max(lookup[cc=parse.space()]|0, prec); i < parse.operator.length;) {
30
+ if (cc===end || i<prec) break // if lookup got prec lower than current - end group
31
+ else if (mapped = parse.operator[i++](node, cc, i, end))
32
+ mapped.indexOf(nil) >=0 && err('Bad expression'),
33
+ node = mapped, i = Math.max(lookup[cc=parse.space()]|0, prec); // we pass i+1 as precision
34
+ }
35
+
36
+ if (!prec && end && code()!=end) err('Unclosed paren')
37
+
38
+ return node
39
+ },
40
+
41
+ // can be extended with comments, so we export
42
+ space = parse.space = cc => { while (cc = code(), cc <= SPACE) idx++; return cc },
43
+
44
+ // tokens
45
+ token = parse.token = [
46
+ // 1.2e+3, .5 - fast & small version, but consumes corrupted nums as well
47
+ (number) => {
48
+ if (number = skip(c => (c > 47 && c < 58) || c === PERIOD)) {
49
+ if (code() === 69 || code() === 101) number += skip(2) + skip(c => c >= 48 && c <= 57)
50
+ return isNaN(number = parseFloat(number)) ? err('Bad number') : number
51
+ }
52
+ return nil
53
+ },
54
+ // "a"
55
+ (q, qc) => q === 34 ? (skip() + skip(c => c-q) + skip()) : nil,
56
+ // (...exp)
57
+ c => c === OPAREN ? (++idx, c=expr(0,CPAREN), ++idx, c===nil?err():c) : nil,
58
+ // var
59
+ c => skip(c =>
60
+ (c >= 48 && c <= 57) || // 0..9
61
+ (c >= 65 && c <= 90) || // A...Z
62
+ (c >= 97 && c <= 122) || // a...z
63
+ c == 36 || c == 95 || // $, _,
64
+ (c >= 192 && c != 215 && c != 247) // any non-ASCII
65
+ )
66
+ ],
67
+
68
+ // create binary operator parser
69
+ binary = (is) => (a,cc,prec,end, list,len,op) => {
70
+ if (a!==nil && (len = is(cc)|0)) {
71
+ // consume same-op group, do..while saves op lookups
72
+ list = [op=char(len),a]
73
+ do { skip(len), list.push(expr(prec,end)) } while (parse.space()==cc && char(len)==op)
74
+ return list
75
+ }
76
+ },
77
+ unary = (is, post=false) => post ?
78
+ (a,cc,prec,end,l) => a!==nil && (l=is(cc)|0) && [skip(l), a] :
79
+ (a,cc,prec,end,l) => a===nil && (l=is(cc)|0) && [skip(l), expr(prec-1,end)],
80
+
81
+ operator = parse.operator = [
82
+ // ','
83
+ binary(c => c==COMMA),
84
+ // '||' '&&'
85
+ binary(c => c==OR && code(1)==c && 2),
86
+ binary(c => c==AND && code(1)==c && 2),
87
+ // '|' '^' '&'
88
+ binary(c => c==OR),
89
+ binary(c => c==HAT),
90
+ binary(c => c==AND),
91
+ // '==' '!='
92
+ binary(c => (c==EQ || c==EXCL) && code(1)==EQ && (code(1)==code(2) ? 3 : 2)),
93
+ // '<' '>' '<=' '>='
94
+ binary(c => (c==GT || c==LT) && c!=code(1)),
95
+ // '<<' '>>' '>>>'
96
+ binary(c => (c==LT || c==GT) && c==code(1) && (c==code(2) ? 3 : 2)),
97
+ // '+' '-'
98
+ binary(c => (c==PLUS || c==MINUS) && code(1)!=c),
99
+ // '*' '/' '%'
100
+ binary(c => (c==MUL && code(1) != MUL) || c==DIV || c==MOD),
101
+ // -- ++ unaries
102
+ unary(c => (c==PLUS || c==MINUS) && code(1) == c && 2, true),
103
+ // - + ! unaries
104
+ unary(c => (c==PLUS || c==MINUS || c==EXCL) && (code(1)==c ? 2 : 1)),
105
+ // '()', '[]', '.'
106
+ (a,cc,prec,end,b) => (
107
+ // a.b[c](d)
108
+ cc==PERIOD ? [skip(), (a), typeof (b = (expr(prec,end))) === 'string' ? '"' + b + '"' : b] :
109
+ cc==OBRACK ? (idx++, a = ['.', (a), (expr(0,CBRACK))], idx++, a) :
110
+ cc==OPAREN ? (
111
+ idx++, b=expr(0,CPAREN), idx++,
112
+ Array.isArray(b) && b[0]===',' ? (b[0]=a, b) :
113
+ b === nil ? [a] :
114
+ [a, b]
115
+ ) : nil
116
+ )
117
+ ],
118
+
119
+ // fast operator lookup table
120
+ lookup = []
121
+
122
+ lookup[COMMA] = 0
123
+ lookup[OR] = 1
124
+ lookup[AND] = 2
125
+ lookup[HAT] = 4
126
+ lookup[EQ] = lookup[EXCL] = 6
127
+ lookup[LT] = lookup[GT] = 7
128
+ lookup[PLUS] = lookup[MINUS] = 9
129
+ lookup[MUL] = lookup[DIV] = lookup[MOD] = 10
130
+ lookup[PERIOD] = lookup[OBRACK] = lookup[OPAREN] = 13
131
+
132
+
133
+
134
+ export default parse
package/subscript.js CHANGED
@@ -1,5 +1,5 @@
1
- import parse from './src/parse.js'
2
- import evaluate from './src/evaluate.js'
1
+ import parse from './parse.js'
2
+ import evaluate from './evaluate.js'
3
3
 
4
4
  export { parse, evaluate }
5
5
 
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- var e,r,t,l=l=>(r=l,e=t=0,u()),n=()=>{for(;f()<=32;)e++},o=(r,l,n,o=3)=>{if(e&&t&&t[3]===e)return t;for(;o;)if(null!=(n=r[l=s(o--)]))return t=[l,n,l.length,e]},u=(r,t=-1)=>{n();let l,a,i,c=f(),y=0,A=e;if(c!==r){for(;A===e&&y<p.length;)a=p[y++](c);if(A===e)(l=o(h))&&(e+=l[2],a=[l[0],u(r,l[1])]);else{if(n(),c=f(),c===r)return a;for(y=0;y<d.length;)(i=d[y](a,c))!==a?(a=i,y=0,n(),c=f()):y++}for(n();(c=f())&&c!==r&&(l=o(g))&&l[1]>t;){a=[l[0],a];do{e+=l[2],a.push(u(r,l[1]))}while(s(l[2])===l[0]);n()}return a}},a=e=>(e=c((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192)))&&y.hasOwnProperty(e)?y[e]:e,f=()=>r.charCodeAt(e),s=(t=1)=>r.substr(e,t),i=r=>{throw Error(r+" at "+e)},c=(t=1,l=e)=>{if("number"==typeof t)e+=t;else for(;t(f());)++e>r.length&&i("Unexpected end "+t);return e>l?r.slice(l,e):null},p=l.token=[(r,t)=>40===r?(e++,t=u(41),e++,t):null,(r,t,l)=>{if(r=c(l=e=>e>=48&&e<=57)||"",46===f()&&(e++,r+="."+c(l)),r)return(69===(t=f())||101===t)&&(e++,r+="e",(43===(t=f())||45===t)&&(r+=s(),e++),r+=c(l)),parseFloat(r)},(r,t)=>34===r?(t=s(),e++,t+c((e=>e!==r))+(e++,t)):null,a],y=l.literal={true:!0,false:!1,null:null},d=l.postfix=[(r,t,l)=>(46===t?(e++,n(),r=[".",r,'"'+a()+'"']):91===t?(e++,r=[".",r,u(93)],e++):40===t&&(e++,l=u(41),r=Array.isArray(l)&&","===l[0]?(l[0]=r,l):null==l?[r]:[r,l],e++),r),(t,l)=>43!==l&&45!==l||r.charCodeAt(e+1)!==l?t:[c(2),t]],h=l.unary={"-":17,"!":17,"+":17,"++":17,"--":17},g=l.binary={",":1,"||":6,"&&":7,"|":8,"^":9,"&":10,"==":11,"!=":11,"<":12,">":12,"<=":12,">=":12,"<<":13,">>":13,">>>":13,"+":14,"-":14,"*":15,"/":15,"%":15},A=l,b=e=>Array.isArray(e)&&("string"==typeof e[0]||b(e[0])),m=(e,r={},t,l)=>b(e)?("string"==typeof(t=e[0])&&(l=v[t]),"function"!=typeof(t=l||m(t,r))?t:t.call(...e.map((e=>m(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,v=m.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":(...e)=>e.reduce(((e,r)=>e&&e[r])),"%":(...e)=>e.reduce(((e,r)=>e%r)),"/":(...e)=>e.reduce(((e,r)=>e/r)),"*":(...e)=>e.reduce(((e,r)=>e*r)),"+":(...e)=>e.reduce(((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)=>e.reduce(((e,r)=>r))},w=m,x=e=>(e="string"==typeof e?A(e):e,r=>w(e,r));export{x as default,w as evaluate,A as parse};
1
+ var e,r,a=(a,o)=>(r=a,e=0,o=c(),e<r.length?t():o),t=(a="Bad syntax")=>{throw Error(a+" `"+r[e]+"` at "+e)},o=(a=1,t=e)=>{if("number"==typeof a)e+=a;else for(;a(s());)e++;return r.slice(t,e)||p},s=(a=0)=>r.charCodeAt(e+a),n=(a=1)=>r.substr(e,a),p="",c=(r=0,o,n=a.space(),c,i=e,u=0,f)=>{for(;i===e&&u<a.token.length;)c=a.token[u++](n);for(u=Math.max(0|l[n=a.space()],r);u<a.operator.length&&!(n===o||u<r);)(f=a.operator[u++](c,n,u,o))&&(f.indexOf(p)>=0&&t("Bad expression"),c=f,u=Math.max(0|l[n=a.space()],r));return!r&&o&&s()!=o&&t("Unclosed paren"),c},i=(a.space=r=>{for(;(r=s())<=32;)e++;return r},a.token=[e=>(e=o((e=>e>47&&e<58||46===e)))?((69===s()||101===s())&&(e+=o(2)+o((e=>e>=48&&e<=57))),isNaN(e=parseFloat(e))?t("Bad number"):e):p,(e,r)=>34===e?o()+o((r=>r-e))+o():p,r=>40===r?(++e,r=c(0,41),++e,r===p?t():r):p,e=>o((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192&&215!=e&&247!=e))],e=>(r,t,s,i,u,l,f)=>{if(r!==p&&(l=0|e(t))){u=[f=n(l),r];do{o(l),u.push(c(s,i))}while(a.space()==t&&n(l)==f);return u}}),u=(e,r=!1)=>r?(r,a,t,s,n)=>r!==p&&(n=0|e(a))&&[o(n),r]:(r,a,t,s,n)=>r===p&&(n=0|e(a))&&[o(n),c(t-1,s)],l=(a.operator=[i((e=>44==e)),i((e=>124==e&&s(1)==e&&2)),i((e=>38==e&&s(1)==e&&2)),i((e=>124==e)),i((e=>94==e)),i((e=>38==e)),i((e=>(61==e||33==e)&&61==s(1)&&(s(1)==s(2)?3:2))),i((e=>(62==e||60==e)&&e!=s(1))),i((e=>(60==e||62==e)&&e==s(1)&&(e==s(2)?3:2))),i((e=>(43==e||45==e)&&s(1)!=e)),i((e=>42==e&&42!=s(1)||47==e||37==e)),u((e=>(43==e||45==e)&&s(1)==e&&2),!0),u((e=>(43==e||45==e||33==e)&&(s(1)==e?2:1))),(r,a,t,s,n)=>46==a?[o(),r,"string"==typeof(n=c(t,s))?'"'+n+'"':n]:91==a?(e++,r=[".",r,c(0,93)],e++,r):40==a?(e++,n=c(0,41),e++,Array.isArray(n)&&","===n[0]?(n[0]=r,n):n===p?[r]:[r,n]):p],[]);l[44]=0,l[124]=1,l[38]=2,l[94]=4,l[61]=l[33]=6,l[60]=l[62]=7,l[43]=l[45]=9,l[42]=l[47]=l[37]=10,l[46]=l[91]=l[40]=13;var f=a,d=e=>Array.isArray(e)&&("string"==typeof e[0]||d(e[0])),y=(e,r={},a,t)=>d(e)?("string"==typeof(a=e[0])&&(t=h[a]),"function"!=typeof(a=t||y(a,r))?a:a.call(...e.map((e=>y(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,h=y.operator={"!":e=>!e,"++":e=>++e,"--":e=>--e,".":(...e)=>e.reduce(((e,r)=>e&&e[r])),"%":(...e)=>e.reduce(((e,r)=>e%r)),"/":(...e)=>e.reduce(((e,r)=>e/r)),"*":(...e)=>e.reduce(((e,r)=>e*r)),"+":(...e)=>e.reduce(((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)=>e.reduce(((e,r)=>r))},g=y,m=e=>(e="string"==typeof e?f(e):e,r=>g(e,r));export{m as default,g as evaluate,f as parse};
package/src/parse.js DELETED
@@ -1,132 +0,0 @@
1
- const PERIOD = 46, OPAREN = 40, CPAREN = 41, OBRACK = 91, CBRACK = 93, PLUS = 43, MINUS = 45
2
-
3
- export let index, current, lastOp
4
-
5
- export const parse = str => (current=str, index=lastOp=0, expr()),
6
-
7
- space = () => { while (code() <= 32) index++ },
8
-
9
- // consume operator that resides within current group by precedence
10
- operator = (ops, op, prec, l=3) => {
11
- // memoize by index - saves 20% to perf
12
- if (index && lastOp && lastOp[3] === index) return lastOp
13
-
14
- // ascending lookup is faster 1-char operators, longer for 2+ char ops
15
- while (l) if ((prec=ops[op=char(l--)])!=null) return lastOp = [op, prec, op.length, index] //opinfo
16
- },
17
-
18
- expr = (end, prec=-1) => {
19
- space()
20
-
21
- let cc = code(), op, node, i=0, mapped, from=index
22
-
23
- if (cc === end) return
24
-
25
- // parse node by token parsers (direct loop is faster than stack entry)
26
- while (from===index && i < token.length) node = token[i++](cc)
27
-
28
- // unary prefix
29
- if (from===index) (op = operator(unary)) && (index += op[2], node = [op[0], expr(end, op[1])])
30
-
31
- // postfix handlers allow a.b[c](d).e, postfix operators, literals etc.
32
- else {
33
- if (space(), cc=code(), cc === end) return node
34
- for (i=0; i < postfix.length;) if ((mapped=postfix[i](node, cc)) !== node) node=mapped, i=0, space(), cc=code(); else i++
35
- }
36
- // else do {space(), cc=code()} while (postfix.find((parse, mapped) => (mapped = parse(node, cc)) !== node && (node = mapped)))
37
-
38
- space()
39
-
40
- // consume expression for current precedence or group (== highest precedence)
41
- while ((cc = code()) && cc !== end && (op = operator(binary)) && op[1] > prec) {
42
- node = [op[0], node]
43
- // consume same-op group, do..while both saves op lookups and space
44
- do { index += op[2], node.push(expr(end, op[1])) } while (char(op[2]) === op[0])
45
- space()
46
- }
47
-
48
- return node;
49
- },
50
-
51
- // tokens
52
- // 1.2e+3, .5
53
- float = (number, c, isDigit) => {
54
- number = next(isDigit = c => c >= 48 && c <= 57) || ''
55
- if (code() === PERIOD) index++, number += '.' + next(isDigit)
56
- if (number) {
57
- if ((c = code()) === 69 || c === 101) { // e, E
58
- index++, number += 'e'
59
- if ((c=code()) === PLUS || c === MINUS) // +-
60
- number += char(), index++
61
- number += next(isDigit)
62
- }
63
- return parseFloat(number)
64
- }
65
- },
66
-
67
- // "a"
68
- string = (q, qc) => q === 34 ? (qc = char(), index++, qc) + next(c => c !== q) + (index++, qc) : null,
69
-
70
- // (...exp)
71
- group = (c, node) => c === OPAREN ? (index++, node = expr(CPAREN), index++, node) : null,
72
-
73
- id = name => (name = next(c =>
74
- (c >= 48 && c <= 57) || // 0..9
75
- (c >= 65 && c <= 90) || // A...Z
76
- (c >= 97 && c <= 122) || // a...z
77
- c == 36 || c == 95 || // $, _,
78
- c >= 192 // any non-ASCII
79
- )) && literal.hasOwnProperty(name) ? literal[name] : name,
80
-
81
-
82
- // ------------ util
83
- code = () => current.charCodeAt(index), // current char code
84
- char = (n=1) => current.substr(index, n), // next n chars
85
- err = (msg) => { throw Error(msg + ' at ' + index) },
86
- next = (is=1, from=index) => { // number indicates skip & stop (don't check)
87
- if (typeof is === 'number') index += is
88
- else while (is(code())) ++index > current.length && err('Unexpected end ' + is) // 1 + true === 2;
89
- return index > from ? current.slice(from, index) : null
90
- },
91
-
92
-
93
- // ----------- config
94
- token = parse.token = [ group, float, string, id ],
95
-
96
- literal = parse.literal = {true:true, false:false, null:null},
97
-
98
- postfix = parse.postfix = [
99
- // a.b[c](d), 3 in 1 for performance
100
- (node, cc, arg) => {
101
- if (cc === PERIOD) index++, space(), node = ['.', node, '"'+id()+'"']
102
- else if (cc === OBRACK) index++, node = ['.', node, expr(CBRACK)], index++
103
- else if (cc === OPAREN)
104
- index++, arg=expr(CPAREN),
105
- node = Array.isArray(arg) && arg[0]===',' ? (arg[0]=node, arg) : arg == null ? [node] : [node, arg],
106
- index++
107
- return node
108
- },
109
-
110
- // a++, a--
111
- (node, cc) => (cc===0x2b || cc===0x2d) && current.charCodeAt(index+1)===cc ? [next(2), node] : node,
112
- ],
113
-
114
- unary = parse.unary = {
115
- '-': 17,
116
- '!': 17,
117
- '+': 17,
118
- '++': 17,
119
- '--': 17
120
- },
121
-
122
- binary = parse.binary = {
123
- ',': 1,
124
- '||': 6, '&&': 7, '|': 8, '^': 9, '&': 10,
125
- '==': 11, '!=': 11,
126
- '<': 12, '>': 12, '<=': 12, '>=': 12,
127
- '<<': 13, '>>': 13, '>>>': 13,
128
- '+': 14, '-': 14,
129
- '*': 15, '/': 15, '%': 15
130
- }
131
-
132
- export default parse