subscript 7.6.2 → 8.0.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 +100 -215
- package/feature/access.js +11 -0
- package/feature/add.js +22 -0
- package/feature/array.js +11 -0
- package/feature/assign.js +11 -0
- package/feature/bitwise.js +15 -0
- package/feature/bool.js +5 -0
- package/feature/call.js +15 -0
- package/feature/comment.js +6 -0
- package/feature/compare.js +11 -0
- package/feature/group.js +12 -0
- package/feature/in.js +6 -0
- package/feature/increment.js +16 -0
- package/feature/logic.js +15 -0
- package/feature/mult.js +25 -0
- package/feature/number.js +11 -0
- package/feature/object.js +17 -0
- package/feature/pow.js +5 -0
- package/feature/string.js +19 -0
- package/feature/ternary.js +7 -0
- package/justin.js +24 -71
- package/justin.min.js +1 -1
- package/package.json +5 -5
- package/src/compile.d.ts +17 -0
- package/src/compile.js +26 -0
- package/src/const.js +40 -0
- package/src/parse.d.ts +19 -0
- package/{parse.js → src/parse.js} +6 -6
- package/subscript.js +22 -127
- package/subscript.min.js +1 -1
- package/compile.js +0 -8
package/justin.js
CHANGED
|
@@ -1,41 +1,31 @@
|
|
|
1
1
|
// justin lang https://github.com/endojs/Jessie/issues/66
|
|
2
|
-
import { skip, cur, idx, err, expr, lookup, token, binary } from './parse.js'
|
|
3
|
-
import compile, { operator } from './compile.js'
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
if (c === BSLASH) skip(), c = skip(), str += escape[c] || c
|
|
16
|
-
else str += skip()
|
|
17
|
-
}
|
|
18
|
-
skip() || err('Bad string')
|
|
19
|
-
return ['', str]
|
|
20
|
-
}
|
|
2
|
+
import { skip, cur, idx, err, expr, lookup, token, binary, unary } from './src/parse.js'
|
|
3
|
+
import compile, { operator } from './src/compile.js'
|
|
4
|
+
import { CPAREN, COLON, PREC_ASSIGN, PREC_PREFIX, PREC_OR, PREC_ACCESS, PREC_COMP, PREC_EXP, PREC_GROUP } from './src/const.js'
|
|
5
|
+
|
|
6
|
+
// register subscript operators set
|
|
7
|
+
import subscript from './subscript.js'
|
|
8
|
+
import './feature/comment.js'
|
|
9
|
+
import './feature/pow.js'
|
|
10
|
+
import './feature/in.js'
|
|
11
|
+
import './feature/ternary.js'
|
|
12
|
+
import './feature/bool.js'
|
|
13
|
+
import './feature/array.js'
|
|
14
|
+
import './feature/object.js'
|
|
21
15
|
|
|
22
16
|
// operators
|
|
23
17
|
// set('===', PREC_EQ, (a, b) => a === b)
|
|
24
18
|
// set('!==', PREC_EQ, (a, b) => a !== b)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
// ?:
|
|
28
|
-
token('?', PREC_COND, (a, b, c) => a && (b = expr(2, 58)) && (c = expr(3), ['?', a, b, c]))
|
|
29
|
-
operator('?', (a, b, c) => (a = compile(a), b = compile(b), c = compile(c), ctx => a(ctx) ? b(ctx) : c(ctx)))
|
|
30
|
-
|
|
31
|
-
set('??', PREC_OR, (a, b) => a ?? b)
|
|
19
|
+
binary('??', PREC_OR), operator('??', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx) ?? b(ctx)))
|
|
32
20
|
|
|
33
21
|
// a?.[, a?.( - postfix operator
|
|
34
|
-
token('?.',
|
|
22
|
+
token('?.', PREC_ACCESS, a => a && ['?.', a])
|
|
23
|
+
// a ?.
|
|
35
24
|
operator('?.', a => (a = compile(a), ctx => a(ctx) || (() => { })))
|
|
36
25
|
|
|
37
26
|
// a?.b, a?.() - optional chain operator
|
|
38
|
-
token('?.',
|
|
27
|
+
token('?.', PREC_ACCESS, (a, b) => a && (b = expr(PREC_ACCESS), !b?.map) && ['?.', a, b])
|
|
28
|
+
// a ?. b
|
|
39
29
|
operator('?.', (a, b) => b && (a = compile(a), ctx => a(ctx)?.[b]))
|
|
40
30
|
|
|
41
31
|
// a?.x() - keep context, but watch out a?.()
|
|
@@ -43,59 +33,22 @@ operator('(', (a, b, container, args, path, optional) => (b != null) && (a[0] ==
|
|
|
43
33
|
args = b == '' ? () => [] : // a()
|
|
44
34
|
b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(a => a(ctx))) : // a(b,c)
|
|
45
35
|
(b = compile(b), ctx => [b(ctx)]), // a(b)
|
|
36
|
+
|
|
46
37
|
// a?.()
|
|
47
38
|
!a[2] && (optional = true, a = a[1]),
|
|
39
|
+
|
|
48
40
|
// a?.['x']?.()
|
|
49
|
-
a[0] === '[' ? (path = compile(a[2])) : (path =
|
|
41
|
+
a[0] === '[' ? (path = compile(a[2])) : (path = () => a[2]),
|
|
50
42
|
(container = compile(a[1]), optional ?
|
|
51
43
|
ctx => (container(ctx)?.[path(ctx)]?.(...args(ctx))) :
|
|
52
44
|
ctx => (container(ctx)?.[path(ctx)](...args(ctx)))
|
|
53
45
|
)
|
|
54
46
|
))
|
|
55
47
|
|
|
56
|
-
// a in b
|
|
57
|
-
set('in', PREC_COMP, (a, b) => a in b)
|
|
58
|
-
|
|
59
|
-
// "' with /
|
|
60
|
-
lookup[DQUOTE] = string(DQUOTE)
|
|
61
|
-
lookup[QUOTE] = string(QUOTE)
|
|
62
|
-
|
|
63
|
-
// /**/, //
|
|
64
|
-
token('/*', 20, (a, prec) => (skip(c => c !== 42 && cur.charCodeAt(idx + 1) !== 47), skip(2), a || expr(prec) || ['']))
|
|
65
|
-
token('//', 20, (a, prec) => (skip(c => c >= 32), a || expr(prec) || ['']))
|
|
66
|
-
|
|
67
48
|
// literals
|
|
68
|
-
token('null', 20, a => a ? err() : [
|
|
69
|
-
token('
|
|
70
|
-
token('
|
|
71
|
-
// token('undefined', 20, a => a ? err() : ['', undefined])
|
|
72
|
-
// token('NaN', 20, a => a ? err() : ['', NaN])
|
|
73
|
-
|
|
74
|
-
set(';', -1, (...args) => args[args.length - 1])
|
|
75
|
-
|
|
76
|
-
// right order
|
|
77
|
-
// '**', (a,prec,b=expr(PREC_EXP-1)) => ctx=>a(ctx)**b(ctx), PREC_EXP,
|
|
78
|
-
set('**', -PREC_EXP, (a, b) => a ** b)
|
|
79
|
-
|
|
80
|
-
// [a,b,c]
|
|
81
|
-
token('[', 20, (a) => !a && ['[', expr(0, 93) || ''])
|
|
82
|
-
operator('[', (a, b) => !b && (
|
|
83
|
-
!a ? () => [] : // []
|
|
84
|
-
a[0] === ',' ? (a = a.slice(1).map(compile), ctx => a.map(a => a(ctx))) : // [a,b,c]
|
|
85
|
-
(a = compile(a), ctx => [a(ctx)]) // [a]
|
|
86
|
-
))
|
|
87
|
-
|
|
88
|
-
// {a:1, b:2, c:3}
|
|
89
|
-
token('{', 20, a => !a && (['{', expr(0, 125) || '']))
|
|
90
|
-
operator('{', (a, b) => (
|
|
91
|
-
!a ? ctx => ({}) : // {}
|
|
92
|
-
a[0] === ',' ? (a = a.slice(1).map(compile), ctx => Object.fromEntries(a.map(a => a(ctx)))) : // {a:1,b:2}
|
|
93
|
-
a[0] === ':' ? (a = compile(a), ctx => Object.fromEntries([a(ctx)])) : // {a:1}
|
|
94
|
-
(b = compile(a), ctx => ({ [a]: b(ctx) }))
|
|
95
|
-
))
|
|
96
|
-
|
|
97
|
-
token(':', 1.1, (a, b) => (b = expr(1.1) || err(), [':', a, b]))
|
|
98
|
-
operator(':', (a, b) => (b = compile(b), a = Array.isArray(a) ? compile(a) : (a => a).bind(0, a), ctx => [a(ctx), b(ctx)]))
|
|
49
|
+
token('null', 20, a => a ? err() : [, null])
|
|
50
|
+
// token('undefined', 20, a => a ? err() : [, undefined])
|
|
51
|
+
// token('NaN', 20, a => a ? err() : [, NaN])
|
|
99
52
|
|
|
100
53
|
export default subscript
|
|
101
54
|
export * from './subscript.js'
|
package/justin.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let e,t
|
|
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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "subscript",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.1",
|
|
4
4
|
"description": "Fast and tiny expression evaluator with minimal syntax.",
|
|
5
5
|
"main": "subscript.js",
|
|
6
6
|
"module": "subscript.js",
|
|
@@ -8,15 +8,15 @@
|
|
|
8
8
|
"types": "./subscript.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": "./subscript.js",
|
|
11
|
-
"./parse.js": "./parse.js",
|
|
12
|
-
"./compile.js": "./compile.js",
|
|
11
|
+
"./parse.js": "./src/parse.js",
|
|
12
|
+
"./compile.js": "./src/compile.js",
|
|
13
13
|
"./subscript.js": "./subscript.js",
|
|
14
14
|
"./justin.js": "./justin.js"
|
|
15
15
|
},
|
|
16
16
|
"type": "module",
|
|
17
17
|
"files": [
|
|
18
|
-
"
|
|
19
|
-
"
|
|
18
|
+
"src",
|
|
19
|
+
"feature",
|
|
20
20
|
"subscript.js",
|
|
21
21
|
"subscript.min.js",
|
|
22
22
|
"justin.js",
|
package/src/compile.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export type OperatorFunction = (...args: any[]) => any;
|
|
2
|
+
export type OperatorMap = {
|
|
3
|
+
[key: string]: OperatorFunction;
|
|
4
|
+
};
|
|
5
|
+
export type Node = string | [string | undefined, ...Node[]];
|
|
6
|
+
export function compile(node: Node): ((ctx?: any) => any) | OperatorFunction;
|
|
7
|
+
export const operators: OperatorMap;
|
|
8
|
+
export function operator(op: string, fn: OperatorFunction): void;
|
|
9
|
+
|
|
10
|
+
type AccessorFunction = (ctx: any) => any;
|
|
11
|
+
export function access(
|
|
12
|
+
a: [string, ...any[]] | string,
|
|
13
|
+
fn: Function,
|
|
14
|
+
generic: boolean
|
|
15
|
+
): AccessorFunction;
|
|
16
|
+
|
|
17
|
+
export default compile;
|
package/src/compile.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { err } from "./parse.js"
|
|
2
|
+
|
|
3
|
+
// build optimized evaluator for the tree
|
|
4
|
+
export const compile = (node) => !Array.isArray(node) ? ctx => ctx?.[node] : !node[0] ? () => node[1] : operators[node[0]](...node.slice(1)),
|
|
5
|
+
|
|
6
|
+
// registered operators
|
|
7
|
+
operators = {},
|
|
8
|
+
|
|
9
|
+
// register an operator
|
|
10
|
+
operator = (op, fn, prev = operators[op]) => (operators[op] = (...args) => fn(...args) || prev && prev(...args)),
|
|
11
|
+
|
|
12
|
+
// takes node and returns evaluator depending on the case with passed params (container, path, ctx) =>
|
|
13
|
+
access = (a, fn, generic) => (
|
|
14
|
+
// (((x))) => x
|
|
15
|
+
a[0] === '()' ? access(a[1], fn, generic) :
|
|
16
|
+
// (_, name, ctx) => ctx[path]
|
|
17
|
+
typeof a === 'string' ? fn.bind(0, ctx => ctx, () => a) :
|
|
18
|
+
// (container, path, ctx) => container(ctx)[path]
|
|
19
|
+
a[0] === '.' ? fn.bind(0, compile(a[1]), (a = a[2], () => a)) :
|
|
20
|
+
// (container, path, ctx) => container(ctx)[path(ctx)]
|
|
21
|
+
a[0] === '[' ? fn.bind(0, compile(a[1]), compile(a[2])) :
|
|
22
|
+
// (src, _, ctx) => src(ctx)
|
|
23
|
+
generic ? (a = compile(a), fn.bind(0, ctx => [a(ctx)], () => 0)) : () => err('Bad left value')
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
export default compile
|
package/src/const.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export const
|
|
2
|
+
PERIOD = 46,
|
|
3
|
+
OPAREN = 40,
|
|
4
|
+
CPAREN = 41,
|
|
5
|
+
OBRACK = 91,
|
|
6
|
+
CBRACK = 93,
|
|
7
|
+
OBRACE = 123,
|
|
8
|
+
CBRACE = 125,
|
|
9
|
+
SPACE = 32,
|
|
10
|
+
COLON = 58,
|
|
11
|
+
DQUOTE = 34,
|
|
12
|
+
QUOTE = 39,
|
|
13
|
+
_0 = 48,
|
|
14
|
+
_9 = 57,
|
|
15
|
+
_E = 69,
|
|
16
|
+
_e = 101,
|
|
17
|
+
BSLASH = 92,
|
|
18
|
+
SLASH = 47,
|
|
19
|
+
STAR = 42
|
|
20
|
+
|
|
21
|
+
// ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence
|
|
22
|
+
export const
|
|
23
|
+
PREC_SEQ = 1,
|
|
24
|
+
PREC_ASSIGN = 2,
|
|
25
|
+
PREC_LOR = 3,
|
|
26
|
+
PREC_LAND = 4,
|
|
27
|
+
PREC_OR = 5,
|
|
28
|
+
PREC_XOR = 6,
|
|
29
|
+
PREC_AND = 7,
|
|
30
|
+
PREC_EQ = 8,
|
|
31
|
+
PREC_COMP = 9,
|
|
32
|
+
PREC_SHIFT = 10,
|
|
33
|
+
PREC_ADD = 11,
|
|
34
|
+
PREC_MULT = 12,
|
|
35
|
+
PREC_EXP = 13,
|
|
36
|
+
PREC_PREFIX = 14,
|
|
37
|
+
PREC_POSTFIX = 15,
|
|
38
|
+
PREC_ACCESS = 17,
|
|
39
|
+
PREC_GROUP = 18,
|
|
40
|
+
PREC_TOKEN = 20
|
package/src/parse.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export let idx: any;
|
|
2
|
+
export let cur: any;
|
|
3
|
+
export function parse(s: string): any;
|
|
4
|
+
export namespace parse {
|
|
5
|
+
function space(cc: any): any;
|
|
6
|
+
function id(n: any): any;
|
|
7
|
+
}
|
|
8
|
+
export function err(msg?: string, frag?: string): never;
|
|
9
|
+
export function skip(is: number | ((c: number) => number)): string;
|
|
10
|
+
export const lookup: ((a: any, b: any) => any)[];
|
|
11
|
+
export function token(op: string, prec: number, map: (a: any, curPrec: number, from: number) => any): (a: any, curPrec: number, from?: any) => any;
|
|
12
|
+
export function binary(op: string, prec: number, right?: boolean | undefined): (a: any, curPrec: number, from?: any) => any;
|
|
13
|
+
export function unary(op: string, prec: number, post?: boolean | undefined): (a: any, curPrec: number, from?: any) => any;
|
|
14
|
+
export function nary(op: string, prec: number, skips?: boolean | undefined): (a: any, curPrec: number, from?: any) => any;
|
|
15
|
+
export function expr(prec: number, end?: string | undefined): any;
|
|
16
|
+
export function isId(c: number): boolean;
|
|
17
|
+
export function space(): number;
|
|
18
|
+
export function id(): string;
|
|
19
|
+
export default parse;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { SPACE } from "./const.js"
|
|
2
2
|
|
|
3
3
|
// current string, index and collected ids
|
|
4
4
|
export let idx, cur,
|
|
@@ -7,13 +7,12 @@ export let idx, cur,
|
|
|
7
7
|
parse = s => (idx = 0, cur = s, s = expr(), cur[idx] ? err() : s || ''),
|
|
8
8
|
|
|
9
9
|
err = (msg = 'Bad syntax',
|
|
10
|
-
frag = cur[idx],
|
|
11
10
|
lines = cur.slice(0, idx).split('\n'),
|
|
12
11
|
last = lines.pop()
|
|
13
12
|
) => {
|
|
14
13
|
let before = cur.slice(idx - 108, idx).split('\n').pop()
|
|
15
|
-
let after = cur.slice(idx
|
|
16
|
-
throw EvalError(`${msg} at ${lines.length}:${last.length} \`${
|
|
14
|
+
let after = cur.slice(idx, idx + 108).split('\n').shift()
|
|
15
|
+
throw EvalError(`${msg} at ${lines.length}:${last.length} \`${idx >= 108 ? '…' : ''}${before}▶${after}\``, 'font-weight: bold')
|
|
17
16
|
},
|
|
18
17
|
|
|
19
18
|
skip = (is = 1, from = idx, l) => {
|
|
@@ -49,11 +48,12 @@ export let idx, cur,
|
|
|
49
48
|
c == 36 || c == 95 || // $, _,
|
|
50
49
|
(c >= 192 && c != 215 && c != 247), // any non-ASCII
|
|
51
50
|
|
|
51
|
+
// parse identifier (configurable)
|
|
52
|
+
id = parse.id = n => skip(isId),
|
|
53
|
+
|
|
52
54
|
// skip space chars, return first non-space character
|
|
53
55
|
space = parse.space = cc => { while ((cc = cur.charCodeAt(idx)) <= SPACE) idx++; return cc },
|
|
54
56
|
|
|
55
|
-
id = parse.id = n => skip(isId),
|
|
56
|
-
|
|
57
57
|
// operator/token lookup table
|
|
58
58
|
// lookup[0] is id parser to let configs redefine it
|
|
59
59
|
lookup = [],
|
package/subscript.js
CHANGED
|
@@ -1,127 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
(
|
|
24
|
-
unary(op, prec),
|
|
25
|
-
operator(op, (a, b) => !b && (a = compile(a), !a.length ? (a = fn(a()), () => a) : ctx => fn(a(ctx))))
|
|
26
|
-
)
|
|
27
|
-
),
|
|
28
|
-
|
|
29
|
-
num = a => a ? err() : ['', (a = +skip(c => c === PERIOD || (c >= _0 && c <= _9) || (c === 69 || c === 101 ? 2 : 0))) != a ? err() : a],
|
|
30
|
-
|
|
31
|
-
// create increment-assign pair from fn
|
|
32
|
-
inc = (op, prec, fn, ev) => (
|
|
33
|
-
token(op, prec, a => a ? [op === '++' ? '-' : '+', [op, a], ['', 1]] : [op, expr(prec - 1)]), // ++a → [++, a], a++ → [-,[++,a],1]
|
|
34
|
-
operator(op, ev = (a, b) => (
|
|
35
|
-
a[0] === '(' ? ev(a[1]) : // ++(((a)))
|
|
36
|
-
a[0] === '.' ? (b = a[2], a = compile(a[1]), ctx => fn(a(ctx), b)) : // ++a.b
|
|
37
|
-
a[0] === '[' ? ([, a, b] = a, a = compile(a), b = compile(b), ctx => fn(a(ctx), b(ctx))) : // ++a[b]
|
|
38
|
-
(ctx => fn(ctx, a)) // ++a
|
|
39
|
-
))
|
|
40
|
-
)
|
|
41
|
-
|
|
42
|
-
// literals
|
|
43
|
-
// null operator returns first value (needed for direct literals)
|
|
44
|
-
operator('', v => () => v)
|
|
45
|
-
|
|
46
|
-
// "a"
|
|
47
|
-
lookup[DQUOTE] = (a) => (a ? err() : ['', (skip() + skip(c => c - DQUOTE ? 1 : 0) + (skip() || err('Bad string'))).slice(1, -1)])
|
|
48
|
-
|
|
49
|
-
// .1
|
|
50
|
-
lookup[PERIOD] = a => (!a && num())
|
|
51
|
-
|
|
52
|
-
// 0-9
|
|
53
|
-
for (let i = 0; i <= 9; i++) lookup[_0 + i] = num
|
|
54
|
-
|
|
55
|
-
// sequences
|
|
56
|
-
set(',', PREC_SEQ, (...args) => args[args.length - 1])
|
|
57
|
-
set('||', PREC_SOME, (...args) => { let i = 0, v; for (; !v && i < args.length;) v = args[i++]; return v })
|
|
58
|
-
set('&&', PREC_EVERY, (...args) => { let i = 0, v = true; for (; v && i < args.length;) v = args[i++]; return v })
|
|
59
|
-
|
|
60
|
-
// assignment
|
|
61
|
-
binary('=', 10, true)
|
|
62
|
-
operator('=', (a, b) => {
|
|
63
|
-
let calc = compile(b), container, path,
|
|
64
|
-
set = typeof a === 'string' ? (ctx, v) => ctx[a] = v :
|
|
65
|
-
a[0] === '.' ? (container = compile(a[1]), path = a[2], (ctx, v) => container(ctx)[path] = v) :
|
|
66
|
-
a[0] === '[' ? (container = compile(a[1]), path = compile(a[2]), (ctx, v) => container(ctx)[path(ctx)] = v) :
|
|
67
|
-
err('Bad left value');
|
|
68
|
-
return ctx => set(ctx, calc(ctx))
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
// binaries
|
|
72
|
-
set('+', PREC_SUM, (a, b) => a + b)
|
|
73
|
-
set('-', PREC_SUM, (a, b) => a - b)
|
|
74
|
-
set('*', PREC_MULT, (a, b) => a * b)
|
|
75
|
-
set('/', PREC_MULT, (a, b) => a / b)
|
|
76
|
-
set('%', PREC_MULT, (a, b) => a % b)
|
|
77
|
-
set('|', PREC_OR, (a, b) => a | b)
|
|
78
|
-
set('&', PREC_AND, (a, b) => a & b)
|
|
79
|
-
set('^', PREC_XOR, (a, b) => a ^ b)
|
|
80
|
-
set('==', PREC_EQ, (a, b) => a == b)
|
|
81
|
-
set('!=', PREC_EQ, (a, b) => a != b)
|
|
82
|
-
set('>', PREC_COMP, (a, b) => a > b)
|
|
83
|
-
set('>=', PREC_COMP, (a, b) => a >= b)
|
|
84
|
-
set('<', PREC_COMP, (a, b) => a < b)
|
|
85
|
-
set('<=', PREC_COMP, (a, b) => a <= b)
|
|
86
|
-
set('>>', PREC_SHIFT, (a, b) => a >> b)
|
|
87
|
-
set('>>>', PREC_SHIFT, (a, b) => a >>> b)
|
|
88
|
-
set('<<', PREC_SHIFT, (a, b) => a << b)
|
|
89
|
-
|
|
90
|
-
// unaries
|
|
91
|
-
set('+', PREC_UNARY, a => +a)
|
|
92
|
-
set('-', PREC_UNARY, a => -a)
|
|
93
|
-
set('!', PREC_UNARY, a => !a)
|
|
94
|
-
|
|
95
|
-
// increments
|
|
96
|
-
inc('++', PREC_UNARY, (a, b) => ++a[b])
|
|
97
|
-
inc('--', PREC_UNARY, (a, b) => --a[b])
|
|
98
|
-
|
|
99
|
-
// a[b]
|
|
100
|
-
token('[', PREC_CALL, a => a && ['[', a, expr(0, CBRACK) || err()])
|
|
101
|
-
operator('[', (a, b) => b && (a = compile(a), b = compile(b), ctx => a(ctx)[b(ctx)]))
|
|
102
|
-
|
|
103
|
-
// a.b
|
|
104
|
-
token('.', PREC_CALL, (a, b) => a && (b = expr(PREC_CALL)) && ['.', a, b])
|
|
105
|
-
operator('.', (a, b) => (a = compile(a), b = !b[0] ? b[1] : b, ctx => a(ctx)[b])) // a.true, a.1 → needs to work fine
|
|
106
|
-
|
|
107
|
-
// (a,b,c), (a)
|
|
108
|
-
token('(', PREC_CALL, a => !a && ['(', expr(0, CPAREN) || err()])
|
|
109
|
-
|
|
110
|
-
// a(b,c,d), a()
|
|
111
|
-
token('(', PREC_CALL, (a, b) => a && (b = expr(0, CPAREN), b ? ['(', a, b] : ['(', a, '']))
|
|
112
|
-
operator('(', (a, b, path, container, args) => b == null ? (compile(a, b)) : (
|
|
113
|
-
args = b == '' ? () => [] : // a()
|
|
114
|
-
b[0] === ',' ? (b = b.slice(1).map(compile), ctx => b.map(arg => arg(ctx))) : // a(b,c)
|
|
115
|
-
(b = compile(b), ctx => [b(ctx)]), // a(b)
|
|
116
|
-
|
|
117
|
-
a[0] === '.' ? (path = a[2], a = compile(a[1]), ctx => a(ctx)[path](...args(ctx))) : // a.b(...args)
|
|
118
|
-
a[0] === '[' ? (path = compile(a[2]), a = compile(a[1]), ctx => a(ctx)[path(ctx)](...args(ctx))) : // a[b](...args)
|
|
119
|
-
(a = compile(a), ctx => a(ctx)(...args(ctx))) // a(...args)
|
|
120
|
-
)
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
export default subscript
|
|
125
|
-
export { set }
|
|
126
|
-
export * from './parse.js'
|
|
127
|
-
export * from './compile.js'
|
|
1
|
+
/**
|
|
2
|
+
* Subscript dialect includes common operators / primitives for all languages
|
|
3
|
+
*/
|
|
4
|
+
import './feature/number.js'
|
|
5
|
+
import './feature/string.js'
|
|
6
|
+
import './feature/call.js'
|
|
7
|
+
import './feature/access.js'
|
|
8
|
+
import './feature/group.js'
|
|
9
|
+
import './feature/mult.js'
|
|
10
|
+
import './feature/add.js'
|
|
11
|
+
import './feature/increment.js'
|
|
12
|
+
import './feature/bitwise.js'
|
|
13
|
+
import './feature/compare.js'
|
|
14
|
+
import './feature/logic.js'
|
|
15
|
+
import './feature/assign.js'
|
|
16
|
+
import compile from './src/compile.js'
|
|
17
|
+
import parse from './src/parse.js'
|
|
18
|
+
|
|
19
|
+
export * from './src/parse.js'
|
|
20
|
+
export * from './src/compile.js'
|
|
21
|
+
|
|
22
|
+
export default s => compile(parse(s))
|
package/subscript.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
let
|
|
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};
|
package/compile.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
// build optimized evaluator for the tree
|
|
2
|
-
export const compile = (node) => !Array.isArray(node) ? ctx => ctx?.[node] : operators[node[0]](...node.slice(1)),
|
|
3
|
-
|
|
4
|
-
operators = {},
|
|
5
|
-
|
|
6
|
-
operator = (op, fn, prev = operators[op]) => (operators[op] = (...args) => fn(...args) || prev && prev(...args))
|
|
7
|
-
|
|
8
|
-
export default compile
|