subscript 3.0.2 → 3.0.3

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,8 +1,8 @@
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
- * It has well-known syntax
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
8
  * It's very fast ([see performance](#performance))
@@ -104,6 +104,7 @@ It adds support for:
104
104
  + `{...}` Object literal
105
105
  + `in` binary operator
106
106
  + `;` expression separator
107
+ + unary word operators
107
108
  <!-- + `//, /* */` comments -->
108
109
  <!-- + `undefined` literal -->
109
110
  <!-- + `?` chaining operator -->
@@ -263,7 +264,7 @@ Subscript shows relatively good performance within other evaluators:
263
264
  // parse 30k times
264
265
 
265
266
  subscript: ~280 ms
266
- jsep: ~290 ms
267
+ jsep: ~281 ms
267
268
  expr-eval: ~480 ms
268
269
  jexl: ~1200 ms
269
270
  new Function: ~1400 ms
@@ -278,6 +279,6 @@ new Function: ~1400 ms
278
279
  * [expression-eval](https://github.com/donmccurdy/expression-eval)
279
280
  * [jsep](https://github.com/EricSmekens/jsep)
280
281
  * [string-math](https://github.com/devrafalko/string-math)
281
-
282
+ * [nerdamer](https://github.com/jiggzson/nerdamer)
282
283
 
283
284
  <p align=center>🕉</p>
File without changes
package/justin.js CHANGED
@@ -1,13 +1,37 @@
1
1
  // justin lang https://github.com/endojs/Jessie/issues/66
2
- import {evaluate, operator} from './src/evaluate.js'
2
+ import {evaluate, operator} from './evaluate.js'
3
3
  import {parse, binary, unary, postfix, token, literal,
4
- code, char, skip, space, expr} from './src/parse.js'
4
+ code, char, skip, space, expr} from './parse.js'
5
5
 
6
6
  // undefined
7
7
  literal['undefined'] = undefined
8
8
 
9
- // '
10
- token.push((q, qc) => q === 39 ? (qc = char(), index++, qc) + skip(c => c !== q) + (index++, qc) : null)
9
+ // "' with /
10
+ token[2] = (q, qc, c, str) => {
11
+ if (q !== 34 && q !== 39) return
12
+ qc = char(), skip(), str = ''
13
+ while (c=code(), c-q) {
14
+ if (c === 92) skip(), str += escape[char()] || char(); else str+=char()
15
+ skip()
16
+ }
17
+ return skip(), qc + str + qc
18
+ }
19
+ const escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'}
20
+
21
+ // unary word
22
+ postfix.push((node, prec) => typeof node === 'string' && (prec=unary[node]) ? [node, expr(prec)] : node)
23
+
24
+ // detect custom operators
25
+ token[3] = name => (name = skip(c =>
26
+ (
27
+ (c >= 48 && c <= 57) || // 0..9
28
+ (c >= 65 && c <= 90) || // A...Z
29
+ (c >= 97 && c <= 122) || // a...z
30
+ c == 36 || c == 95 || // $, _,
31
+ c >= 192 // any non-ASCII
32
+ ) && !binary[String.fromCharCode(c)]
33
+ )),
34
+
11
35
 
12
36
  // **
13
37
  binary['**'] = 16
@@ -28,7 +52,7 @@ operator['?:']=(a,b,c)=>a?b:c
28
52
  postfix.push(node => {
29
53
  let a, b
30
54
  if (code() !== 63) return node
31
- skip(), space(), a = expr(58)
55
+ skip(), space(), a = expr(-1,58)
32
56
  if (code() !== 58) return node
33
57
  skip(), space(), b = expr()
34
58
  return ['?:',node, a, b]
@@ -47,7 +71,7 @@ operator['['] = (...args) => Array(...args)
47
71
  token.push((node, arg) =>
48
72
  code() === 91 ?
49
73
  (
50
- skip(), arg=expr(93),
74
+ skip(), arg=expr(-1,93),
51
75
  node = arg==null ? ['['] : arg[0] === ',' ? (arg[0]='[',arg) : ['[',arg],
52
76
  skip(), node
53
77
  ) : null
@@ -55,7 +79,7 @@ token.push((node, arg) =>
55
79
 
56
80
  // {}
57
81
  binary[':'] = 2
58
- token.unshift((node) => code() === 123 ? (skip(), node = map(['{',expr(125)]), skip(), node) : null)
82
+ token.unshift((node) => code() === 123 ? (skip(), node = map(['{',expr(-1,125)]), skip(), node) : null)
59
83
  operator['{'] = (...args)=>Object.fromEntries(args)
60
84
  operator[':'] = (a,b)=>[a,b]
61
85
 
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 r,e,n,t,l=r=>Array.isArray(r)&&("string"==typeof r[0]||l(r[0])),o=(r,e={},n,t)=>l(r)?("string"==typeof(n=r[0])&&(t=u[n]),"function"!=typeof(n=t||o(n,e))?n:n.call(...r.map((r=>o(r,e))))):r&&"string"==typeof r?'"'===r[0]?r.slice(1,-1):"@"===r[0]?r.slice(1):r in e?e[r]:r:r,u=o.operator={"!":r=>!r,"++":r=>++r,"--":r=>--r,".":(...r)=>r.reduce(((r,e)=>r&&r[e])),"%":(...r)=>r.reduce(((r,e)=>r%e)),"/":(...r)=>r.reduce(((r,e)=>r/e)),"*":(...r)=>r.reduce(((r,e)=>r*e)),"+":(...r)=>r.reduce(((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)=>r.reduce(((r,e)=>e))},i=o,a=(t,l)=>(e=t,r=n=0,l=c(),r<e.length?p():l),s=()=>e.charCodeAt(r),f=(n=1)=>e.substr(r,n),p=(e="Bad syntax "+f())=>{throw Error(e+" at "+r)},d=(n=1,t=r)=>{if("number"==typeof n)r+=n;else for(;n(s());)++r>e.length&&p("End by "+n);return r>t?e.slice(t,r):null},h=()=>{for(;s()<=32;)r++},y=(e,t,l,o=3)=>{if(r&&n&&n[3]===r)return n;for(;o;)if(null!=(l=e[t=f(o--)]))return n=[t,l,t.length,r]},c=(e=-1,n)=>{h();let l,o,u,i,a=s(),d=0,g=r;if(n){if(a===n)return;i=t,t=n}for(;g===r&&d<b.length;)o=b[d++](a);if(g===r)(l=y(m))&&(r+=l[2],o=[l[0],c(l[1])]);else for(h(),a=s(),d=0;d<A.length;)(u=A[d](o,a))!==o?(o=u,h(),a=s()):d++;for(;a=s()&&a!==t&&(l=y(w))&&l[1]>e;){o=[l[0],o];do{r+=l[2],o.push(c(l[1]))}while(f(l[2])===l[0]);h()}return n&&(t=s()!==n?p("Unclosed paren"):i),o},g=r=>d((r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192)),b=a.token=[r=>{if(r=d((r=>r>=48&&r<=57||46===r)))return(69===s()||101===s())&&(r+=d(2)+d((r=>r>=48&&r<=57))),isNaN(r=parseFloat(r))?p("Bad number"):r},(e,n)=>40===e?(r++,n=c(-1,41),r++,n):null,(e,n)=>34===e?(n=f(),r++,n+d((r=>r-e))+(r++,n)):null,g],v=a.literal={true:!0,false:!1,null:null},A=a.postfix=[(n,t,l)=>(46===t?(r++,h(),n=[".",n,'"'+g()+'"']):91===t?(r++,n=[".",n,c(-1,93)],r++):40===t?(r++,l=c(-1,41),n=Array.isArray(l)&&","===l[0]?(l[0]=n,l):null==l?[n]:[n,l],r++):43!==t&&45!==t||e.charCodeAt(r+1)!==t?"string"==typeof n&&v.hasOwnProperty(n)&&(n=v[n]):n=[d(2),n],n)],m=a.unary={"-":17,"!":17,"+":17,"++":17,"--":17},w=a.binary={",":1,"||":6,"&&":7,"|":8,"^":9,"&":10,"==":11,"!=":11,"<":12,">":12,"<=":12,">=":12,"<<":13,">>":13,">>>":13,"+":14,"-":14,"*":15,"/":15,"%":15},x=a,B=r=>(r="string"==typeof r?x(r):r,e=>i(r,e));v.undefined=void 0,b[2]=(r,e,n,t)=>{if(34===r||39===r){for(e=f(),d(),t="";(n=s())-r;)92===n?(d(),t+=C[f()]||f()):t+=f(),d();return d(),e+t+e}};var C={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};A.push(((r,e)=>"string"==typeof r&&(e=m[r])?[r,c(e)]:r)),b[3]=r=>d((r=>(r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192)&&!w[String.fromCharCode(r)])),w["**"]=16,u["**"]=(...r)=>r.reduceRight(((r,e)=>Math.pow(e,r))),m["~"]=17,u["~"]=r=>~r,w[";"]=1,u["?:"]=(r,e,n)=>r?e:n,A.push((r=>{let e,n;return 63!==s()||(d(),h(),e=c(-1,58),58!==s())?r:(d(),h(),n=c(),["?:",r,e,n])})),o.operator.in=(r,e)=>r in e,a.postfix.unshift((r=>"in"===f(2)?(d(2),["in",'"'+r+'"',c()]):r)),u["["]=(...r)=>Array(...r),b.push(((r,e)=>91===s()?(d(),r=null==(e=c(-1,93))?["["]:","===e[0]?(e[0]="[",e):["[",e],d(),r):null)),w[":"]=2,b.unshift((r=>123===s()?(d(),r=E(["{",c(-1,125)]),d(),r):null)),u["{"]=(...r)=>Object.fromEntries(r),u[":"]=(r,e)=>[r,e];var E=(r,e)=>(null==r[1]?e=[]:":"==r[1][0]?e=[r[1]]:","==r[1][0]&&(e=r[1].slice(1)),["{",...e]);export{B as default,o as evaluate,a as parse};
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "3.0.2",
3
+ "version": "3.0.3",
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",
@@ -1,11 +1,21 @@
1
1
  const PERIOD = 46, OPAREN = 40, CPAREN = 41, OBRACK = 91, CBRACK = 93, PLUS = 43, MINUS = 45
2
2
 
3
- export let index, current, lastOp
3
+ export let index, current, lastOp, end
4
4
 
5
- export const parse = str => (current=str, index=lastOp=0, expr()),
5
+ export const parse = (str, tree) => (current=str, index=lastOp=0, tree=expr(), index < current.length ? err() : tree),
6
6
 
7
+ // ------------ util
8
+ code = () => current.charCodeAt(index), // current char code
9
+ char = (n=1) => current.substr(index, n), // skip n chars
10
+ err = (msg='Bad syntax '+char()) => { throw Error(msg + ' at ' + index) },
11
+ skip = (is=1, from=index) => { // consume N or until condition matches
12
+ if (typeof is === 'number') index += is
13
+ else while (is(code())) ++index > current.length && err('End by ' + is) // 1 + true === 2;
14
+ return index > from ? current.slice(from, index) : null
15
+ },
7
16
  space = () => { while (code() <= 32) index++ },
8
17
 
18
+ // ------------- expr
9
19
  // consume operator
10
20
  operator = (ops, op, prec, l=3) => {
11
21
  // memoize by index - saves 20% to perf
@@ -15,95 +25,91 @@ operator = (ops, op, prec, l=3) => {
15
25
  while (l) if ((prec=ops[op=char(l--)])!=null) return lastOp = [op, prec, op.length, index] //opinfo
16
26
  },
17
27
 
18
- expr = (end, prec=-1) => {
28
+ expr = (prec=-1, curEnd) => {
19
29
  space()
20
30
 
21
- let cc = code(), op, node, i=0, mapped, from=index
31
+ let cc = code(), op, node, i=0, mapped, from=index, prevEnd
22
32
 
23
- if (cc === end) return
33
+ if (curEnd) if (cc === curEnd) return; else prevEnd = end, end = curEnd // global end marker saves operator lookups
24
34
 
25
35
  // parse node by token parsers (direct loop is faster than token.find)
26
36
  while (from===index && i < token.length) node = token[i++](cc)
27
37
 
28
38
  // unary prefix
29
- if (from===index) (op = operator(unary)) && (index += op[2], node = [op[0], expr(end, op[1])])
39
+ if (from===index) (op = operator(unary)) && (index += op[2], node = [op[0], expr(op[1])])
30
40
 
31
- // postfix handlers allow a.b[c](d).e, postfix operators, literals etc.
41
+ // postfix handlers
32
42
  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++
43
+ for (space(), cc=code(), i=0; i < postfix.length;)
44
+ if ((mapped = postfix[i](node, cc)) !== node) node = mapped, space(), cc=code(); else i++
35
45
  }
36
46
  // ALT: seems to be slower
37
47
  // else do {space(), cc=code()} while (postfix.find((parse, mapped) => (mapped = parse(node, cc)) !== node && (node = mapped)))
38
48
 
39
- space()
40
-
41
- // consume expression for current precedence or higher
42
- while ((cc = code()) && cc !== end && (op = operator(binary)) && op[1] > prec) {
49
+ // consume binary expression for current precedence or higher
50
+ while (cc = code() && (cc !== end) && (op = operator(binary)) && op[1] > prec) {
43
51
  node = [op[0], node]
44
52
  // consume same-op group, do..while both saves op lookups and space
45
- do { index += op[2], node.push(expr(end, op[1])) } while (char(op[2]) === op[0])
53
+ do { index += op[2], node.push(expr(op[1])) } while (char(op[2]) === op[0])
46
54
  space()
47
55
  }
48
56
 
57
+ if (curEnd) end = code() !== curEnd ? err('Unclosed paren') : prevEnd
58
+ // if (node == null) err('Missing argument')
59
+
49
60
  return node;
50
61
  },
51
62
 
52
63
  // ------------------- tokens
53
64
  // 1.2e+3, .5 - fast & small version, but consumes corrupted nums as well
54
- float = (number, c) => {
65
+ float = (number) => {
55
66
  if (number = skip(c => (c >= 48 && c <= 57) || c === PERIOD)) {
56
67
  if (code() === 69 || code() === 101) number += skip(2) + skip(c => c >= 48 && c <= 57)
57
- return parseFloat(number)
68
+ return isNaN(number = parseFloat(number)) ? err('Bad number') : number
58
69
  }
59
70
  },
60
71
 
61
72
  // "a"
62
- string = (q, qc) => q === 34 ? (qc = char(), index++, qc) + skip(c => c !== q) + (index++, qc) : null,
73
+ string = (q, qc) => q === 34 ? (qc = char(), index++, qc) + skip(c => c-q) + (index++, qc) : null,
63
74
 
64
75
  // (...exp)
65
- group = (c, node) => c === OPAREN ? (index++, node = expr(CPAREN), index++, node) : null,
76
+ group = (c, node) => c === OPAREN ? (index++, node = expr(-1,CPAREN), index++, node) : null,
66
77
 
67
78
  // var or literal
68
79
  id = name => (name = skip(c =>
69
- (c >= 48 && c <= 57) || // 0..9
70
- (c >= 65 && c <= 90) || // A...Z
71
- (c >= 97 && c <= 122) || // a...z
72
- c == 36 || c == 95 || // $, _,
73
- c >= 192 // any non-ASCII
74
- )) && literal.hasOwnProperty(name) ? literal[name] : name,
75
-
76
-
77
- // ------------ util
78
- code = () => current.charCodeAt(index), // current char code
79
- char = (n=1) => current.substr(index, n), // skip n chars
80
- err = (msg) => { throw Error(msg + ' at ' + index) },
81
- skip = (is=1, from=index) => { // consume N or until condition matches
82
- if (typeof is === 'number') index += is
83
- else while (is(code())) ++index > current.length && err('Unexpected end ' + is) // 1 + true === 2;
84
- return index > from ? current.slice(from, index) : null
85
- },
86
-
80
+ (
81
+ (c >= 48 && c <= 57) || // 0..9
82
+ (c >= 65 && c <= 90) || // A...Z
83
+ (c >= 97 && c <= 122) || // a...z
84
+ c == 36 || c == 95 || // $, _,
85
+ c >= 192 // any non-ASCII
86
+ )
87
+ )),
87
88
 
88
89
  // ----------- config
89
- token = parse.token = [ group, float, string, id ],
90
+ token = parse.token = [ float, group, string, id ],
90
91
 
91
92
  literal = parse.literal = {true:true, false:false, null:null},
92
93
 
93
94
  postfix = parse.postfix = [
94
- // a.b[c](d), 3 in 1 for performance
95
+ // postfix parsers merged into 1 for performance & compactness
95
96
  (node, cc, arg) => {
97
+ // a.b[c](d)
96
98
  if (cc === PERIOD) index++, space(), node = ['.', node, '"'+id()+'"']
97
- else if (cc === OBRACK) index++, node = ['.', node, expr(CBRACK)], index++
99
+ else if (cc === OBRACK) index++, node = ['.', node, expr(-1,CBRACK)], index++
98
100
  else if (cc === OPAREN)
99
- index++, arg=expr(CPAREN),
101
+ index++, arg=expr(-1,CPAREN),
100
102
  node = Array.isArray(arg) && arg[0]===',' ? (arg[0]=node, arg) : arg == null ? [node] : [node, arg],
101
103
  index++
102
- return node
103
- },
104
104
 
105
- // a++, a--
106
- (node, cc) => (cc===0x2b || cc===0x2d) && current.charCodeAt(index+1)===cc ? [skip(2), node] : node,
105
+ // a++, a--
106
+ else if ((cc===0x2b || cc===0x2d) && current.charCodeAt(index+1)===cc) node = [skip(2), node]
107
+
108
+ // literal
109
+ else if (typeof node === 'string' && literal.hasOwnProperty(node)) node = literal[node]
110
+
111
+ return node
112
+ }
107
113
  ],
108
114
 
109
115
  unary = parse.unary = {
@@ -124,4 +130,5 @@ binary = parse.binary = {
124
130
  '*': 15, '/': 15, '%': 15
125
131
  }
126
132
 
133
+
127
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,(e,r)=>{if(e=c((e=>e>=48&&e<=57||46===e)))return(69===f()||101===f())&&(e+=c(2)+c((e=>e>=48&&e<=57))),parseFloat(e)},(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,t,n,l=(n,l)=>(r=n,e=t=0,l=y(),e<r.length?u():l),a=()=>r.charCodeAt(e),o=(t=1)=>r.substr(e,t),u=(r="Bad syntax "+o())=>{throw Error(r+" at "+e)},s=(t=1,n=e)=>{if("number"==typeof t)e+=t;else for(;t(a());)++e>r.length&&u("End by "+t);return e>n?r.slice(n,e):null},f=()=>{for(;a()<=32;)e++},i=(r,n,l,a=3)=>{if(e&&t&&t[3]===e)return t;for(;a;)if(null!=(l=r[n=o(a--)]))return t=[n,l,n.length,e]},y=(r=-1,t)=>{f();let l,s,p,d,b=a(),m=0,B=e;if(t){if(b===t)return;d=n,n=t}for(;B===e&&m<c.length;)s=c[m++](b);if(B===e)(l=i(g))&&(e+=l[2],s=[l[0],y(l[1])]);else for(f(),b=a(),m=0;m<h.length;)(p=h[m](s,b))!==s?(s=p,f(),b=a()):m++;for(;b=a()&&b!==n&&(l=i(A))&&l[1]>r;){s=[l[0],s];do{e+=l[2],s.push(y(l[1]))}while(o(l[2])===l[0]);f()}return t&&(n=a()!==t?u("Unclosed paren"):d),s},p=e=>s((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192)),c=l.token=[e=>{if(e=s((e=>e>=48&&e<=57||46===e)))return(69===a()||101===a())&&(e+=s(2)+s((e=>e>=48&&e<=57))),isNaN(e=parseFloat(e))?u("Bad number"):e},(r,t)=>40===r?(e++,t=y(-1,41),e++,t):null,(r,t)=>34===r?(t=o(),e++,t+s((e=>e-r))+(e++,t)):null,p],d=l.literal={true:!0,false:!1,null:null},h=l.postfix=[(t,n,l)=>(46===n?(e++,f(),t=[".",t,'"'+p()+'"']):91===n?(e++,t=[".",t,y(-1,93)],e++):40===n?(e++,l=y(-1,41),t=Array.isArray(l)&&","===l[0]?(l[0]=t,l):null==l?[t]:[t,l],e++):43!==n&&45!==n||r.charCodeAt(e+1)!==n?"string"==typeof t&&d.hasOwnProperty(t)&&(t=d[t]):t=[s(2),t],t)],g=l.unary={"-":17,"!":17,"+":17,"++":17,"--":17},A=l.binary={",":1,"||":6,"&&":7,"|":8,"^":9,"&":10,"==":11,"!=":11,"<":12,">":12,"<=":12,">=":12,"<<":13,">>":13,">>>":13,"+":14,"-":14,"*":15,"/":15,"%":15},b=l,m=e=>Array.isArray(e)&&("string"==typeof e[0]||m(e[0])),B=(e,r={},t,n)=>m(e)?("string"==typeof(t=e[0])&&(n=v[t]),"function"!=typeof(t=n||B(t,r))?t:t.call(...e.map((e=>B(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=B.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=B,x=e=>(e="string"==typeof e?b(e):e,r=>w(e,r));export{x as default,w as evaluate,b as parse};