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 +48 -42
- package/evaluate.js +3 -35
- package/justin.js +188 -71
- package/justin.min.js +1 -1
- package/package.json +1 -1
- package/parse.js +36 -106
- package/subscript.js +125 -2
- package/subscript.min.js +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
#
|
|
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/
|
|
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
|
-
##
|
|
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
|
-
|
|
75
|
-
* `1.2e+3` floats
|
|
76
|
-
* `()` expression groups or fn calls
|
|
77
|
-
* `.`, `[]` property access
|
|
55
|
+
### Operators
|
|
78
56
|
|
|
79
|
-
|
|
57
|
+
Default operators include common operators for the listed languages in the following precedence:
|
|
80
58
|
|
|
81
|
-
|
|
59
|
+
* `++ --` unary postfix
|
|
60
|
+
* `! + - ++ --` unary prefix
|
|
61
|
+
* `* / %`
|
|
62
|
+
* `+ -`
|
|
63
|
+
* `<< >> >>>`
|
|
64
|
+
* `< <= > >=`
|
|
65
|
+
* `== !=`
|
|
66
|
+
* `&`
|
|
67
|
+
* `^`
|
|
68
|
+
* `|`
|
|
69
|
+
* `&&`
|
|
70
|
+
* `||`
|
|
82
71
|
|
|
83
|
-
|
|
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
|
-
//
|
|
90
|
-
// TODO
|
|
91
|
-
// parse.operator['=>'] = 10
|
|
77
|
+
parse.operator('=>', 10) // precedence=10, type=default (0 - binary, 1 - postfix, -1 - prefix)
|
|
92
78
|
|
|
93
|
-
|
|
94
|
-
|
|
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 =
|
|
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,
|
|
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
|
-
|
|
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
|
-
|
|
31
|
-
|
|
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
|
-
//
|
|
38
|
-
|
|
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
|
-
|
|
83
|
-
|
|
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,
|
|
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
package/parse.js
CHANGED
|
@@ -1,39 +1,30 @@
|
|
|
1
|
-
|
|
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)
|
|
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
|
|
25
|
-
//
|
|
26
|
-
while (
|
|
27
|
-
|
|
28
|
-
|
|
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 (
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(
|
|
56
|
-
//
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
]
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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=
|
|
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};
|