subscript 8.0.1 → 8.1.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,8 +1,8 @@
1
- # <img alt="subscript" src="/subscript2.svg" height=28/> <!--sub͘<em>script</em>--> <!--<sub>SUB͘<em>SCRIPT</em></sub>--> <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> <a href="https://bundlephobia.com/package/subscript"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip"/></a> <a href="http://npmjs.org/subscript"><img src="https://img.shields.io/npm/v/subscript"/></a> <a href="http://microjs.com/#subscript"><img src="https://img.shields.io/badge/microjs-subscript-blue?color=darkslateblue"/></a>
1
+ # sub<em>script</em> <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> <a href="https://bundlephobia.com/package/subscript"><img alt="npm bundle size" src="https://img.shields.io/bundlephobia/minzip/subscript/latest?color=brightgreen&label=gzip"/></a> <a href="http://npmjs.org/subscript"><img src="https://img.shields.io/npm/v/subscript"/></a> <a href="http://microjs.com/#subscript"><img src="https://img.shields.io/badge/microjs-subscript-blue?color=darkslateblue"/></a>
2
2
 
3
- > _Subscript_ is fast, tiny & extensible expression evaluator / microlanguage.
3
+ > _Subscript_ is fast, tiny & extensible expression evaluator / microlanguage with standard syntax.
4
4
 
5
- Used for:
5
+ #### Used for:
6
6
 
7
7
  * templates (eg. [sprae](https://github.com/dy/sprae), [templize](https://github.com/dy/templize))
8
8
  * expressions evaluators, calculators
@@ -82,7 +82,7 @@ fn = compile(tree)
82
82
  fn({ a: {b: 1}, c: 2 }) // 3
83
83
  ```
84
84
 
85
- ## Syntax Tree
85
+ ### Syntax Tree
86
86
 
87
87
  AST has simplified lispy tree structure (inspired by [frisk](https://ghub.io/frisk) / [nisp](https://github.com/ysmood/nisp)), opposed to [ESTree](https://github.com/estree/estree):
88
88
 
@@ -90,34 +90,52 @@ AST has simplified lispy tree structure (inspired by [frisk](https://ghub.io/fri
90
90
  * reflects execution sequence, rather than code layout;
91
91
  * has minimal overhead, directly maps to operators;
92
92
  * simplifies manual evaluation and debugging;
93
- * has conventional form and one-line docs:
93
+ * has conventional form and one-liner docs:
94
94
 
95
95
  ```js
96
96
  import { compile } from 'subscript.js'
97
97
 
98
98
  const fn = compile(['+', ['*', 'min', [,60]], [,'sec']])
99
-
100
99
  fn({min: 5}) // min*60 + "sec" == "300sec"
100
+
101
+ // node kinds
102
+ ['+', a]; // unary prefix or postfix operator `+a`
103
+ ['+', a, b]; // binary operator `a + b`
104
+ ['+', a, b, c]; // n-ary operator `a + b + c`
105
+ ['()', a]; // group operator `(a)`
106
+ ['(', a, b]; // access operator `a(b)`
107
+ [, a]; // literal value `'a'`
108
+ a; // variable (from scope)
101
109
  ```
102
110
 
103
111
  ## Extending
104
112
 
105
- _Subscript_ provides API to customize or extend syntax:
113
+ _Subscript_ provides premade language [features](./features) and API to customize syntax:
106
114
 
107
- * `unary(str, precedence, postfix=false)` − register unary operator, either prefix or postfix.
108
- * `binary(str, precedence, rightAssoc=false)` − register binary operator, optionally right-associative.
109
- * `nary(str, precedence, allowSkip=false)` − register n-ary (sequence) operator, optionally allowing skipping args.
110
- * `token(str, precedence, prevNode => curNode)` register custom token or literal. Function takes last token and returns tree node.
111
- * `operator(str, (a, b) => ctx => result)` register evaluator for an operator. Function takes node arguments and returns evaluator function.
115
+ * `unary(str, precedence, postfix=false)` − register unary operator, either prefix `⚬a` or postfix `a⚬`.
116
+ * `binary(str, precedence, rassoc=false)` − register binary operator `a ⚬ b`, optionally right-associative.
117
+ * `nary(str, precedence)` − register n-ary (sequence) operator like `a; b;` or `a, b`, allows missing args.
118
+ * `group(str, precedence)` - register group, like `[a]`, `{a}`, `(a)` etc.
119
+ * `access(str, precedence)` - register access operator, like `a[b]`, `a(b)` etc.
120
+ * `token(str, precedence, lnode => node)` − register custom token or literal. Callback takes left-side node and returns complete expression node.
121
+ * `operator(str, (a, b) => ctx => value)` − register evaluator for an operator. Callback takes node arguments and returns evaluator function.
112
122
 
113
123
  ```js
114
124
  import script, { compile, operator, unary, binary, token } from './subscript.js'
115
125
 
116
- // add identity operators with precedence 9
126
+ // enable objects/arrays syntax
127
+ import 'subscript/feature/array.js';
128
+ import 'subscript/feature/object.js';
129
+
130
+ // add identity operators (precedence of comparison)
117
131
  binary('===', 9), binary('!==', 9)
118
132
  operator('===', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx)===b(ctx)))
119
133
  operator('===', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx)!==b(ctx)))
120
134
 
135
+ // add nullish coalescing (precedence of logical or)
136
+ binary('??', 3)
137
+ operator('??', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) ?? b(ctx)))
138
+
121
139
  // add JS literals
122
140
  token('undefined', 20, a => a ? err() : [, undefined])
123
141
  token('NaN', 20, a => a ? err() : [, NaN])
package/feature/access.js CHANGED
@@ -1,11 +1,11 @@
1
- import { token, expr, err } from '../src/parse.js'
2
- import { operator, compile, access } from '../src/compile.js'
3
- import { CBRACK, CPAREN, PREC_ACCESS } from '../src/const.js'
1
+ import { access, binary, group } from '../src/parse.js'
2
+ import { operator, compile } from '../src/compile.js'
3
+ import { CBRACK, PREC_ACCESS } from '../src/const.js'
4
4
 
5
5
  // a[b]
6
- token('[', PREC_ACCESS, a => a && ['[', a, expr(0, CBRACK) || err()])
7
- operator('[', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx)[b(ctx)]))
6
+ access('[]', PREC_ACCESS)
7
+ operator('[', (a, b) => !b ? err() : (a = compile(a), b = compile(b), ctx => a(ctx)[b(ctx)]))
8
8
 
9
9
  // a.b
10
- token('.', PREC_ACCESS, (a, b) => a && (b = expr(PREC_ACCESS)) && ['.', a, b])
10
+ binary('.', PREC_ACCESS)
11
11
  operator('.', (a, b) => (a = compile(a), b = !b[0] ? b[1] : b, ctx => a(ctx)[b])) // a.true, a.1 → needs to work fine
package/feature/add.js CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  import { binary, unary } from '../src/parse.js'
3
3
  import { PREC_ADD, PREC_PREFIX, PREC_ASSIGN } from '../src/const.js'
4
- import { compile, access, operator } from '../src/compile.js'
4
+ import { compile, prop, operator } from '../src/compile.js'
5
5
 
6
6
  unary('+', PREC_PREFIX), operator('+', (a, b) => !b && (a = compile(a), ctx => +a(ctx)))
7
7
  unary('-', PREC_PREFIX), operator('-', (a, b) => !b && (a = compile(a), ctx => -a(ctx)))
@@ -12,11 +12,11 @@ binary('-', PREC_ADD), operator('-', (a, b) => b && (a = compile(a), b = compile
12
12
  binary('+=', PREC_ASSIGN, true)
13
13
  operator('+=', (a, b) => (
14
14
  b = compile(b),
15
- access(a, (container, path, ctx) => container(ctx)[path(ctx)] += b(ctx))
15
+ prop(a, (container, path, ctx) => container(ctx)[path(ctx)] += b(ctx))
16
16
  ))
17
17
 
18
18
  binary('-=', PREC_ASSIGN, true)
19
19
  operator('-=', (a, b) => (
20
20
  b = compile(b),
21
- access(a, (container, path, ctx) => (container(ctx)[path(ctx)] -= b(ctx)))
21
+ prop(a, (container, path, ctx) => (container(ctx)[path(ctx)] -= b(ctx)))
22
22
  ))
package/feature/array.js CHANGED
@@ -1,10 +1,10 @@
1
- import { token, expr } from '../src/parse.js'
1
+ import { token, expr, group } from '../src/parse.js'
2
2
  import { operator, compile } from '../src/compile.js'
3
- import { CBRACK, PREC_TOKEN } from '../src/const.js'
3
+ import { PREC_TOKEN } from '../src/const.js'
4
4
 
5
5
  // [a,b,c]
6
- token('[', PREC_TOKEN, (a) => !a && ['[', expr(0, CBRACK) || ''])
7
- operator('[', (a, b) => !b && (
6
+ group('[]', PREC_TOKEN)
7
+ operator('[]', (a, b) => (
8
8
  !a ? () => [] : // []
9
9
  a[0] === ',' ? (a = a.slice(1).map(compile), ctx => a.map(a => a(ctx))) : // [a,b,c]
10
10
  (a = compile(a), ctx => [a(ctx)]) // [a]
@@ -0,0 +1,23 @@
1
+ import { binary, group } from "../src/parse.js"
2
+ import { compile, operator } from "../src/compile.js"
3
+ import { PREC_ASSIGN, PREC_TOKEN } from "../src/const.js"
4
+
5
+ // arrow functions (useful for array methods)
6
+ binary('=>', PREC_ASSIGN, true)
7
+ operator('=>',
8
+ (a, b) => (
9
+ a = a[0] === '()' ? a[1] : a,
10
+ a = !a ? [] : // () =>
11
+ a[0] === ',' ? (a = a.slice(1)) : // (a,c) =>
12
+ (a = [a]), // a =>
13
+
14
+ b = compile(b[0] === '{}' ? b[1] : b), // `=> {x}` -> `=> x`
15
+
16
+ (ctx = null) => (
17
+ ctx = Object.create(ctx),
18
+ (...args) => (a.map((a, i) => ctx[a] = args[i]), b(ctx))
19
+ )
20
+ )
21
+ )
22
+
23
+ binary('')
package/feature/assign.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { binary, err } from "../src/parse.js";
2
- import { compile, operator, operators, access } from "../src/compile.js";
2
+ import { compile, operator, operators, prop } from "../src/compile.js";
3
3
  import { PREC_ASSIGN } from "../src/const.js";
4
4
 
5
5
  // assignments
@@ -7,5 +7,5 @@ binary('=', PREC_ASSIGN, true)
7
7
  operator('=', (a, b) => (
8
8
  b = compile(b),
9
9
  // a = x, ((a)) = x, a.b = x, a['b'] = x
10
- access(a, (container, path, ctx) => container(ctx)[path(ctx)] = b(ctx))
10
+ prop(a, (container, path, ctx) => container(ctx)[path(ctx)] = b(ctx))
11
11
  ))
package/feature/call.js CHANGED
@@ -1,15 +1,15 @@
1
- import { token, expr, err } from '../src/parse.js'
2
- import { operator, compile, access } from '../src/compile.js'
3
- import { CBRACK, CPAREN, PREC_ACCESS } from '../src/const.js'
1
+ import { access } from '../src/parse.js'
2
+ import { operator, compile, prop } from '../src/compile.js'
3
+ import { PREC_ACCESS } from '../src/const.js'
4
4
 
5
5
  // a(b,c,d), a()
6
- token('(', PREC_ACCESS, (a, b) => a && (b = expr(0, CPAREN), b ? ['(', a, b] : ['(', a, '']))
6
+ access('()', PREC_ACCESS)
7
7
  operator('(', (a, b, args) => (
8
- args = b == '' ? () => [] : // a()
9
- b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(arg => arg(ctx))) : // a(b,c)
8
+ args = !b ? () => [] : // a()
9
+ b[0] === ',' ? (b = b.slice(1).map(b => !b ? err() : compile(b)), ctx => b.map(arg => arg(ctx))) : // a(b,c)
10
10
  (b = compile(b), ctx => [b(ctx)]), // a(b)
11
11
 
12
12
  // a(...args), a.b(...args), a[b](...args)
13
- access(a, (obj, path, ctx) => obj(ctx)[path(ctx)](...args(ctx)), true)
13
+ prop(a, (obj, path, ctx) => obj(ctx)[path(ctx)](...args(ctx)), true)
14
14
  )
15
15
  )
@@ -2,5 +2,6 @@ import { SPACE, STAR, PREC_TOKEN } from "../src/const.js"
2
2
  import { token, skip, cur, idx, expr } from "../src/parse.js"
3
3
 
4
4
  // /**/, //
5
- token('/*', PREC_TOKEN, (a, prec) => (skip(c => c !== STAR && cur.charCodeAt(idx + 1) !== 47), skip(2), a || expr(prec) || ['']))
5
+ // FIXME: try replacing with group
6
+ token('/*', PREC_TOKEN, (a, prec) => (skip(c => c !== STAR && cur.charCodeAt(idx + 1) !== 47), skip(2), a || expr(prec) || []))
6
7
  token('//', PREC_TOKEN, (a, prec) => (skip(c => c >= SPACE), a || expr(prec) || ['']))
package/feature/group.js CHANGED
@@ -1,11 +1,11 @@
1
- import { token, expr, err, nary } from '../src/parse.js'
1
+ import { err, nary, group } from '../src/parse.js'
2
2
  import { compile, operator } from '../src/compile.js'
3
- import { CPAREN, PREC_ACCESS, PREC_GROUP, PREC_SEQ } from '../src/const.js'
3
+ import { PREC_ACCESS, PREC_GROUP, PREC_SEQ } from '../src/const.js'
4
4
 
5
5
  // (a,b,c), (a)
6
6
  // FIXME: try raising group precedence (it causes conflict in ?. though)
7
- token('(', PREC_ACCESS, (a) => (!a && ['()', expr(0, CPAREN) || err('Empty group')]))
8
- operator('()', (a) => (compile(a)))
7
+ group('()', PREC_ACCESS)
8
+ operator('()', (a) => (!a && err('Empty ()'), compile(a)))
9
9
 
10
10
  const last = (...args) => (args = args.map(compile), ctx => args.map(arg => arg(ctx)).pop())
11
11
  nary(',', PREC_SEQ), operator(',', last)
@@ -1,16 +1,16 @@
1
1
  import { token, expr } from "../src/parse.js"
2
- import { operator, compile, access } from "../src/compile.js"
2
+ import { operator, compile, prop } from "../src/compile.js"
3
3
  import { PREC_POSTFIX } from "../src/const.js"
4
4
 
5
5
  let inc, dec
6
6
  token('++', PREC_POSTFIX, a => a ? ['-', ['++', a], [, 1]] : ['++', expr(PREC_POSTFIX - 1)])
7
7
  operator('++', inc = (a) =>
8
8
  // ++a, ++((a)), ++a.b, ++a[b]
9
- access(a, (obj, path, ctx) => ++obj(ctx)[path(ctx)])
9
+ prop(a, (obj, path, ctx) => ++obj(ctx)[path(ctx)])
10
10
  )
11
11
 
12
12
  token('--', PREC_POSTFIX, a => a ? ['+', ['--', a], [, 1]] : ['--', expr(PREC_POSTFIX - 1)])
13
13
  operator('--', dec = (a) => (
14
14
  // --a, --a.b, --a[b]
15
- access(a, (obj, path, ctx) => --obj(ctx)[path(ctx)])
15
+ prop(a, (obj, path, ctx) => --obj(ctx)[path(ctx)])
16
16
  ))
package/feature/logic.js CHANGED
@@ -1,15 +1,11 @@
1
1
  import { PREC_LOR, PREC_LAND, PREC_PREFIX } from '../src/const.js';
2
- import { unary, binary, nary } from "../src/parse.js"
2
+ import { unary, binary } from "../src/parse.js"
3
3
  import { operator, compile } from "../src/compile.js"
4
4
 
5
5
  unary('!', PREC_PREFIX), operator('!', (a, b) => !b && (a = compile(a), ctx => !a(ctx)))
6
6
 
7
- nary('||', PREC_LOR), operator('||', (...args) => (
8
- args = args.map(compile),
9
- ctx => { let arg, res; for (arg of args) if (res = arg(ctx)) return res; return res }
10
- ))
7
+ binary('||', PREC_LOR)
8
+ operator('||', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) || b(ctx)))
11
9
 
12
- nary('&&', PREC_LAND), operator('&&', (...args) => (
13
- args = args.map(compile),
14
- ctx => { let arg, res; for (arg of args) if (!(res = arg(ctx))) return res; return res }
15
- ))
10
+ binary('&&', PREC_LAND)
11
+ operator('&&', (a, b) => (a = compile(a), b = compile(b), ctx => a(ctx) && b(ctx)))
package/feature/mult.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { binary } from '../src/parse.js'
2
- import { operator, compile, access } from '../src/compile.js'
2
+ import { operator, compile, prop } from '../src/compile.js'
3
3
  import { PREC_MULT, PREC_ASSIGN } from '../src/const.js'
4
4
 
5
5
  binary('*', PREC_MULT), operator('*', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) * b(ctx)))
@@ -9,17 +9,17 @@ binary('%', PREC_MULT), operator('%', (a, b) => b && (a = compile(a), b = compil
9
9
  binary('*=', PREC_ASSIGN, true)
10
10
  operator('*=', (a, b) => (
11
11
  b = compile(b),
12
- access(a, (container, path, ctx) => container(ctx)[path(ctx)] *= b(ctx))
12
+ prop(a, (container, path, ctx) => container(ctx)[path(ctx)] *= b(ctx))
13
13
  ))
14
14
 
15
15
  binary('/=', PREC_ASSIGN, true)
16
16
  operator('/=', (a, b) => (
17
17
  b = compile(b),
18
- access(a, (container, path, ctx) => container(ctx)[path(ctx)] /= b(ctx))
18
+ prop(a, (container, path, ctx) => container(ctx)[path(ctx)] /= b(ctx))
19
19
  ))
20
20
 
21
21
  binary('%=', PREC_ASSIGN, true)
22
22
  operator('%=', (a, b) => (
23
23
  b = compile(b),
24
- access(a, (container, path, ctx) => container(ctx)[path(ctx)] %= b(ctx))
24
+ prop(a, (container, path, ctx) => container(ctx)[path(ctx)] %= b(ctx))
25
25
  ))
package/feature/object.js CHANGED
@@ -1,17 +1,16 @@
1
- import { token, expr } from '../src/parse.js'
1
+ import { token, expr, group, binary } from '../src/parse.js'
2
2
  import { operator, compile } from '../src/compile.js'
3
- import { CBRACE, PREC_SEQ, PREC_TOKEN } from '../src/const.js'
3
+ import { PREC_ASSIGN, PREC_SEQ, PREC_TOKEN } from '../src/const.js'
4
4
 
5
5
 
6
6
  // {a:1, b:2, c:3}
7
- token('{', PREC_TOKEN, a => !a && (['{', expr(0, CBRACE) || '']))
8
- operator('{', (a, b) => (
9
- !a ? ctx => ({}) : // {}
7
+ group('{}', PREC_TOKEN)
8
+ operator('{}', (a, b) => (
9
+ !a ? () => ({}) : // {}
10
10
  a[0] === ',' ? (a = a.slice(1).map(compile), ctx => Object.fromEntries(a.map(a => a(ctx)))) : // {a:1,b:2}
11
11
  a[0] === ':' ? (a = compile(a), ctx => Object.fromEntries([a(ctx)])) : // {a:1}
12
12
  (b = compile(a), ctx => ({ [a]: b(ctx) }))
13
13
  ))
14
14
 
15
- // FIXME: mb we don't need this seq raise
16
- token(':', PREC_SEQ + 0.1, (a, b) => (b = expr(PREC_SEQ + 0.1) || err(), [':', a, b]))
15
+ binary(':', PREC_ASSIGN, true)
17
16
  operator(':', (a, b) => (b = compile(b), a = Array.isArray(a) ? compile(a) : (a => a).bind(0, a), ctx => [a(ctx), b(ctx)]))
@@ -0,0 +1,30 @@
1
+ import { token, expr } from '../src/parse.js'
2
+ import { operator, compile } from '../src/compile.js'
3
+ import { PREC_ACCESS } from '../src/const.js'
4
+
5
+ // a?.[, a?.( - postfix operator
6
+ token('?.', PREC_ACCESS, a => a && ['?.', a])
7
+ // a ?.
8
+ operator('?.', a => (a = compile(a), ctx => a(ctx) || (() => { })))
9
+
10
+ // a?.b, a?.() - optional chain operator
11
+ token('?.', PREC_ACCESS, (a, b) => a && (b = expr(PREC_ACCESS), !b?.map) && ['?.', a, b])
12
+ // a ?. b
13
+ operator('?.', (a, b) => b && (a = compile(a), ctx => a(ctx)?.[b]))
14
+
15
+ // a?.x() - keep context, but watch out a?.()
16
+ operator('(', (a, b, container, args, path, optional) => (a[0] === '?.') && (a[2] || Array.isArray(a[1])) && (
17
+ args = !b ? () => [] : // a()
18
+ b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(a => a(ctx))) : // a(b,c)
19
+ (b = compile(b), ctx => [b(ctx)]), // a(b)
20
+
21
+ // a?.()
22
+ !a[2] && (optional = true, a = a[1]),
23
+
24
+ // a?.['x']?.()
25
+ a[0] === '[' ? (path = compile(a[2])) : (path = () => a[2]),
26
+ (container = compile(a[1]), optional ?
27
+ ctx => (container(ctx)?.[path(ctx)]?.(...args(ctx))) :
28
+ ctx => (container(ctx)?.[path(ctx)](...args(ctx)))
29
+ )
30
+ ))
package/justin.js CHANGED
@@ -12,43 +12,9 @@ import './feature/ternary.js'
12
12
  import './feature/bool.js'
13
13
  import './feature/array.js'
14
14
  import './feature/object.js'
15
+ import './feature/optional.js'
15
16
 
16
- // operators
17
- // set('===', PREC_EQ, (a, b) => a === b)
18
- // set('!==', PREC_EQ, (a, b) => a !== b)
19
- binary('??', PREC_OR), operator('??', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) ?? b(ctx)))
20
-
21
- // a?.[, a?.( - postfix operator
22
- token('?.', PREC_ACCESS, a => a && ['?.', a])
23
- // a ?.
24
- operator('?.', a => (a = compile(a), ctx => a(ctx) || (() => { })))
25
-
26
- // a?.b, a?.() - optional chain operator
27
- token('?.', PREC_ACCESS, (a, b) => a && (b = expr(PREC_ACCESS), !b?.map) && ['?.', a, b])
28
- // a ?. b
29
- operator('?.', (a, b) => b && (a = compile(a), ctx => a(ctx)?.[b]))
30
-
31
- // a?.x() - keep context, but watch out a?.()
32
- operator('(', (a, b, container, args, path, optional) => (b != null) && (a[0] === '?.') && (a[2] || Array.isArray(a[1])) && (
33
- args = b == '' ? () => [] : // a()
34
- b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(a => a(ctx))) : // a(b,c)
35
- (b = compile(b), ctx => [b(ctx)]), // a(b)
36
-
37
- // a?.()
38
- !a[2] && (optional = true, a = a[1]),
39
-
40
- // a?.['x']?.()
41
- a[0] === '[' ? (path = compile(a[2])) : (path = () => a[2]),
42
- (container = compile(a[1]), optional ?
43
- ctx => (container(ctx)?.[path(ctx)]?.(...args(ctx))) :
44
- ctx => (container(ctx)?.[path(ctx)](...args(ctx)))
45
- )
46
- ))
47
-
48
- // literals
49
17
  token('null', 20, a => a ? err() : [, null])
50
- // token('undefined', 20, a => a ? err() : [, undefined])
51
- // token('NaN', 20, a => a ? err() : [, NaN])
52
18
 
53
19
  export default subscript
54
20
  export * from './subscript.js'
package/justin.min.js CHANGED
@@ -1 +1 @@
1
- let r,e,t=t=>(r=0,e=t,t=i(),e[r]?a():t||""),a=(t="Bad syntax",a=e.slice(0,r).split("\n"),n=a.pop())=>{let i=e.slice(r-108,r).split("\n").pop(),s=e.slice(r,r+108).split("\n").shift();throw EvalError(`${t} at ${a.length}:${n.length} \`${r>=108?"…":""}${i}▶${s}\``,"font-weight: bold")},n=(t=1,a=r,n)=>{if("number"==typeof t)r+=t;else for(;n=t(e.charCodeAt(r));)r+=n;return e.slice(a,r)},i=(e=0,n,i,s,l,p)=>{for(;(i=t.space())&&(l=((p=o[i])&&p(s,e))??(!s&&t.id()));)s=l;return n&&(i==n?r++:a()),s},s=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r,l=t.id=r=>n(s),p=t.space=t=>{for(;(t=e.charCodeAt(r))<=32;)r++;return t},o=[],c=(t,a=32,n,i=t.charCodeAt(0),l=t.length,p=o[i],c=t.toUpperCase()!==t)=>o[i]=(i,o,f=r)=>o<a&&(l<2||e.substr(r,l)==t)&&(!c||!s(e.charCodeAt(r+l)))&&(r+=l,n(i,o))||(r=f,p?.(i,o)),f=(r,e,t=0)=>c(r,e,((a,n)=>a&&(n=i(e-t/2))&&[r,a,n])),d=(r,e,t)=>c(r,e,(a=>t?a&&[r,a]:!a&&(a=i(e-.5))&&[r,a])),u=(r,e,t)=>{c(r,e,((a,n)=>(a||t)&&((n=i(e))||t)&&((!a||a[0]!==r)&&(a=[r,a]),(n||t)&&a.push(n),a)))};const m=r=>Array.isArray(r)?r[0]?h[r[0]](...r.slice(1)):()=>r[1]:e=>e?.[r],h={},b=(r,e,t=h[r])=>h[r]=(...r)=>e(...r)||t&&t(...r),A=(r,e,t)=>"()"===r[0]?A(r[1],e,t):"string"==typeof r?e.bind(0,(r=>r),(()=>r)):"."===r[0]?e.bind(0,m(r[1]),(r=r[2],()=>r)):"["===r[0]?e.bind(0,m(r[1]),m(r[2])):t?(r=m(r),e.bind(0,(e=>[r(e)]),(()=>0))):()=>a("Bad left value"),y=r=>r?a():[,(r=+n((r=>46===r||r>=48&&r<=57||(69===r||101===r?2:0))))!=r?a():r];o[46]=r=>!r&&y();for(let r=48;r<=57;r++)o[r]=y;const g={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},C=t=>(i,s,l="")=>{for(i&&a("Unexpected string"),n();(s=e.charCodeAt(r))-t;)92===s?(n(),s=n(),l+=g[s]||s):l+=n();return n()||a("Bad string"),[,l]};o[34]=C(34),o[39]=C(39),c("(",17,((r,e)=>r&&((e=i(0,41))?["(",r,e]:["(",r,""]))),b("(",((r,e,t)=>(t=""==e?()=>[]:","===e[0]?(e=e.slice(1).map(m),r=>e.map((e=>e(r)))):(e=m(e),r=>[e(r)]),A(r,((r,e,a)=>r(a)[e(a)](...t(a))),!0)))),c("[",17,(r=>r&&["[",r,i(0,93)||a()])),b("[",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)[e(t)]))),c(".",17,((r,e)=>r&&(e=i(17))&&[".",r,e])),b(".",((r,e)=>(r=m(r),e=e[0]?e:e[1],t=>r(t)[e]))),c("(",17,(r=>!r&&["()",i(0,41)||a("Empty group")])),b("()",(r=>m(r)));const $=(...r)=>(r=r.map(m),e=>r.map((r=>r(e))).pop());u(",",1),b(",",$),u(";",1,!0),b(";",$),f("*",12),b("*",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)*e(t)))),f("/",12),b("/",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)/e(t)))),f("%",12),b("%",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)%e(t)))),f("*=",2,!0),b("*=",((r,e)=>(e=m(e),A(r,((r,t,a)=>r(a)[t(a)]*=e(a)))))),f("/=",2,!0),b("/=",((r,e)=>(e=m(e),A(r,((r,t,a)=>r(a)[t(a)]/=e(a)))))),f("%=",2,!0),b("%=",((r,e)=>(e=m(e),A(r,((r,t,a)=>r(a)[t(a)]%=e(a)))))),d("+",14),b("+",((r,e)=>!e&&(r=m(r),e=>+r(e)))),d("-",14),b("-",((r,e)=>!e&&(r=m(r),e=>-r(e)))),f("+",11),b("+",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)+e(t)))),f("-",11),b("-",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)-e(t)))),f("+=",2,!0),b("+=",((r,e)=>(e=m(e),A(r,((r,t,a)=>r(a)[t(a)]+=e(a)))))),f("-=",2,!0),b("-=",((r,e)=>(e=m(e),A(r,((r,t,a)=>r(a)[t(a)]-=e(a)))))),c("++",15,(r=>r?["-",["++",r],[,1]]:["++",i(14)])),b("++",(r=>A(r,((r,e,t)=>++r(t)[e(t)])))),c("--",15,(r=>r?["+",["--",r],[,1]]:["--",i(14)])),b("--",(r=>A(r,((r,e,t)=>--r(t)[e(t)])))),d("~",14),b("~",((r,e)=>!e&&(r=m(r),e=>~r(e)))),f("|",5),b("|",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)|e(t)))),f("&",7),b("&",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)&e(t)))),f("^",6),b("^",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)^e(t)))),f(">>",10),b(">>",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)>>e(t)))),f("<<",10),b("<<",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)<<e(t)))),f("==",8),b("==",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)==e(t)))),f("!=",8),b("!=",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)!=e(t)))),f(">",8),b(">",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)>e(t)))),f("<",8),b("<",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)<e(t)))),f(">=",8),b(">=",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)>=e(t)))),f("<=",8),b("<=",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)<=e(t)))),d("!",14),b("!",((r,e)=>!e&&(r=m(r),e=>!r(e)))),u("||",3),b("||",((...r)=>(r=r.map(m),e=>{let t,a;for(t of r)if(a=t(e))return a;return a}))),u("&&",4),b("&&",((...r)=>(r=r.map(m),e=>{let t,a;for(t of r)if(!(a=t(e)))return a;return a}))),f("=",2,!0),b("=",((r,e)=>(e=m(e),A(r,((r,t,a)=>r(a)[t(a)]=e(a))))));var v=r=>m(t(r));c("/*",20,((t,a)=>(n((t=>42!==t&&47!==e.charCodeAt(r+1))),n(2),t||i(a)||[""]))),c("//",20,((r,e)=>(n((r=>r>=32)),r||i(e)||[""]))),f("**",13,!0),b("**",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)**e(t)))),f("in",9),b("in",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)in e(t)))),c("?",2,((r,e,t)=>r&&(e=i(2,58))&&["?",r,e,i(3)])),b("?",((r,e,t)=>(r=m(r),e=m(e),t=m(t),a=>r(a)?e(a):t(a)))),c("true",20,(r=>r?err():[,!0])),c("false",20,(r=>r?err():[,!1])),c("[",20,(r=>!r&&["[",i(0,93)||""])),b("[",((r,e)=>!e&&(r?","===r[0]?(r=r.slice(1).map(m),e=>r.map((r=>r(e)))):(r=m(r),e=>[r(e)]):()=>[]))),c("{",20,(r=>!r&&["{",i(0,125)||""])),b("{",((r,e)=>r?","===r[0]?(r=r.slice(1).map(m),e=>Object.fromEntries(r.map((r=>r(e))))):":"===r[0]?(r=m(r),e=>Object.fromEntries([r(e)])):(e=m(r),t=>({[r]:e(t)})):r=>({}))),c(":",1.1,((r,e)=>[":",r,i(1.1)||err()])),b(":",((r,e)=>(e=m(e),r=Array.isArray(r)?m(r):(r=>r).bind(0,r),t=>[r(t),e(t)]))),f("??",5),b("??",((r,e)=>e&&(r=m(r),e=m(e),t=>r(t)??e(t)))),c("?.",17,(r=>r&&["?.",r])),b("?.",(r=>(r=m(r),e=>r(e)||(()=>{})))),c("?.",17,((r,e)=>r&&!(e=i(17))?.map&&["?.",r,e])),b("?.",((r,e)=>e&&(r=m(r),t=>r(t)?.[e]))),b("(",((r,e,t,a,n,i)=>null!=e&&"?."===r[0]&&(r[2]||Array.isArray(r[1]))&&(a=""==e?()=>[]:","===e[0]?(e=e.slice(1).map(m),r=>e.map((e=>e(r)))):(e=m(e),r=>[e(r)]),!r[2]&&(r=r[1]),n="["===r[0]?m(r[2]):()=>r[2],t=m(r[1]),r=>t(r)?.[n(r)]?.(...a(r))))),c("null",20,(r=>r?a():[,null]));export{A as access,f as binary,m as compile,e as cur,v as default,a as err,i as expr,l as id,r as idx,s as isId,o as lookup,u as nary,b as operator,h as operators,t as parse,n as skip,p as space,c as token,d as unary};
1
+ let r,e,t=t=>(r=0,e=t,t=n(),e[r]?a():t||""),a=(t="Bad syntax",a=e.slice(0,r).split("\n"),s=a.pop())=>{let n=e.slice(r-108,r).split("\n").pop(),i=e.slice(r,r+108).split("\n").shift();throw EvalError(`${t} at ${a.length}:${s.length} \`${r>=108?"…":""}${n}▶${i}\``,"font-weight: bold")},s=(t=1,a=r,s)=>{if("number"==typeof t)r+=t;else for(;s=t(e.charCodeAt(r));)r+=s;return e.slice(a,r)},n=(e=0,s,n,i,p,l)=>{for(;(n=t.space())&&(p=((l=o[n])&&l(i,e))??(!i&&t.id()));)i=p;return s&&(n==s?r++:a()),i},i=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r,p=t.id=()=>s(i),l=t.space=t=>{for(;(t=e.charCodeAt(r))<=32;)r++;return t},o=[],c=(t,a=32,s,n=t.charCodeAt(0),p=t.length,l=o[n],c=t.toUpperCase()!==t)=>o[n]=(n,o,d=r)=>o<a&&(p<2||e.substr(r,p)==t)&&(!c||!i(e.charCodeAt(r+p)))&&(r+=p,s(n,o))||(r=d,l?.(n,o)),d=(r,e,t=!1)=>c(r,e,((a,s)=>a&&(s=n(e-(t?.5:0)))&&[r,a,s])),f=(r,e,t)=>c(r,e,(a=>t?a&&[r,a]:!a&&(a=n(e-.5))&&[r,a])),h=(r,e)=>{c(r,e,((t,a)=>(a=n(e),(!t||t[0]!==r)&&(t=[r,t]),t.push(a),t)))},m=(r,e)=>c(r[0],e,(e=>!e&&[r,n(0,r.charCodeAt(1))])),A=(r,e)=>c(r[0],e,(e=>e&&[r[0],e,n(0,r.charCodeAt(1))]));const b=r=>Array.isArray(r)?r[0]?u[r[0]](...r.slice(1)):()=>r[1]:e=>e?.[r],u={},y=(r,e,t=u[r])=>u[r]=(...r)=>e(...r)||t&&t(...r),C=(r,e,t)=>"()"===r[0]?C(r[1],e,t):"string"==typeof r?e.bind(0,(r=>r),(()=>r)):"."===r[0]?e.bind(0,b(r[1]),(r=r[2],()=>r)):"["===r[0]?e.bind(0,b(r[1]),b(r[2])):t?(r=b(r),e.bind(0,(e=>[r(e)]),(()=>0))):()=>a("Bad left value"),g=r=>r?a():[,(r=+s((r=>46===r||r>=48&&r<=57||(69===r||101===r?2:0))))!=r?a():r];o[46]=r=>!r&&g();for(let r=48;r<=57;r++)o[r]=g;const $={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},v=t=>(n,i,p="")=>{for(n&&a("Unexpected string"),s();(i=e.charCodeAt(r))-t;)92===i?(s(),i=s(),p+=$[i]||i):p+=s();return s()||a("Bad string"),[,p]};o[34]=v(34),o[39]=v(39),A("()",17),y("(",((r,e,t)=>(t=e?","===e[0]?(e=e.slice(1).map((r=>r?b(r):err())),r=>e.map((e=>e(r)))):(e=b(e),r=>[e(r)]):()=>[],C(r,((r,e,a)=>r(a)[e(a)](...t(a))),!0)))),A("[]",17),y("[",((r,e)=>e?(r=b(r),e=b(e),t=>r(t)[e(t)]):err())),d(".",17),y(".",((r,e)=>(r=b(r),e=e[0]?e:e[1],t=>r(t)[e]))),m("()",17),y("()",(r=>(!r&&a("Empty ()"),b(r))));const E=(...r)=>(r=r.map(b),e=>r.map((r=>r(e))).pop());h(",",1),y(",",E),h(";",1),y(";",E),d("*",12),y("*",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)*e(t)))),d("/",12),y("/",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)/e(t)))),d("%",12),y("%",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)%e(t)))),d("*=",2,!0),y("*=",((r,e)=>(e=b(e),C(r,((r,t,a)=>r(a)[t(a)]*=e(a)))))),d("/=",2,!0),y("/=",((r,e)=>(e=b(e),C(r,((r,t,a)=>r(a)[t(a)]/=e(a)))))),d("%=",2,!0),y("%=",((r,e)=>(e=b(e),C(r,((r,t,a)=>r(a)[t(a)]%=e(a)))))),f("+",14),y("+",((r,e)=>!e&&(r=b(r),e=>+r(e)))),f("-",14),y("-",((r,e)=>!e&&(r=b(r),e=>-r(e)))),d("+",11),y("+",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)+e(t)))),d("-",11),y("-",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)-e(t)))),d("+=",2,!0),y("+=",((r,e)=>(e=b(e),C(r,((r,t,a)=>r(a)[t(a)]+=e(a)))))),d("-=",2,!0),y("-=",((r,e)=>(e=b(e),C(r,((r,t,a)=>r(a)[t(a)]-=e(a)))))),c("++",15,(r=>r?["-",["++",r],[,1]]:["++",n(14)])),y("++",(r=>C(r,((r,e,t)=>++r(t)[e(t)])))),c("--",15,(r=>r?["+",["--",r],[,1]]:["--",n(14)])),y("--",(r=>C(r,((r,e,t)=>--r(t)[e(t)])))),f("~",14),y("~",((r,e)=>!e&&(r=b(r),e=>~r(e)))),d("|",5),y("|",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)|e(t)))),d("&",7),y("&",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)&e(t)))),d("^",6),y("^",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)^e(t)))),d(">>",10),y(">>",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)>>e(t)))),d("<<",10),y("<<",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)<<e(t)))),d("==",8),y("==",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)==e(t)))),d("!=",8),y("!=",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)!=e(t)))),d(">",8),y(">",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)>e(t)))),d("<",8),y("<",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)<e(t)))),d(">=",8),y(">=",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)>=e(t)))),d("<=",8),y("<=",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)<=e(t)))),f("!",14),y("!",((r,e)=>!e&&(r=b(r),e=>!r(e)))),d("||",3),y("||",((r,e)=>(r=b(r),e=b(e),t=>r(t)||e(t)))),d("&&",4),y("&&",((r,e)=>(r=b(r),e=b(e),t=>r(t)&&e(t)))),d("=",2,!0),y("=",((r,e)=>(e=b(e),C(r,((r,t,a)=>r(a)[t(a)]=e(a))))));var x=r=>b(t(r));c("/*",20,((t,a)=>(s((t=>42!==t&&47!==e.charCodeAt(r+1))),s(2),t||n(a)||[]))),c("//",20,((r,e)=>(s((r=>r>=32)),r||n(e)||[""]))),d("**",13,!0),y("**",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)**e(t)))),d("in",9),y("in",((r,e)=>e&&(r=b(r),e=b(e),t=>r(t)in e(t)))),c("?",2,((r,e,t)=>r&&(e=n(2,58))&&["?",r,e,n(3)])),y("?",((r,e,t)=>(r=b(r),e=b(e),t=b(t),a=>r(a)?e(a):t(a)))),c("true",20,(r=>r?err():[,!0])),c("false",20,(r=>r?err():[,!1])),m("[]",20),y("[]",((r,e)=>r?","===r[0]?(r=r.slice(1).map(b),e=>r.map((r=>r(e)))):(r=b(r),e=>[r(e)]):()=>[])),m("{}",20),y("{}",((r,e)=>r?","===r[0]?(r=r.slice(1).map(b),e=>Object.fromEntries(r.map((r=>r(e))))):":"===r[0]?(r=b(r),e=>Object.fromEntries([r(e)])):(e=b(r),t=>({[r]:e(t)})):()=>({}))),d(":",2,!0),y(":",((r,e)=>(e=b(e),r=Array.isArray(r)?b(r):(r=>r).bind(0,r),t=>[r(t),e(t)]))),c("?.",17,(r=>r&&["?.",r])),y("?.",(r=>(r=b(r),e=>r(e)||(()=>{})))),c("?.",17,((r,e)=>r&&!(e=n(17))?.map&&["?.",r,e])),y("?.",((r,e)=>e&&(r=b(r),t=>r(t)?.[e]))),y("(",((r,e,t,a,s,n)=>"?."===r[0]&&(r[2]||Array.isArray(r[1]))&&(a=e?","===e[0]?(e=e.slice(1).map(b),r=>e.map((e=>e(r)))):(e=b(e),r=>[e(r)]):()=>[],!r[2]&&(r=r[1]),s="["===r[0]?b(r[2]):()=>r[2],t=b(r[1]),r=>t(r)?.[s(r)]?.(...a(r))))),c("null",20,(r=>r?a():[,null]));export{A as access,d as binary,b as compile,e as cur,x as default,a as err,n as expr,m as group,p as id,r as idx,i as isId,o as lookup,h as nary,y as operator,u as operators,t as parse,C as prop,s as skip,l as space,c as token,f as unary};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "subscript",
3
- "version": "8.0.1",
3
+ "version": "8.1.1",
4
4
  "description": "Fast and tiny expression evaluator with minimal syntax.",
5
5
  "main": "subscript.js",
6
6
  "module": "subscript.js",
package/src/compile.js CHANGED
@@ -10,9 +10,9 @@ export const compile = (node) => !Array.isArray(node) ? ctx => ctx?.[node] : !no
10
10
  operator = (op, fn, prev = operators[op]) => (operators[op] = (...args) => fn(...args) || prev && prev(...args)),
11
11
 
12
12
  // takes node and returns evaluator depending on the case with passed params (container, path, ctx) =>
13
- access = (a, fn, generic) => (
13
+ prop = (a, fn, generic) => (
14
14
  // (((x))) => x
15
- a[0] === '()' ? access(a[1], fn, generic) :
15
+ a[0] === '()' ? prop(a[1], fn, generic) :
16
16
  // (_, name, ctx) => ctx[path]
17
17
  typeof a === 'string' ? fn.bind(0, ctx => ctx, () => a) :
18
18
  // (container, path, ctx) => container(ctx)[path]
package/src/parse.js CHANGED
@@ -35,7 +35,6 @@ export let idx, cur,
35
35
  ) token = newNode;
36
36
 
37
37
  // check end character
38
- // FIXME: can't show "Unclosed paren", because can be unknown operator within group as well
39
38
  if (end) cc == end ? idx++ : err()
40
39
 
41
40
  return token
@@ -49,7 +48,7 @@ export let idx, cur,
49
48
  (c >= 192 && c != 215 && c != 247), // any non-ASCII
50
49
 
51
50
  // parse identifier (configurable)
52
- id = parse.id = n => skip(isId),
51
+ id = parse.id = () => skip(isId),
53
52
 
54
53
  // skip space chars, return first non-space character
55
54
  space = parse.space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
@@ -73,22 +72,29 @@ export let idx, cur,
73
72
  (idx = from, prev?.(a, curPrec)),
74
73
 
75
74
  // right assoc is indicated by negative precedence (meaning go from right to left)
76
- binary = (op, prec, right = 0) => token(op, prec, (a, b) => a && (b = expr(prec - right / 2)) && [op, a, b]),
75
+ binary = (op, prec, right = false) => token(op, prec, (a, b) => a && (b = expr(prec - (right ? .5 : 0))) && [op, a, b]),
77
76
 
78
77
  // post indicates postfix rather than prefix operator
79
78
  unary = (op, prec, post) => token(op, prec, a => post ? (a && [op, a]) : (!a && (a = expr(prec - .5)) && [op, a])),
80
79
 
81
80
  // skips means ,,, ;;; are allowed
82
- nary = (op, prec, skips) => {
81
+ nary = (op, prec) => {
83
82
  token(op, prec, (a, b) => (
84
- (a || skips) && // if lhs exists or we're ok to skip
85
- (b = expr(prec), b || skips) && // either rhs exists or we're ok to skip rhs
83
+ (b = expr(prec)),
86
84
  (
87
85
  (!a || a[0] !== op) && (a = [op, a]), // if beginning of sequence - init node
88
- (b || skips) && a.push(b),
86
+ a.push(b),
89
87
  a
90
88
  ))
91
89
  )
92
- }
90
+ },
91
+
92
+ // register (a), [b], {c} etc groups
93
+ // FIXME: add "Unclosed paren" error
94
+ group = (op, prec) => token(op[0], prec, a => (!a && ([op, expr(0, op.charCodeAt(1))]))),
95
+
96
+ // register a(b), a[b], a<b> etc,
97
+ access = (op, prec) => token(op[0], prec, a => (a && [op[0], a, expr(0, op.charCodeAt(1))]))
98
+
93
99
 
94
100
  export default parse
package/subscript.min.js CHANGED
@@ -1 +1 @@
1
- let t,r,e=e=>(t=0,r=e,e=s(),r[t]?n():e||""),n=(e="Bad syntax",n=r.slice(0,t).split("\n"),o=n.pop())=>{let s=r.slice(t-108,t).split("\n").pop(),a=r.slice(t,t+108).split("\n").shift();throw EvalError(`${e} at ${n.length}:${o.length} \`${t>=108?"…":""}${s}▶${a}\``,"font-weight: bold")},o=(e=1,n=t,o)=>{if("number"==typeof e)t+=e;else for(;o=e(r.charCodeAt(t));)t+=o;return r.slice(n,t)},s=(r=0,o,s,a,p,i)=>{for(;(s=e.space())&&(p=((i=l[s])&&i(a,r))??(!a&&e.id()));)a=p;return o&&(s==o?t++:n()),a},a=t=>t>=48&&t<=57||t>=65&&t<=90||t>=97&&t<=122||36==t||95==t||t>=192&&215!=t&&247!=t,p=e.id=t=>o(a),i=e.space=e=>{for(;(e=r.charCodeAt(t))<=32;)t++;return e},l=[],f=(e,n=32,o,s=e.charCodeAt(0),p=e.length,i=l[s],f=e.toUpperCase()!==e)=>l[s]=(s,l,c=t)=>l<n&&(p<2||r.substr(t,p)==e)&&(!f||!a(r.charCodeAt(t+p)))&&(t+=p,o(s,l))||(t=c,i?.(s,l)),c=(t,r,e=0)=>f(t,r,((n,o)=>n&&(o=s(r-e/2))&&[t,n,o])),d=(t,r,e)=>f(t,r,(n=>e?n&&[t,n]:!n&&(n=s(r-.5))&&[t,n])),u=(t,r,e)=>{f(t,r,((n,o)=>(n||e)&&((o=s(r))||e)&&((!n||n[0]!==t)&&(n=[t,n]),(o||e)&&n.push(o),n)))};const h=t=>t?n():[,(t=+o((t=>46===t||t>=48&&t<=57||(69===t||101===t?2:0))))!=t?n():t];l[46]=t=>!t&&h();for(let t=48;t<=57;t++)l[t]=h;const b={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},g=e=>(s,a,p="")=>{for(s&&n("Unexpected string"),o();(a=r.charCodeAt(t))-e;)92===a?(o(),a=o(),p+=b[a]||a):p+=o();return o()||n("Bad string"),[,p]};l[34]=g(34),l[39]=g(39);const m=t=>Array.isArray(t)?t[0]?A[t[0]](...t.slice(1)):()=>t[1]:r=>r?.[t],A={},y=(t,r,e=A[t])=>A[t]=(...t)=>r(...t)||e&&e(...t),C=(t,r,e)=>"()"===t[0]?C(t[1],r,e):"string"==typeof t?r.bind(0,(t=>t),(()=>t)):"."===t[0]?r.bind(0,m(t[1]),(t=t[2],()=>t)):"["===t[0]?r.bind(0,m(t[1]),m(t[2])):e?(t=m(t),r.bind(0,(r=>[t(r)]),(()=>0))):()=>n("Bad left value");f("(",17,((t,r)=>t&&((r=s(0,41))?["(",t,r]:["(",t,""]))),y("(",((t,r,e)=>(e=""==r?()=>[]:","===r[0]?(r=r.slice(1).map(m),t=>r.map((r=>r(t)))):(r=m(r),t=>[r(t)]),C(t,((t,r,n)=>t(n)[r(n)](...e(n))),!0)))),f("[",17,(t=>t&&["[",t,s(0,93)||n()])),y("[",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)[r(e)]))),f(".",17,((t,r)=>t&&(r=s(17))&&[".",t,r])),y(".",((t,r)=>(t=m(t),r=r[0]?r:r[1],e=>t(e)[r]))),f("(",17,(t=>!t&&["()",s(0,41)||n("Empty group")])),y("()",(t=>m(t)));const $=(...t)=>(t=t.map(m),r=>t.map((t=>t(r))).pop());u(",",1),y(",",$),u(";",1,!0),y(";",$),c("*",12),y("*",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)*r(e)))),c("/",12),y("/",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)/r(e)))),c("%",12),y("%",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)%r(e)))),c("*=",2,!0),y("*=",((t,r)=>(r=m(r),C(t,((t,e,n)=>t(n)[e(n)]*=r(n)))))),c("/=",2,!0),y("/=",((t,r)=>(r=m(r),C(t,((t,e,n)=>t(n)[e(n)]/=r(n)))))),c("%=",2,!0),y("%=",((t,r)=>(r=m(r),C(t,((t,e,n)=>t(n)[e(n)]%=r(n)))))),d("+",14),y("+",((t,r)=>!r&&(t=m(t),r=>+t(r)))),d("-",14),y("-",((t,r)=>!r&&(t=m(t),r=>-t(r)))),c("+",11),y("+",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)+r(e)))),c("-",11),y("-",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)-r(e)))),c("+=",2,!0),y("+=",((t,r)=>(r=m(r),C(t,((t,e,n)=>t(n)[e(n)]+=r(n)))))),c("-=",2,!0),y("-=",((t,r)=>(r=m(r),C(t,((t,e,n)=>t(n)[e(n)]-=r(n)))))),f("++",15,(t=>t?["-",["++",t],[,1]]:["++",s(14)])),y("++",(t=>C(t,((t,r,e)=>++t(e)[r(e)])))),f("--",15,(t=>t?["+",["--",t],[,1]]:["--",s(14)])),y("--",(t=>C(t,((t,r,e)=>--t(e)[r(e)])))),d("~",14),y("~",((t,r)=>!r&&(t=m(t),r=>~t(r)))),c("|",5),y("|",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)|r(e)))),c("&",7),y("&",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)&r(e)))),c("^",6),y("^",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)^r(e)))),c(">>",10),y(">>",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)>>r(e)))),c("<<",10),y("<<",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)<<r(e)))),c("==",8),y("==",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)==r(e)))),c("!=",8),y("!=",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)!=r(e)))),c(">",8),y(">",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)>r(e)))),c("<",8),y("<",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)<r(e)))),c(">=",8),y(">=",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)>=r(e)))),c("<=",8),y("<=",((t,r)=>r&&(t=m(t),r=m(r),e=>t(e)<=r(e)))),d("!",14),y("!",((t,r)=>!r&&(t=m(t),r=>!t(r)))),u("||",3),y("||",((...t)=>(t=t.map(m),r=>{let e,n;for(e of t)if(n=e(r))return n;return n}))),u("&&",4),y("&&",((...t)=>(t=t.map(m),r=>{let e,n;for(e of t)if(!(n=e(r)))return n;return n}))),c("=",2,!0),y("=",((t,r)=>(r=m(r),C(t,((t,e,n)=>t(n)[e(n)]=r(n))))));var v=t=>m(e(t));export{C as access,c as binary,m as compile,r as cur,v as default,n as err,s as expr,p as id,t as idx,a as isId,l as lookup,u as nary,y as operator,A as operators,e as parse,o as skip,i as space,f as token,d as unary};
1
+ let r,t,e=e=>(r=0,t=e,e=n(),t[r]?s():e||""),s=(e="Bad syntax",s=t.slice(0,r).split("\n"),a=s.pop())=>{let n=t.slice(r-108,r).split("\n").pop(),o=t.slice(r,r+108).split("\n").shift();throw EvalError(`${e} at ${s.length}:${a.length} \`${r>=108?"…":""}${n}▶${o}\``,"font-weight: bold")},a=(e=1,s=r,a)=>{if("number"==typeof e)r+=e;else for(;a=e(t.charCodeAt(r));)r+=a;return t.slice(s,r)},n=(t=0,a,n,o,p,i)=>{for(;(n=e.space())&&(p=((i=l[n])&&i(o,t))??(!o&&e.id()));)o=p;return a&&(n==a?r++:s()),o},o=r=>r>=48&&r<=57||r>=65&&r<=90||r>=97&&r<=122||36==r||95==r||r>=192&&215!=r&&247!=r,p=e.id=()=>a(o),i=e.space=e=>{for(;(e=t.charCodeAt(r))<=32;)r++;return e},l=[],c=(e,s=32,a,n=e.charCodeAt(0),p=e.length,i=l[n],c=e.toUpperCase()!==e)=>l[n]=(n,l,d=r)=>l<s&&(p<2||t.substr(r,p)==e)&&(!c||!o(t.charCodeAt(r+p)))&&(r+=p,a(n,l))||(r=d,i?.(n,l)),d=(r,t,e=!1)=>c(r,t,((s,a)=>s&&(a=n(t-(e?.5:0)))&&[r,s,a])),f=(r,t,e)=>c(r,t,(s=>e?s&&[r,s]:!s&&(s=n(t-.5))&&[r,s])),h=(r,t)=>{c(r,t,((e,s)=>(s=n(t),(!e||e[0]!==r)&&(e=[r,e]),e.push(s),e)))},b=(r,t)=>c(r[0],t,(t=>!t&&[r,n(0,r.charCodeAt(1))])),u=(r,t)=>c(r[0],t,(t=>t&&[r[0],t,n(0,r.charCodeAt(1))]));const A=r=>r?s():[,(r=+a((r=>46===r||r>=48&&r<=57||(69===r||101===r?2:0))))!=r?s():r];l[46]=r=>!r&&A();for(let r=48;r<=57;r++)l[r]=A;const C={n:"\n",r:"\r",t:"\t",b:"\b",f:"\f",v:"\v"},g=e=>(n,o,p="")=>{for(n&&s("Unexpected string"),a();(o=t.charCodeAt(r))-e;)92===o?(a(),o=a(),p+=C[o]||o):p+=a();return a()||s("Bad string"),[,p]};l[34]=g(34),l[39]=g(39);const m=r=>Array.isArray(r)?r[0]?y[r[0]](...r.slice(1)):()=>r[1]:t=>t?.[r],y={},$=(r,t,e=y[r])=>y[r]=(...r)=>t(...r)||e&&e(...r),v=(r,t,e)=>"()"===r[0]?v(r[1],t,e):"string"==typeof r?t.bind(0,(r=>r),(()=>r)):"."===r[0]?t.bind(0,m(r[1]),(r=r[2],()=>r)):"["===r[0]?t.bind(0,m(r[1]),m(r[2])):e?(r=m(r),t.bind(0,(t=>[r(t)]),(()=>0))):()=>s("Bad left value");u("()",17),$("(",((r,t,e)=>(e=t?","===t[0]?(t=t.slice(1).map((r=>r?m(r):err())),r=>t.map((t=>t(r)))):(t=m(t),r=>[t(r)]):()=>[],v(r,((r,t,s)=>r(s)[t(s)](...e(s))),!0)))),u("[]",17),$("[",((r,t)=>t?(r=m(r),t=m(t),e=>r(e)[t(e)]):err())),d(".",17),$(".",((r,t)=>(r=m(r),t=t[0]?t:t[1],e=>r(e)[t]))),b("()",17),$("()",(r=>(!r&&s("Empty ()"),m(r))));const x=(...r)=>(r=r.map(m),t=>r.map((r=>r(t))).pop());h(",",1),$(",",x),h(";",1),$(";",x),d("*",12),$("*",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)*t(e)))),d("/",12),$("/",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)/t(e)))),d("%",12),$("%",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)%t(e)))),d("*=",2,!0),$("*=",((r,t)=>(t=m(t),v(r,((r,e,s)=>r(s)[e(s)]*=t(s)))))),d("/=",2,!0),$("/=",((r,t)=>(t=m(t),v(r,((r,e,s)=>r(s)[e(s)]/=t(s)))))),d("%=",2,!0),$("%=",((r,t)=>(t=m(t),v(r,((r,e,s)=>r(s)[e(s)]%=t(s)))))),f("+",14),$("+",((r,t)=>!t&&(r=m(r),t=>+r(t)))),f("-",14),$("-",((r,t)=>!t&&(r=m(r),t=>-r(t)))),d("+",11),$("+",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)+t(e)))),d("-",11),$("-",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)-t(e)))),d("+=",2,!0),$("+=",((r,t)=>(t=m(t),v(r,((r,e,s)=>r(s)[e(s)]+=t(s)))))),d("-=",2,!0),$("-=",((r,t)=>(t=m(t),v(r,((r,e,s)=>r(s)[e(s)]-=t(s)))))),c("++",15,(r=>r?["-",["++",r],[,1]]:["++",n(14)])),$("++",(r=>v(r,((r,t,e)=>++r(e)[t(e)])))),c("--",15,(r=>r?["+",["--",r],[,1]]:["--",n(14)])),$("--",(r=>v(r,((r,t,e)=>--r(e)[t(e)])))),f("~",14),$("~",((r,t)=>!t&&(r=m(r),t=>~r(t)))),d("|",5),$("|",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)|t(e)))),d("&",7),$("&",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)&t(e)))),d("^",6),$("^",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)^t(e)))),d(">>",10),$(">>",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)>>t(e)))),d("<<",10),$("<<",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)<<t(e)))),d("==",8),$("==",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)==t(e)))),d("!=",8),$("!=",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)!=t(e)))),d(">",8),$(">",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)>t(e)))),d("<",8),$("<",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)<t(e)))),d(">=",8),$(">=",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)>=t(e)))),d("<=",8),$("<=",((r,t)=>t&&(r=m(r),t=m(t),e=>r(e)<=t(e)))),f("!",14),$("!",((r,t)=>!t&&(r=m(r),t=>!r(t)))),d("||",3),$("||",((r,t)=>(r=m(r),t=m(t),e=>r(e)||t(e)))),d("&&",4),$("&&",((r,t)=>(r=m(r),t=m(t),e=>r(e)&&t(e)))),d("=",2,!0),$("=",((r,t)=>(t=m(t),v(r,((r,e,s)=>r(s)[e(s)]=t(s))))));var B=r=>m(e(r));export{u as access,d as binary,m as compile,t as cur,B as default,s as err,n as expr,b as group,p as id,r as idx,o as isId,l as lookup,h as nary,$ as operator,y as operators,e as parse,v as prop,a as skip,i as space,c as token,f as unary};