subscript 5.4.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +76 -72
- package/justin.js +62 -201
- package/justin.min.js +1 -1
- package/package.json +5 -2
- package/subscript.js +67 -109
- package/subscript.min.js +1 -1
- package/evaluate.js +0 -21
- package/parse.js +0 -70
package/README.md
CHANGED
|
@@ -3,18 +3,18 @@
|
|
|
3
3
|
<a href="http://npmjs.org/subscript"><img src="https://img.shields.io/npm/v/subscript?color=indianred"/></a>
|
|
4
4
|
<a href="http://microjs.com/#subscript"><img src="https://img.shields.io/badge/microjs-subscript-blue?color=darkslateblue"/></a>
|
|
5
5
|
|
|
6
|
-
_Subscript_ is micro-language with common syntax subset of C++, JS, Java, Python, Go, Rust
|
|
6
|
+
_Subscript_ is micro-language with common syntax subset of C++, JS, Java, Python, Go, Rust etc.<br/>
|
|
7
7
|
|
|
8
|
-
*
|
|
9
|
-
* Any
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Standard conventional syntax
|
|
9
|
+
* Any fragment can be copy-pasted to any target language
|
|
10
|
+
* Tiny size <sub><a href="https://bundlephobia.com/package/subscript@6.0.0"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip"/></a></sub>
|
|
11
|
+
* :rocket: fast ([performance](#performance))
|
|
12
12
|
* Configurable & extensible
|
|
13
|
-
* Trivial to use
|
|
13
|
+
* Trivial to use
|
|
14
14
|
|
|
15
15
|
```js
|
|
16
|
-
import
|
|
17
|
-
let fn =
|
|
16
|
+
import script from 'subscript.js'
|
|
17
|
+
let fn = script`a.b + c(d - 1)`
|
|
18
18
|
fn({ a: { b:1 }, c: x => x * 2, d: 3 }) // 5
|
|
19
19
|
```
|
|
20
20
|
|
|
@@ -29,32 +29,12 @@ _Subscript_ is designed to be useful for:
|
|
|
29
29
|
* sandboxes, playgrounds, safe eval
|
|
30
30
|
* custom DSL
|
|
31
31
|
|
|
32
|
-
[
|
|
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_ + [4.5kb](https://npmfs.com/package/expression-eval/5.0.0/dist/expression-eval.module.js) _expression-eval_, with _jsep_ test coverage and better performance.
|
|
32
|
+
_Subscript_ has [2kb](https://npmfs.com/package/subscript/6.0.0/subscript.min.js) footprint, compared to [11.4kb](https://npmfs.com/package/jsep/1.2.0/dist/jsep.min.js) _jsep_ + [4.5kb](https://npmfs.com/package/expression-eval/5.0.0/dist/expression-eval.module.js) _expression-eval_, with better test coverage and better performance.
|
|
34
33
|
|
|
35
34
|
|
|
36
|
-
##
|
|
35
|
+
## Design
|
|
37
36
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
+ minimal possible overhead
|
|
41
|
-
+ clear precedence
|
|
42
|
-
+ overloading by context
|
|
43
|
-
+ manual evaluation and debugging
|
|
44
|
-
+ conventional form
|
|
45
|
-
+ one-liner docs:
|
|
46
|
-
|
|
47
|
-
```js
|
|
48
|
-
import {evaluate} from 'subscript.js'
|
|
49
|
-
|
|
50
|
-
evaluate(['+', ['*', 'min', 60], '"sec"'], { min: 5 }) // min*60 + "sec" == "300sec"
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
## Extending
|
|
54
|
-
|
|
55
|
-
### Operators
|
|
56
|
-
|
|
57
|
-
Default operators include common operators for the listed languages in the following precedence:
|
|
37
|
+
Default operators (precedence order):
|
|
58
38
|
|
|
59
39
|
* `++ --` unary postfix
|
|
60
40
|
* `! + - ++ --` unary prefix
|
|
@@ -69,74 +49,75 @@ Default operators include common operators for the listed languages in the follo
|
|
|
69
49
|
* `&&`
|
|
70
50
|
* `||`
|
|
71
51
|
|
|
72
|
-
|
|
52
|
+
Default literals:
|
|
73
53
|
|
|
74
|
-
|
|
75
|
-
|
|
54
|
+
* `"abc"` strings
|
|
55
|
+
* `1.2e+3` numbers
|
|
56
|
+
|
|
57
|
+
Everything else can be extended via `parse.set(operator, precedence, fn)` for unary or binary operators (detected by number of arguments in `fn`), or via `parse.set(operator, parser, precedence)` for custom tokens.
|
|
58
|
+
|
|
59
|
+
See [subscript.js](subscript.js) or [justin.js](./justin.js) for examples.
|
|
76
60
|
|
|
77
|
-
|
|
61
|
+
<!--
|
|
62
|
+
Operators can be extended via .
|
|
63
|
+
|
|
64
|
+
```js
|
|
65
|
+
import script from 'subscript.js'
|
|
78
66
|
|
|
79
|
-
|
|
80
|
-
evaluate.operator('|', ( a, b ) => a.pipe(b))
|
|
67
|
+
script.set('|', 10, ( a, b ) => a.pipe(b))
|
|
81
68
|
|
|
82
|
-
let
|
|
69
|
+
let evaluate = script(`
|
|
83
70
|
interval(350)
|
|
84
71
|
| take(25)
|
|
85
72
|
| map(gaussian)
|
|
86
|
-
|
|
|
73
|
+
| "•".repeat(Math.floor(it * 65)))
|
|
87
74
|
`)
|
|
88
|
-
evaluate(
|
|
75
|
+
evaluate({ Math, map, take, interval, gaussian })
|
|
89
76
|
```
|
|
90
77
|
|
|
91
|
-
|
|
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.
|
|
78
|
+
Literals are extensible by providing custom parser to `lookup`, can be added support of _booleans_, function calls, prop chains, groups, _regexes_, _strings_, _numbers_ and any other constructs.
|
|
100
79
|
|
|
101
80
|
```js
|
|
102
|
-
import
|
|
103
|
-
import evaluate from 'subscript/evaluate.js'
|
|
81
|
+
import script from 'subscript.js'
|
|
104
82
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
evaluate(parse(`this.x`)) // 1
|
|
83
|
+
script.literal.unshift(c => skip('this') && {x:1})
|
|
84
|
+
script`this.x`() // 1
|
|
108
85
|
```
|
|
109
86
|
|
|
110
|
-
###
|
|
87
|
+
### Identifiers
|
|
88
|
+
|
|
89
|
+
Identifiers include
|
|
111
90
|
|
|
112
|
-
|
|
91
|
+
### Spaces/comments
|
|
113
92
|
|
|
93
|
+
Comments can be added via extending `parse.space`.
|
|
94
|
+
-->
|
|
114
95
|
|
|
115
96
|
## Justin
|
|
116
97
|
|
|
117
|
-
_Justin_
|
|
118
|
-
|
|
98
|
+
_Justin_ is minimal JS subset − JSON with JS expressions (see original [thread](https://github.com/endojs/Jessie/issues/66)).<br/>
|
|
99
|
+
|
|
100
|
+
It extends _subscript_ with:
|
|
119
101
|
|
|
120
102
|
+ `===`, `!==` operators
|
|
121
|
-
+ `**`
|
|
122
|
-
+ `~`
|
|
103
|
+
+ `**` exponentiation operator (right-assoc)
|
|
104
|
+
+ `~` bit inversion operator
|
|
123
105
|
+ `'` strings
|
|
124
106
|
+ `?:` ternary operator
|
|
107
|
+
+ `?.` optional chain operator
|
|
125
108
|
+ `[...]` Array literal
|
|
126
109
|
+ `{...}` Object literal
|
|
127
|
-
+ `in` binary
|
|
110
|
+
+ `in` binary
|
|
128
111
|
+ `;` expression separator
|
|
129
|
-
+ unary word operators
|
|
130
112
|
+ `//`, `/* */` comments
|
|
131
113
|
+ `true`, `false`, `null`, `undefined` literals
|
|
132
|
-
<!-- + `?` chaining operator -->
|
|
133
114
|
<!-- + `...x` unary operator -->
|
|
134
115
|
<!-- + strings interpolation -->
|
|
135
116
|
|
|
136
117
|
```js
|
|
137
118
|
import { parse, evaluate } from 'subscript/justin.js'
|
|
138
119
|
|
|
139
|
-
let xy = parse('{ x: 1, "y": 2+2 }["x"]') // ['[', {x:1, y: ['+', 2, 2]}, '
|
|
120
|
+
let xy = parse('{ x: 1, "y": 2+2 }["x"]') // ['[', {x:1, y: ['+', 2, 2]}, '@x']
|
|
140
121
|
evaluate(xy) // 1
|
|
141
122
|
```
|
|
142
123
|
|
|
@@ -282,19 +263,38 @@ Examples: sonr, template-parts, neural-chunks
|
|
|
282
263
|
Subscript shows relatively good performance within other evaluators:
|
|
283
264
|
|
|
284
265
|
```
|
|
285
|
-
|
|
286
|
-
|
|
266
|
+
1 + (a * b / c % d) - 2.0 + -3e-3 * +4.4e4 / f.g[0] - i.j(+k == 1)(0)
|
|
267
|
+
```
|
|
287
268
|
|
|
288
|
-
|
|
289
|
-
|
|
269
|
+
Parse 30k times:
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
subscript: ~170 ms
|
|
273
|
+
justin: ~183 ms
|
|
274
|
+
jsep: ~250 ms
|
|
275
|
+
mr-parser: ~420 ms
|
|
290
276
|
expr-eval: ~480 ms
|
|
291
|
-
|
|
292
|
-
|
|
277
|
+
math-parser: ~570 ms
|
|
278
|
+
jexl: ~1056 ms
|
|
279
|
+
mathjs: ~1200 ms
|
|
280
|
+
new Function: ~1154 ms
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Eval 30k times:
|
|
284
|
+
```
|
|
285
|
+
subscript: ~15 ms
|
|
286
|
+
justin: ~15 ms
|
|
287
|
+
jsep (expression-eval): ~30 ms
|
|
288
|
+
mr-parser: -
|
|
289
|
+
expr-eval: ~72 ms
|
|
290
|
+
math-parser: -
|
|
291
|
+
jexl: ~110 ms
|
|
292
|
+
mathjs: ~119 ms
|
|
293
|
+
new Function: ~5 ms
|
|
293
294
|
```
|
|
294
295
|
|
|
295
|
-
##
|
|
296
|
+
## Alternatives
|
|
296
297
|
|
|
297
|
-
* [Jessie](https://github.com/endojs/Jessie) − Minimal JS subset.
|
|
298
298
|
* [jexl](https://github.com/TomFrost/Jexl)
|
|
299
299
|
* [mozjexl](https://github.com/mozilla/mozjexl)
|
|
300
300
|
* [expr-eval](https://github.com/silentmatt/expr-eval)
|
|
@@ -302,5 +302,9 @@ new Function: ~1400 ms
|
|
|
302
302
|
* [jsep](https://github.com/EricSmekens/jsep)
|
|
303
303
|
* [string-math](https://github.com/devrafalko/string-math)
|
|
304
304
|
* [nerdamer](https://github.com/jiggzson/nerdamer)
|
|
305
|
+
* [math-codegen](https://github.com/mauriciopoppe/math-codegen)
|
|
306
|
+
* [math-parser](https://www.npmjs.com/package/math-parser)
|
|
307
|
+
* [math.js](https://mathjs.org/docs/expressions/parsing.html)
|
|
308
|
+
* [Jessie](https://github.com/endojs/Jessie)
|
|
305
309
|
|
|
306
310
|
<p align=center>🕉</p>
|
package/justin.js
CHANGED
|
@@ -1,212 +1,73 @@
|
|
|
1
1
|
// justin lang https://github.com/endojs/Jessie/issues/66
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
2
|
+
import {parse, set, lookup, skip, cur, idx, err, expr, isId, space} from './index.js'
|
|
3
|
+
import './subscript.js'
|
|
4
|
+
|
|
5
|
+
const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, QUOTE=39, _0=48, _9=57, BSLASH=92,
|
|
6
|
+
PREC_SEQ=1, PREC_COND=3, 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_EXP=14, PREC_UNARY=15, PREC_POSTFIX=16, PREC_CALL=18, PREC_GROUP=19
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
let u, list, op, prec, fn,
|
|
11
|
+
escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'},
|
|
12
|
+
string = q => (qc, c, str='') => {
|
|
13
|
+
qc&&err() // must not follow another token
|
|
14
|
+
while (c=cur.charCodeAt(idx), c-q) {
|
|
15
|
+
if (c === BSLASH) skip(), c=skip(), str += escape[c] || c
|
|
16
|
+
else str += skip()
|
|
17
|
+
}
|
|
18
|
+
return skip()||err('Bad string'), () => str
|
|
19
|
+
}
|
|
4
20
|
|
|
5
|
-
|
|
21
|
+
// operators
|
|
22
|
+
for (list=[
|
|
23
|
+
// "' with /
|
|
24
|
+
'"', string(DQUOTE),,
|
|
25
|
+
"'", string(QUOTE),,
|
|
6
26
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
27
|
+
// /**/, //
|
|
28
|
+
'/*', (a, prec) => (skip(c => c !== 42 && cur.charCodeAt(idx+1) !== 47), skip(2), a||expr(prec)),,
|
|
29
|
+
'//', (a, prec) => (skip(c => c >= 32), a||expr(prec)),,
|
|
10
30
|
|
|
31
|
+
// literals
|
|
32
|
+
'null', a => a ? err() : ()=>null,,
|
|
33
|
+
'true', a => a ? err() : ()=>true,,
|
|
34
|
+
'false', a => a ? err() : ()=>false,,
|
|
35
|
+
'undefined', a => a ? err() : ()=>undefined,,
|
|
11
36
|
|
|
12
|
-
|
|
13
|
-
parse.token.push(
|
|
14
|
-
// 1.2e+3, .5 - fast & small version, but consumes corrupted nums as well
|
|
15
|
-
(number) => (
|
|
16
|
-
(number = skip(c => (c > 47 && c < 58) || c == PERIOD)) && (
|
|
17
|
-
(code() == 69 || code() == 101) && (number += skip(2) + skip(c => c >= 48 && c <= 57)),
|
|
18
|
-
isNaN(number = new Number(number)) ? err('Bad number') : number
|
|
19
|
-
)
|
|
20
|
-
),
|
|
37
|
+
';', a => expr()||(()=>{}),,
|
|
21
38
|
|
|
22
|
-
//
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
while (c=code(), c-q) {
|
|
27
|
-
if (c === 92) skip(), str += escape[char()] || char(); else str+=char()
|
|
28
|
-
skip()
|
|
29
|
-
}
|
|
30
|
-
return skip(), qc + str + qc
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
// id
|
|
34
|
-
c => skip(c =>
|
|
35
|
-
(c >= 48 && c <= 57) || // 0..9
|
|
36
|
-
(c >= 65 && c <= 90) || // A...Z
|
|
37
|
-
(c >= 97 && c <= 122) || // a...z
|
|
38
|
-
c == 36 || c == 95 || // $, _,
|
|
39
|
-
(c >= 192 && c != 215 && c != 247) // any non-ASCII
|
|
40
|
-
)
|
|
41
|
-
)
|
|
42
|
-
|
|
43
|
-
const escape = {n:'\n', r:'\r', t:'\t', b:'\b', f:'\f', v:'\v'}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// /**/, //
|
|
47
|
-
parse.space = cc => {
|
|
48
|
-
while (cc = code(), cc <= 32 || cc === 47) {
|
|
49
|
-
if (cc <= 32) skip()
|
|
50
|
-
else if (cc === 47)
|
|
51
|
-
// /**/
|
|
52
|
-
if (code(1) === 42) skip(2), skip(c => c !== 42 && code(1) !== 47), skip(2)
|
|
53
|
-
// //
|
|
54
|
-
else if (code(1) === 47) skip(2), skip(c => c >= 32)
|
|
55
|
-
else break
|
|
56
|
-
}
|
|
57
|
-
return cc
|
|
58
|
-
}
|
|
39
|
+
// operators
|
|
40
|
+
'===', PREC_EQ, (a,b) => a===b,
|
|
41
|
+
'!==', PREC_EQ, (a,b) => a!==b,
|
|
42
|
+
'~', PREC_UNARY, (a) => ~a,
|
|
59
43
|
|
|
44
|
+
// right order
|
|
45
|
+
'**', (a,prec,b=expr(PREC_EXP-1)) => ctx=>a(ctx)**b(ctx), PREC_EXP,
|
|
46
|
+
|
|
47
|
+
// ?:
|
|
48
|
+
':', 3.1, (a,b) => [a,b],
|
|
49
|
+
'?', 3, (a,b) => a ? b[2] : b[1],
|
|
50
|
+
|
|
51
|
+
// a?.[, a?.( - postfix operator
|
|
52
|
+
'?.', a => a && (ctx => a(ctx)||(()=>{})),,//(a) => a||(()=>{}),
|
|
53
|
+
// a?.b - optional chain operator
|
|
54
|
+
'?.', (a,id) => (space(), id=skip(isId)) && (ctx => a(ctx)?.[id]),,
|
|
55
|
+
|
|
56
|
+
'in', PREC_COMP, (a,b) => a in b,
|
|
60
57
|
|
|
61
|
-
// operators
|
|
62
|
-
const addOps = (add, stride=2, list) => {
|
|
63
|
-
for (let i = 0; i < list.length; i+=stride) add(list[i], list[i+1], list[i+2])
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
addOps(parse.operator, 3, [
|
|
67
|
-
// subscript ones
|
|
68
|
-
// TODO: add ,, as node here?
|
|
69
|
-
',', PREC_SEQ,,
|
|
70
|
-
|
|
71
|
-
'|', PREC_OR,,
|
|
72
|
-
'||', PREC_SOME,,
|
|
73
|
-
|
|
74
|
-
'&', PREC_AND,,
|
|
75
|
-
'&&', PREC_EVERY,,
|
|
76
|
-
|
|
77
|
-
'^', PREC_XOR,,
|
|
78
|
-
|
|
79
|
-
// ==, !=
|
|
80
|
-
'==', PREC_EQ,,
|
|
81
|
-
'!=', PREC_EQ,,
|
|
82
|
-
|
|
83
|
-
// > >= >> >>>, < <= <<
|
|
84
|
-
'>', PREC_COMP,,
|
|
85
|
-
'>=', PREC_COMP,,
|
|
86
|
-
'>>', PREC_SHIFT,,
|
|
87
|
-
'>>>', PREC_SHIFT,,
|
|
88
|
-
'<', PREC_COMP,,
|
|
89
|
-
'<=', PREC_COMP,,
|
|
90
|
-
'<<', PREC_SHIFT,,
|
|
91
|
-
|
|
92
|
-
// + ++ - --
|
|
93
|
-
'+', PREC_SUM,,
|
|
94
|
-
'+', PREC_UNARY, -1,
|
|
95
|
-
'++', PREC_UNARY, -1,
|
|
96
|
-
'++', PREC_UNARY, +1,
|
|
97
|
-
'-', PREC_SUM,,
|
|
98
|
-
'-', PREC_UNARY, -1,
|
|
99
|
-
'--', PREC_UNARY, -1,
|
|
100
|
-
'--', PREC_UNARY, +1,
|
|
101
|
-
|
|
102
|
-
// !
|
|
103
|
-
'!', PREC_UNARY, -1,
|
|
104
|
-
|
|
105
|
-
// * / %
|
|
106
|
-
'*', PREC_MULT,,
|
|
107
|
-
'/', PREC_MULT,,
|
|
108
|
-
'%', PREC_MULT,,
|
|
109
|
-
|
|
110
|
-
// a.b
|
|
111
|
-
'.', PREC_CALL, (node,b) => node && [skip(),node, typeof (b = expr(PREC_CALL)) === 'string' ? '"' + b + '"' : b.valueOf()],
|
|
112
|
-
|
|
113
|
-
// a[b]
|
|
114
|
-
'[', PREC_CALL, (node) => (skip(), node = ['.', node, val(expr(0,CBRACK))], node),
|
|
115
|
-
']',,,
|
|
116
|
-
|
|
117
|
-
// a(b)
|
|
118
|
-
'(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN),
|
|
119
|
-
Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, val(b)] : [node]
|
|
120
|
-
),
|
|
121
|
-
// (a+b)
|
|
122
|
-
'(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(), b),
|
|
123
|
-
')',,,
|
|
124
|
-
|
|
125
|
-
// justin extension
|
|
126
|
-
';', PREC_SEQ,,
|
|
127
|
-
'===', PREC_EQ,,
|
|
128
|
-
'!==', PREC_EQ,,
|
|
129
|
-
'**', PREC_EXP,,
|
|
130
|
-
'~', PREC_UNARY, -1,
|
|
131
|
-
'?', PREC_TERN, (node) => {
|
|
132
|
-
if (!node) err('Expected expression')
|
|
133
|
-
let a, b
|
|
134
|
-
skip(), parse.space(), a = expr()
|
|
135
|
-
return ['?:', node, a[1], a[2]]
|
|
136
|
-
},
|
|
137
|
-
'}',,,
|
|
138
|
-
':',2,,
|
|
139
|
-
'in', PREC_COMP, (node) => code(2) <= 32 && [skip(2), '"'+node+'"', expr(PREC_COMP)],
|
|
140
|
-
|
|
141
|
-
// as operator it's faster to lookup (no need to extra rule check), smaller and no conflict with word names
|
|
142
58
|
// [a,b,c]
|
|
143
|
-
'[',
|
|
144
|
-
|
|
145
|
-
!
|
|
146
|
-
)
|
|
59
|
+
'[', (a, args) => !a && (
|
|
60
|
+
a=expr(0,CBRACK),
|
|
61
|
+
!a ? ctx => [] : a.all ? ctx => a.all(ctx) : ctx => [a(ctx)]
|
|
62
|
+
),,
|
|
147
63
|
|
|
148
|
-
// {a:
|
|
149
|
-
'{',
|
|
150
|
-
|
|
151
|
-
|
|
64
|
+
// {a:1, b:2, c:3}
|
|
65
|
+
'{', (a, args) => !a && (
|
|
66
|
+
a=expr(0,125),
|
|
67
|
+
!a ? ctx => ({}) : ctx => (args=(a.all||a)(ctx), Object.fromEntries(a.all?args:[args]))
|
|
68
|
+
),,
|
|
69
|
+
':', (a, prec, b) => (b=expr(3.1)||err(), ctx => [(a.id||a)(ctx), b(ctx), a(ctx)]), 3.1
|
|
152
70
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
'true', PREC_TOKEN, node=>!node&&(skip(4),v(true)),
|
|
157
|
-
'undefined', PREC_TOKEN, node=>!node&&(skip(9),v(undefined)),
|
|
158
|
-
])
|
|
159
|
-
const v = v => ({valueOf:()=>v})
|
|
160
|
-
|
|
161
|
-
addOps(evaluate.operator, 2, [
|
|
162
|
-
// subscript
|
|
163
|
-
'!', a=>!a,
|
|
164
|
-
'++', a=>++a,
|
|
165
|
-
'--', a=>--a,
|
|
166
|
-
|
|
167
|
-
'.', (a,b)=>a?a[b]:a,
|
|
168
|
-
|
|
169
|
-
'%', (a,b)=>a%b,
|
|
170
|
-
'/', (a,b)=>a/b,
|
|
171
|
-
'*', (a,b)=>a*b,
|
|
172
|
-
|
|
173
|
-
'+', (a,b=0)=>a+b,
|
|
174
|
-
'-', (a,b)=>b==null ? -a : a-b,
|
|
175
|
-
|
|
176
|
-
'>>>', (a,b)=>a>>>b,
|
|
177
|
-
'>>', (a,b)=>a>>b,
|
|
178
|
-
'<<', (a,b)=>a<<b,
|
|
179
|
-
|
|
180
|
-
'>=', (a,b)=>a>=b,
|
|
181
|
-
'>', (a,b)=>a>b,
|
|
182
|
-
'<=', (a,b)=>a<=b,
|
|
183
|
-
'<', (a,b)=>a<b,
|
|
184
|
-
|
|
185
|
-
'!=', (a,b)=>a!=b,
|
|
186
|
-
'==', (a,b)=>a==b,
|
|
187
|
-
|
|
188
|
-
'&', (a,b)=>a&b,
|
|
189
|
-
'^', (a,b)=>a^b,
|
|
190
|
-
'|', (a,b)=>a|b,
|
|
191
|
-
'&&', (...a)=>a.every(Boolean),
|
|
192
|
-
'||', (...a)=>a.some(Boolean),
|
|
193
|
-
',', (a,b)=>(a,b),
|
|
194
|
-
|
|
195
|
-
// justin extension
|
|
196
|
-
'**', (...args)=>args.reduceRight((a,b)=>Math.pow(b,a)),
|
|
197
|
-
'~', a=>~a,
|
|
198
|
-
'?:', (a,b,c)=>a?b:c,
|
|
199
|
-
'in', (a,b)=>a in b,
|
|
200
|
-
|
|
201
|
-
'[', (...args) => Array(...args),
|
|
202
|
-
'{', (...args)=>Object.fromEntries(args),
|
|
203
|
-
':', (a,b)=>[a,b]
|
|
204
|
-
])
|
|
205
|
-
|
|
206
|
-
// TODO ...
|
|
207
|
-
// TODO: strings interpolation
|
|
208
|
-
|
|
209
|
-
export { parse, evaluate }
|
|
210
|
-
|
|
211
|
-
// code → evaluator
|
|
212
|
-
export default s => (s = typeof s == 'string' ? parse(s) : s, ctx => evaluate(s, ctx))
|
|
71
|
+
]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
|
|
72
|
+
|
|
73
|
+
export default parse
|
package/justin.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
let r,e,t,l,a,o,n=(t,...l)=>(e=t.raw?String.raw(t,...l):t,r=0,!(t=i())||e[r]?f():r=>t(r||{})),d=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r,f=(t="Bad syntax",l=e[r])=>{throw Error(t+" `"+l+"` at "+r)},h=(t=1,l=r,a)=>{if("number"==typeof t)r+=t;else for(;t(e.charCodeAt(r));)r++;return e.slice(l,r)},i=(e=0,t,l,a,o,n)=>{for(;(l=s())&&(o=(n=c[l])&&n(a,e)||!a&&u());)a=o;return t&&(l==t?r++:f("Unclosed")),a},s=t=>{for(;(t=e.charCodeAt(r))<=32;)r++;return t},u=(r=h(d),e)=>r?((e=e=>e[r]).id=()=>r,e):0,c=[],C=n.set=(t,l,a=32,o=t.charCodeAt(0),n=t.length,f=c[o],h=a.length||([a,l]=[l,a],0),s=t.toUpperCase()!==t,u=(h>1?(r,e)=>r&&(e=i(l))&&(r.length||e.length?t=>a(r(t),e(t)):(r=a(r(),e()),()=>r)):h?r=>!r&&(r=i(l-1))&&(e=>a(r(e))):a))=>c[o]=(a,o,h=r)=>o<l&&(n<2||e.substr(r,n)==t)&&(!s||!d(e.charCodeAt(r+n)))&&(r+=n,u(a,o))||(r=h,f&&f(a,o)),A=r=>r>=48&&r<=57,g=t=>(t&&f(),t=h((r=>46==r||A(r))),(69==e.charCodeAt(r)||101==e.charCodeAt(r))&&(t+=h(2)+h(A)),(t=+t)!=t?f("Bad number"):()=>t),p=(r,e,t=r.of)=>l=>e(t?t(l):l,r.id());for(l=48;l<=57;)c[l++]=g;for(t=['"',r=>(r=r?f():h((r=>r-34)),h()||f("Bad string"),()=>r),,".",(r,e,t)=>r?(s(),e=h(d)||f(),(t=t=>r(t)[e]).id=()=>e,t.of=r,t):g(h(-1)),18,"[",(r,e,t)=>r&&(e=i(0,93)||f(),(t=t=>r(t)[e(t)]).id=e,t.of=r,t),18,"(",(r,e,t)=>(e=i(0,41),r?t=>r(t).apply(r.of?.(t),e?e.all?e.all(t):[e(t)]:[]):e||f()),18,",",(r,e,t=i(1))=>(t.all=r.all?(e,l,a=r.all(e))=>a.push(t(e))&&a:e=>[r(e),t(e)],t),1,"|",6,(r,e)=>r|e,"||",4,(r,e)=>r||e,"&",8,(r,e)=>r&e,"&&",5,(r,e)=>r&&e,"^",7,(r,e)=>r^e,"==",9,(r,e)=>r==e,"!=",9,(r,e)=>r!=e,">",10,(r,e)=>r>e,">=",10,(r,e)=>r>=e,">>",11,(r,e)=>r>>e,">>>",11,(r,e)=>r>>>e,"<",10,(r,e)=>r<e,"<=",10,(r,e)=>r<=e,"<<",11,(r,e)=>r<<e,"+",12,(r,e)=>r+e,"+",15,r=>+r,"++",r=>p(r||i(14),r?(r,e)=>r[e]++:(r,e)=>++r[e]),15,"-",12,(r,e)=>r-e,"-",15,r=>-r,"--",r=>p(r||i(14),r?(r,e)=>r[e]--:(r,e)=>--r[e]),15,"!",15,r=>!r,"*",13,(r,e)=>r*e,"/",13,(r,e)=>r/e,"%",13,(r,e)=>r%e];[l,a,o,...t]=t,l;)C(l,a,o);let b,B,m,w,y={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},v=t=>(l,a,o="")=>{for(l&&f();(a=e.charCodeAt(r))-t;)92===a?(h(),a=h(),o+=y[a]||a):o+=h();return h()||f("Bad string"),()=>o};for((b=['"',v(34),,"'",v(39),,"/*",(t,l)=>(h((t=>42!==t&&47!==e.charCodeAt(r+1))),h(2),t||i(l)),,"//",(r,e)=>(h((r=>r>=32)),r||i(e)),,"null",r=>r?f():()=>null,,"true",r=>r?f():()=>!0,,"false",r=>r?f():()=>!1,,"undefined",r=>r?f():()=>{},,";",r=>i()||(()=>{}),,"===",9,(r,e)=>r===e,"!==",9,(r,e)=>r!==e,"~",15,r=>~r,"**",(r,e,t=i(13))=>e=>r(e)**t(e),14,":",3.1,(r,e)=>[r,e],"?",3,(r,e)=>r?e[2]:e[1],"?.",r=>r&&(e=>r(e)||(()=>{})),,"?.",(r,e)=>(s(),(e=h(d))&&(t=>r(t)?.[e])),,"in",10,(r,e)=>r in e,"[",(r,e)=>!r&&((r=i(0,93))?r.all?e=>r.all(e):e=>[r(e)]:r=>[]),,"{",(r,e)=>!r&&((r=i(0,125))?t=>(e=(r.all||r)(t),Object.fromEntries(r.all?e:[e])):r=>({})),,":",(r,e,t)=>(t=i(3.1)||f(),e=>[(r.id||r)(e),t(e),r(e)]),3.1]);[B,m,w,...b]=b,B;)C(B,m,w);export{n as default};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subscript",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Microlanguage with common syntax for JS/C++/Python/Rust",
|
|
5
5
|
"main": "subscript.js",
|
|
6
6
|
"type": "module",
|
|
@@ -45,7 +45,10 @@
|
|
|
45
45
|
"calculator",
|
|
46
46
|
"calc",
|
|
47
47
|
"lisp",
|
|
48
|
-
"frisk"
|
|
48
|
+
"frisk",
|
|
49
|
+
"math.js",
|
|
50
|
+
"math-codegen",
|
|
51
|
+
"math-parser"
|
|
49
52
|
],
|
|
50
53
|
"author": "Dmitry Iv.",
|
|
51
54
|
"license": "ISC",
|
package/subscript.js
CHANGED
|
@@ -1,130 +1,88 @@
|
|
|
1
|
-
import parse,
|
|
2
|
-
import evaluate, {operator as evalOp} from './evaluate.js'
|
|
3
|
-
|
|
4
|
-
const PERIOD=46, OPAREN=40, CPAREN=41, CBRACK=93, SPACE=32,
|
|
1
|
+
import {parse, set, lookup, skip, cur, idx, err, expr, isId, space} from './index.js'
|
|
5
2
|
|
|
3
|
+
const PERIOD=46, OPAREN=40, CPAREN=41, OBRACK=91, CBRACK=93, SPACE=32, DQUOTE=34, _0=48, _9=57,
|
|
6
4
|
PREC_SEQ=1, PREC_SOME=4, PREC_EVERY=5, PREC_OR=6, PREC_XOR=7, PREC_AND=8,
|
|
7
5
|
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
6
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
7
|
+
let u, list, op, prec, fn,
|
|
8
|
+
isNum = c => c>=_0 && c<=_9,
|
|
9
|
+
// 1.2e+3, .5
|
|
10
|
+
num = n => (
|
|
11
|
+
n&&err(),
|
|
12
|
+
n = skip(c=>c==PERIOD || isNum(c)),
|
|
13
|
+
(cur.charCodeAt(idx) == 69 || cur.charCodeAt(idx) == 101) && (n += skip(2) + skip(isNum)),
|
|
14
|
+
n=+n, n!=n ? err('Bad number') : () => n // 0 args means token is static
|
|
15
|
+
),
|
|
16
|
+
|
|
17
|
+
inc = (a,fn,c=a.of) => ctx => fn(c?c(ctx):ctx, a.id())
|
|
18
|
+
|
|
19
|
+
// numbers
|
|
20
|
+
for (op=_0;op<=_9;) lookup[op++] = num
|
|
21
|
+
|
|
22
|
+
// operators
|
|
23
|
+
for (list=[
|
|
17
24
|
// "a"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
(
|
|
23
|
-
(c >= 97 && c <= 122) || // a...z
|
|
24
|
-
c == 36 || c == 95 || // $, _,
|
|
25
|
-
c >= 192 // any non-ASCII
|
|
26
|
-
)
|
|
27
|
-
)
|
|
25
|
+
'"', a => (a=a?err():skip(c => c-DQUOTE), skip()||err('Bad string'), ()=>a),,
|
|
26
|
+
|
|
27
|
+
// a.b, .2, 1.2 parser in one
|
|
28
|
+
'.', (a,id,fn) => !a ? num(skip(-1)) : // FIXME: .123 is not operator, so we skip back, but mb reorganizing num would be better
|
|
29
|
+
(space(), id=skip(isId)||err(), fn=ctx=>a(ctx)[id], fn.id=()=>id, fn.of=a, fn), PREC_CALL,
|
|
28
30
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
// a[b]
|
|
32
|
+
'[', (a,b,fn) => a && (b=expr(0,CBRACK)||err(), fn=ctx=>a(ctx)[b(ctx)], fn.id=b, fn.of=a, fn), PREC_CALL,
|
|
33
|
+
|
|
34
|
+
// a(), a(b), (a,b), (a+b)
|
|
35
|
+
'(', (a,b,fn) => (
|
|
36
|
+
b=expr(0,CPAREN),
|
|
37
|
+
// a(), a(b), a(b,c,d)
|
|
38
|
+
a ? ctx => a(ctx).apply(a.of?.(ctx), b ? b.all ? b.all(ctx) : [b(ctx)] : []) :
|
|
39
|
+
// (a+b)
|
|
40
|
+
b || err()
|
|
41
|
+
), PREC_CALL,
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
',', PREC_SEQ
|
|
43
|
+
// [a,b,c] or (a,b,c)
|
|
44
|
+
',', (a,prec,b=expr(PREC_SEQ)) => (
|
|
45
|
+
b.all = a.all ? (ctx,prec,arr=a.all(ctx)) => arr.push(b(ctx)) && arr : ctx => [a(ctx),b(ctx)],
|
|
46
|
+
b
|
|
47
|
+
), PREC_SEQ,
|
|
35
48
|
|
|
36
|
-
'|', PREC_OR
|
|
37
|
-
'||', PREC_SOME
|
|
49
|
+
'|', PREC_OR, (a,b)=>a|b,
|
|
50
|
+
'||', PREC_SOME, (a,b)=>a||b,
|
|
38
51
|
|
|
39
|
-
'&', PREC_AND
|
|
40
|
-
'&&', PREC_EVERY
|
|
52
|
+
'&', PREC_AND, (a,b)=>a&b,
|
|
53
|
+
'&&', PREC_EVERY, (a,b)=>a&&b,
|
|
41
54
|
|
|
42
|
-
'^', PREC_XOR
|
|
55
|
+
'^', PREC_XOR, (a,b)=>a^b,
|
|
43
56
|
|
|
44
57
|
// ==, !=
|
|
45
|
-
'==', PREC_EQ
|
|
46
|
-
'!=', PREC_EQ
|
|
58
|
+
'==', PREC_EQ, (a,b)=>a==b,
|
|
59
|
+
'!=', PREC_EQ, (a,b)=>a!=b,
|
|
47
60
|
|
|
48
61
|
// > >= >> >>>, < <= <<
|
|
49
|
-
'>', PREC_COMP
|
|
50
|
-
'>=', PREC_COMP
|
|
51
|
-
'>>', PREC_SHIFT
|
|
52
|
-
'>>>', PREC_SHIFT
|
|
53
|
-
'<', PREC_COMP
|
|
54
|
-
'<=', PREC_COMP
|
|
55
|
-
'<<', PREC_SHIFT
|
|
62
|
+
'>', PREC_COMP, (a,b)=>a>b,
|
|
63
|
+
'>=', PREC_COMP, (a,b)=>a>=b,
|
|
64
|
+
'>>', PREC_SHIFT, (a,b)=>a>>b,
|
|
65
|
+
'>>>', PREC_SHIFT, (a,b)=>a>>>b,
|
|
66
|
+
'<', PREC_COMP, (a,b)=>a<b,
|
|
67
|
+
'<=', PREC_COMP, (a,b)=>a<=b,
|
|
68
|
+
'<<', PREC_SHIFT, (a,b)=>a<<b,
|
|
56
69
|
|
|
57
70
|
// + ++ - --
|
|
58
|
-
'+', PREC_SUM
|
|
59
|
-
'+', PREC_UNARY,
|
|
60
|
-
'++', PREC_UNARY
|
|
61
|
-
|
|
62
|
-
'-', PREC_SUM
|
|
63
|
-
'-', PREC_UNARY,
|
|
64
|
-
'--', PREC_UNARY
|
|
65
|
-
'--', PREC_POSTFIX, +1,
|
|
71
|
+
'+', PREC_SUM, (a,b)=>a+b,
|
|
72
|
+
'+', PREC_UNARY, (a)=>+a,
|
|
73
|
+
'++', a => inc(a||expr(PREC_UNARY-1), a ? (a,b)=>a[b]++ : (a,b)=>++a[b]), PREC_UNARY,
|
|
74
|
+
|
|
75
|
+
'-', PREC_SUM, (a,b)=>a-b,
|
|
76
|
+
'-', PREC_UNARY, (a)=>-a,
|
|
77
|
+
'--', a => inc(a||expr(PREC_UNARY-1), a ? (a,b)=>a[b]-- : (a,b)=>--a[b]), PREC_UNARY,
|
|
66
78
|
|
|
67
79
|
// ! ~
|
|
68
|
-
'!', PREC_UNARY,
|
|
80
|
+
'!', PREC_UNARY, (a)=>!a,
|
|
69
81
|
|
|
70
82
|
// * / %
|
|
71
|
-
'*', PREC_MULT
|
|
72
|
-
'/', PREC_MULT
|
|
73
|
-
'%', PREC_MULT
|
|
83
|
+
'*', PREC_MULT, (a,b)=>a*b,
|
|
84
|
+
'/', PREC_MULT, (a,b)=>a/b,
|
|
85
|
+
'%', PREC_MULT, (a,b)=>a%b
|
|
86
|
+
]; [op,prec,fn,...list]=list, op;) set(op,prec,fn)
|
|
74
87
|
|
|
75
|
-
|
|
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, val(expr(0,CBRACK))], node),
|
|
80
|
-
']',,,
|
|
81
|
-
|
|
82
|
-
// a(b)
|
|
83
|
-
'(', PREC_CALL, (node,b) => ( skip(), b=expr(0,CPAREN),
|
|
84
|
-
Array.isArray(b) && b[0]===',' ? (b[0]=node, b) : b ? [node, val(b)] : [node]
|
|
85
|
-
),
|
|
86
|
-
// (a+b)
|
|
87
|
-
'(', PREC_GROUP, (node,b) => !node && (skip(), b=expr(0,CPAREN) || err(), 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=0)=>a+b,
|
|
105
|
-
'-', (a,b)=>b==null ? -a : 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
|
-
])
|
|
126
|
-
|
|
127
|
-
export { parse, evaluate }
|
|
128
|
-
|
|
129
|
-
// code → evaluator
|
|
130
|
-
export default s => (s = typeof s == 'string' ? parse(s) : s, ctx => evaluate(s, ctx))
|
|
88
|
+
export default parse
|
package/subscript.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let r,e
|
|
1
|
+
let r,e,t,a,o,l,d=(t,...a)=>(e=t.raw?String.raw(t,...a):t,r=0,!(t=s())||e[r]?f():r=>t(r||{})),n=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r,f=(t="Bad syntax",a=e[r])=>{throw Error(t+" `"+a+"` at "+r)},h=(t=1,a=r,o)=>{if("number"==typeof t)r+=t;else for(;t(e.charCodeAt(r));)r++;return e.slice(a,r)},s=(e=0,t,a,o,l,d)=>{for(;(a=c())&&(l=(d=u[a])&&d(o,e)||!o&&i());)o=l;return t&&(a==t?r++:f("Unclosed")),o},c=t=>{for(;(t=e.charCodeAt(r))<=32;)r++;return t},i=(r=h(n),e)=>r?((e=e=>e[r]).id=()=>r,e):0,u=[],p=d.set=(t,a,o=32,l=t.charCodeAt(0),d=t.length,f=u[l],h=o.length||([o,a]=[a,o],0),c=t.toUpperCase()!==t,i=(h>1?(r,e)=>r&&(e=s(a))&&(r.length||e.length?t=>o(r(t),e(t)):(r=o(r(),e()),()=>r)):h?r=>!r&&(r=s(a-1))&&(e=>o(r(e))):o))=>u[l]=(o,l,h=r)=>l<a&&(d<2||e.substr(r,d)==t)&&(!c||!n(e.charCodeAt(r+d)))&&(r+=d,i(o,l))||(r=h,f&&f(o,l)),C=r=>r>=48&&r<=57,g=t=>(t&&f(),t=h((r=>46==r||C(r))),(69==e.charCodeAt(r)||101==e.charCodeAt(r))&&(t+=h(2)+h(C)),(t=+t)!=t?f("Bad number"):()=>t),A=(r,e,t=r.of)=>a=>e(t?t(a):a,r.id());for(a=48;a<=57;)u[a++]=g;for(t=['"',r=>(r=r?f():h((r=>r-34)),h()||f("Bad string"),()=>r),,".",(r,e,t)=>r?(c(),e=h(n)||f(),(t=t=>r(t)[e]).id=()=>e,t.of=r,t):g(h(-1)),18,"[",(r,e,t)=>r&&(e=s(0,93)||f(),(t=t=>r(t)[e(t)]).id=e,t.of=r,t),18,"(",(r,e,t)=>(e=s(0,41),r?t=>r(t).apply(r.of?.(t),e?e.all?e.all(t):[e(t)]:[]):e||f()),18,",",(r,e,t=s(1))=>(t.all=r.all?(e,a,o=r.all(e))=>o.push(t(e))&&o:e=>[r(e),t(e)],t),1,"|",6,(r,e)=>r|e,"||",4,(r,e)=>r||e,"&",8,(r,e)=>r&e,"&&",5,(r,e)=>r&&e,"^",7,(r,e)=>r^e,"==",9,(r,e)=>r==e,"!=",9,(r,e)=>r!=e,">",10,(r,e)=>r>e,">=",10,(r,e)=>r>=e,">>",11,(r,e)=>r>>e,">>>",11,(r,e)=>r>>>e,"<",10,(r,e)=>r<e,"<=",10,(r,e)=>r<=e,"<<",11,(r,e)=>r<<e,"+",12,(r,e)=>r+e,"+",15,r=>+r,"++",r=>A(r||s(14),r?(r,e)=>r[e]++:(r,e)=>++r[e]),15,"-",12,(r,e)=>r-e,"-",15,r=>-r,"--",r=>A(r||s(14),r?(r,e)=>r[e]--:(r,e)=>--r[e]),15,"!",15,r=>!r,"*",13,(r,e)=>r*e,"/",13,(r,e)=>r/e,"%",13,(r,e)=>r%e];[a,o,l,...t]=t,a;)p(a,o,l);export{d as default};
|
package/evaluate.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// calltree → result
|
|
2
|
-
export const evaluate = (node, ctx={}) => {
|
|
3
|
-
if (typeof node === 'string')
|
|
4
|
-
return node[0] === '"' ? node.slice(1,-1) : node[0]==='@' ? node.slice(1) : node in ctx ? ctx[node] : node
|
|
5
|
-
|
|
6
|
-
if (Array.isArray(node)) {
|
|
7
|
-
// [[a,b], c] or ['+', a, b] or ['myfn', a, b], or
|
|
8
|
-
let c = node[0], fn = Array.isArray(c) ? evaluate(c, ctx) : (lookup[c] || ctx[c] || c), args=[], i = 1
|
|
9
|
-
for (;i<node.length;i++) args.push(evaluate(node[i], ctx))
|
|
10
|
-
return args.length > fn.length && fn.length ? args.reduce(fn) : fn.apply(c,args)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
return node
|
|
14
|
-
},
|
|
15
|
-
lookup = {},
|
|
16
|
-
|
|
17
|
-
// op evaluators
|
|
18
|
-
// multiple args allows shortcuts, lisp compatible, easy manual eval, functions anyways take multiple arguments
|
|
19
|
-
operator = evaluate.operator = (op, fn) => lookup[op] = fn
|
|
20
|
-
|
|
21
|
-
export default evaluate
|
package/parse.js
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
const SPACE=32
|
|
2
|
-
|
|
3
|
-
// current string & index
|
|
4
|
-
let idx, cur
|
|
5
|
-
|
|
6
|
-
export const parse = (str, tree) => (cur=str, idx=0, tree=expr(), idx<cur.length ? err() : val(tree)),
|
|
7
|
-
|
|
8
|
-
err = (msg='Bad syntax') => { throw Error(msg + ' `' + cur[idx] + '` at ' + idx) },
|
|
9
|
-
|
|
10
|
-
skip = (is=1, from=idx) => {
|
|
11
|
-
if (typeof is === 'number') idx += is
|
|
12
|
-
else while (is(code())) idx++;
|
|
13
|
-
return cur.slice(from, idx)
|
|
14
|
-
},
|
|
15
|
-
|
|
16
|
-
code = (i=0) => cur.charCodeAt(idx+i),
|
|
17
|
-
|
|
18
|
-
char = (n=1) => cur.substr(idx, n),
|
|
19
|
-
|
|
20
|
-
// a + b - c
|
|
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;
|
|
26
|
-
|
|
27
|
-
// skip end character, if expected
|
|
28
|
-
if (end) cc != end ? err('Unclosed paren') : idx++
|
|
29
|
-
|
|
30
|
-
return node
|
|
31
|
-
},
|
|
32
|
-
|
|
33
|
-
// can be extended with comments, so we export
|
|
34
|
-
space = parse.space = cc => { while (cc = code(), cc <= SPACE) idx++; return cc },
|
|
35
|
-
|
|
36
|
-
// tokens
|
|
37
|
-
tokens = parse.token = [],
|
|
38
|
-
token = (c,i=0,node) => { while(i<tokens.length) if (node = tokens[i++](c)) return node },
|
|
39
|
-
|
|
40
|
-
// operator lookup table
|
|
41
|
-
lookup = [],
|
|
42
|
-
|
|
43
|
-
// create operator checker/mapper (see examples)
|
|
44
|
-
// @param op is operator string
|
|
45
|
-
// @param prec is operator precedenc to check
|
|
46
|
-
// @param map is either number +1 - postfix unary, -1 prefix unary, 0 binary, else - custom mapper function
|
|
47
|
-
operator = parse.operator = (
|
|
48
|
-
op, prec=0, type=0, map, c=op.charCodeAt(0), l=op.length,
|
|
49
|
-
prev=lookup[c],
|
|
50
|
-
spaced=type<=0&&op.toUpperCase()!==op // non-postfix word operator must have space after
|
|
51
|
-
) => (
|
|
52
|
-
map = !type ? node => { // binary, consume same-op group
|
|
53
|
-
node = [op, val(node)]
|
|
54
|
-
do { idx+=l, node.push(val(expr(prec))) }
|
|
55
|
-
while (parse.space()==c && (l<2||char(l)==op) && (!spaced||code(l)<=SPACE))
|
|
56
|
-
return node
|
|
57
|
-
} :
|
|
58
|
-
type > 0 ? node => node && [skip(l), val(node)] : // postfix unary
|
|
59
|
-
type < 0 ? node => !node && [skip(l), val(expr(prec-1))] : // prefix unary
|
|
60
|
-
type,
|
|
61
|
-
|
|
62
|
-
lookup[c] = (node, curPrec) =>
|
|
63
|
-
curPrec < prec && (l<2||char(l)==op) && (!spaced||code(l)<=SPACE) &&
|
|
64
|
-
map(node) || (prev && prev(node, curPrec))
|
|
65
|
-
),
|
|
66
|
-
|
|
67
|
-
// in order to support literal tokens, we call valueOf any time we create or modify calltree node
|
|
68
|
-
val = node => Array.isArray(node) ? node : (node || err()).valueOf()
|
|
69
|
-
|
|
70
|
-
export default parse
|