@traqula/core 0.0.1-alpha.145 → 0.0.1-alpha.176

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.
Files changed (51) hide show
  1. package/README.md +44 -22
  2. package/lib/generator-builder/builderTypes.d.ts +20 -0
  3. package/lib/generator-builder/builderTypes.js.map +1 -0
  4. package/lib/generator-builder/dynamicGenerator.d.ts +7 -0
  5. package/lib/generator-builder/dynamicGenerator.js +28 -0
  6. package/lib/generator-builder/dynamicGenerator.js.map +1 -0
  7. package/lib/generator-builder/generatorBuilder.d.ts +58 -0
  8. package/lib/generator-builder/generatorBuilder.js +101 -0
  9. package/lib/generator-builder/generatorBuilder.js.map +1 -0
  10. package/lib/generator-builder/generatorTypes.d.ts +27 -0
  11. package/lib/generator-builder/generatorTypes.js +2 -0
  12. package/lib/generator-builder/generatorTypes.js.map +1 -0
  13. package/lib/index.cjs +388 -643
  14. package/lib/index.d.ts +7 -6
  15. package/lib/index.js +11 -6
  16. package/lib/index.js.map +1 -1
  17. package/lib/lexer-builder/LexerBuilder.d.ts +7 -9
  18. package/lib/lexer-builder/LexerBuilder.js +12 -4
  19. package/lib/lexer-builder/LexerBuilder.js.map +1 -1
  20. package/lib/parser-builder/builderTypes.d.ts +24 -0
  21. package/lib/parser-builder/builderTypes.js +2 -0
  22. package/lib/parser-builder/builderTypes.js.map +1 -0
  23. package/lib/parser-builder/dynamicParser.d.ts +9 -0
  24. package/lib/parser-builder/dynamicParser.js +113 -0
  25. package/lib/parser-builder/dynamicParser.js.map +1 -0
  26. package/lib/parser-builder/parserBuilder.d.ts +73 -0
  27. package/lib/parser-builder/parserBuilder.js +161 -0
  28. package/lib/parser-builder/parserBuilder.js.map +1 -0
  29. package/lib/{grammar-builder → parser-builder}/ruleDefTypes.d.ts +45 -29
  30. package/lib/parser-builder/ruleDefTypes.js.map +1 -0
  31. package/lib/utils.d.ts +17 -0
  32. package/lib/utils.js +8 -0
  33. package/lib/utils.js.map +1 -0
  34. package/package.json +8 -10
  35. package/lib/Wildcard.d.ts +0 -9
  36. package/lib/Wildcard.js +0 -19
  37. package/lib/Wildcard.js.map +0 -1
  38. package/lib/grammar-builder/builderTypes.d.ts +0 -19
  39. package/lib/grammar-builder/builderTypes.js.map +0 -1
  40. package/lib/grammar-builder/parserBuilder.d.ts +0 -50
  41. package/lib/grammar-builder/parserBuilder.js +0 -276
  42. package/lib/grammar-builder/parserBuilder.js.map +0 -1
  43. package/lib/grammar-builder/ruleDefTypes.js.map +0 -1
  44. package/lib/grammar-helpers/utils.d.ts +0 -16
  45. package/lib/grammar-helpers/utils.js +0 -53
  46. package/lib/grammar-helpers/utils.js.map +0 -1
  47. package/lib/lexer-helper/utils.d.ts +0 -6
  48. package/lib/lexer-helper/utils.js +0 -5
  49. package/lib/lexer-helper/utils.js.map +0 -1
  50. /package/lib/{grammar-builder → generator-builder}/builderTypes.js +0 -0
  51. /package/lib/{grammar-builder → parser-builder}/ruleDefTypes.js +0 -0
package/README.md CHANGED
@@ -1,9 +1,11 @@
1
- # TRAQULA core package
1
+ # Traqula core package
2
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
3
+ **WARNING:** V2 will come shortly and will have lots of breaking changes.
4
+
5
+ Traqula core contains core components of Traqula.
6
+ Most importantly, its [lexer builder](./lib/lexer-builder/LexerBuilder.ts), [parser builder](./lib/parser-builder/parserBuilder.ts), and [generator builder](./lib/generator-builder/generatorBuilder.ts).
7
+ This library heavily relies on the amazing [Chevrotain package](https://chevrotain.io/docs/).
8
+ Knowing the basics of that package will allow you to quickly generate your own grammars.
7
9
 
8
10
  ## Installation
9
11
 
@@ -19,12 +21,12 @@ yarn add @traqula/core
19
21
 
20
22
  ## Usage
21
23
 
22
- Each parser contains two steps:
24
+ Each parser contains two steps:
23
25
  1. a lexer
24
26
  2. a grammar + abstract syntax tree generation step.
25
27
 
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
+ Sometimes grammar definitions and abstract syntax tree generation is split into separate steps.
29
+ In this library, we choose to keep the two together when building a parser.
28
30
 
29
31
  ### Lexer Builder
30
32
 
@@ -38,10 +40,10 @@ To create a token definition, you use the provided function `createToken` like:
38
40
  const select = createToken({ name: 'Select', pattern: /select/i, label: 'SELECT' });
39
41
  ```
40
42
 
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.
43
+ 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**](https://chevrotain.io/docs/tutorial/step1_lexing.html#creating-the-lexer) that matches.
42
44
  Note that the order of definitions in the list is thus essential.
43
45
 
44
- We therefore use a `lexer-builder` which allows you to easily:
46
+ We therefore use a [lexer builder](./lib/lexer-builder/LexerBuilder.ts) which allows you to easily:
45
47
  1. change the order of lexer rules,
46
48
  2. and create a new lexer staring from an existing one.
47
49
 
@@ -56,11 +58,11 @@ A new lexer can be created from an existing one by calling:
56
58
  const sparql11AdjustTokens = sparql11Tokens.addBefore(select, BuiltInAdjust);
57
59
  ```
58
60
 
59
- ### Grammar Builder
61
+ ### Parser Builder
60
62
 
61
63
  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
+ Grammar rule definitions come in the form of [ParserRule](./lib/parser-builder/ruleDefTypes.ts) objects.
65
+ Each `ParserRule` object contains its name and its returnType.
64
66
  Optionally, it can also contain arguments that should be provided to the SUBRULE calls.
65
67
  A simple example of a grammar rule is the rule bellow that allows you to parse booleanLiterals.
66
68
 
@@ -69,7 +71,7 @@ A simple example of a grammar rule is the rule bellow that allows you to parse b
69
71
  * Parses a boolean literal.
70
72
  * [[134]](https://www.w3.org/TR/sparql11-query/#rBooleanLiteral)
71
73
  */
72
- export const booleanLiteral: RuleDef<'booleanLiteral', LiteralTerm> = <const> {
74
+ export const booleanLiteral: ParserRule<'booleanLiteral', LiteralTerm> = <const> {
73
75
  name: 'booleanLiteral',
74
76
  impl: ({ CONSUME, OR, context }) => () => OR([
75
77
  { ALT: () => context.dataFactory.literal(
@@ -84,20 +86,19 @@ export const booleanLiteral: RuleDef<'booleanLiteral', LiteralTerm> = <const> {
84
86
  };
85
87
  ```
86
88
 
87
- The `impl` member of `RuleDef` is a function that receives:
89
+ The `impl` member of `ParserRule` is a function that receives:
88
90
  1. essential functions to create a grammar rule (capitalized members),
89
91
  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.
92
+ 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, [increasing parser performance](https://chevrotain.io/docs/guide/performance.html#caching-arrays-of-alternatives).
91
93
 
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
+ You cannot unpack the context entry in the function definition itself because the parser uses a [recording phase](https://chevrotain.io/docs/guide/internals.html#grammar-recording) to optimize itself. During this phase, the context entry will be undefined, as such, it can only be accessed within the `ACTION` function.
94
95
 
95
96
  The result of an `impl` call is a function called a `rule`.
96
97
  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.
98
+ Personally I create a function that can be used to create multiple `ParserRule` objects.
99
+ The result of a rule should match the type provided in the `ParserRule` definition, and is the result of a call of `SUBRULE` with that rule.
99
100
 
100
- ### Patching rules
101
+ #### Patching rules
101
102
 
102
103
  When a rule definition calls to a subrule using `SUBRULE(mySub)`, the implementation itself is not necessarily called.
103
104
  That is because the SUBRULE function will call the function with the same name as `mySub` that is present in the current grammarBuilder.
@@ -112,4 +113,25 @@ const myBuilder = Builder
112
113
  ```
113
114
 
114
115
  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.
116
+ it will instead call `selectRuleAlternative` since it overwrote the function `selectRule` with the same name.
117
+
118
+ ### Generator Builder
119
+
120
+ The generator builder function in much the same as the [parser builder](#parser-builder).
121
+ Your builder expects objects of type [GeneratorRule](lib/generator-builder/generatorTypes.ts),
122
+ containing the implementation of the generator in the `gImpl` member.
123
+ The `gImpl` function gets essential functions to create a generator rule (capitalized members),
124
+ returning a function that will get the AST and context, returning a string.
125
+ For generator rules, you can unpack the context since no recording phase is present in this case.
126
+ The idea is that GeneratorRules and ParserRules can be tied together in the same object, as such, similar behaviour is grouped together.
127
+
128
+ ```typescript
129
+ /**
130
+ * Parses a named node, either as an IRI or as a prefixed name.
131
+ * [[136]](https://www.w3.org/TR/sparql11-query/#riri)
132
+ */
133
+ export const iri: GeneratorRule<'iri', IriTerm> = <const> {
134
+ name: 'iri',
135
+ gImpl: () => ast => ast.value,
136
+ };
137
+ ```
@@ -0,0 +1,20 @@
1
+ import type { GeneratorRule } from './generatorTypes';
2
+ /**
3
+ * Get union-type of names used in list of ruledefs.
4
+ */
5
+ export type GenNamesFromList<T extends readonly GeneratorRule[]> = T[number]['name'];
6
+ /**
7
+ * Convert a list of ruledefs to a record that maps each rule name to its definition.
8
+ */
9
+ export type GenRuleMap<RuleNames extends string> = {
10
+ [Key in RuleNames]: GeneratorRule<any, Key>;
11
+ };
12
+ /**
13
+ * Convert a list of RuleDefs to a Record with the name of the RuleDef as the key, matching the RuleDefMap type.
14
+ */
15
+ export type GenRulesToObject<T extends readonly GeneratorRule[], Names extends string = GenNamesFromList<T>, Agg extends Record<string, GeneratorRule> = Record<never, never>> = T extends readonly [infer First, ...infer Rest] ? (First extends GeneratorRule ? (Rest extends readonly GeneratorRule[] ? (GenRulesToObject<Rest, Names, {
16
+ [K in keyof Agg | First['name']]: K extends First['name'] ? First : Agg[K];
17
+ }>) : never) : never) : GenRuleMap<Names> & Agg;
18
+ export type GeneratorFromRules<Context, Names extends string, RuleDefs extends GenRuleMap<Names>> = {
19
+ [K in Names]: RuleDefs[K] extends GeneratorRule<Context, K, infer RET, infer ARGS> ? (input: RET, context: Context, args: ARGS) => string : never;
20
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"builderTypes.js","sourceRoot":"","sources":["builderTypes.ts"],"names":[],"mappings":"","sourcesContent":["import type { GeneratorRule } from './generatorTypes';\n\n/**\n * Get union-type of names used in list of ruledefs.\n */\nexport type GenNamesFromList<T extends readonly GeneratorRule[]> = T[number]['name'];\n\n/**\n * Convert a list of ruledefs to a record that maps each rule name to its definition.\n */\nexport type GenRuleMap<RuleNames extends string> = {[Key in RuleNames]: GeneratorRule<any, Key> };\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 GenRulesToObject<\n T extends readonly GeneratorRule[],\n Names extends string = GenNamesFromList<T>,\n Agg extends Record<string, GeneratorRule> = Record<never, never>,\n> = T extends readonly [infer First, ...infer Rest] ? (\n First extends GeneratorRule ? (\n Rest extends readonly GeneratorRule[] ? (\n GenRulesToObject<Rest, Names, {[K in keyof Agg | First['name']]: K extends First['name'] ? First : Agg[K] }>\n ) : never\n ) : never\n) : GenRuleMap<Names> & Agg;\n\nexport type GeneratorFromRules<Context, Names extends string, RuleDefs extends GenRuleMap<Names>> = {\n [K in Names]: RuleDefs[K] extends GeneratorRule<Context, K, infer RET, infer ARGS> ?\n (input: RET, context: Context, args: ARGS) => string : never\n};\n"]}
@@ -0,0 +1,7 @@
1
+ import type { GenRuleMap } from './builderTypes';
2
+ export declare class DynamicGenerator<Context, Names extends string, RuleDefs extends GenRuleMap<Names>> {
3
+ private __context;
4
+ setContext(context: Context): void;
5
+ private getSafeContext;
6
+ constructor(rules: RuleDefs);
7
+ }
@@ -0,0 +1,28 @@
1
+ export class DynamicGenerator {
2
+ setContext(context) {
3
+ this.__context = context;
4
+ }
5
+ getSafeContext() {
6
+ return this.__context;
7
+ }
8
+ constructor(rules) {
9
+ this.__context = undefined;
10
+ const selfRef = {
11
+ SUBRULE: (cstDef, input, arg) => {
12
+ const def = rules[cstDef.name];
13
+ if (!def) {
14
+ throw new Error(`Rule ${cstDef.name} not found`);
15
+ }
16
+ return def.gImpl(selfRef)(input, this.getSafeContext(), arg);
17
+ },
18
+ };
19
+ // eslint-disable-next-line ts/no-unnecessary-type-assertion
20
+ for (const rule of Object.values(rules)) {
21
+ this[rule.name] = ((input, context, args) => {
22
+ this.setContext(context);
23
+ return rule.gImpl(selfRef)(input, this.getSafeContext(), args);
24
+ });
25
+ }
26
+ }
27
+ }
28
+ //# sourceMappingURL=dynamicGenerator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dynamicGenerator.js","sourceRoot":"","sources":["dynamicGenerator.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,gBAAgB;IAGpB,UAAU,CAAC,OAAgB;QAChC,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC;IAC3B,CAAC;IAEO,cAAc;QACpB,OAAiB,IAAI,CAAC,SAAS,CAAC;IAClC,CAAC;IAED,YAAmB,KAAe;QAV1B,cAAS,GAAwB,SAAS,CAAC;QAWjD,MAAM,OAAO,GAAe;YAC1B,OAAO,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE;gBAC9B,MAAM,GAAG,GAAG,KAAK,CAAQ,MAAM,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,CAAC,GAAG,EAAE,CAAC;oBACT,MAAM,IAAI,KAAK,CAAC,QAAQ,MAAM,CAAC,IAAI,YAAY,CAAC,CAAC;gBACnD,CAAC;gBACD,OAAO,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,CAAC,CAAC;YAC/D,CAAC;SACF,CAAC;QAEF,4DAA4D;QAC5D,KAAK,MAAM,IAAI,IAAqB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,IAAI,CAAsB,IAAI,CAAC,IAAI,CAAC,GAAQ,CAAC,CAAC,KAAU,EAAE,OAAgB,EAAE,IAAS,EAAE,EAAE;gBACvF,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;gBACzB,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,IAAI,CAAC,CAAC;YACjE,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF","sourcesContent":["import type { GenRuleMap } from './builderTypes';\nimport type { GeneratorRule, RuleDefArg } from './generatorTypes';\n\nexport class DynamicGenerator<Context, Names extends string, RuleDefs extends GenRuleMap<Names>> {\n private __context: Context | undefined = undefined;\n\n public setContext(context: Context): void {\n this.__context = context;\n }\n\n private getSafeContext(): Context {\n return <Context> this.__context;\n }\n\n public constructor(rules: RuleDefs) {\n const selfRef: RuleDefArg = {\n SUBRULE: (cstDef, input, arg) => {\n const def = rules[<Names>cstDef.name];\n if (!def) {\n throw new Error(`Rule ${cstDef.name} not found`);\n }\n return def.gImpl(selfRef)(input, this.getSafeContext(), arg);\n },\n };\n\n // eslint-disable-next-line ts/no-unnecessary-type-assertion\n for (const rule of <GeneratorRule[]>Object.values(rules)) {\n this[<keyof (typeof this)>rule.name] = <any>((input: any, context: Context, args: any) => {\n this.setContext(context);\n return rule.gImpl(selfRef)(input, this.getSafeContext(), args);\n });\n }\n }\n}\n"]}
@@ -0,0 +1,58 @@
1
+ import type { CheckOverlap } from '../utils';
2
+ import type { GeneratorFromRules, GenNamesFromList, GenRuleMap, GenRulesToObject } from './builderTypes';
3
+ import type { GeneratorRule } from './generatorTypes';
4
+ export declare class GeneratorBuilder<Context, Names extends string, RuleDefs extends GenRuleMap<Names>> {
5
+ /**
6
+ * Create a GeneratorBuilder from some initial grammar rules or an existing GeneratorBuilder.
7
+ * If a GeneratorBuilder is provided, a new copy will be created.
8
+ */
9
+ static createBuilder<Context, Names extends string, RuleDefs extends GenRuleMap<Names>>(args: GeneratorBuilder<Context, Names, RuleDefs>): GeneratorBuilder<Context, Names, RuleDefs>;
10
+ static createBuilder<Rules extends readonly GeneratorRule[] = readonly GeneratorRule[], Context = Rules[0] extends GeneratorRule<infer context> ? context : never, Names extends string = GenNamesFromList<Rules>, RuleDefs extends GenRuleMap<Names> = GenRulesToObject<Rules>>(rules: Rules): GeneratorBuilder<Context, Names, RuleDefs>;
11
+ private rules;
12
+ private constructor();
13
+ typePatch<Patch extends {
14
+ [Key in Names]?: any;
15
+ }>(): GeneratorBuilder<Context, Names, {
16
+ [Key in Names]: Key extends keyof Patch ? (RuleDefs[Key] extends GeneratorRule<Context, Key, any, infer Args> ? GeneratorRule<Context, Key, Patch[Key], Args> : never) : (RuleDefs[Key] extends GeneratorRule<Context, Key> ? RuleDefs[Key] : never);
17
+ }>;
18
+ /**
19
+ * Change the implementation of an existing generator rule.
20
+ */
21
+ patchRule<U extends Names, RET, ARGS>(patch: GeneratorRule<Context, U, RET, ARGS>): GeneratorBuilder<Context, Names, {
22
+ [Key in Names]: Key extends U ? GeneratorRule<Context, Key, RET, ARGS> : (RuleDefs[Key] extends GeneratorRule<Context, Key> ? RuleDefs[Key] : never);
23
+ }>;
24
+ /**
25
+ * Add a rule to the grammar. If the rule already exists, but the implementation differs, an error will be thrown.
26
+ */
27
+ addRuleRedundant<U extends string, RET, ARGS>(rule: GeneratorRule<Context, U, RET, ARGS>): GeneratorBuilder<Context, Names | U, {
28
+ [K in Names | U]: K extends Names ? (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never) : (K extends U ? GeneratorRule<Context, K, RET, ARGS> : never);
29
+ }>;
30
+ /**
31
+ * Add a rule to the grammar. Will raise a typescript error if the rule already exists in the grammar.
32
+ */
33
+ addRule<U extends string, RET, ARGS>(rule: CheckOverlap<U, Names, GeneratorRule<Context, U, RET, ARGS>>): GeneratorBuilder<Context, Names | U, {
34
+ [K in Names | U]: K extends Names ? (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never) : (K extends U ? GeneratorRule<Context, K, RET, ARGS> : never);
35
+ }>;
36
+ addMany<U extends readonly GeneratorRule<Context>[]>(...rules: CheckOverlap<GenNamesFromList<U>, Names, U>): GeneratorBuilder<Context, Names | GenNamesFromList<U>, {
37
+ [K in Names | GenNamesFromList<U>]: K extends keyof GenRulesToObject<typeof rules> ? (GenRulesToObject<typeof rules>[K] extends GeneratorRule<Context, K> ? GenRulesToObject<typeof rules>[K] : never) : (K extends Names ? (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never) : never);
38
+ }>;
39
+ /**
40
+ * Delete a grammar rule by its name.
41
+ */
42
+ deleteRule<U extends Names>(ruleName: U): GeneratorBuilder<Context, Exclude<Names, U>, {
43
+ [K in Exclude<Names, U>]: RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never;
44
+ }>;
45
+ /**
46
+ * Merge this grammar GeneratorBuilder with another.
47
+ * It is best to merge the bigger grammar with the smaller one.
48
+ * If the two builders both have a grammar rule with the same name,
49
+ * no error will be thrown case they map to the same ruledef object.
50
+ * If they map to a different object, an error will be thrown.
51
+ * To fix this problem, the overridingRules array should contain a rule with the same conflicting name,
52
+ * this rule implementation will be used.
53
+ */
54
+ merge<OtherNames extends string, OtherRules extends GenRuleMap<OtherNames>, OW extends readonly GeneratorRule<Context>[]>(GeneratorBuilder: GeneratorBuilder<Context, OtherNames, OtherRules>, overridingRules: OW): GeneratorBuilder<Context, Names | OtherNames | GenNamesFromList<OW>, {
55
+ [K in Names | OtherNames | GenNamesFromList<OW>]: K extends keyof GenRulesToObject<OW> ? (GenRulesToObject<OW>[K] extends GeneratorRule<Context, K> ? GenRulesToObject<OW>[K] : never) : (K extends Names ? (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never) : K extends OtherNames ? (OtherRules[K] extends GeneratorRule<Context, K> ? OtherRules[K] : never) : never);
56
+ }>;
57
+ build(): GeneratorFromRules<Context, Names, RuleDefs>;
58
+ }
@@ -0,0 +1,101 @@
1
+ import { DynamicGenerator } from './dynamicGenerator';
2
+ /**
3
+ * Converts a list of ruledefs to a record mapping a name to the corresponding ruledef.
4
+ */
5
+ function listToRuleDefMap(rules) {
6
+ const newRules = {};
7
+ for (const rule of rules) {
8
+ newRules[rule.name] = rule;
9
+ }
10
+ return newRules;
11
+ }
12
+ export class GeneratorBuilder {
13
+ static createBuilder(start) {
14
+ if (start instanceof GeneratorBuilder) {
15
+ return new GeneratorBuilder({ ...start.rules });
16
+ }
17
+ return new GeneratorBuilder(listToRuleDefMap(start));
18
+ }
19
+ constructor(startRules) {
20
+ this.rules = startRules;
21
+ }
22
+ typePatch() {
23
+ return this;
24
+ }
25
+ /**
26
+ * Change the implementation of an existing generator rule.
27
+ */
28
+ patchRule(patch) {
29
+ const self = this;
30
+ self.rules[patch.name] = patch;
31
+ return self;
32
+ }
33
+ /**
34
+ * Add a rule to the grammar. If the rule already exists, but the implementation differs, an error will be thrown.
35
+ */
36
+ addRuleRedundant(rule) {
37
+ const self = this;
38
+ const rules = self.rules;
39
+ if (rules[rule.name] !== undefined && rules[rule.name] !== rule) {
40
+ throw new Error(`Rule ${rule.name} already exists in the GeneratorBuilder`);
41
+ }
42
+ rules[rule.name] = rule;
43
+ return self;
44
+ }
45
+ /**
46
+ * Add a rule to the grammar. Will raise a typescript error if the rule already exists in the grammar.
47
+ */
48
+ addRule(rule) {
49
+ return this.addRuleRedundant(rule);
50
+ }
51
+ addMany(...rules) {
52
+ this.rules = { ...this.rules, ...listToRuleDefMap(rules) };
53
+ return this;
54
+ }
55
+ /**
56
+ * Delete a grammar rule by its name.
57
+ */
58
+ deleteRule(ruleName) {
59
+ delete this.rules[ruleName];
60
+ return this;
61
+ }
62
+ /**
63
+ * Merge this grammar GeneratorBuilder with another.
64
+ * It is best to merge the bigger grammar with the smaller one.
65
+ * If the two builders both have a grammar rule with the same name,
66
+ * no error will be thrown case they map to the same ruledef object.
67
+ * If they map to a different object, an error will be thrown.
68
+ * To fix this problem, the overridingRules array should contain a rule with the same conflicting name,
69
+ * this rule implementation will be used.
70
+ */
71
+ merge(GeneratorBuilder, overridingRules) {
72
+ // Assume the other grammar is bigger than yours. So start from that one and add this one
73
+ const otherRules = { ...GeneratorBuilder.rules };
74
+ const myRules = this.rules;
75
+ for (const rule of Object.values(myRules)) {
76
+ if (otherRules[rule.name] === undefined) {
77
+ otherRules[rule.name] = rule;
78
+ }
79
+ else {
80
+ const existingRule = otherRules[rule.name];
81
+ // If same rule, no issue, move on. Else
82
+ if (existingRule !== rule) {
83
+ const override = overridingRules.find(x => x.name === rule.name);
84
+ // If override specified, take override, else, inform user that there is a conflict
85
+ if (override) {
86
+ otherRules[rule.name] = override;
87
+ }
88
+ else {
89
+ throw new Error(`Rule with name "${rule.name}" already exists in the GeneratorBuilder, specify an override to resolve conflict`);
90
+ }
91
+ }
92
+ }
93
+ }
94
+ this.rules = otherRules;
95
+ return this;
96
+ }
97
+ build() {
98
+ return new DynamicGenerator(this.rules);
99
+ }
100
+ }
101
+ //# sourceMappingURL=generatorBuilder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generatorBuilder.js","sourceRoot":"","sources":["generatorBuilder.ts"],"names":[],"mappings":"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","sourcesContent":["import type { CheckOverlap } from '../utils';\nimport type { GeneratorFromRules, GenNamesFromList, GenRuleMap, GenRulesToObject } from './builderTypes';\nimport { DynamicGenerator } from './dynamicGenerator';\nimport type { GeneratorRule } from './generatorTypes';\n\n/**\n * Converts a list of ruledefs to a record mapping a name to the corresponding ruledef.\n */\nfunction listToRuleDefMap<T extends readonly GeneratorRule[]>(rules: T): GenRulesToObject<T> {\n const newRules: Record<string, GeneratorRule> = {};\n for (const rule of rules) {\n newRules[rule.name] = rule;\n }\n return <GenRulesToObject<T>>newRules;\n}\n\nexport class GeneratorBuilder<Context, Names extends string, RuleDefs extends GenRuleMap<Names>> {\n /**\n * Create a GeneratorBuilder from some initial grammar rules or an existing GeneratorBuilder.\n * If a GeneratorBuilder is provided, a new copy will be created.\n */\n public static createBuilder<Context, Names extends string, RuleDefs extends GenRuleMap<Names>>(\n args: GeneratorBuilder<Context, Names, RuleDefs>\n ): GeneratorBuilder<Context, Names, RuleDefs>;\n public static createBuilder<\n Rules extends readonly GeneratorRule[] = readonly GeneratorRule[],\n Context = Rules[0] extends GeneratorRule<infer context> ? context : never,\n Names extends string = GenNamesFromList<Rules>,\n RuleDefs extends GenRuleMap<Names> = GenRulesToObject<Rules>,\n >(rules: Rules): GeneratorBuilder<Context, Names, RuleDefs>;\n public static createBuilder<\n Rules extends readonly GeneratorRule[] = readonly GeneratorRule[],\n Context = Rules[0] extends GeneratorRule<infer context> ? context : never,\n Names extends string = GenNamesFromList<Rules>,\n RuleDefs extends GenRuleMap<Names> = GenRulesToObject<Rules>,\n >(\n start: Rules | GeneratorBuilder<Context, Names, RuleDefs>,\n ): GeneratorBuilder<Context, Names, RuleDefs> {\n if (start instanceof GeneratorBuilder) {\n return new GeneratorBuilder({ ...start.rules });\n }\n return <GeneratorBuilder<Context, Names, RuleDefs>> <unknown> new GeneratorBuilder(listToRuleDefMap(start));\n }\n\n private rules: RuleDefs;\n\n private constructor(startRules: RuleDefs) {\n this.rules = startRules;\n }\n\n public typePatch<Patch extends {[Key in Names]?: any }>():\n GeneratorBuilder<Context, Names, {[Key in Names]: Key extends keyof Patch ? (\n RuleDefs[Key] extends GeneratorRule<Context, Key, any, infer Args> ?\n GeneratorRule<Context, Key, Patch[Key], Args> : never\n ) : (RuleDefs[Key] extends GeneratorRule<Context, Key> ? RuleDefs[Key] : never) }> {\n return <GeneratorBuilder<Context, Names, {[Key in Names]: Key extends keyof Patch ? (\n RuleDefs[Key] extends GeneratorRule<Context, Key, any, infer Args> ?\n GeneratorRule<Context, Key, Patch[Key], Args> : never\n ) : (RuleDefs[Key] extends GeneratorRule<Context, Key> ? RuleDefs[Key] : never) }>> <unknown> this;\n }\n\n /**\n * Change the implementation of an existing generator rule.\n */\n public patchRule<U extends Names, RET, ARGS>(patch: GeneratorRule<Context, U, RET, ARGS>):\n GeneratorBuilder<Context, Names, {[Key in Names]: Key extends U ?\n GeneratorRule<Context, Key, RET, ARGS> :\n (RuleDefs[Key] extends GeneratorRule<Context, Key> ? RuleDefs[Key] : never)\n } > {\n const self = <GeneratorBuilder<Context, Names, {[Key in Names]: Key extends U ?\n GeneratorRule<Context, Key, RET, ARGS> :\n (RuleDefs[Key] extends GeneratorRule<Context, Key> ? RuleDefs[Key] : never) }>>\n <unknown> this;\n self.rules[patch.name] = <any> patch;\n return self;\n }\n\n /**\n * Add a rule to the grammar. If the rule already exists, but the implementation differs, an error will be thrown.\n */\n public addRuleRedundant<U extends string, RET, ARGS>(rule: GeneratorRule<Context, U, RET, ARGS>):\n GeneratorBuilder<Context, Names | U, {[K in Names | U]: K extends Names ?\n (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never)\n : (K extends U ? GeneratorRule<Context, K, RET, ARGS> : never)\n }> {\n const self = <GeneratorBuilder<Context, Names | U, {[K in Names | U]: K extends Names ?\n (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never)\n : (K extends U ? GeneratorRule<Context, K, RET, ARGS> : never) }>>\n <unknown> this;\n const rules = <Record<string, GeneratorRule<Context>>> self.rules;\n if (rules[rule.name] !== undefined && rules[rule.name] !== rule) {\n throw new Error(`Rule ${rule.name} already exists in the GeneratorBuilder`);\n }\n rules[rule.name] = rule;\n return self;\n }\n\n /**\n * Add a rule to the grammar. Will raise a typescript error if the rule already exists in the grammar.\n */\n public addRule<U extends string, RET, ARGS>(\n rule: CheckOverlap<U, Names, GeneratorRule<Context, U, RET, ARGS>>,\n ): GeneratorBuilder<Context, Names | U, {[K in Names | U]: K extends Names ?\n (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never)\n : (K extends U ? GeneratorRule<Context, K, RET, ARGS> : never)\n }> {\n return this.addRuleRedundant(rule);\n }\n\n public addMany<U extends readonly GeneratorRule<Context>[]>(\n ...rules: CheckOverlap<GenNamesFromList<U>, Names, U>\n ): GeneratorBuilder<\n Context,\n Names | GenNamesFromList<U>,\n {[K in Names | GenNamesFromList<U>]:\n K extends keyof GenRulesToObject<typeof rules> ? (\n GenRulesToObject<typeof rules>[K] extends GeneratorRule<Context, K> ? GenRulesToObject<typeof rules>[K] : never\n ) : (\n K extends Names ? (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never) : never\n )\n }\n > {\n this.rules = { ...this.rules, ...listToRuleDefMap(rules) };\n return <any> <unknown> this;\n }\n\n /**\n * Delete a grammar rule by its name.\n */\n public deleteRule<U extends Names>(ruleName: U):\n GeneratorBuilder<Context, Exclude<Names, U>, {[K in Exclude<Names, U>]:\n RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never }> {\n delete this.rules[ruleName];\n return <GeneratorBuilder<Context, Exclude<Names, U>, {[K in Exclude<Names, U>]:\n RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never }>>\n <unknown> this;\n }\n\n /**\n * Merge this grammar GeneratorBuilder with another.\n * It is best to merge the bigger grammar with the smaller one.\n * If the two builders both have a grammar rule with the same name,\n * no error will be thrown case they map to the same ruledef object.\n * If they map to a different object, an error will be thrown.\n * To fix this problem, the overridingRules array should contain a rule with the same conflicting name,\n * this rule implementation will be used.\n */\n public merge<\n OtherNames extends string,\n OtherRules extends GenRuleMap<OtherNames>,\n OW extends readonly GeneratorRule<Context>[],\n >(\n GeneratorBuilder: GeneratorBuilder<Context, OtherNames, OtherRules>,\n overridingRules: OW,\n ):\n GeneratorBuilder<\n Context,\n Names | OtherNames | GenNamesFromList<OW>,\n {[K in Names | OtherNames | GenNamesFromList<OW>]:\n K extends keyof GenRulesToObject<OW> ? (\n GenRulesToObject<OW>[K] extends GeneratorRule<Context, K> ? GenRulesToObject<OW>[K] : never\n )\n : (\n K extends Names ? (RuleDefs[K] extends GeneratorRule<Context, K> ? RuleDefs[K] : never)\n : K extends OtherNames ? (OtherRules[K] extends GeneratorRule<Context, K> ? OtherRules[K] : never)\n : never\n ) }\n > {\n // Assume the other grammar is bigger than yours. So start from that one and add this one\n const otherRules: Record<string, GeneratorRule<Context>> = { ...GeneratorBuilder.rules };\n const myRules: Record<string, GeneratorRule<Context>> = this.rules;\n\n for (const rule of Object.values(myRules)) {\n if (otherRules[rule.name] === undefined) {\n otherRules[rule.name] = rule;\n } else {\n const existingRule = otherRules[rule.name];\n // If same rule, no issue, move on. Else\n if (existingRule !== rule) {\n const override = overridingRules.find(x => x.name === rule.name);\n // If override specified, take override, else, inform user that there is a conflict\n if (override) {\n otherRules[rule.name] = override;\n } else {\n throw new Error(`Rule with name \"${rule.name}\" already exists in the GeneratorBuilder, specify an override to resolve conflict`);\n }\n }\n }\n }\n\n this.rules = <any> <unknown> otherRules;\n return <any> <unknown> this;\n }\n\n public build(): GeneratorFromRules<Context, Names, RuleDefs> {\n return <GeneratorFromRules<Context, Names, RuleDefs>> new DynamicGenerator(this.rules);\n }\n}\n"]}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Type used to declare generator rules.
3
+ */
4
+ export type GeneratorRule<
5
+ /**
6
+ * Context object available in rule implementation.
7
+ */
8
+ Context = any,
9
+ /**
10
+ * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.
11
+ */
12
+ NameType extends string = string,
13
+ /**
14
+ * Type that will be returned after a correct parse of this rule.
15
+ * This type will be the return type of calling SUBRULE with this grammar rule.
16
+ */
17
+ ReturnType = any,
18
+ /**
19
+ * Function arguments that can be given to convey the state of the current parse operation.
20
+ */
21
+ ParamType = any> = {
22
+ name: NameType;
23
+ gImpl: (def: RuleDefArg) => (ast: ReturnType, context: Context, params: ParamType) => string;
24
+ };
25
+ export interface RuleDefArg {
26
+ SUBRULE: <T, U>(cstDef: GeneratorRule<any, any, T, U>, input: T, arg: U) => string;
27
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=generatorTypes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generatorTypes.js","sourceRoot":"","sources":["generatorTypes.ts"],"names":[],"mappings":"","sourcesContent":["/**\n * Type used to declare generator rules.\n */\nexport type GeneratorRule<\n /**\n * Context object available in rule implementation.\n */\n Context = any,\n /**\n * Name of grammar rule, should be a strict subtype of string like 'myGrammarRule'.\n */\n NameType extends string = string,\n /**\n * Type that will be returned after a correct parse of this rule.\n * This type will be the return type of calling SUBRULE with this grammar rule.\n */\n ReturnType = any,\n /**\n * Function arguments that can be given to convey the state of the current parse operation.\n */\n ParamType = any,\n> = {\n name: NameType;\n gImpl: (def: RuleDefArg) =>\n (ast: ReturnType, context: Context, params: ParamType) => string;\n};\n\nexport interface RuleDefArg {\n SUBRULE: <T, U>(cstDef: GeneratorRule<any, any, T, U>, input: T, arg: U) => string;\n}\n"]}