@traqula/core 0.0.1-alpha.137
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.txt +22 -0
- package/README.md +115 -0
- package/lib/Wildcard.d.ts +9 -0
- package/lib/Wildcard.js +19 -0
- package/lib/Wildcard.js.map +1 -0
- package/lib/grammar-builder/builderTypes.d.ts +19 -0
- package/lib/grammar-builder/builderTypes.js +2 -0
- package/lib/grammar-builder/builderTypes.js.map +1 -0
- package/lib/grammar-builder/parserBuilder.d.ts +33 -0
- package/lib/grammar-builder/parserBuilder.js +365 -0
- package/lib/grammar-builder/parserBuilder.js.map +1 -0
- package/lib/grammar-builder/ruleDefTypes.d.ts +339 -0
- package/lib/grammar-builder/ruleDefTypes.js +2 -0
- package/lib/grammar-builder/ruleDefTypes.js.map +1 -0
- package/lib/grammar-helpers/utils.d.ts +16 -0
- package/lib/grammar-helpers/utils.js +47 -0
- package/lib/grammar-helpers/utils.js.map +1 -0
- package/lib/index.cjs +10033 -0
- package/lib/index.d.ts +7 -0
- package/lib/index.js +8 -0
- package/lib/index.js.map +1 -0
- package/lib/lexer-builder/LexerBuilder.d.ts +21 -0
- package/lib/lexer-builder/LexerBuilder.js +84 -0
- package/lib/lexer-builder/LexerBuilder.js.map +1 -0
- package/lib/lexer-helper/utils.d.ts +6 -0
- package/lib/lexer-helper/utils.js +5 -0
- package/lib/lexer-helper/utils.js.map +1 -0
- package/package.json +45 -0
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2024–now Jitse De Smet
|
|
4
|
+
Comunica Association and Ghent University – imec, Belgium
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
8
|
+
in the Software without restriction, including without limitation the rights
|
|
9
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
22
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# TRAQULA core package
|
|
2
|
+
|
|
3
|
+
TRAQULA core contains core components of traqula.
|
|
4
|
+
Most importantly, its `lexer-builder` and `grammar-builder`.
|
|
5
|
+
This library heavily relies on the amazing [chevrotain package](https://chevrotain.io/docs/).
|
|
6
|
+
Knowing the basics of that package will allow you to quickly generate your own grammars
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @traqula/core
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
or
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
yarn add @traqula/core
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
Each parser contains two steps:
|
|
23
|
+
1. a lexer
|
|
24
|
+
2. a grammar + abstract syntax tree generation step.
|
|
25
|
+
|
|
26
|
+
Sometimes grammar definitions and abstract syntax tree generation is split into separate steps.
|
|
27
|
+
In this library, we choose to keep the two together.
|
|
28
|
+
|
|
29
|
+
### Lexer Builder
|
|
30
|
+
|
|
31
|
+
To tackle the first step, a lexer should be created.
|
|
32
|
+
This is a system that separates different groups of characters into annotated groups.
|
|
33
|
+
In human language for example the sentence 'I eat apples' is lexed into different groups called **tokens** namely `words` and `spaces`:
|
|
34
|
+
`I`, ` `, `eat`, ` `, `apples`.
|
|
35
|
+
|
|
36
|
+
To create a token definition, you use the provided function `createToken` like:
|
|
37
|
+
```typescript
|
|
38
|
+
const select = createToken({ name: 'Select', pattern: /select/i, label: 'SELECT' });
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Lexer definitions are then put in a list and when a lexer is build, the lexer will match a string to the first token in the list that matches.
|
|
42
|
+
Note that the order of definitions in the list is thus essential.
|
|
43
|
+
|
|
44
|
+
We therefore use a `lexer-builder` which allows you to easily:
|
|
45
|
+
1. change the order of lexer rules,
|
|
46
|
+
2. and create a new lexer staring from an existing one.
|
|
47
|
+
|
|
48
|
+
Creating a builder is as easy as:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const sparql11Tokens = LexerBuilder.create(<const> [select, describe]);
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A new lexer can be created from an existing one by calling:
|
|
55
|
+
```typescript
|
|
56
|
+
const sparql11AdjustTokens = sparql11Tokens.addBefore(select, BuiltInAdjust);
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Grammar Builder
|
|
60
|
+
|
|
61
|
+
The grammar builder is used to link together grammar rules such that they can be converted into a parser.
|
|
62
|
+
Grammar rule definitions come in the form of `RuleDef` objects.
|
|
63
|
+
Each `RuleDef` object contains its name and its returnType.
|
|
64
|
+
Optionally, it can also contain arguments that should be provided to the SUBRULE calls.
|
|
65
|
+
A simple example of a grammar rule is the rule bellow that allows you to parse booleanLiterals.
|
|
66
|
+
|
|
67
|
+
```typescript
|
|
68
|
+
/**
|
|
69
|
+
* Parses a boolean literal.
|
|
70
|
+
* [[134]](https://www.w3.org/TR/sparql11-query/#rBooleanLiteral)
|
|
71
|
+
*/
|
|
72
|
+
export const booleanLiteral: RuleDef<'booleanLiteral', LiteralTerm> = <const> {
|
|
73
|
+
name: 'booleanLiteral',
|
|
74
|
+
impl: ({ CONSUME, OR, context }) => () => OR([
|
|
75
|
+
{ ALT: () => context.dataFactory.literal(
|
|
76
|
+
CONSUME(l.true_).image.toLowerCase(),
|
|
77
|
+
context.dataFactory.namedNode(CommonIRIs.BOOLEAN),
|
|
78
|
+
) },
|
|
79
|
+
{ ALT: () => context.dataFactory.literal(
|
|
80
|
+
CONSUME(l.false_).image.toLowerCase(),
|
|
81
|
+
context.dataFactory.namedNode(CommonIRIs.BOOLEAN),
|
|
82
|
+
) },
|
|
83
|
+
]),
|
|
84
|
+
};
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The `impl` member of `RuleDef` is a function that receives:
|
|
88
|
+
1. essential functions to create a grammar rule (capitalized members),
|
|
89
|
+
2. a context object that can be used by the rules,
|
|
90
|
+
3. a cache object ([WeakMap](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap)) that can be used to cache the creation of long lists in the parser.
|
|
91
|
+
|
|
92
|
+
As a warning, we advise against unpacking the context entry in the function definition itself.
|
|
93
|
+
Doing so will cause the unpacked entries to be captured in the closure which will cause unwanted behaviour since the context entry can be reset between runs.
|
|
94
|
+
|
|
95
|
+
The result of an `impl` call is a function called a `rule`.
|
|
96
|
+
Rules can be [parameterized](https://chevrotain.io/docs/features/parameterized_rules.html), although I have not found a scenario where that is usefully.
|
|
97
|
+
Personally I create a function that can be used to create multiple `RuleDef` objects.
|
|
98
|
+
The result of a rule should match the type provided in the `RuleDef` definition, and is the result of a call of `SUBRULE` with that rule.
|
|
99
|
+
|
|
100
|
+
### Patching rules
|
|
101
|
+
|
|
102
|
+
When a rule definition calls to a subrule using `SUBRULE(mySub)`, the implementation itself is not necessarily called.
|
|
103
|
+
That is because the SUBRULE function will call the function with the same name as `mySub` that is present in the current grammarBuilder.
|
|
104
|
+
|
|
105
|
+
A builder is thus free to override definitions as it pleases. Doing so does however **break the types** and should thus only be done with care.
|
|
106
|
+
An example patch is:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
const myBuilder = Builder
|
|
110
|
+
.createBuilder(<const> [selectOrDescribe, selectRule, describeRule])
|
|
111
|
+
.patchRule(selectRuleAlternative);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
When `selectOrDescribe` calls what it thinks to be `selectRule`,
|
|
115
|
+
it will instead call `selectRuleAlternative` since it overwrote the function `selectRule` with the same name.
|
package/lib/Wildcard.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export class Wildcard {
|
|
2
|
+
constructor() {
|
|
3
|
+
this.value = '*';
|
|
4
|
+
this.termType = 'Wildcard';
|
|
5
|
+
// eslint-disable-next-line no-constructor-return
|
|
6
|
+
return WILDCARD ?? this;
|
|
7
|
+
}
|
|
8
|
+
equals(other) {
|
|
9
|
+
return Boolean(other && (this.termType === other.termType));
|
|
10
|
+
}
|
|
11
|
+
toJSON() {
|
|
12
|
+
// eslint-disable-next-line unused-imports/no-unused-vars
|
|
13
|
+
const { value, ...rest } = this;
|
|
14
|
+
return rest;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
let WILDCARD;
|
|
18
|
+
WILDCARD = new Wildcard();
|
|
19
|
+
//# sourceMappingURL=Wildcard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Wildcard.js","sourceRoot":"","sources":["Wildcard.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,QAAQ;IAGnB;QAFO,UAAK,GAAW,GAAG,CAAC;QACpB,aAAQ,GAAW,UAAU,CAAC;QAEnC,iDAAiD;QACjD,OAAO,QAAQ,IAAI,IAAI,CAAC;IAC1B,CAAC;IAEM,MAAM,CAAC,KAA+C;QAC3D,OAAO,OAAO,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC9D,CAAC;IAEM,MAAM;QACX,yDAAyD;QACzD,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAED,IAAI,QAA8B,CAAC;AACnC,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAC","sourcesContent":["export class Wildcard {\n public value = <const> '*';\n public termType = <const> 'Wildcard';\n public constructor() {\n // eslint-disable-next-line no-constructor-return\n return WILDCARD ?? this;\n }\n\n public equals(other: { termType: unknown } | undefined | null): boolean {\n return Boolean(other && (this.termType === other.termType));\n }\n\n public toJSON(): object {\n // eslint-disable-next-line unused-imports/no-unused-vars\n const { value, ...rest } = this;\n return rest;\n }\n}\n\nlet WILDCARD: Wildcard | undefined;\nWILDCARD = new Wildcard();\n"]}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { ParserMethod } from 'chevrotain';
|
|
2
|
+
import type { RuleDef } from './ruleDefTypes';
|
|
3
|
+
export type RuleNamesFromList<T extends readonly RuleDef[]> = T[number]['name'];
|
|
4
|
+
export type RuleDefMap<RuleNames extends string> = {
|
|
5
|
+
[Key in RuleNames]: RuleDef<Key>;
|
|
6
|
+
};
|
|
7
|
+
export type CheckOverlap<T, U, V, W = never> = T & U extends never ? V : W;
|
|
8
|
+
/**
|
|
9
|
+
* Convert a list of RuleDefs to a Record with the name of the RuleDef as the key, matching the RuleDefMap type.
|
|
10
|
+
*/
|
|
11
|
+
export type RuleListToObject<T extends readonly RuleDef[], Agg extends Record<string, RuleDef> = Record<never, never>> = T extends readonly [infer First, ...infer Rest] ? (First extends RuleDef ? (Rest extends readonly RuleDef[] ? (RuleListToObject<Rest, {
|
|
12
|
+
[K in keyof Agg | First['name']]: K extends First['name'] ? First : Agg[K];
|
|
13
|
+
}>) : never) : never) : Agg;
|
|
14
|
+
export type ParserFromRules<Names extends string, RuleDefs extends RuleDefMap<Names>> = {
|
|
15
|
+
[K in Names]: RuleDefs[K] extends RuleDef<K, infer RET, infer ARGS> ? (...args: ARGS) => RET : never;
|
|
16
|
+
};
|
|
17
|
+
export type ParseMethodsFromRules<Names extends string, RuleDefs extends RuleDefMap<Names>> = {
|
|
18
|
+
[K in Names]: RuleDefs[K] extends RuleDef<K, infer RET, infer ARGS> ? ParserMethod<ARGS, RET> : never;
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builderTypes.js","sourceRoot":"","sources":["builderTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { ParserMethod } from 'chevrotain';\nimport type { RuleDef } from './ruleDefTypes';\n\nexport type RuleNamesFromList<T extends readonly RuleDef[]> = T[number]['name'];\n\nexport type RuleDefMap<RuleNames extends string> = {[Key in RuleNames]: RuleDef<Key> };\n\nexport type CheckOverlap<T, U, V, W = never> = T & U extends never ? V : W;\n\n/**\n * Convert a list of RuleDefs to a Record with the name of the RuleDef as the key, matching the RuleDefMap type.\n */\nexport type RuleListToObject<\n T extends readonly RuleDef[],\n Agg extends Record<string, RuleDef> = Record<never, never>,\n> = T extends readonly [infer First, ...infer Rest] ? (\n First extends RuleDef ? (\n Rest extends readonly RuleDef[] ? (\n RuleListToObject<Rest, {[K in keyof Agg | First['name']]: K extends First['name'] ? First : Agg[K] }>\n ) : never\n ) : never\n) : Agg;\n\nexport type ParserFromRules<Names extends string, RuleDefs extends RuleDefMap<Names>> = {\n [K in Names]: RuleDefs[K] extends RuleDef<K, infer RET, infer ARGS> ? (...args: ARGS) => RET : never\n};\n\nexport type ParseMethodsFromRules<Names extends string, RuleDefs extends RuleDefMap<Names>> = {\n [K in Names]: RuleDefs[K] extends RuleDef<K, infer RET, infer ARGS> ? ParserMethod<ARGS, RET> : never\n};\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ILexerConfig, IParserConfig } from '@chevrotain/types';
|
|
2
|
+
import type { TokenType, TokenVocabulary } from 'chevrotain';
|
|
3
|
+
import { EmbeddedActionsParser } from 'chevrotain';
|
|
4
|
+
import type { CheckOverlap, RuleDefMap, ParserFromRules, RuleListToObject, RuleNamesFromList, ParseMethodsFromRules } from './builderTypes';
|
|
5
|
+
import type { ImplArgs, RuleDef } from './ruleDefTypes';
|
|
6
|
+
export declare class Builder<Names extends string, RuleDefs extends RuleDefMap<Names>> {
|
|
7
|
+
static createBuilder<Rules extends readonly RuleDef[] = RuleDef[], Names extends string = RuleNamesFromList<Rules>, RuleDefs extends RuleDefMap<Names> = RuleListToObject<Rules>>(start: Rules | Builder<Names, RuleDefs>): Builder<Names, RuleDefs>;
|
|
8
|
+
private rules;
|
|
9
|
+
private constructor();
|
|
10
|
+
patchRule<U extends Names, RET, ARGS extends unknown[]>(patch: RuleDef<U, RET, ARGS>): Builder<Names, {
|
|
11
|
+
[Key in Names]: Key extends U ? RuleDef<Key, RET, ARGS> : RuleDefs[Key];
|
|
12
|
+
}>;
|
|
13
|
+
addRuleRedundant<U extends string, RET, ARGS extends undefined[]>(rule: RuleDef<U, RET, ARGS>): Builder<Names | U, {
|
|
14
|
+
[K in Names | U]: K extends U ? RuleDef<K, RET, ARGS> : RuleDefs[K];
|
|
15
|
+
}>;
|
|
16
|
+
addRule<U extends string, RET, ARGS extends unknown[]>(rule: CheckOverlap<U, Names, RuleDef<U, RET, ARGS>>): Builder<Names | U, {
|
|
17
|
+
[K in Names | U]: K extends U ? RuleDef<K, RET, ARGS> : RuleDefs[K];
|
|
18
|
+
}>;
|
|
19
|
+
addMany<U extends RuleDef[]>(...rules: CheckOverlap<RuleNamesFromList<U>, Names, U>): Builder<Names | RuleNamesFromList<U>, RuleDefs & RuleListToObject<U>>;
|
|
20
|
+
deleteRule<U extends Names>(ruleName: U): Builder<Exclude<Names, U>, Omit<RuleDefs, U>>;
|
|
21
|
+
merge<OtherNames extends string, OtherRules extends RuleDefMap<OtherNames>, OW extends readonly RuleDef[]>(builder: Builder<OtherNames, OtherRules>, overridingRules: OW): Builder<Names | OtherNames | RuleNamesFromList<OW>, {
|
|
22
|
+
[K in Names | OtherNames | RuleNamesFromList<OW>]: K extends Names | OtherNames ? (K extends Names ? RuleDefs[K] : (K extends OtherNames ? OtherRules[K] : never)) : (K extends keyof RuleListToObject<OW> ? RuleListToObject<OW>[K] : never);
|
|
23
|
+
}>;
|
|
24
|
+
consumeToParser({ tokenVocabulary, parserConfig, lexerConfig }: {
|
|
25
|
+
tokenVocabulary: TokenType[];
|
|
26
|
+
parserConfig?: IParserConfig;
|
|
27
|
+
lexerConfig?: ILexerConfig;
|
|
28
|
+
}, context?: Partial<ImplArgs['context']>): ParserFromRules<Names, RuleDefs>;
|
|
29
|
+
consume({ tokenVocabulary, config }: {
|
|
30
|
+
tokenVocabulary: TokenVocabulary;
|
|
31
|
+
config?: IParserConfig;
|
|
32
|
+
}, context?: Partial<ImplArgs['context']>): EmbeddedActionsParser & ParseMethodsFromRules<Names, RuleDefs>;
|
|
33
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { EmbeddedActionsParser, Lexer } from 'chevrotain';
|
|
2
|
+
import { DataFactory } from 'rdf-data-factory';
|
|
3
|
+
function listToRuleDefMap(rules) {
|
|
4
|
+
const newRules = {};
|
|
5
|
+
for (const rule of rules) {
|
|
6
|
+
newRules[rule.name] = rule;
|
|
7
|
+
}
|
|
8
|
+
return newRules;
|
|
9
|
+
}
|
|
10
|
+
export class Builder {
|
|
11
|
+
static createBuilder(start) {
|
|
12
|
+
if (start instanceof Builder) {
|
|
13
|
+
return new Builder({ ...start.rules });
|
|
14
|
+
}
|
|
15
|
+
// @ts-expect-error TS2344
|
|
16
|
+
return new Builder(listToRuleDefMap(start));
|
|
17
|
+
}
|
|
18
|
+
constructor(startRules) {
|
|
19
|
+
this.rules = startRules;
|
|
20
|
+
}
|
|
21
|
+
patchRule(patch) {
|
|
22
|
+
// @ts-expect-error TS2322
|
|
23
|
+
this.rules[patch.name] = patch;
|
|
24
|
+
// @ts-expect-error TS2344
|
|
25
|
+
return this;
|
|
26
|
+
}
|
|
27
|
+
addRuleRedundant(rule) {
|
|
28
|
+
const rules = this.rules;
|
|
29
|
+
if (rules[rule.name] !== undefined && rules[rule.name] !== rule) {
|
|
30
|
+
throw new Error(`Rule ${rule.name} already exists in the builder`);
|
|
31
|
+
}
|
|
32
|
+
// @ts-expect-error TS2536
|
|
33
|
+
this.rules[rule.name] = rule;
|
|
34
|
+
// @ts-expect-error TS2536
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
addRule(rule) {
|
|
38
|
+
return this.addRuleRedundant(rule);
|
|
39
|
+
}
|
|
40
|
+
addMany(...rules
|
|
41
|
+
// @ts-expect-error TS2536
|
|
42
|
+
) {
|
|
43
|
+
this.rules = { ...this.rules, ...listToRuleDefMap(rules) };
|
|
44
|
+
// @ts-expect-error TS2536
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
deleteRule(ruleName) {
|
|
48
|
+
delete this.rules[ruleName];
|
|
49
|
+
// @ts-expect-error TS2536
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
merge(builder, overridingRules) {
|
|
53
|
+
// Assume the other grammar is bigger than yours. So start from that one and add this one
|
|
54
|
+
const otherRules = { ...builder.rules };
|
|
55
|
+
const myRules = this.rules;
|
|
56
|
+
for (const rule of Object.values(myRules)) {
|
|
57
|
+
if (otherRules[rule.name] === undefined) {
|
|
58
|
+
otherRules[rule.name] = rule;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
const existingRule = otherRules[rule.name];
|
|
62
|
+
// If same rule, no issue, move on. Else
|
|
63
|
+
if (existingRule !== rule) {
|
|
64
|
+
const override = overridingRules.find(x => x.name === rule.name);
|
|
65
|
+
// If override specified, take override, else, inform user that there is a conflict
|
|
66
|
+
if (override) {
|
|
67
|
+
otherRules[rule.name] = override;
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
throw new Error(`Rule with name "${rule.name}" already exists in the builder, specify an override to resolve conflict`);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// @ts-expect-error TS2322
|
|
76
|
+
this.rules = otherRules;
|
|
77
|
+
// @ts-expect-error TS2322
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
consumeToParser({ tokenVocabulary, parserConfig = {}, lexerConfig = {} }, context = {}) {
|
|
81
|
+
const lexer = new Lexer(tokenVocabulary, {
|
|
82
|
+
positionTracking: 'onlyStart',
|
|
83
|
+
recoveryEnabled: false,
|
|
84
|
+
// SafeMode: true,
|
|
85
|
+
// SkipValidations: true,
|
|
86
|
+
ensureOptimizations: true,
|
|
87
|
+
...lexerConfig,
|
|
88
|
+
});
|
|
89
|
+
const parser = this.consume({ tokenVocabulary, config: parserConfig }, context);
|
|
90
|
+
const selfSufficientParser = {};
|
|
91
|
+
// eslint-disable-next-line ts/no-unnecessary-type-assertion
|
|
92
|
+
for (const rule of Object.values(this.rules)) {
|
|
93
|
+
// @ts-expect-error TS7053
|
|
94
|
+
selfSufficientParser[rule.name] = (input, ...args) => {
|
|
95
|
+
// Transform input in accordance to 19.2
|
|
96
|
+
input = input.replaceAll(/\\u([0-9a-fA-F]{4})|\\U([0-9a-fA-F]{8})/gu, (_, unicode4, unicode8) => {
|
|
97
|
+
if (unicode4) {
|
|
98
|
+
const charCode = Number.parseInt(unicode4, 16);
|
|
99
|
+
return String.fromCodePoint(charCode);
|
|
100
|
+
}
|
|
101
|
+
const charCode = Number.parseInt(unicode8, 16);
|
|
102
|
+
if (charCode < 0xFFFF) {
|
|
103
|
+
return String.fromCodePoint(charCode);
|
|
104
|
+
}
|
|
105
|
+
const substractedCharCode = charCode - 0x10000;
|
|
106
|
+
return String.fromCodePoint(0xD800 + (substractedCharCode >> 10), 0xDC00 + (substractedCharCode & 0x3FF));
|
|
107
|
+
});
|
|
108
|
+
// Test for invalid unicode surrogate pairs
|
|
109
|
+
if (/[\uD800-\uDBFF]([^\uDC00-\uDFFF]|$)/u.test(input)) {
|
|
110
|
+
throw new Error(`Invalid unicode codepoint of surrogate pair without corresponding codepoint`);
|
|
111
|
+
}
|
|
112
|
+
const lexResult = lexer.tokenize(input);
|
|
113
|
+
// Console.log(lexResult.tokens);
|
|
114
|
+
parser.reset();
|
|
115
|
+
parser.input = lexResult.tokens;
|
|
116
|
+
const result = parser[rule.name](...args);
|
|
117
|
+
if (parser.errors.length > 0) {
|
|
118
|
+
// Console.log(lexResult.tokens);
|
|
119
|
+
throw new Error(`Parse error on line ${parser.errors.map(x => x.token.startLine).join(', ')}
|
|
120
|
+
${parser.errors.map(x => `${x.token.startLine}: ${x.message}`).join('\n')}`);
|
|
121
|
+
}
|
|
122
|
+
return result;
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
return selfSufficientParser;
|
|
126
|
+
}
|
|
127
|
+
consume({ tokenVocabulary, config = {} }, context = {}) {
|
|
128
|
+
const rules = this.rules;
|
|
129
|
+
class MyParser extends EmbeddedActionsParser {
|
|
130
|
+
constructor() {
|
|
131
|
+
super(tokenVocabulary, {
|
|
132
|
+
// RecoveryEnabled: true,
|
|
133
|
+
maxLookahead: 2,
|
|
134
|
+
// SkipValidations: true,
|
|
135
|
+
...config,
|
|
136
|
+
});
|
|
137
|
+
const selfRef = this.getSelfRef();
|
|
138
|
+
// Remember to change the reset function accordingly!
|
|
139
|
+
this.initialParseContext = {
|
|
140
|
+
dataFactory: new DataFactory({ blankNodePrefix: 'g_' }),
|
|
141
|
+
baseIRI: undefined,
|
|
142
|
+
flushedBlankNodeLabels: new Set(),
|
|
143
|
+
usedBlankNodeLabels: new Set(),
|
|
144
|
+
parseMode: new Set(),
|
|
145
|
+
skipValidation: false,
|
|
146
|
+
...context,
|
|
147
|
+
prefixes: context.prefixes ? { ...context.prefixes } : {},
|
|
148
|
+
};
|
|
149
|
+
this.runningContext = {
|
|
150
|
+
...this.initialParseContext,
|
|
151
|
+
prefixes: { ...this.initialParseContext.prefixes },
|
|
152
|
+
parseMode: new Set(this.initialParseContext.parseMode),
|
|
153
|
+
};
|
|
154
|
+
const implArgs = {
|
|
155
|
+
...selfRef,
|
|
156
|
+
cache: new WeakMap(),
|
|
157
|
+
context: this.runningContext,
|
|
158
|
+
};
|
|
159
|
+
for (const rule of Object.values(rules)) {
|
|
160
|
+
// @ts-expect-error TS7053
|
|
161
|
+
this[rule.name] = this.RULE(rule.name, rule.impl(implArgs));
|
|
162
|
+
}
|
|
163
|
+
this.performSelfAnalysis();
|
|
164
|
+
}
|
|
165
|
+
reset() {
|
|
166
|
+
super.reset();
|
|
167
|
+
// We need to keep the original object reference.
|
|
168
|
+
Object.assign(this.runningContext, {
|
|
169
|
+
...this.initialParseContext,
|
|
170
|
+
});
|
|
171
|
+
this.runningContext.prefixes = { ...this.initialParseContext.prefixes };
|
|
172
|
+
this.runningContext.parseMode = new Set(this.initialParseContext.parseMode);
|
|
173
|
+
this.runningContext.usedBlankNodeLabels.clear();
|
|
174
|
+
this.runningContext.flushedBlankNodeLabels.clear();
|
|
175
|
+
}
|
|
176
|
+
getSelfRef() {
|
|
177
|
+
return {
|
|
178
|
+
CONSUME: (tokenType, option) => this.CONSUME(tokenType, option),
|
|
179
|
+
CONSUME1: (tokenType, option) => this.CONSUME1(tokenType, option),
|
|
180
|
+
CONSUME2: (tokenType, option) => this.CONSUME2(tokenType, option),
|
|
181
|
+
CONSUME3: (tokenType, option) => this.CONSUME3(tokenType, option),
|
|
182
|
+
CONSUME4: (tokenType, option) => this.CONSUME4(tokenType, option),
|
|
183
|
+
CONSUME5: (tokenType, option) => this.CONSUME5(tokenType, option),
|
|
184
|
+
CONSUME6: (tokenType, option) => this.CONSUME6(tokenType, option),
|
|
185
|
+
CONSUME7: (tokenType, option) => this.CONSUME7(tokenType, option),
|
|
186
|
+
CONSUME8: (tokenType, option) => this.CONSUME8(tokenType, option),
|
|
187
|
+
CONSUME9: (tokenType, option) => this.CONSUME9(tokenType, option),
|
|
188
|
+
OPTION: actionORMethodDef => this.OPTION(actionORMethodDef),
|
|
189
|
+
OPTION1: actionORMethodDef => this.OPTION1(actionORMethodDef),
|
|
190
|
+
OPTION2: actionORMethodDef => this.OPTION2(actionORMethodDef),
|
|
191
|
+
OPTION3: actionORMethodDef => this.OPTION3(actionORMethodDef),
|
|
192
|
+
OPTION4: actionORMethodDef => this.OPTION4(actionORMethodDef),
|
|
193
|
+
OPTION5: actionORMethodDef => this.OPTION5(actionORMethodDef),
|
|
194
|
+
OPTION6: actionORMethodDef => this.OPTION6(actionORMethodDef),
|
|
195
|
+
OPTION7: actionORMethodDef => this.OPTION7(actionORMethodDef),
|
|
196
|
+
OPTION8: actionORMethodDef => this.OPTION8(actionORMethodDef),
|
|
197
|
+
OPTION9: actionORMethodDef => this.OPTION9(actionORMethodDef),
|
|
198
|
+
OR: altsOrOpts => this.OR(altsOrOpts),
|
|
199
|
+
OR1: altsOrOpts => this.OR1(altsOrOpts),
|
|
200
|
+
OR2: altsOrOpts => this.OR2(altsOrOpts),
|
|
201
|
+
OR3: altsOrOpts => this.OR3(altsOrOpts),
|
|
202
|
+
OR4: altsOrOpts => this.OR4(altsOrOpts),
|
|
203
|
+
OR5: altsOrOpts => this.OR5(altsOrOpts),
|
|
204
|
+
OR6: altsOrOpts => this.OR6(altsOrOpts),
|
|
205
|
+
OR7: altsOrOpts => this.OR7(altsOrOpts),
|
|
206
|
+
OR8: altsOrOpts => this.OR8(altsOrOpts),
|
|
207
|
+
OR9: altsOrOpts => this.OR9(altsOrOpts),
|
|
208
|
+
MANY: actionORMethodDef => this.MANY(actionORMethodDef),
|
|
209
|
+
MANY1: actionORMethodDef => this.MANY1(actionORMethodDef),
|
|
210
|
+
MANY2: actionORMethodDef => this.MANY2(actionORMethodDef),
|
|
211
|
+
MANY3: actionORMethodDef => this.MANY3(actionORMethodDef),
|
|
212
|
+
MANY4: actionORMethodDef => this.MANY4(actionORMethodDef),
|
|
213
|
+
MANY5: actionORMethodDef => this.MANY5(actionORMethodDef),
|
|
214
|
+
MANY6: actionORMethodDef => this.MANY6(actionORMethodDef),
|
|
215
|
+
MANY7: actionORMethodDef => this.MANY7(actionORMethodDef),
|
|
216
|
+
MANY8: actionORMethodDef => this.MANY8(actionORMethodDef),
|
|
217
|
+
MANY9: actionORMethodDef => this.MANY9(actionORMethodDef),
|
|
218
|
+
MANY_SEP: options => this.MANY_SEP(options),
|
|
219
|
+
MANY_SEP1: options => this.MANY_SEP1(options),
|
|
220
|
+
MANY_SEP2: options => this.MANY_SEP2(options),
|
|
221
|
+
MANY_SEP3: options => this.MANY_SEP3(options),
|
|
222
|
+
MANY_SEP4: options => this.MANY_SEP4(options),
|
|
223
|
+
MANY_SEP5: options => this.MANY_SEP5(options),
|
|
224
|
+
MANY_SEP6: options => this.MANY_SEP6(options),
|
|
225
|
+
MANY_SEP7: options => this.MANY_SEP7(options),
|
|
226
|
+
MANY_SEP8: options => this.MANY_SEP8(options),
|
|
227
|
+
MANY_SEP9: options => this.MANY_SEP9(options),
|
|
228
|
+
AT_LEAST_ONE: actionORMethodDef => this.AT_LEAST_ONE(actionORMethodDef),
|
|
229
|
+
AT_LEAST_ONE1: actionORMethodDef => this.AT_LEAST_ONE1(actionORMethodDef),
|
|
230
|
+
AT_LEAST_ONE2: actionORMethodDef => this.AT_LEAST_ONE2(actionORMethodDef),
|
|
231
|
+
AT_LEAST_ONE3: actionORMethodDef => this.AT_LEAST_ONE3(actionORMethodDef),
|
|
232
|
+
AT_LEAST_ONE4: actionORMethodDef => this.AT_LEAST_ONE4(actionORMethodDef),
|
|
233
|
+
AT_LEAST_ONE5: actionORMethodDef => this.AT_LEAST_ONE5(actionORMethodDef),
|
|
234
|
+
AT_LEAST_ONE6: actionORMethodDef => this.AT_LEAST_ONE6(actionORMethodDef),
|
|
235
|
+
AT_LEAST_ONE7: actionORMethodDef => this.AT_LEAST_ONE7(actionORMethodDef),
|
|
236
|
+
AT_LEAST_ONE8: actionORMethodDef => this.AT_LEAST_ONE8(actionORMethodDef),
|
|
237
|
+
AT_LEAST_ONE9: actionORMethodDef => this.AT_LEAST_ONE9(actionORMethodDef),
|
|
238
|
+
AT_LEAST_ONE_SEP: options => this.AT_LEAST_ONE_SEP(options),
|
|
239
|
+
AT_LEAST_ONE_SEP1: options => this.AT_LEAST_ONE_SEP1(options),
|
|
240
|
+
AT_LEAST_ONE_SEP2: options => this.AT_LEAST_ONE_SEP2(options),
|
|
241
|
+
AT_LEAST_ONE_SEP3: options => this.AT_LEAST_ONE_SEP3(options),
|
|
242
|
+
AT_LEAST_ONE_SEP4: options => this.AT_LEAST_ONE_SEP4(options),
|
|
243
|
+
AT_LEAST_ONE_SEP5: options => this.AT_LEAST_ONE_SEP5(options),
|
|
244
|
+
AT_LEAST_ONE_SEP6: options => this.AT_LEAST_ONE_SEP6(options),
|
|
245
|
+
AT_LEAST_ONE_SEP7: options => this.AT_LEAST_ONE_SEP7(options),
|
|
246
|
+
AT_LEAST_ONE_SEP8: options => this.AT_LEAST_ONE_SEP8(options),
|
|
247
|
+
AT_LEAST_ONE_SEP9: options => this.AT_LEAST_ONE_SEP9(options),
|
|
248
|
+
ACTION: func => this.ACTION(func),
|
|
249
|
+
BACKTRACK: (cstDef, ...args) => {
|
|
250
|
+
try {
|
|
251
|
+
// @ts-expect-error TS7053
|
|
252
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
253
|
+
return this.BACKTRACK(this[cstDef.name], { ARGS: args });
|
|
254
|
+
}
|
|
255
|
+
catch (error) {
|
|
256
|
+
throw error;
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
SUBRULE: (cstDef, ...args) => {
|
|
260
|
+
try {
|
|
261
|
+
// @ts-expect-error TS7053
|
|
262
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
263
|
+
return this.SUBRULE(this[cstDef.name], { ARGS: args });
|
|
264
|
+
}
|
|
265
|
+
catch (error) {
|
|
266
|
+
throw error;
|
|
267
|
+
}
|
|
268
|
+
},
|
|
269
|
+
SUBRULE1: (cstDef, ...args) => {
|
|
270
|
+
try {
|
|
271
|
+
// @ts-expect-error TS7053
|
|
272
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
273
|
+
return this.SUBRULE1(this[cstDef.name], { ARGS: args });
|
|
274
|
+
}
|
|
275
|
+
catch (error) {
|
|
276
|
+
throw error;
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
SUBRULE2: (cstDef, ...args) => {
|
|
280
|
+
try {
|
|
281
|
+
// @ts-expect-error TS7053
|
|
282
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
283
|
+
return this.SUBRULE2(this[cstDef.name], { ARGS: args });
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
throw error;
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
SUBRULE3: (cstDef, ...args) => {
|
|
290
|
+
try {
|
|
291
|
+
// @ts-expect-error TS7053
|
|
292
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
293
|
+
return this.SUBRULE3(this[cstDef.name], { ARGS: args });
|
|
294
|
+
}
|
|
295
|
+
catch (error) {
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
},
|
|
299
|
+
SUBRULE4: (cstDef, ...args) => {
|
|
300
|
+
try {
|
|
301
|
+
// @ts-expect-error TS7053
|
|
302
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
303
|
+
return this.SUBRULE4(this[cstDef.name], { ARGS: args });
|
|
304
|
+
}
|
|
305
|
+
catch (error) {
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
SUBRULE5: (cstDef, ...args) => {
|
|
310
|
+
try {
|
|
311
|
+
// @ts-expect-error TS7053
|
|
312
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
313
|
+
return this.SUBRULE5(this[cstDef.name], { ARGS: args });
|
|
314
|
+
}
|
|
315
|
+
catch (error) {
|
|
316
|
+
throw error;
|
|
317
|
+
}
|
|
318
|
+
},
|
|
319
|
+
SUBRULE6: (cstDef, ...args) => {
|
|
320
|
+
try {
|
|
321
|
+
// @ts-expect-error TS7053
|
|
322
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
323
|
+
return this.SUBRULE6(this[cstDef.name], { ARGS: args });
|
|
324
|
+
}
|
|
325
|
+
catch (error) {
|
|
326
|
+
throw error;
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
SUBRULE7: (cstDef, ...args) => {
|
|
330
|
+
try {
|
|
331
|
+
// @ts-expect-error TS7053
|
|
332
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
333
|
+
return this.SUBRULE7(this[cstDef.name], { ARGS: args });
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
},
|
|
339
|
+
SUBRULE8: (cstDef, ...args) => {
|
|
340
|
+
try {
|
|
341
|
+
// @ts-expect-error TS7053
|
|
342
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
343
|
+
return this.SUBRULE8(this[cstDef.name], { ARGS: args });
|
|
344
|
+
}
|
|
345
|
+
catch (error) {
|
|
346
|
+
throw error;
|
|
347
|
+
}
|
|
348
|
+
},
|
|
349
|
+
SUBRULE9: (cstDef, ...args) => {
|
|
350
|
+
try {
|
|
351
|
+
// @ts-expect-error TS7053
|
|
352
|
+
// eslint-disable-next-line ts/no-unsafe-argument
|
|
353
|
+
return this.SUBRULE9(this[cstDef.name], { ARGS: args });
|
|
354
|
+
}
|
|
355
|
+
catch (error) {
|
|
356
|
+
throw error;
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return new MyParser();
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
//# sourceMappingURL=parserBuilder.js.map
|