subscript 4.0.0 → 5.2.1

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,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=orangered"/></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
 
@@ -27,28 +30,9 @@ _Subscript_ is designed to be useful for:
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/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.
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_ and more test coverage and better performance.
31
34
 
32
35
 
33
- ## Operators
34
-
35
- Default operators include common operators for the listed languages in the following precedence:
36
-
37
- * `++ --` unary postfix
38
- * `! + - ++ --` unary prefix
39
- * `* / %`
40
- * `+ -`
41
- * `<< >> >>>`
42
- * `< <= > >=`
43
- * `== !=`
44
- * `&`
45
- * `^`
46
- * `|`
47
- * `&&`
48
- * `||`
49
-
50
- All other operators can be extended, see [extension](#extension).
51
-
52
36
  ## Evaluation
53
37
 
54
38
  _Subscript_ parser generates lispy calltree (compatible with [frisk](https://npmjs.com/frisk)), which is compared to esprima AST has:
@@ -66,34 +50,34 @@ import {evaluate} from 'subscript.js'
66
50
  evaluate(['+', ['*', 'min', 60], '"sec"'], { min: 5 }) // min*60 + "sec" == "300sec"
67
51
  ```
68
52
 
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:
53
+ ## Extending
73
54
 
74
- * `"abc"` strings
75
- * `1.2e+3` floats
76
- * `()` expression groups or fn calls
77
- * `.`, `[]` property access
55
+ ### Operators
78
56
 
79
- Operators can be extended via `parse.operator` to add support for any unary/binary/postfix operators, calls, props or chains.
57
+ Default operators include common operators for the listed languages in the following precedence:
80
58
 
81
- Comments can be added via extending `parse.space`.
59
+ * `++ --` unary postfix
60
+ * `! + - ++ --` unary prefix
61
+ * `* / %`
62
+ * `+ -`
63
+ * `<< >> >>>`
64
+ * `< <= > >=`
65
+ * `== !=`
66
+ * `&`
67
+ * `^`
68
+ * `|`
69
+ * `&&`
70
+ * `||`
82
71
 
83
- For now see justin extension how things can be done.
72
+ Operators can be extended via `parse.operator(str, prec, type)` and `evaluate.operator(str, fn)` functions for any unary/binary/postfix operators, calls, props, groups, arrays, objects etc.
84
73
 
85
- <!--
86
74
  ```js
87
75
  import { parse, evaluate } from 'subscript.js'
88
76
 
89
- // add precedences
90
- // TODO
91
- // parse.operator['=>'] = 10
77
+ parse.operator('=>', 10) // precedence=10, type=default (0 - binary, 1 - postfix, -1 - prefix)
92
78
 
93
- // define evaluators
94
- // TODO
95
- // evaluate.operator['=>'] = ( args, body ) => evaluate(body, args)
96
- // evaluate.operator['|'] = ( a, ...b ) => a.pipe(...b)
79
+ evaluate.operator('=>', ( args, body ) => evaluate(body, args))
80
+ evaluate.operator('|', ( a, ...b ) => a.pipe(...b))
97
81
 
98
82
  let tree = parse(`
99
83
  interval(350)
@@ -103,7 +87,29 @@ let tree = parse(`
103
87
  `)
104
88
  evaluate(tree, { Math, map, take, interval, gaussian })
105
89
  ```
106
- -->
90
+
91
+ ### Tokens
92
+
93
+ Default tokens include:
94
+
95
+ * `"abc"` strings
96
+ * `1.2e+3` floats
97
+ * `name` identifiers
98
+
99
+ Tokens are extensible via `parse.token` list, can be added support of _literals_, _regexes_, _strings_, _numbers_ and others.
100
+
101
+ ```js
102
+ import parse, {char} from 'subscript/parse.js'
103
+ import evaluate from 'subscript/evaluate.js'
104
+
105
+ conts ctx = {x:1}
106
+ parse.token.unshift(c => char(4) === 'this' ? ctx : null)
107
+ evaluate(parse(`this.x`)) // 1
108
+ ```
109
+
110
+ ### Spaces/comments
111
+
112
+ Comments can be added via extending `parse.space`. See [justin.js](./justin.js) for more examples.
107
113
 
108
114
 
109
115
  ## Justin
@@ -111,6 +117,7 @@ evaluate(tree, { Math, map, take, interval, gaussian })
111
117
  _Justin_ extension (original [thread](https://github.com/endojs/Jessie/issues/66)) is minimal JS subset − JSON with JS expressions.<br/>
112
118
  It adds support of:
113
119
 
120
+ + `===`, `!==` operators
114
121
  + `**` binary operator
115
122
  + `~` unary operator
116
123
  + `'` strings
@@ -122,7 +129,6 @@ It adds support of:
122
129
  + unary word operators
123
130
  + `//`, `/* */` comments
124
131
  + `true`, `false`, `null`, `undefined` literals
125
- <!-- + `===`, `!==` operators -->
126
132
  <!-- + `?` chaining operator -->
127
133
  <!-- + `...x` unary operator -->
128
134
  <!-- + strings interpolation -->
package/evaluate.js CHANGED
@@ -4,10 +4,9 @@ export const isCmd = a => Array.isArray(a) && (typeof a[0] === 'string' || isCmd
4
4
  evaluate = (s, ctx={}, c, op) => {
5
5
  if (isCmd(s)) {
6
6
  c = s[0]
7
- if (typeof c === 'string') op = operator[c]
7
+ if (typeof c === 'string') op = lookup[c]
8
8
  c = op || evaluate(c, ctx) // [[a,b], c]
9
9
  if (typeof c !== 'function') return c
10
-
11
10
  return c.call(...s.map(a => evaluate(a,ctx)))
12
11
  }
13
12
  if (s && typeof s === 'string')
@@ -17,41 +16,10 @@ evaluate = (s, ctx={}, c, op) => {
17
16
 
18
17
  return s
19
18
  },
19
+ lookup = {},
20
20
 
21
21
  // op evaluators
22
22
  // multiple args allows shortcuts, lisp compatible, easy manual eval, functions anyways take multiple arguments
23
- operator = evaluate.operator = {
24
- '!':a=>!a,
25
- '++':a=>++a,
26
- '--':a=>--a,
27
-
28
- '.':(...a)=>a.reduce((a,b)=>a?a[b]:a),
29
-
30
- '%':(...a)=>a.reduce((a,b)=>a%b),
31
- '/':(...a)=>a.reduce((a,b)=>a/b),
32
- '*':(...a)=>a.reduce((a,b)=>a*b),
33
-
34
- '+':(...a)=>a.reduce((a,b)=>a+b),
35
- '-':(...a)=>a.length < 2 ? -a : a.reduce((a,b)=>a-b),
36
-
37
- '>>>':(a,b)=>a>>>b,
38
- '>>':(a,b)=>a>>b,
39
- '<<':(a,b)=>a<<b,
40
-
41
- '>=':(a,b)=>a>=b,
42
- '>':(a,b)=>a>b,
43
- '<=':(a,b)=>a<=b,
44
- '<':(a,b)=>a<b,
45
-
46
- '!=':(a,b)=>a!=b,
47
- '==':(a,b)=>a==b,
48
-
49
- '&':(a,b)=>a&b,
50
- '^':(a,b)=>a^b,
51
- '|':(a,b)=>a|b,
52
- '&&':(...a)=>a.every(Boolean),
53
- '||':(...a)=>a.some(Boolean),
54
- ',':(...a)=>a.reduce((a,b)=>(a,b))
55
- }
23
+ operator = evaluate.operator = (op, fn) => lookup[op] = fn.length == 2 ? (...a)=>a.reduce(fn) : fn
56
24
 
57
25
  export default evaluate
package/justin.js CHANGED
@@ -1,54 +1,56 @@
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, nil, binary, unary} from './parse.js'
4
-
5
- // ;
6
- parse.operator[0] = binary(c => c==44||c==59)
7
-
8
- // 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
- )
3
+ import {parse, code, char, skip, expr, err} from './parse.js'
16
4
 
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'}
5
+ const PERIOD=46, OPAREN=40, CPAREN=41, CBRACK=93, SPACE=32,
28
6
 
29
- // **
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))
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
32
10
 
33
- // ~
34
- parse.operator.splice(parse.operator.length-2, 0, unary(cc => cc === 126))
35
- evaluate.operator['~'] = a=>~a
36
11
 
37
- // TODO ...
38
- // // unary[1]['...']=true
12
+ // tokens
13
+ const v = v => ({valueOf:()=>v})
14
+ parse.token.push(
15
+ // 1.2e+3, .5 - fast & small version, but consumes corrupted nums as well
16
+ (number) => (
17
+ (number = skip(c => (c > 47 && c < 58) || c == PERIOD)) && (
18
+ (code() == 69 || code() == 101) && (number += skip(2) + skip(c => c >= 48 && c <= 57)),
19
+ isNaN(number = new Number(number)) ? err('Bad number') : number
20
+ )
21
+ ),
39
22
 
23
+ // "' with /
24
+ (q, qc, c, str) => {
25
+ if (q !== 34 && q !== 39) return
26
+ qc = char(), skip(), str = ''
27
+ while (c=code(), c-q) {
28
+ if (c === 92) skip(), str += escape[char()] || char(); else str+=char()
29
+ skip()
30
+ }
31
+ return skip(), qc + str + qc
32
+ },
33
+
34
+ // literal
35
+ c =>
36
+ c === 116 && char(4) === 'true' && skip(4) ? v(true) :
37
+ c === 102 && char(5) === 'false' && skip(5) ? v(false) :
38
+ c === 110 && char(4) === 'null' && skip(4) ? v(null) :
39
+ c === 117 && char(9) === 'undefined' && skip(9) ? v(undefined) :
40
+ null,
41
+
42
+ // id
43
+ c => skip(c =>
44
+ (c >= 48 && c <= 57) || // 0..9
45
+ (c >= 65 && c <= 90) || // A...Z
46
+ (c >= 97 && c <= 122) || // a...z
47
+ c == 36 || c == 95 || // $, _,
48
+ (c >= 192 && c != 215 && c != 247) // any non-ASCII
49
+ )
50
+ )
51
+
52
+ const escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'}
40
53
 
41
- // ?:
42
- evaluate.operator['?:']=(a,b,c)=>a?b:c
43
- parse.operator.splice(1,0, (node,cc,prec,end) => {
44
- let 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]
51
- })
52
54
 
53
55
  // /**/, //
54
56
  parse.space = cc => {
@@ -63,37 +65,152 @@ parse.space = cc => {
63
65
  return cc
64
66
  }
65
67
 
66
- // in
67
- evaluate.operator['in'] = (a,b)=>a in b
68
- parse.operator.splice(6,0,(a,cc,prec,end) => (char(2) === 'in' && [skip(2), '"' + a + '"', expr(prec,end)]))
69
-
70
- // []
71
- evaluate.operator['['] = (...args) => Array(...args)
72
- parse.token.unshift((cc, node, arg) =>
73
- cc === 91 &&
74
- (
75
- skip(), arg=expr(0,93),
76
- node = arg===nil ? ['['] : arg[0] === ',' ? (arg[0]='[',arg) : ['[',arg],
77
- skip(), node
78
- )
79
- )
80
68
 
81
- // {}
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]
88
-
89
- const map = (n, args) => {
90
- if (n[1]===nil) args = []
91
- else if (n[1][0]==':') args = [n[1]]
92
- else if (n[1][0]==',') args = n[1].slice(1)
93
- return ['{', ...args]
69
+ // operators
70
+ const addOps = (add, stride=2, list) => {
71
+ for (let i = 0; i < list.length; i+=stride) add(list[i], list[i+1], list[i+2])
94
72
  }
95
73
 
74
+ addOps(parse.operator, 3, [
75
+ // subscript ones
76
+ // TODO: add ,, as node here?
77
+ ',', PREC_SEQ,,
78
+
79
+ '|', PREC_OR,,
80
+ '||', PREC_SOME,,
81
+
82
+ '&', PREC_AND,,
83
+ '&&', PREC_EVERY,,
84
+
85
+ '^', PREC_XOR,,
86
+
87
+ // ==, !=
88
+ '==', PREC_EQ,,
89
+ '!=', PREC_EQ,,
90
+
91
+ // > >= >> >>>, < <= <<
92
+ '>', PREC_COMP,,
93
+ '>=', PREC_COMP,,
94
+ '>>', PREC_SHIFT,,
95
+ '>>>', PREC_SHIFT,,
96
+ '<', PREC_COMP,,
97
+ '<=', PREC_COMP,,
98
+ '<<', PREC_SHIFT,,
99
+
100
+ // + ++ - --
101
+ '+', PREC_SUM,,
102
+ '+', PREC_UNARY, -1,
103
+ '++', PREC_UNARY, -1,
104
+ '++', PREC_UNARY, +1,
105
+ '-', PREC_SUM,,
106
+ '-', PREC_UNARY, -1,
107
+ '--', PREC_UNARY, -1,
108
+ '--', PREC_UNARY, +1,
109
+
110
+ // !
111
+ '!', PREC_UNARY, -1,
112
+
113
+ // * / %
114
+ '*', PREC_MULT,,
115
+ '/', PREC_MULT,,
116
+ '%', PREC_MULT,,
117
+
118
+ // a.b
119
+ '.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
120
+
121
+ // a[b]
122
+ '[', PREC_CALL, (node) => (skip(), node = ['.', node, expr(0,CBRACK).valueOf()], skip(), node),
123
+ ']',,,
124
+
125
+ // a(b)
126
+ '(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN), skip(),
127
+ Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, b.valueOf()] : [node]
128
+ ),
129
+ // (a+b)
130
+ '(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(), skip(), b),
131
+ ')',,,
132
+
133
+ // justin extension
134
+ ';', PREC_SEQ,,
135
+ '===', PREC_EQ,,
136
+ '!==', PREC_EQ,,
137
+ '**', PREC_EXP,,
138
+ '~', PREC_UNARY, -1,
139
+ '?', PREC_TERN, (node) => {
140
+ if (!node) err('Expected expression')
141
+ let a, b
142
+ skip(), parse.space(), a = expr()
143
+ if (code() !== 58) err('Expected :')
144
+ skip(), parse.space(), b = expr()
145
+ return ['?:', node, a, b]
146
+ },
147
+ '}',,,
148
+ ':',,,
149
+ 'in', PREC_COMP, (node) => code(2) <= 32 && [skip(2), '"'+node+'"', expr(PREC_COMP)],
150
+
151
+ // [a,b,c]
152
+ '[', PREC_TOKEN, (node,arg) => !node && (
153
+ skip(), arg=expr(0,93), skip(),
154
+ !arg ? ['['] : arg[0] == ',' ? (arg[0]='[',arg) : ['[',arg]
155
+ ),
156
+
157
+ // {a:0, b:1}
158
+ '{', PREC_TOKEN, (node,arg) => !node && (skip(), arg=expr(0,125), skip(),
159
+ !arg ? ['{'] : arg[0] == ':' ? ['{',arg] : arg[0] == ',' ? (arg[0]='{',arg) : ['[',arg])
160
+ ,
161
+ ])
162
+
163
+ addOps(evaluate.operator, 2, [
164
+ // subscript
165
+ '!', a=>!a,
166
+ '++', a=>++a,
167
+ '--', a=>--a,
168
+
169
+ '.', (a,b)=>a?a[b]:a,
170
+
171
+ '%', (a,b)=>a%b,
172
+ '/', (a,b)=>a/b,
173
+ '*', (a,b)=>a*b,
174
+
175
+ '+', (a,b)=>a+b,
176
+ '-', (...a)=>a.length < 2 ? -a : a.reduce((a,b)=>a-b),
177
+
178
+ '>>>', (a,b)=>a>>>b,
179
+ '>>', (a,b)=>a>>b,
180
+ '<<', (a,b)=>a<<b,
181
+
182
+ '>=', (a,b)=>a>=b,
183
+ '>', (a,b)=>a>b,
184
+ '<=', (a,b)=>a<=b,
185
+ '<', (a,b)=>a<b,
186
+
187
+ '!=', (a,b)=>a!=b,
188
+ '==', (a,b)=>a==b,
189
+
190
+ '&', (a,b)=>a&b,
191
+ '^', (a,b)=>a^b,
192
+ '|', (a,b)=>a|b,
193
+ '&&', (...a)=>a.every(Boolean),
194
+ '||', (...a)=>a.some(Boolean),
195
+ ',', (a,b)=>(a,b),
196
+
197
+ // justin extension
198
+ '**', (...args)=>args.reduceRight((a,b)=>Math.pow(b,a)),
199
+ '~', a=>~a,
200
+ '?:', (a,b,c)=>a?b:c,
201
+ 'in', (a,b)=>a in b,
202
+
203
+ // []
204
+ '[', (...args) => Array(...args),
205
+ // as operator it's faster to lookup (no need to call extra rule check), smaller and no conflict with word names
206
+ '{', (...args)=>Object.fromEntries(args),
207
+ ':', (a,b)=>[a,b]
208
+ ])
209
+
210
+ // TODO ...
96
211
  // TODO: strings interpolation
97
212
 
98
- export default parse
99
213
  export { parse, evaluate }
214
+
215
+ // code → evaluator
216
+ export default s => (s = typeof s == 'string' ? parse(s) : s, ctx => evaluate(s, ctx))
package/justin.min.js CHANGED
@@ -1 +1 @@
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};
1
+ var e,r,t=e=>Array.isArray(e)&&("string"==typeof e[0]||t(e[0])),a=(e,r={},o,l)=>t(e)?("string"==typeof(o=e[0])&&(l=n[o]),"function"!=typeof(o=l||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?l():a.valueOf())),l=(t="Bad syntax")=>{throw Error(t+" `"+r[e]+"` at "+e)},s=(t=1,a=e)=>{if("number"==typeof t)e+=t;else for(;t(u());)e++;return r.slice(a,e)},u=(t=0)=>r.charCodeAt(e+t),f=(t=1)=>r.substr(e,t),p=(e=0,r,t,a,n=0,s,u)=>{for(;(t=o.space())&&(u=v[t]?.(a,e)||!a&&c(t));)a=u;return r&&t!==r&&l("Unclosed paren"),a},i=(o.space=r=>{for(;(r=u())<=32;)e++;return r},o.token=[]),c=(e,r=0,t)=>{for(;r<i.length;)if(t=i[r++](e))return t},v=[],d=(o.operator=(r,t=0,a=0,n,i=r.charCodeAt(0),c=r.length,d=v[i],h=r.toUpperCase()!==r,y)=>(y=c<2?h?e=>u(1)<=32:e=>1:h?e=>f(c)==r&&u(c)<=32:e=>f(c)==r,n=a?a>0?e=>e&&[s(c),e]:a<0?e=>!e&&[s(c),(p(t-1)||l()).valueOf()]:a:a=>{a=[r,a||l()];do{e+=c,a.push((p(t)||l()).valueOf())}while(o.space()==i&&y());return a},v[i]=(e,r)=>r<t&&y()&&n(e)||d&&d(e,r)),10),h=15,y=e=>({valueOf:()=>e});o.token.push((e=>(e=s((e=>e>47&&e<58||46==e)))&&((69==u()||101==u())&&(e+=s(2)+s((e=>e>=48&&e<=57))),isNaN(e=new Number(e))?l("Bad number"):e)),((e,r,t,a)=>{if(34===e||39===e){for(r=f(),s(),a="";(t=u())-e;)92===t?(s(),a+=g[f()]||f()):a+=f(),s();return s(),r+a+r}}),(e=>116===e&&"true"===f(4)&&s(4)?y(!0):102===e&&"false"===f(5)&&s(5)?y(!1):110===e&&"null"===f(4)&&s(4)?y(null):117===e&&"undefined"===f(9)&&s(9)?y(void 0):null),(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))));var g={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"};o.space=e=>{for(;(e=u())<=32;)s(),47===u()&&(42===u(1)?(s(2),s((e=>42!==e&&47!==u(1))),s(2)):47===u(1)&&(s(2),s((e=>e>=32))));return e};var O=(e,r=2,t)=>{for(let a=0;a<t.length;a+=r)e(t[a],t[a+1],t[a+2])};O(o.operator,3,[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",d,,">=",d,,">>",11,,">>>",11,,"<",d,,"<=",d,,"<<",11,,"+",12,,"+",h,-1,"++",h,-1,"++",h,1,"-",12,,"-",h,-1,"--",h,-1,"--",h,1,"!",h,-1,"*",13,,"/",13,,"%",13,,".",18,(e,r)=>e&&[s(),e,"string"==typeof(r=p(18))?'"'+r+'"':r.valueOf()],"[",18,e=>(s(),e=[".",e,p(0,93).valueOf()],s(),e),"]",,,"(",18,(e,r)=>(s(),r=p(0,41),s(),Array.isArray(r)&&","===r[0]?(r[0]=e,r):r?[e,r.valueOf()]:[e]),"(",19,(e,r)=>!e&&(s(),r=p(0,41)||l(),s(),r),")",,,";",1,,"===",9,,"!==",9,,"**",14,,"~",h,-1,"?",3,e=>{let r,t;return e||l("Expected expression"),s(),o.space(),r=p(),58!==u()&&l("Expected :"),s(),o.space(),t=p(),["?:",e,r,t]},"}",,,":",,,"in",d,e=>u(2)<=32&&[s(2),'"'+e+'"',p(d)],"[",20,(e,r)=>!e&&(s(),r=p(0,93),s(),r?","==r[0]?(r[0]="[",r):["[",r]:["["]),"{",20,(e,r)=>!e&&(s(),r=p(0,125),s(),r?":"==r[0]?["{",r]:","==r[0]?(r[0]="{",r):["[",r]:["{"])]),O(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 b=e=>(e="string"==typeof e?o(e):e,r=>a(e,r));export{b as default,a as evaluate,o as parse};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "4.0.0",
3
+ "version": "5.2.1",
4
4
  "description": "Microlanguage with common syntax for JS/C++/Python/Rust",
5
5
  "main": "subscript.js",
6
6
  "type": "module",
package/parse.js CHANGED
@@ -1,39 +1,30 @@
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
1
+ const SPACE=32
3
2
 
4
3
  // current string & index
5
4
  let idx, cur
6
5
 
7
- 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() : tree.valueOf()),
8
7
 
9
8
  err = (msg='Bad syntax') => { throw Error(msg + ' `' + cur[idx] + '` at ' + idx) },
10
9
 
11
10
  skip = (is=1, from=idx) => {
12
11
  if (typeof is === 'number') idx += is
13
12
  else while (is(code())) idx++;
14
- return cur.slice(from, idx) || nil
13
+ return cur.slice(from, idx)
15
14
  },
16
15
 
17
16
  code = (i=0) => cur.charCodeAt(idx+i),
18
17
 
19
18
  char = (n=1) => cur.substr(idx, n),
20
19
 
21
- nil = '',
22
-
23
20
  // 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
- }
21
+ expr = (prec=0, end, cc, node, i=0, map, newNode) => {
22
+ // chunk/token parser
23
+ while (
24
+ (cc=parse.space()) && (newNode = lookup[cc]?.(node, prec) || (!node && token(cc)) )
25
+ ) node = newNode;
35
26
 
36
- if (!prec && end && code()!=end) err('Unclosed paren')
27
+ if (end && cc !== end) err('Unclosed paren')
37
28
 
38
29
  return node
39
30
  },
@@ -42,93 +33,32 @@ expr = (prec=0, end, cc=parse.space(), node, from=idx, i=0, mapped) => {
42
33
  space = parse.space = cc => { while (cc = code(), cc <= SPACE) idx++; return cc },
43
34
 
44
35
  // 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
-
36
+ tokens = parse.token = [],
37
+ token = (c,i=0,node) => { while(i<tokens.length) if (node = tokens[i++](c)) return node },
38
+
39
+ // operator lookup table
40
+ lookup = [],
41
+
42
+ // create operator checker/mapper (see examples)
43
+ // @param op is operator string
44
+ // @param prec is operator precedenc to check
45
+ // @param map is either number +1 - postfix unary, -1 prefix unary, 0 binary, else - custom mapper function
46
+ operator = parse.operator = (op, prec=0, type=0, map, c=op.charCodeAt(0), l=op.length, prev=lookup[c], word=op.toUpperCase()!==op, isop) => (
47
+ isop = l<2 ? // word operator must have space after
48
+ !word ? c=>1 : c=>code(1)<=SPACE :
49
+ !word ? c=>char(l)==op : c=>char(l)==op&&code(l)<=SPACE,
50
+
51
+ map = !type ? node => { // binary, consume same-op group
52
+ node = [op, node || err()]
53
+ // in order to support literal tokens, we call valueOf any time we create or modify calltree node
54
+ do { idx+=l, node.push((expr(prec) || err()).valueOf()) } while (parse.space()==c && isop())
55
+ return node
56
+ } :
57
+ type > 0 ? node => node && [skip(l), node] : // postfix unary
58
+ type < 0 ? node => !node && [skip(l), (expr(prec-1) || err()).valueOf()] : // prefix unary
59
+ type,
60
+
61
+ lookup[c] = (node, curPrec) => curPrec < prec && isop() && map(node) || (prev && prev(node, curPrec))
62
+ )
133
63
 
134
64
  export default parse
package/subscript.js CHANGED
@@ -1,5 +1,128 @@
1
- import parse from './parse.js'
2
- import evaluate from './evaluate.js'
1
+ import parse, {skip, expr, code, tokens, operator as parseOp} from './parse.js'
2
+ import evaluate, {operator as evalOp} from './evaluate.js'
3
+
4
+ const PERIOD=46, OPAREN=40, CPAREN=41, CBRACK=93, SPACE=32,
5
+
6
+ PREC_SEQ=1, 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_UNARY=15, PREC_POSTFIX=16, PREC_CALL=18, PREC_GROUP=19
8
+
9
+ tokens.push(
10
+ // 1.2e+3, .5 - fast & small version, but consumes corrupted nums as well
11
+ (number) => (
12
+ (number = skip(c => (c > 47 && c < 58) || c == PERIOD)) && (
13
+ (code() == 69 || code() == 101) && (number += skip(2) + skip(c => c >= 48 && c <= 57)),
14
+ isNaN(number = new Number(number)) ? err('Bad number') : number
15
+ )
16
+ ),
17
+ // "a"
18
+ (q, qc) => q == 34 && (skip() + skip(c => c-q) + skip()),
19
+ // id
20
+ c => skip(c =>
21
+ (c >= 48 && c <= 57) || // 0..9
22
+ (c >= 65 && c <= 90) || // A...Z
23
+ (c >= 97 && c <= 122) || // a...z
24
+ c == 36 || c == 95 || // $, _,
25
+ c >= 192 // any non-ASCII
26
+ )
27
+ )
28
+
29
+ const addOps = (add, stride=2, list) => {
30
+ for (let i = 0; i < list.length; i+=stride) add(list[i], list[i+1], list[i+2])
31
+ }
32
+
33
+ addOps(parseOp, 3, [
34
+ ',', PREC_SEQ,,
35
+
36
+ '|', PREC_OR,,
37
+ '||', PREC_SOME,,
38
+
39
+ '&', PREC_AND,,
40
+ '&&', PREC_EVERY,,
41
+
42
+ '^', PREC_XOR,,
43
+
44
+ // ==, !=
45
+ '==', PREC_EQ,,
46
+ '!=', PREC_EQ,,
47
+
48
+ // > >= >> >>>, < <= <<
49
+ '>', PREC_COMP,,
50
+ '>=', PREC_COMP,,
51
+ '>>', PREC_SHIFT,,
52
+ '>>>', PREC_SHIFT,,
53
+ '<', PREC_COMP,,
54
+ '<=', PREC_COMP,,
55
+ '<<', PREC_SHIFT,,
56
+
57
+ // + ++ - --
58
+ '+', PREC_SUM,,
59
+ '+', PREC_UNARY, -1,
60
+ '++', PREC_UNARY, -1,
61
+ '++', PREC_UNARY, +1,
62
+ '-', PREC_SUM,,
63
+ '-', PREC_UNARY, -1,
64
+ '--', PREC_UNARY, -1,
65
+ '--', PREC_UNARY, +1,
66
+
67
+ // ! ~
68
+ '!', PREC_UNARY, -1,
69
+
70
+ // * / %
71
+ '*', PREC_MULT,,
72
+ '/', PREC_MULT,,
73
+ '%', PREC_MULT,,
74
+
75
+ // a.b
76
+ '.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
77
+
78
+ // a[b]
79
+ '[', PREC_CALL, (node) => (skip(), node = ['.', node, expr(0,CBRACK).valueOf()], skip(), node),
80
+ ']',,,
81
+
82
+ // a(b)
83
+ '(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN), skip(),
84
+ Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, b.valueOf()] : [node]
85
+ ),
86
+ // (a+b)
87
+ '(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(), skip(), b),
88
+ ')',,,
89
+ ])
90
+
91
+
92
+ // evaluators
93
+ addOps(evalOp, 2, [
94
+ '!', a=>!a,
95
+ '++', a=>++a,
96
+ '--', a=>--a,
97
+
98
+ '.', (a,b)=>a?a[b]:a,
99
+
100
+ '%', (a,b)=>a%b,
101
+ '/', (a,b)=>a/b,
102
+ '*', (a,b)=>a*b,
103
+
104
+ '+', (a,b)=>a+b,
105
+ '-', (...a)=>a.length < 2 ? -a : a.reduce((a,b)=>a-b),
106
+
107
+ '>>>', (a,b)=>a>>>b,
108
+ '>>', (a,b)=>a>>b,
109
+ '<<', (a,b)=>a<<b,
110
+
111
+ '>=', (a,b)=>a>=b,
112
+ '>', (a,b)=>a>b,
113
+ '<=', (a,b)=>a<=b,
114
+ '<', (a,b)=>a<b,
115
+
116
+ '!=', (a,b)=>a!=b,
117
+ '==', (a,b)=>a==b,
118
+
119
+ '&', (a,b)=>a&b,
120
+ '^', (a,b)=>a^b,
121
+ '|', (a,b)=>a|b,
122
+ '&&', (...a)=>a.every(Boolean),
123
+ '||', (...a)=>a.some(Boolean),
124
+ ',', (a,b)=>(a,b)
125
+ ])
3
126
 
4
127
  export { parse, evaluate }
5
128
 
package/subscript.min.js CHANGED
@@ -1 +1 @@
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};
1
+ var e,r,a=(a,o)=>(r=a,e=0,o=l(),e<r.length?t():o.valueOf()),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(n());)e++;return r.slice(t,e)},n=(a=0)=>r.charCodeAt(e+a),s=(a=1)=>r.substr(e,a),l=(e=0,r,o,n,s=0,l,f)=>{for(;(o=a.space())&&(f=p[o]?.(n,e)||!n&&u(o));)n=f;return r&&o!==r&&t("Unclosed paren"),n},f=(a.space=r=>{for(;(r=n())<=32;)e++;return r},a.token=[]),u=(e,r=0,a)=>{for(;r<f.length;)if(a=f[r++](e))return a},p=[],i=a.operator=(r,f=0,u=0,i,c=r.charCodeAt(0),y=r.length,h=p[c],g=r.toUpperCase()!==r,v)=>(v=y<2?g?e=>n(1)<=32:e=>1:g?e=>s(y)==r&&n(y)<=32:e=>s(y)==r,i=u?u>0?e=>e&&[o(y),e]:u<0?e=>!e&&[o(y),(l(f-1)||t()).valueOf()]:u:o=>{o=[r,o||t()];do{e+=y,o.push((l(f)||t()).valueOf())}while(a.space()==c&&v());return o},p[c]=(e,r)=>r<f&&v()&&i(e)||h&&h(e,r)),c=a,y=e=>Array.isArray(e)&&("string"==typeof e[0]||y(e[0])),h=(e,r={},a,t)=>y(e)?("string"==typeof(a=e[0])&&(t=g[a]),"function"!=typeof(a=t||h(a,r))?a:a.call(...e.map((e=>h(e,r))))):e&&"string"==typeof e?'"'===e[0]?e.slice(1,-1):"@"===e[0]?e.slice(1):e in r?r[e]:e:e,g={},v=h.operator=(e,r)=>g[e]=2==r.length?(...e)=>e.reduce(r):r,d=h,A=15;f.push((e=>(e=o((e=>e>47&&e<58||46==e)))&&((69==n()||101==n())&&(e+=o(2)+o((e=>e>=48&&e<=57))),isNaN(e=new Number(e))?err("Bad number"):e)),((e,r)=>34==e&&o()+o((r=>r-e))+o()),(e=>o((e=>e>=48&&e<=57||e>=65&&e<=90||e>=97&&e<=122||36==e||95==e||e>=192))));var O=(e,r=2,a)=>{for(let t=0;t<a.length;t+=r)e(a[t],a[t+1],a[t+2])};O(i,3,[",",1,,"|",6,,"||",4,,"&",8,,"&&",5,,"^",7,,"==",9,,"!=",9,,">",10,,">=",10,,">>",11,,">>>",11,,"<",10,,"<=",10,,"<<",11,,"+",12,,"+",A,-1,"++",A,-1,"++",A,1,"-",12,,"-",A,-1,"--",A,-1,"--",A,1,"!",A,-1,"*",13,,"/",13,,"%",13,,".",18,(e,r)=>e&&[o(),e,"string"==typeof(r=l(18))?'"'+r+'"':r.valueOf()],"[",18,e=>(o(),e=[".",e,l(0,93).valueOf()],o(),e),"]",,,"(",18,(e,r)=>(o(),r=l(0,41),o(),Array.isArray(r)&&","===r[0]?(r[0]=e,r):r?[e,r.valueOf()]:[e]),"(",19,(e,r)=>!e&&(o(),r=l(0,41)||err(),o(),r),")",,,]),O(v,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]);var m=e=>(e="string"==typeof e?c(e):e,r=>d(e,r));export{m as default,d as evaluate,c as parse};