@bablr/helpers 0.1.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/LICENSE +21 -0
- package/README.md +3 -0
- package/lib/.babelrc.json +7 -0
- package/lib/decorators.js +1 -0
- package/lib/enhancers.js +53 -0
- package/lib/grammar.js +40 -0
- package/lib/object.js +48 -0
- package/lib/path.js +1 -0
- package/lib/productions.generated.js +83 -0
- package/lib/productions.js +33 -0
- package/lib/shorthand.js +1 -0
- package/lib/symbols.js +6 -0
- package/lib/token.js +23 -0
- package/package.json +49 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Conrad Buck
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@bablr/boot-helpers/decorators';
|
package/lib/enhancers.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const { getOwnPropertyNames, hasOwn } = Object;
|
|
2
|
+
|
|
3
|
+
export const memoize = (original) => {
|
|
4
|
+
const cache = new WeakMap();
|
|
5
|
+
const memoized = (...args) => {
|
|
6
|
+
if (args.length > 1) throw new Error('A memoized function accepts only one argument');
|
|
7
|
+
const arg = args[0];
|
|
8
|
+
|
|
9
|
+
if (cache.has(arg)) {
|
|
10
|
+
return cache.get(arg);
|
|
11
|
+
} else {
|
|
12
|
+
return original(arg);
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
return memoized;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const identity = (x) => x;
|
|
19
|
+
|
|
20
|
+
export const compose = (functions) => {
|
|
21
|
+
let first = true;
|
|
22
|
+
let f = identity;
|
|
23
|
+
for (const g of functions) {
|
|
24
|
+
if (first) {
|
|
25
|
+
f = g;
|
|
26
|
+
} else {
|
|
27
|
+
const f_ = f;
|
|
28
|
+
f = (x) => f_(g(x));
|
|
29
|
+
}
|
|
30
|
+
first = false;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return f;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const mapProductions = (fn, Grammar) => {
|
|
37
|
+
let { prototype } = Grammar;
|
|
38
|
+
|
|
39
|
+
class MappedGrammar extends Grammar {}
|
|
40
|
+
|
|
41
|
+
const mapped = MappedGrammar.prototype;
|
|
42
|
+
|
|
43
|
+
while (prototype) {
|
|
44
|
+
for (const key of getOwnPropertyNames(prototype)) {
|
|
45
|
+
if (!hasOwn(mapped, key)) {
|
|
46
|
+
mapped[key] = fn(prototype[key], key);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
({ prototype } = prototype);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return MappedGrammar;
|
|
53
|
+
};
|
package/lib/grammar.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import every from 'iter-tools-es/methods/every';
|
|
2
|
+
import isString from 'iter-tools-es/methods/is-string';
|
|
3
|
+
import { objectEntries } from './object.js';
|
|
4
|
+
|
|
5
|
+
const { isArray } = Array;
|
|
6
|
+
const isSymbol = (value) => typeof value === 'symbol';
|
|
7
|
+
const isType = (value) => isString(value) || isSymbol(value);
|
|
8
|
+
|
|
9
|
+
export const explodeSubtypes = (aliases, exploded, types) => {
|
|
10
|
+
for (const type of types) {
|
|
11
|
+
const explodedTypes = aliases.get(type);
|
|
12
|
+
if (explodedTypes) {
|
|
13
|
+
for (const explodedType of explodedTypes) {
|
|
14
|
+
exploded.add(explodedType);
|
|
15
|
+
const subtypes = aliases.get(explodedType);
|
|
16
|
+
if (subtypes) {
|
|
17
|
+
explodeSubtypes(aliases, exploded, subtypes);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const buildCovers = (rawAliases) => {
|
|
25
|
+
const aliases = new Map();
|
|
26
|
+
|
|
27
|
+
for (const alias of objectEntries(rawAliases)) {
|
|
28
|
+
if (!isType(alias[0])) throw new Error('alias[0] key must be a string or symbol');
|
|
29
|
+
if (!isArray(alias[1])) throw new Error('alias[1] must be an array');
|
|
30
|
+
if (!every(isType, alias[1])) throw new Error('alias[1] values must be strings or symbols');
|
|
31
|
+
|
|
32
|
+
aliases.set(alias[0], new Set(alias[1]));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
for (const [type, types] of aliases.entries()) {
|
|
36
|
+
explodeSubtypes(aliases, aliases.get(type), types);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return new Map(aliases);
|
|
40
|
+
};
|
package/lib/object.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import map from 'iter-tools-es/methods/map';
|
|
2
|
+
|
|
3
|
+
export const { hasOwn, getOwnPropertySymbols, fromEntries } = Object;
|
|
4
|
+
|
|
5
|
+
export const isObject = (obj) => obj !== null && typeof obj === 'object';
|
|
6
|
+
export const { isArray } = Array;
|
|
7
|
+
export const isFunction = (obj) => typeof obj === 'function';
|
|
8
|
+
export const isSymbol = (obj) => typeof obj === 'symbol';
|
|
9
|
+
export const isString = (obj) => typeof obj === 'string';
|
|
10
|
+
export const isRegex = (obj) => obj instanceof RegExp;
|
|
11
|
+
export const isPattern = (obj) => isString(obj) || isRegex(obj);
|
|
12
|
+
export const isType = (obj) => isSymbol(obj) || isString(obj);
|
|
13
|
+
|
|
14
|
+
export const objectKeys = (obj) => {
|
|
15
|
+
return {
|
|
16
|
+
*[Symbol.iterator]() {
|
|
17
|
+
for (let key in obj) if (hasOwn(obj, key)) yield key;
|
|
18
|
+
yield* getOwnPropertySymbols(obj);
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const objectValues = (obj) => {
|
|
24
|
+
return {
|
|
25
|
+
*[Symbol.iterator]() {
|
|
26
|
+
for (let key in obj) if (hasOwn(obj, key)) yield obj[key];
|
|
27
|
+
yield* map((sym) => obj[sym], getOwnPropertySymbols(obj));
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export const objectEntries = (obj) => {
|
|
33
|
+
return {
|
|
34
|
+
*[Symbol.iterator]() {
|
|
35
|
+
for (let key in obj) if (hasOwn(obj, key)) yield [key, obj[key]];
|
|
36
|
+
yield* map((sym) => [sym, obj[sym]], getOwnPropertySymbols(obj));
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const mapObject = (fn, obj) => {
|
|
42
|
+
let result = {};
|
|
43
|
+
for (let key in obj) if (hasOwn(obj, key)) result[key] = fn(obj[key]);
|
|
44
|
+
for (const sym of getOwnPropertySymbols(obj)) result[sym] = fn(obj[sym]);
|
|
45
|
+
return result;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
export const arrayLast = (arr) => arr[arr.length - 1];
|
package/lib/path.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@bablr/boot-helpers/path';
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { interpolateString as _interpolateString } from "@bablr/boot-helpers/template";
|
|
2
|
+
import { interpolateArray as _interpolateArray } from "@bablr/boot-helpers/template";
|
|
3
|
+
import * as _t from "@bablr/boot-helpers/types";
|
|
4
|
+
export function* List({
|
|
5
|
+
props: {
|
|
6
|
+
element,
|
|
7
|
+
separator,
|
|
8
|
+
allowHoles = false,
|
|
9
|
+
allowTrailingSeparator = true
|
|
10
|
+
}
|
|
11
|
+
}) {
|
|
12
|
+
let sep, it;
|
|
13
|
+
for (;;) {
|
|
14
|
+
it = yield _t.node("Instruction", "Call", [_t.ref`verb`, _t.ref`arguments`], {
|
|
15
|
+
verb: _t.node("Instruction", "Identifier", [_t.lit`eatMatch`], {}, {}),
|
|
16
|
+
arguments: _t.node("Instruction", "Tuple", [_t.ref`open`, _t.ref`values`, _t.ref`close`], {
|
|
17
|
+
open: _t.node("Instruction", "Punctuator", [_t.lit`(`], {}, {}),
|
|
18
|
+
values: [..._interpolateArray(element)],
|
|
19
|
+
close: _t.node("Instruction", "Punctuator", [_t.lit`)`], {}, {})
|
|
20
|
+
}, {})
|
|
21
|
+
}, {});
|
|
22
|
+
if (it || allowTrailingSeparator) {
|
|
23
|
+
sep = yield _t.node("Instruction", "Call", [_t.ref`verb`, _t.ref`arguments`], {
|
|
24
|
+
verb: _t.node("Instruction", "Identifier", [_t.lit`eatMatch`], {}, {}),
|
|
25
|
+
arguments: _t.node("Instruction", "Tuple", [_t.ref`open`, _t.ref`values`, _t.ref`close`], {
|
|
26
|
+
open: _t.node("Instruction", "Punctuator", [_t.lit`(`], {}, {}),
|
|
27
|
+
values: [..._interpolateArray(separator)],
|
|
28
|
+
close: _t.node("Instruction", "Punctuator", [_t.lit`)`], {}, {})
|
|
29
|
+
}, {})
|
|
30
|
+
}, {});
|
|
31
|
+
}
|
|
32
|
+
if (!(sep || allowHoles)) break;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export function* Any({
|
|
36
|
+
props: {
|
|
37
|
+
matchers
|
|
38
|
+
}
|
|
39
|
+
}) {
|
|
40
|
+
for (const matcher of matchers) {
|
|
41
|
+
if (yield _t.node("Instruction", "Call", [_t.ref`verb`, _t.ref`arguments`], {
|
|
42
|
+
verb: _t.node("Instruction", "Identifier", [_t.lit`eatMatch`], {}, {}),
|
|
43
|
+
arguments: _t.node("Instruction", "Tuple", [_t.ref`open`, _t.ref`values`, _t.ref`close`], {
|
|
44
|
+
open: _t.node("Instruction", "Punctuator", [_t.lit`(`], {}, {}),
|
|
45
|
+
values: [..._interpolateArray(matcher)],
|
|
46
|
+
close: _t.node("Instruction", "Punctuator", [_t.lit`)`], {}, {})
|
|
47
|
+
}, {})
|
|
48
|
+
}, {})) break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
export function* All({
|
|
52
|
+
props: {
|
|
53
|
+
matchers
|
|
54
|
+
}
|
|
55
|
+
}) {
|
|
56
|
+
for (const matcher of matchers) {
|
|
57
|
+
yield _t.node("Instruction", "Call", [_t.ref`verb`, _t.ref`arguments`], {
|
|
58
|
+
verb: _t.node("Instruction", "Identifier", [_t.lit`eat`], {}, {}),
|
|
59
|
+
arguments: _t.node("Instruction", "Tuple", [_t.ref`open`, _t.ref`values`, _t.ref`close`], {
|
|
60
|
+
open: _t.node("Instruction", "Punctuator", [_t.lit`(`], {}, {}),
|
|
61
|
+
values: [..._interpolateArray(matcher)],
|
|
62
|
+
close: _t.node("Instruction", "Punctuator", [_t.lit`)`], {}, {})
|
|
63
|
+
}, {})
|
|
64
|
+
}, {});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function* Optional({
|
|
68
|
+
props: {
|
|
69
|
+
matchers
|
|
70
|
+
}
|
|
71
|
+
}) {
|
|
72
|
+
if (matchers.length > 1) {
|
|
73
|
+
throw new Error('Optional only allows one matcher');
|
|
74
|
+
}
|
|
75
|
+
yield _t.node("Instruction", "Call", [_t.ref`verb`, _t.ref`arguments`], {
|
|
76
|
+
verb: _t.node("Instruction", "Identifier", [_t.lit`eatMatch`], {}, {}),
|
|
77
|
+
arguments: _t.node("Instruction", "Tuple", [_t.ref`open`, _t.ref`values`, _t.ref`close`], {
|
|
78
|
+
open: _t.node("Instruction", "Punctuator", [_t.lit`(`], {}, {}),
|
|
79
|
+
values: [..._interpolateArray(matchers[0])],
|
|
80
|
+
close: _t.node("Instruction", "Punctuator", [_t.lit`)`], {}, {})
|
|
81
|
+
}, {})
|
|
82
|
+
}, {});
|
|
83
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { i } from '@bablr/boot/shorthand.macro';
|
|
2
|
+
|
|
3
|
+
export function* List({
|
|
4
|
+
props: { element, separator, allowHoles = false, allowTrailingSeparator = true },
|
|
5
|
+
}) {
|
|
6
|
+
let sep, it;
|
|
7
|
+
for (;;) {
|
|
8
|
+
it = yield i`eatMatch(${element})`;
|
|
9
|
+
if (it || allowTrailingSeparator) {
|
|
10
|
+
sep = yield i`eatMatch(${separator})`;
|
|
11
|
+
}
|
|
12
|
+
if (!(sep || allowHoles)) break;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function* Any({ props: { matchers } }) {
|
|
17
|
+
for (const matcher of matchers) {
|
|
18
|
+
if (yield i`eatMatch(${matcher})`) break;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function* All({ props: { matchers } }) {
|
|
23
|
+
for (const matcher of matchers) {
|
|
24
|
+
yield i`eat(${matcher})`;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function* Optional({ props: { matchers } }) {
|
|
29
|
+
if (matchers.length > 1) {
|
|
30
|
+
throw new Error('Optional only allows one matcher');
|
|
31
|
+
}
|
|
32
|
+
yield i`eatMatch(${matchers[0]})`;
|
|
33
|
+
}
|
package/lib/shorthand.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { i, re, spam } from '@bablr/boot';
|
package/lib/symbols.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const node = Symbol.for('@bablr/node');
|
|
2
|
+
|
|
3
|
+
export const active = Symbol.for('@bablr/active');
|
|
4
|
+
export const suspended = Symbol.for('@bablr/suspended');
|
|
5
|
+
export const accepted = Symbol.for('@bablr/accepted');
|
|
6
|
+
export const rejected = Symbol.for('@bablr/rejected');
|
package/lib/token.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export const getCooked = (token) => {
|
|
2
|
+
return token.children
|
|
3
|
+
.map((child) => {
|
|
4
|
+
if (child.type === 'Escape') {
|
|
5
|
+
return child.value.cooked;
|
|
6
|
+
} else if (child.type === 'Literal') {
|
|
7
|
+
return child.value;
|
|
8
|
+
} else throw new Error();
|
|
9
|
+
})
|
|
10
|
+
.join('');
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
export const getRaw = (token) => {
|
|
14
|
+
return token.children
|
|
15
|
+
.map((child) => {
|
|
16
|
+
if (child.type === 'Escape') {
|
|
17
|
+
return child.value.raw;
|
|
18
|
+
} else if (child.type === 'Literal') {
|
|
19
|
+
return child.value;
|
|
20
|
+
} else throw new Error();
|
|
21
|
+
})
|
|
22
|
+
.join('');
|
|
23
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bablr/helpers",
|
|
3
|
+
"description": "Command helpers for use in writing BABLR grammars",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"author": "Conrad Buck<conartist6@gmail.com>",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"files": [
|
|
8
|
+
"lib"
|
|
9
|
+
],
|
|
10
|
+
"exports": {
|
|
11
|
+
"./decorators": "./lib/decorators.js",
|
|
12
|
+
"./enhancers": "./lib/enhancers.js",
|
|
13
|
+
"./grammar": "./lib/grammar.js",
|
|
14
|
+
"./object": "./lib/object.js",
|
|
15
|
+
"./path": "./lib/path.js",
|
|
16
|
+
"./productions": "./lib/productions.generated.js",
|
|
17
|
+
"./shorthand": "./lib/shorthand.js",
|
|
18
|
+
"./symbols": "./lib/symbols.js",
|
|
19
|
+
"./token": "./lib/token.js"
|
|
20
|
+
},
|
|
21
|
+
"sideEffects": false,
|
|
22
|
+
"scripts": {
|
|
23
|
+
"generate": "babel lib/productions.js --out-file lib/productions.generated.js",
|
|
24
|
+
"clean": "rm lib/productions.generated.js"
|
|
25
|
+
},
|
|
26
|
+
"dependencies": {
|
|
27
|
+
"@bablr/boot": "0.1.1",
|
|
28
|
+
"@bablr/boot-helpers": "0.1.0",
|
|
29
|
+
"iter-tools-es": "^7.5.3"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@babel/cli": "7.22.15",
|
|
33
|
+
"@babel/core": "7.22.20",
|
|
34
|
+
"@babel/plugin-proposal-decorators": "7.22.15",
|
|
35
|
+
"@babel/plugin-transform-modules-commonjs": "^7.23.0",
|
|
36
|
+
"@babel/plugin-transform-runtime": "^7.22.15",
|
|
37
|
+
"@babel/runtime": "^7.23.2",
|
|
38
|
+
"@bablr/eslint-config-base": "github:bablr-lang/eslint-config-base#c040bc95f2dddac160628e4757a412016044b3ef",
|
|
39
|
+
"babel-plugin-macros": "3.1.0",
|
|
40
|
+
"enhanced-resolve": "^5.12.0",
|
|
41
|
+
"eslint": "^7.32.0",
|
|
42
|
+
"eslint-import-resolver-enhanced-resolve": "^1.0.5",
|
|
43
|
+
"eslint-plugin-import": "^2.27.5",
|
|
44
|
+
"prettier": "^2.6.2"
|
|
45
|
+
},
|
|
46
|
+
"repository": "github:bablr-lang/helpers",
|
|
47
|
+
"homepage": "https://github.com/bablr-lang/helpers",
|
|
48
|
+
"license": "MIT"
|
|
49
|
+
}
|