grammar-well 1.3.3 → 2.0.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/README.md +76 -560
- package/build/generator/artifacts/basic.d.ts +7 -0
- package/build/generator/artifacts/basic.js +24 -0
- package/build/generator/artifacts/basic.js.map +1 -0
- package/build/generator/artifacts/lexer.d.ts +13 -0
- package/build/generator/artifacts/lexer.js +204 -0
- package/build/generator/artifacts/lexer.js.map +1 -0
- package/build/{compiler/generator → generator}/artifacts/lr.d.ts +14 -14
- package/build/{compiler/generator → generator}/artifacts/lr.js +18 -22
- package/build/generator/artifacts/lr.js.map +1 -0
- package/build/generator/builtin/json.d.ts +183 -0
- package/build/generator/builtin/json.js +124 -0
- package/build/generator/builtin/json.js.map +1 -0
- package/build/generator/builtin/registry.json +1 -0
- package/build/generator/builtin/whitespace.d.ts +61 -0
- package/build/generator/builtin/whitespace.js +37 -0
- package/build/generator/builtin/whitespace.js.map +1 -0
- package/build/generator/generator.d.ts +38 -0
- package/build/generator/generator.js +368 -0
- package/build/generator/generator.js.map +1 -0
- package/build/generator/grammars/index.d.ts +2 -0
- package/build/generator/grammars/index.js +3 -0
- package/build/generator/grammars/index.js.map +1 -0
- package/build/generator/grammars/v1.d.ts +1190 -0
- package/build/generator/grammars/v1.js +614 -0
- package/build/generator/grammars/v1.js.map +1 -0
- package/build/generator/grammars/v2.d.ts +1367 -0
- package/build/generator/grammars/v2.js +695 -0
- package/build/generator/grammars/v2.js.map +1 -0
- package/build/generator/import-resolvers/auto.d.ts +2 -0
- package/build/generator/import-resolvers/auto.js +11 -0
- package/build/generator/import-resolvers/auto.js.map +1 -0
- package/build/generator/import-resolvers/browser.d.ts +7 -0
- package/build/generator/import-resolvers/browser.js +13 -0
- package/build/generator/import-resolvers/browser.js.map +1 -0
- package/build/generator/import-resolvers/default.d.ts +2 -0
- package/build/generator/import-resolvers/default.js +11 -0
- package/build/generator/import-resolvers/default.js.map +1 -0
- package/build/generator/import-resolvers/filesystem.d.ts +7 -0
- package/build/generator/import-resolvers/filesystem.js +15 -0
- package/build/generator/import-resolvers/filesystem.js.map +1 -0
- package/build/generator/index.d.ts +3 -0
- package/build/generator/index.js +4 -0
- package/build/generator/index.js.map +1 -0
- package/build/generator/state.d.ts +28 -0
- package/build/generator/state.js +73 -0
- package/build/generator/state.js.map +1 -0
- package/build/generator/stringify/common.d.ts +22 -0
- package/build/generator/stringify/common.js +83 -0
- package/build/generator/stringify/common.js.map +1 -0
- package/build/generator/stringify/exports/javascript.d.ts +3 -0
- package/build/generator/stringify/exports/javascript.js +26 -0
- package/build/generator/stringify/exports/javascript.js.map +1 -0
- package/build/generator/stringify/exports/json.d.ts +2 -0
- package/build/generator/stringify/exports/json.js +4 -0
- package/build/generator/stringify/exports/json.js.map +1 -0
- package/build/generator/stringify/exports/registry.d.ts +20 -0
- package/build/generator/stringify/exports/registry.js +17 -0
- package/build/generator/stringify/exports/registry.js.map +1 -0
- package/build/generator/stringify/exports/typescript.d.ts +2 -0
- package/build/generator/stringify/exports/typescript.js +16 -0
- package/build/generator/stringify/exports/typescript.js.map +1 -0
- package/build/generator/stringify/grammar/v2.d.ts +20 -0
- package/build/generator/stringify/grammar/v2.js +211 -0
- package/build/generator/stringify/grammar/v2.js.map +1 -0
- package/build/generator/stringify/javascript.d.ts +13 -0
- package/build/generator/stringify/javascript.js +83 -0
- package/build/generator/stringify/javascript.js.map +1 -0
- package/build/index.d.ts +7 -6
- package/build/index.js +7 -24
- package/build/index.js.map +1 -1
- package/build/lexers/character-lexer.d.ts +2 -2
- package/build/lexers/character-lexer.js +1 -5
- package/build/lexers/character-lexer.js.map +1 -1
- package/build/lexers/stateful-lexer.d.ts +12 -17
- package/build/lexers/stateful-lexer.js +38 -186
- package/build/lexers/stateful-lexer.js.map +1 -1
- package/build/lexers/token-buffer.d.ts +8 -8
- package/build/lexers/token-buffer.js +1 -5
- package/build/lexers/token-buffer.js.map +1 -1
- package/build/parser/algorithms/cyk.d.ts +6 -6
- package/build/parser/algorithms/cyk.js +10 -13
- package/build/parser/algorithms/cyk.js.map +1 -1
- package/build/parser/algorithms/earley.d.ts +7 -7
- package/build/parser/algorithms/earley.js +7 -11
- package/build/parser/algorithms/earley.js.map +1 -1
- package/build/parser/algorithms/lrk/algorithm.d.ts +3 -3
- package/build/parser/algorithms/lrk/algorithm.js +10 -13
- package/build/parser/algorithms/lrk/algorithm.js.map +1 -1
- package/build/parser/algorithms/lrk/bimap.js +1 -5
- package/build/parser/algorithms/lrk/bimap.js.map +1 -1
- package/build/parser/algorithms/lrk/canonical-collection.d.ts +7 -7
- package/build/parser/algorithms/lrk/canonical-collection.js +11 -15
- package/build/parser/algorithms/lrk/canonical-collection.js.map +1 -1
- package/build/parser/algorithms/lrk/closure.d.ts +3 -3
- package/build/parser/algorithms/lrk/closure.js +3 -7
- package/build/parser/algorithms/lrk/closure.js.map +1 -1
- package/build/parser/algorithms/lrk/stack.d.ts +6 -6
- package/build/parser/algorithms/lrk/stack.js +1 -5
- package/build/parser/algorithms/lrk/stack.js.map +1 -1
- package/build/parser/algorithms/lrk/state.d.ts +5 -5
- package/build/parser/algorithms/lrk/state.js +1 -2
- package/build/parser/parse.d.ts +10 -0
- package/build/parser/parse.js +34 -0
- package/build/parser/parse.js.map +1 -0
- package/build/parser/parser.d.ts +6 -17
- package/build/parser/parser.js +26 -42
- package/build/parser/parser.js.map +1 -1
- package/build/tsconfig.tsbuildinfo +1 -0
- package/build/typings/ast.d.ts +134 -0
- package/build/typings/ast.js +3 -0
- package/build/typings/ast.js.map +1 -0
- package/build/typings/common.d.ts +4 -0
- package/build/typings/common.js +2 -0
- package/build/typings/common.js.map +1 -0
- package/build/typings/generator.d.ts +58 -0
- package/build/typings/generator.js +3 -0
- package/build/typings/generator.js.map +1 -0
- package/build/typings/index.d.ts +43 -0
- package/build/typings/index.js +5 -0
- package/build/typings/index.js.map +1 -0
- package/build/typings/runtime.d.ts +70 -0
- package/build/typings/runtime.js +2 -0
- package/build/typings/runtime.js.map +1 -0
- package/build/utility/format.d.ts +1 -0
- package/build/utility/format.js +12 -0
- package/build/utility/format.js.map +1 -0
- package/build/utility/formatter.d.ts +1 -0
- package/build/utility/formatter.js +12 -0
- package/build/utility/formatter.js.map +1 -0
- package/build/utility/general.d.ts +1 -1
- package/build/utility/general.js +5 -13
- package/build/utility/general.js.map +1 -1
- package/build/utility/index.d.ts +4 -1
- package/build/utility/index.js +4 -17
- package/build/utility/index.js.map +1 -1
- package/build/utility/lint.d.ts +2 -2
- package/build/utility/lint.js +2 -6
- package/build/utility/lint.js.map +1 -1
- package/build/utility/migrate.d.ts +1 -0
- package/build/utility/migrate.js +10 -0
- package/build/utility/migrate.js.map +1 -0
- package/build/utility/monarch.d.ts +2 -2
- package/build/utility/monarch.js +33 -38
- package/build/utility/monarch.js.map +1 -1
- package/build/utility/parsing.d.ts +6 -0
- package/build/utility/parsing.js +26 -0
- package/build/utility/parsing.js.map +1 -0
- package/build/utility/text-format.d.ts +6 -6
- package/build/utility/text-format.js +2 -6
- package/build/utility/text-format.js.map +1 -1
- package/package.json +17 -24
- package/src/generator/artifacts/basic.ts +26 -0
- package/src/generator/artifacts/lexer.ts +228 -0
- package/src/{compiler/generator → generator}/artifacts/lr.ts +25 -24
- package/src/generator/builtin/character.well +7 -0
- package/src/generator/builtin/json.well +85 -0
- package/src/generator/builtin/number.well +21 -0
- package/src/generator/builtin/registry.json +1 -0
- package/src/generator/builtin/string.well +54 -0
- package/src/generator/builtin/whitespace.well +16 -0
- package/src/generator/generator.ts +401 -0
- package/src/generator/grammars/index.ts +2 -0
- package/src/generator/grammars/v1.ts +620 -0
- package/src/generator/grammars/v1.well +422 -0
- package/src/generator/grammars/v2.ts +701 -0
- package/src/generator/grammars/v2.well +413 -0
- package/src/generator/import-resolvers/auto.ts +12 -0
- package/src/generator/import-resolvers/browser.ts +13 -0
- package/src/generator/import-resolvers/filesystem.ts +18 -0
- package/src/generator/index.ts +3 -0
- package/src/generator/state.ts +89 -0
- package/src/generator/stringify/common.ts +90 -0
- package/src/generator/stringify/exports/javascript.ts +29 -0
- package/src/generator/stringify/exports/json.ts +5 -0
- package/src/generator/stringify/exports/registry.ts +20 -0
- package/src/generator/stringify/exports/typescript.ts +17 -0
- package/src/generator/stringify/grammar/v2.ts +223 -0
- package/src/generator/stringify/javascript.ts +94 -0
- package/src/index.ts +7 -6
- package/src/lexers/character-lexer.ts +2 -2
- package/src/lexers/stateful-lexer.ts +46 -203
- package/src/lexers/token-buffer.ts +3 -3
- package/src/parser/algorithms/cyk.ts +13 -12
- package/src/parser/algorithms/earley.ts +10 -10
- package/src/parser/algorithms/lrk/algorithm.ts +8 -7
- package/src/parser/algorithms/lrk/canonical-collection.ts +14 -14
- package/src/parser/algorithms/lrk/closure.ts +6 -6
- package/src/parser/algorithms/lrk/stack.ts +6 -6
- package/src/parser/algorithms/lrk/state.ts +5 -5
- package/src/parser/parse.ts +45 -0
- package/src/typings/ast.ts +148 -0
- package/src/typings/common.ts +2 -0
- package/src/typings/generator.ts +62 -0
- package/src/typings/index.ts +38 -0
- package/src/typings/runtime.ts +82 -0
- package/src/utility/format.ts +12 -0
- package/src/utility/general.ts +1 -2
- package/src/utility/index.ts +4 -1
- package/src/utility/lint.ts +5 -5
- package/src/utility/monarch.ts +34 -34
- package/src/utility/parsing.ts +30 -0
- package/src/utility/text-format.ts +7 -7
- package/.eslintrc.cjs +0 -14
- package/bootstrap.ts +0 -45
- package/build/compiler/builtin.json +0 -1
- package/build/compiler/compiler.d.ts +0 -50
- package/build/compiler/compiler.js +0 -249
- package/build/compiler/compiler.js.map +0 -1
- package/build/compiler/generator/artifacts/lr.js.map +0 -1
- package/build/compiler/generator/artifacts/standard.d.ts +0 -7
- package/build/compiler/generator/artifacts/standard.js +0 -28
- package/build/compiler/generator/artifacts/standard.js.map +0 -1
- package/build/compiler/generator/generator.d.ts +0 -24
- package/build/compiler/generator/generator.js +0 -217
- package/build/compiler/generator/generator.js.map +0 -1
- package/build/compiler/gwell.d.ts +0 -1112
- package/build/compiler/gwell.js +0 -576
- package/build/compiler/gwell.js.map +0 -1
- package/build/compiler/import-resolver.d.ts +0 -15
- package/build/compiler/import-resolver.js +0 -37
- package/build/compiler/import-resolver.js.map +0 -1
- package/build/compiler/index.d.ts +0 -2
- package/build/compiler/index.js +0 -19
- package/build/compiler/index.js.map +0 -1
- package/build/compiler/outputs/javascript.d.ts +0 -3
- package/build/compiler/outputs/javascript.js +0 -29
- package/build/compiler/outputs/javascript.js.map +0 -1
- package/build/compiler/outputs/json.d.ts +0 -2
- package/build/compiler/outputs/json.js +0 -8
- package/build/compiler/outputs/json.js.map +0 -1
- package/build/compiler/outputs/typescript.d.ts +0 -2
- package/build/compiler/outputs/typescript.js +0 -21
- package/build/compiler/outputs/typescript.js.map +0 -1
- package/build/parser/algorithms/lr.d.ts +0 -7
- package/build/parser/algorithms/lr.js +0 -108
- package/build/parser/algorithms/lr.js.map +0 -5
- package/build/parser/algorithms/lr0.d.ts +0 -7
- package/build/parser/algorithms/lr0.js +0 -156
- package/build/parser/algorithms/lr0.js.map +0 -1
- package/build/typings.d.ts +0 -226
- package/build/typings.js +0 -3
- package/build/typings.js.map +0 -1
- package/src/compiler/builtin/json.gwell +0 -74
- package/src/compiler/builtin/number.gwell +0 -20
- package/src/compiler/builtin/string.gwell +0 -48
- package/src/compiler/builtin/whitespace.gwell +0 -10
- package/src/compiler/builtin.json +0 -1
- package/src/compiler/compiler.ts +0 -265
- package/src/compiler/generator/artifacts/standard.ts +0 -26
- package/src/compiler/generator/generator.ts +0 -237
- package/src/compiler/gwell.gwell +0 -294
- package/src/compiler/gwell.js +0 -578
- package/src/compiler/import-resolver.ts +0 -36
- package/src/compiler/index.ts +0 -2
- package/src/compiler/outputs/javascript.ts +0 -27
- package/src/compiler/outputs/json.ts +0 -5
- package/src/compiler/outputs/typescript.ts +0 -18
- package/src/parser/parser.ts +0 -77
- package/src/typings.ts +0 -248
- package/testing.ts +0 -18
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { JavaScriptGenerator } from "../javascript.js";
|
|
2
|
+
|
|
3
|
+
export function TypescriptFormat(generator: JavaScriptGenerator) {
|
|
4
|
+
const exportName = generator.name();
|
|
5
|
+
return `// Generated automatically by Grammar-Well, version ${generator.state.version}
|
|
6
|
+
// https://github.com/0x6563/grammar-well
|
|
7
|
+
// @ts-nocheck
|
|
8
|
+
|
|
9
|
+
${generator.lifecycle('import')}
|
|
10
|
+
|
|
11
|
+
class ${exportName} {
|
|
12
|
+
artifacts = ${generator.artifacts(1)}
|
|
13
|
+
constructor(){${generator.lifecycle('new')}}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default ${exportName};`;
|
|
17
|
+
}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { ASTConfig, ASTDirectives, ASTGrammar, ASTGrammarProduction, ASTGrammarSymbol, ASTImport, ASTLexer, ASTLexerState, ASTLexerStateImportRule, ASTLexerStateMatchRule, ASTLexerStateNonMatchRule, GeneratorGrammarSymbol } from "../../../typings/index.js";
|
|
2
|
+
|
|
3
|
+
export class V2GrammarString {
|
|
4
|
+
source: string = '';
|
|
5
|
+
append(directives: ASTDirectives | (ASTDirectives[])) {
|
|
6
|
+
directives = Array.isArray(directives) ? directives : [directives];
|
|
7
|
+
for (const directive of directives) {
|
|
8
|
+
if ("lifecycle" in directive) {
|
|
9
|
+
this.appendSection("on:" + directive.lifecycle, directive.js.js.trim());
|
|
10
|
+
} else if ("import" in directive) {
|
|
11
|
+
this.appendImportDirective(directive);
|
|
12
|
+
} else if ("config" in directive) {
|
|
13
|
+
this.appendConfigDirective(directive);
|
|
14
|
+
} else if ("grammar" in directive) {
|
|
15
|
+
this.appendGrammarDirective(directive);
|
|
16
|
+
} else if ("lexer" in directive) {
|
|
17
|
+
this.appendLexerDirective(directive);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
appendImportDirective(directive: ASTImport) {
|
|
23
|
+
this.source += `import * from ${directive.path ? JSON.stringify(directive.import) : directive.import};\n`;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
appendConfigDirective(directive: ASTConfig) {
|
|
27
|
+
this.appendSection('config', this.formatKV(directive.config, 1));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
appendGrammarDirective(directive: ASTGrammar) {
|
|
31
|
+
let body = '';
|
|
32
|
+
if (directive.grammar.config) {
|
|
33
|
+
body += this.formatKV(directive.grammar.config, 1);
|
|
34
|
+
}
|
|
35
|
+
if (directive.grammar.rules) {
|
|
36
|
+
for (const rule of directive.grammar.rules) {
|
|
37
|
+
body += this.formatGrammarRule(rule);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
this.appendSection('grammar', body);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
formatGrammarRule(rule: ASTGrammarProduction) {
|
|
44
|
+
let body = '\n' + this.indent(1, `[${rule.name}]`);
|
|
45
|
+
if (rule.postprocess) {
|
|
46
|
+
body += ` ${this.formatPostProcess(rule.postprocess)}`;
|
|
47
|
+
}
|
|
48
|
+
for (const exp of rule.expressions) {
|
|
49
|
+
body += '\n' + this.indent(2, '| ') + this.formatSymbols(exp.symbols as any);
|
|
50
|
+
if (exp.postprocess) {
|
|
51
|
+
body += ` ${this.formatPostProcess(exp.postprocess)}`;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
body += '\n';
|
|
55
|
+
return body;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
formatSymbols(exp: GeneratorGrammarSymbol[]) {
|
|
59
|
+
return exp.map(v => this.formatSymbol(v) + (v.alias ? "@" + v.alias : '')).join(' ');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
formatSymbol(exp: ASTGrammarSymbol | GeneratorGrammarSymbol | string) {
|
|
63
|
+
if (typeof exp == 'string') {
|
|
64
|
+
return JSON.stringify(exp);
|
|
65
|
+
}
|
|
66
|
+
if ('subexpression' in exp) {
|
|
67
|
+
return `(${exp.subexpression.map(v => this.formatSymbols(v.symbols as any)).join(' | ')})`;
|
|
68
|
+
}
|
|
69
|
+
if ('rule' in exp) {
|
|
70
|
+
return exp.rule;
|
|
71
|
+
}
|
|
72
|
+
if ('literal' in exp) {
|
|
73
|
+
return (exp.insensitive ? '\\i ' : '') + JSON.stringify(exp.literal);
|
|
74
|
+
}
|
|
75
|
+
if ('regex' in exp) {
|
|
76
|
+
let { regex, flags } = exp;
|
|
77
|
+
return `r${flags || ''}:{${regex}}`;
|
|
78
|
+
}
|
|
79
|
+
if ('token' in exp) {
|
|
80
|
+
return `<${exp.token}>`;
|
|
81
|
+
}
|
|
82
|
+
if ('expression' in exp) {
|
|
83
|
+
return this.formatSymbol(exp.expression) + (exp.repeat || '');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
formatPostProcess(postProcess: ASTGrammarProduction['postprocess']) {
|
|
88
|
+
|
|
89
|
+
// if ('builtin' in postProcess) {
|
|
90
|
+
// return postProcess;
|
|
91
|
+
// }
|
|
92
|
+
if ('js' in postProcess) {
|
|
93
|
+
return `=> \${ ${postProcess.js} }`;
|
|
94
|
+
}
|
|
95
|
+
if ('template' in postProcess) {
|
|
96
|
+
const prefix = postProcess.template.slice(0, 1);
|
|
97
|
+
const suffix = postProcess.template.slice(-1);
|
|
98
|
+
return `=> ${prefix} ${postProcess.template.slice(1, -1).trim()} ${suffix}`;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
appendLexerDirective(directive: ASTLexer) {
|
|
103
|
+
let body = '';
|
|
104
|
+
if (directive.lexer.start) {
|
|
105
|
+
body += this.formatKV({ start: directive.lexer.start }, 1);
|
|
106
|
+
}
|
|
107
|
+
if (directive.lexer.states) {
|
|
108
|
+
for (const { state, name } of directive.lexer.states) {
|
|
109
|
+
if ('span' in state) {
|
|
110
|
+
body += '\n' + this.indent(1, `[${name}] span {\n`);
|
|
111
|
+
const stateOpen = state.span.find(v => v.name == 'start');
|
|
112
|
+
const stateBody = state.span.find(v => v.name == 'span');
|
|
113
|
+
const stateClose = state.span.find(v => v.name == 'stop');
|
|
114
|
+
if (state.config) {
|
|
115
|
+
body += this.formatKV(state.config, 2);
|
|
116
|
+
}
|
|
117
|
+
if (stateOpen) {
|
|
118
|
+
body += this.formatLexerState('start', stateOpen.state, 2);
|
|
119
|
+
}
|
|
120
|
+
if (stateBody) {
|
|
121
|
+
body += this.formatLexerState('span', stateBody.state, 2);
|
|
122
|
+
}
|
|
123
|
+
if (stateClose) {
|
|
124
|
+
body += this.formatLexerState('stop', stateClose.state, 2);
|
|
125
|
+
}
|
|
126
|
+
body += '\n' + this.indent(1, `}\n`);
|
|
127
|
+
} else {
|
|
128
|
+
body += this.formatLexerState(name, state, 1)
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.appendSection('lexer', body);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
formatLexerState(name: string, state: ASTLexerState, depth: number = 0) {
|
|
137
|
+
let body = '\n' + this.indent(depth, `[${name}]\n`);
|
|
138
|
+
if (state.default) {
|
|
139
|
+
body += this.indent(depth + 1, 'default: ' + this.formatLexerStateRule(state.default) + ';\n');
|
|
140
|
+
}
|
|
141
|
+
if (state.unmatched) {
|
|
142
|
+
body += this.indent(depth + 1, 'unmatched: ' + this.formatLexerStateRule(state.unmatched) + ';\n');
|
|
143
|
+
}
|
|
144
|
+
for (const rule of state.rules) {
|
|
145
|
+
if ('span' in rule)
|
|
146
|
+
continue;
|
|
147
|
+
body += this.indent(depth + 1, '- ' + this.formatLexerStateRule(rule) + '\n');
|
|
148
|
+
}
|
|
149
|
+
return body;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
formatLexerStateRule(rule: ASTLexerStateMatchRule | ASTLexerStateNonMatchRule | ASTLexerStateImportRule) {
|
|
153
|
+
let body = '';
|
|
154
|
+
if ('import' in rule) {
|
|
155
|
+
body += 'import ' + rule.import.join(', ');
|
|
156
|
+
} else {
|
|
157
|
+
if (rule.before) {
|
|
158
|
+
body += 'before ' + this.formatSymbol((rule as ASTLexerStateMatchRule).when);
|
|
159
|
+
} else if (rule.skip) {
|
|
160
|
+
body += 'skip ' + this.formatSymbol((rule as ASTLexerStateMatchRule).when);
|
|
161
|
+
} else if ('when' in rule) {
|
|
162
|
+
body += 'when ' + this.formatSymbol(rule.when as any);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (typeof rule.type != 'undefined') {
|
|
166
|
+
body += ` type ${JSON.stringify(rule.type)}`;
|
|
167
|
+
}
|
|
168
|
+
if (typeof rule.tag != 'undefined') {
|
|
169
|
+
body += ` tag ${rule.tag.map(v => JSON.stringify(v)).join(', ')}`;
|
|
170
|
+
}
|
|
171
|
+
if (typeof rule.open != 'undefined') {
|
|
172
|
+
body += ` open ${JSON.stringify(rule.open)}`;
|
|
173
|
+
}
|
|
174
|
+
if (typeof rule.close != 'undefined') {
|
|
175
|
+
body += ` close ${JSON.stringify(rule.close)}`;
|
|
176
|
+
}
|
|
177
|
+
if (typeof rule.highlight != 'undefined') {
|
|
178
|
+
body += ` highlight ${JSON.stringify(rule.highlight)}`;
|
|
179
|
+
}
|
|
180
|
+
if (typeof rule.unembed != 'undefined') {
|
|
181
|
+
body += ` unembed`;
|
|
182
|
+
}
|
|
183
|
+
if (typeof rule.embed != 'undefined') {
|
|
184
|
+
body += ` embed`;
|
|
185
|
+
}
|
|
186
|
+
if (typeof rule.pop != 'undefined') {
|
|
187
|
+
body += ` pop` + (rule.pop == 'all' || rule.pop > 1 ? ' ' + rule.pop : '');
|
|
188
|
+
}
|
|
189
|
+
if (typeof rule.inset != 'undefined') {
|
|
190
|
+
body += ` inset` + (rule.inset > 1 ? ' ' + rule.inset : '');
|
|
191
|
+
}
|
|
192
|
+
if (typeof rule.goto != 'undefined') {
|
|
193
|
+
body += ` goto ${rule.goto}`;
|
|
194
|
+
}
|
|
195
|
+
if (typeof rule.set != 'undefined') {
|
|
196
|
+
body += ` set ${rule.set}`;
|
|
197
|
+
}
|
|
198
|
+
if ("stay" in rule && rule.stay) {
|
|
199
|
+
body += ` stay`;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return body.trim();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
formatKV(obj: { [key: string]: any }, depth: number = 0) {
|
|
206
|
+
let body = '';
|
|
207
|
+
for (const key in obj) {
|
|
208
|
+
body += this.indent(depth, `${key}: ${JSON.stringify(obj[key])}\n`);
|
|
209
|
+
}
|
|
210
|
+
return body;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
appendSection(label: string, body: string) {
|
|
214
|
+
if (this.source) {
|
|
215
|
+
this.source += '\n';
|
|
216
|
+
}
|
|
217
|
+
this.source += `${label} {\n${body}\n}\n`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
indent(depth: number = 0, content: string) {
|
|
221
|
+
return `\t`.repeat(depth) + content;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Dictionary, GeneratorOutputOptions, GeneratorGrammarProductionRule } from "../../typings/index.js";
|
|
2
|
+
import { BasicGrammarTable } from "../artifacts/basic.js";
|
|
3
|
+
import { LexerArtifact } from "../artifacts/lexer.js";
|
|
4
|
+
import { LRParseTableBuilder } from "../artifacts/lr.js";
|
|
5
|
+
import { GeneratorState } from "../state.js";
|
|
6
|
+
import { CommonGenerator } from "./common.js";
|
|
7
|
+
|
|
8
|
+
const PostProcessors = {
|
|
9
|
+
"join": "({data}) => data.join('')",
|
|
10
|
+
"concat": "({data}) => data[0].concat([data[1]])",
|
|
11
|
+
"null": "() => null",
|
|
12
|
+
"first": "({data}) => data[0]"
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export class JavaScriptGenerator {
|
|
16
|
+
|
|
17
|
+
constructor(public state: GeneratorState, public options: GeneratorOutputOptions) { }
|
|
18
|
+
|
|
19
|
+
name() {
|
|
20
|
+
return this.options.name || 'GWLanguage';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
lifecycle(lifecycle: string) {
|
|
24
|
+
if (this.options.noscript)
|
|
25
|
+
return '';
|
|
26
|
+
return this.state.lifecycle[lifecycle] || '';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
artifacts(depth: number = 0) {
|
|
30
|
+
let output: { [key: string]: string } = {};
|
|
31
|
+
const artifacts = this.options.artifacts || { grammar: true, lexer: true };
|
|
32
|
+
|
|
33
|
+
if (artifacts && artifacts.lr) {
|
|
34
|
+
const table = new LRParseTableBuilder(this);
|
|
35
|
+
output.lr = CommonGenerator.JSON({
|
|
36
|
+
k: "0",
|
|
37
|
+
table: table.stringify(depth + 2)
|
|
38
|
+
}, depth + 1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if ('lexer' in this.state && artifacts.lexer) {
|
|
42
|
+
const l = new LexerArtifact(this.state.lexer);
|
|
43
|
+
output.lexer = l.output(depth + 1);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (artifacts.grammar) {
|
|
47
|
+
const basic = new BasicGrammarTable(this);
|
|
48
|
+
output.grammar = basic.stringify(depth + 1);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return CommonGenerator.JSON(output, depth);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
postProcess(postprocess: GeneratorGrammarProductionRule['postprocess'], alias: Dictionary<number>) {
|
|
55
|
+
postprocess = this.state.grammar.config.postprocessorOverride || postprocess || this.state.grammar.config.postprocessorDefault;
|
|
56
|
+
if (!postprocess)
|
|
57
|
+
return null;
|
|
58
|
+
if ('builtin' in postprocess)
|
|
59
|
+
return PostProcessors[postprocess.builtin];
|
|
60
|
+
if (this.options.noscript)
|
|
61
|
+
return;
|
|
62
|
+
if (typeof postprocess == 'string')
|
|
63
|
+
return postprocess;
|
|
64
|
+
if ('js' in postprocess)
|
|
65
|
+
return postprocess.js;
|
|
66
|
+
if ('template' in postprocess)
|
|
67
|
+
return this.templatePostProcess(postprocess.template, alias);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
grammarRule(rule: GeneratorGrammarProductionRule) {
|
|
71
|
+
const symbols = [];
|
|
72
|
+
const alias = {};
|
|
73
|
+
for (let i = 0; i < rule.symbols.length; i++) {
|
|
74
|
+
symbols.push(CommonGenerator.SerializeSymbol(rule.symbols[i]));
|
|
75
|
+
if (rule.symbols[i].alias) {
|
|
76
|
+
alias[rule.symbols[i].alias] = i;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return CommonGenerator.JSON({
|
|
81
|
+
name: JSON.stringify(rule.name),
|
|
82
|
+
symbols: CommonGenerator.JSON(symbols, -1),
|
|
83
|
+
postprocess: this.postProcess(rule.postprocess, alias)
|
|
84
|
+
}, -1);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private templatePostProcess(templateBody: string, alias: { [key: string]: number }) {
|
|
88
|
+
for (const key in alias) {
|
|
89
|
+
templateBody = templateBody.replace(new RegExp('(?:\\$)' + key + '(?![a-zA-Z\\d\\$_])'), `data[${alias[key]}]`);
|
|
90
|
+
}
|
|
91
|
+
return "({data}) => { return " + templateBody.replace(/\$(\d+)/g, "data[$1]") + "; }";
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export * from './
|
|
2
|
-
export * from './
|
|
3
|
-
export
|
|
4
|
-
export * from './
|
|
5
|
-
export
|
|
6
|
-
export * from './
|
|
1
|
+
export * from './generator/generator.js';
|
|
2
|
+
export * from './generator/import-resolvers/auto.js';
|
|
3
|
+
export { StatefulLexer } from './lexers/stateful-lexer.js';
|
|
4
|
+
export * from './parser/parse.js';
|
|
5
|
+
export * from './utility/parsing.js';
|
|
6
|
+
export * from './typings/index.js';
|
|
7
|
+
export * from './utility/index.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { RuntimeLexerStateMatchRule, ASTLexerStateNonMatchRule, RuntimeLexer, RuntimeLexerConfig, StatefulLexerStateDefinition } from "../typings/index.js";
|
|
2
2
|
|
|
3
|
-
export class StatefulLexer implements
|
|
3
|
+
export class StatefulLexer implements RuntimeLexer {
|
|
4
4
|
private start: string;
|
|
5
|
-
private states: { [key: string]:
|
|
5
|
+
private states: { [key: string]: StatefulLexerStateDefinition } = Object.create(null);
|
|
6
6
|
private buffer: string;
|
|
7
7
|
private stack: string[];
|
|
8
8
|
private index: number;
|
|
@@ -10,20 +10,13 @@ export class StatefulLexer implements Lexer {
|
|
|
10
10
|
private column: number;
|
|
11
11
|
private prefetched?: RegExpExecArray;
|
|
12
12
|
private current: string;
|
|
13
|
-
private unmatched:
|
|
14
|
-
private rules:
|
|
13
|
+
private unmatched: ASTLexerStateNonMatchRule;
|
|
14
|
+
private rules: RuntimeLexerStateMatchRule[];
|
|
15
15
|
private regexp: RegExp;
|
|
16
16
|
private tags = new Map<string[], Set<string>>();
|
|
17
17
|
|
|
18
|
-
constructor({ states, start }:
|
|
19
|
-
|
|
20
|
-
for (const key in states) {
|
|
21
|
-
this.states[key] = {
|
|
22
|
-
regexp: CompileRegExp(states[key] as ResolvedStateDefinition),
|
|
23
|
-
rules: states[key].rules as LexerStateMatchRule[],
|
|
24
|
-
unmatched: states[key].unmatched ? { type: states[key].unmatched } as LexerStateMatchRule : null
|
|
25
|
-
};
|
|
26
|
-
}
|
|
18
|
+
constructor({ states, start }: RuntimeLexerConfig) {
|
|
19
|
+
this.states = states;
|
|
27
20
|
this.start = start;
|
|
28
21
|
this.buffer = '';
|
|
29
22
|
this.stack = [];
|
|
@@ -50,16 +43,31 @@ export class StatefulLexer implements Lexer {
|
|
|
50
43
|
}
|
|
51
44
|
}
|
|
52
45
|
|
|
53
|
-
next() {
|
|
54
|
-
const next = this.matchNext();
|
|
46
|
+
next(skipped: boolean = false) {
|
|
47
|
+
const next = this.matchNext(skipped);
|
|
55
48
|
if (!next) {
|
|
56
49
|
return
|
|
57
50
|
}
|
|
58
51
|
const { rule, text, index } = next;
|
|
59
52
|
if (!rule) {
|
|
60
|
-
throw new Error(`No matching rule for ${text}`);
|
|
53
|
+
throw new Error(`No matching rule for ${text.split(/\n|\r\n/).slice(0, 3).join('\n')}`);
|
|
54
|
+
}
|
|
55
|
+
const token = {
|
|
56
|
+
type: rule.type,
|
|
57
|
+
highlight: rule.highlight,
|
|
58
|
+
open: rule.open,
|
|
59
|
+
close: rule.close,
|
|
60
|
+
tag: this.getTags(rule.tag),
|
|
61
|
+
value: text,
|
|
62
|
+
text: text,
|
|
63
|
+
offset: index,
|
|
64
|
+
line: this.line,
|
|
65
|
+
lines: 0,
|
|
66
|
+
column: this.column,
|
|
67
|
+
state: this.current
|
|
61
68
|
}
|
|
62
|
-
|
|
69
|
+
this.adjustPosition(text);
|
|
70
|
+
token.lines = this.line - token.line;
|
|
63
71
|
this.adjustStack(rule);
|
|
64
72
|
return token;
|
|
65
73
|
}
|
|
@@ -71,7 +79,7 @@ export class StatefulLexer implements Lexer {
|
|
|
71
79
|
this.current = current;
|
|
72
80
|
this.rules = info.rules;
|
|
73
81
|
this.unmatched = info.unmatched;
|
|
74
|
-
this.regexp = info.
|
|
82
|
+
this.regexp = info.regex;
|
|
75
83
|
}
|
|
76
84
|
|
|
77
85
|
private pop() {
|
|
@@ -83,14 +91,14 @@ export class StatefulLexer implements Lexer {
|
|
|
83
91
|
this.set(state)
|
|
84
92
|
}
|
|
85
93
|
|
|
86
|
-
private matchNext() {
|
|
94
|
+
private matchNext(skipped: boolean = false) {
|
|
87
95
|
if (this.index === this.buffer.length) {
|
|
88
96
|
return;
|
|
89
97
|
}
|
|
90
98
|
|
|
91
99
|
const { index, buffer } = this;
|
|
92
100
|
let text;
|
|
93
|
-
let rule:
|
|
101
|
+
let rule: RuntimeLexerStateMatchRule | ASTLexerStateNonMatchRule;
|
|
94
102
|
let match;
|
|
95
103
|
|
|
96
104
|
this.regexp.lastIndex = index;
|
|
@@ -111,6 +119,10 @@ export class StatefulLexer implements Lexer {
|
|
|
111
119
|
rule = this.getGroup(match);
|
|
112
120
|
text = match[0];
|
|
113
121
|
if (rule.before) {
|
|
122
|
+
this.adjustStack(rule);
|
|
123
|
+
return this.matchNext(skipped);
|
|
124
|
+
} else if (rule.skip && !skipped) {
|
|
125
|
+
this.adjustPosition(text);
|
|
114
126
|
this.adjustStack(rule);
|
|
115
127
|
return this.matchNext();
|
|
116
128
|
}
|
|
@@ -119,33 +131,6 @@ export class StatefulLexer implements Lexer {
|
|
|
119
131
|
return { index, rule, text }
|
|
120
132
|
}
|
|
121
133
|
|
|
122
|
-
private createToken(rule: LexerStateMatchRule, text: string, offset: number) {
|
|
123
|
-
const token = {
|
|
124
|
-
type: rule.type,
|
|
125
|
-
highlight: rule.highlight,
|
|
126
|
-
open: rule.open,
|
|
127
|
-
close: rule.close,
|
|
128
|
-
tag: this.getTags(rule.tag),
|
|
129
|
-
value: text,
|
|
130
|
-
text: text,
|
|
131
|
-
offset: offset,
|
|
132
|
-
line: this.line,
|
|
133
|
-
lines: 0,
|
|
134
|
-
column: this.column,
|
|
135
|
-
state: this.current
|
|
136
|
-
}
|
|
137
|
-
for (let i = 0; i < text.length; i++) {
|
|
138
|
-
this.column++;
|
|
139
|
-
if (text[i] == '\n') {
|
|
140
|
-
token.lines++;
|
|
141
|
-
this.column = 1;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
this.index += text.length;
|
|
145
|
-
this.line += token.lines;
|
|
146
|
-
return token;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
134
|
private getTags(tags?: string[]) {
|
|
150
135
|
if (!tags)
|
|
151
136
|
return undefined;
|
|
@@ -154,7 +139,18 @@ export class StatefulLexer implements Lexer {
|
|
|
154
139
|
return this.tags.get(tags);
|
|
155
140
|
}
|
|
156
141
|
|
|
157
|
-
private
|
|
142
|
+
private adjustPosition(text: string) {
|
|
143
|
+
this.index += text.length;
|
|
144
|
+
for (let i = 0; i < text.length; i++) {
|
|
145
|
+
this.column++;
|
|
146
|
+
if (text[i] == '\n') {
|
|
147
|
+
this.line++;
|
|
148
|
+
this.column = 1;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
private adjustStack(rule: RuntimeLexerStateMatchRule) {
|
|
158
154
|
if (rule.pop) {
|
|
159
155
|
let i = rule.pop === 'all' ? this.stack.length : rule.pop;
|
|
160
156
|
while (i-- > 0) {
|
|
@@ -177,7 +173,7 @@ export class StatefulLexer implements Lexer {
|
|
|
177
173
|
}
|
|
178
174
|
}
|
|
179
175
|
|
|
180
|
-
private getGroup(match):
|
|
176
|
+
private getGroup(match): RuntimeLexerStateMatchRule {
|
|
181
177
|
for (let i = 0; i < this.rules.length; i++) {
|
|
182
178
|
if (match[i + 1] !== undefined) {
|
|
183
179
|
return this.rules[i];
|
|
@@ -185,157 +181,4 @@ export class StatefulLexer implements Lexer {
|
|
|
185
181
|
}
|
|
186
182
|
throw new Error('Cannot find token type for matched text')
|
|
187
183
|
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
class RegexLib {
|
|
191
|
-
|
|
192
|
-
static IsRegex(o: any) {
|
|
193
|
-
return o instanceof RegExp;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
static Escape(s: string) {
|
|
197
|
-
return s.replace(/[-/\\^$*+?.()|[\]{}]/g, '\\$&');
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
static HasGroups(s: string) {
|
|
201
|
-
return (new RegExp('|' + s)).exec('').length > 1;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
static Capture(source: string) {
|
|
205
|
-
return '(' + source + ')';
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
static Join(regexps: string[]) {
|
|
209
|
-
if (!regexps.length)
|
|
210
|
-
return '(?!)';
|
|
211
|
-
const source = regexps.map((s) => `(?:${s})`).join('|');
|
|
212
|
-
return `(?:${source})`;
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
static Source(search: string | RegExp) {
|
|
216
|
-
if (typeof search === 'string') {
|
|
217
|
-
return `(?:${RegexLib.Escape(search)})`;
|
|
218
|
-
}
|
|
219
|
-
if (RegexLib.IsRegex(search)) {
|
|
220
|
-
return search.source;
|
|
221
|
-
}
|
|
222
|
-
throw new Error('Not a pattern: ' + search)
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
function CompileRegExp(state: ResolvedStateDefinition): RegExp {
|
|
228
|
-
const rules = [];
|
|
229
|
-
const subexpressions = [];
|
|
230
|
-
|
|
231
|
-
let isUnicode = null;
|
|
232
|
-
let isCI = null;
|
|
233
|
-
for (const options of state.rules) {
|
|
234
|
-
if (RegexLib.IsRegex(options.when)) {
|
|
235
|
-
const when = options.when as RegExp;
|
|
236
|
-
if (isUnicode === null) {
|
|
237
|
-
isUnicode = when.unicode
|
|
238
|
-
} else if (isUnicode !== when.unicode && !state.unmatched) {
|
|
239
|
-
throw new Error(`Inconsistent Regex Flag /u in state: ${state.name}`);
|
|
240
|
-
}
|
|
241
|
-
if (isCI === null) {
|
|
242
|
-
isCI = when.ignoreCase
|
|
243
|
-
} else if (isCI !== when.ignoreCase) {
|
|
244
|
-
throw new Error(`Inconsistent Regex Flag /i in state: ${state.name}`);
|
|
245
|
-
}
|
|
246
|
-
} else {
|
|
247
|
-
if (isCI == null) {
|
|
248
|
-
isCI = false;
|
|
249
|
-
} else if (isCI != false) {
|
|
250
|
-
throw new Error(`Inconsistent Regex Flag /i in state: ${state.name}`);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
rules.push(options);
|
|
255
|
-
const pat = RegexLib.Source(options.when);
|
|
256
|
-
const regexp = new RegExp(pat)
|
|
257
|
-
if (regexp.test("")) {
|
|
258
|
-
throw new Error("RegExp matches empty string: " + regexp)
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
if (RegexLib.HasGroups(pat)) {
|
|
262
|
-
throw new Error("RegExp has capture groups: " + regexp + "\nUse (?: … ) instead")
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
subexpressions.push(RegexLib.Capture(pat))
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
let flags = !state.unmatched ? 'ym' : 'gm';
|
|
269
|
-
if (isUnicode === true)
|
|
270
|
-
flags += "u"
|
|
271
|
-
if (isCI === true)
|
|
272
|
-
flags += "i"
|
|
273
|
-
return new RegExp(RegexLib.Join(subexpressions), flags);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export function ResolveStates(states: { [key: string]: LexerStateDefinition }, start: string) {
|
|
277
|
-
const resolved = new Set<string>();
|
|
278
|
-
const resolving = new Set<string>();
|
|
279
|
-
const chain = new Set<string>();
|
|
280
|
-
|
|
281
|
-
ResolveRuleImports(start, states, resolved, resolving, chain);
|
|
282
|
-
for (const key in states) {
|
|
283
|
-
if (!resolved.has(key)) {
|
|
284
|
-
delete states[key];
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
return states;
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function ResolveRuleImports(name: string, states: { [key: string]: LexerStateDefinition }, resolved: Set<string>, resolving: Set<string>, chain: Set<string>) {
|
|
291
|
-
if (chain.has(name))
|
|
292
|
-
throw new Error(`Can not resolve circular import of ${name}`);
|
|
293
|
-
if (!states[name])
|
|
294
|
-
throw new Error(`Can not import unknown state ${name}`);
|
|
295
|
-
if (resolved.has(name) || resolving.has(name))
|
|
296
|
-
return;
|
|
297
|
-
const state = states[name];
|
|
298
|
-
const rules = new UniqueRules();
|
|
299
|
-
chain.add(name);
|
|
300
|
-
resolving.add(name);
|
|
301
|
-
for (let i = 0; i < state.rules.length; i++) {
|
|
302
|
-
const rule = state.rules[i];
|
|
303
|
-
if ("import" in rule) {
|
|
304
|
-
for (const ref of rule.import) {
|
|
305
|
-
ResolveRuleImports(ref, states, resolved, resolving, chain);
|
|
306
|
-
rules.push(...states[ref].rules as LexerStateMatchRule[]);
|
|
307
|
-
}
|
|
308
|
-
} else {
|
|
309
|
-
rules.push(rule);
|
|
310
|
-
if ("set" in rule && !resolving.has(rule.set)) {
|
|
311
|
-
ResolveRuleImports(rule.set, states, resolved, resolving, new Set());
|
|
312
|
-
}
|
|
313
|
-
if ("goto" in rule && !resolving.has(rule.goto)) {
|
|
314
|
-
ResolveRuleImports(rule.goto, states, resolved, resolving, new Set());
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
state.rules = rules.rules;
|
|
319
|
-
chain.delete(name);
|
|
320
|
-
resolved.add(name);
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
class UniqueRules {
|
|
324
|
-
private regexps = new Set<string>();
|
|
325
|
-
private strings = new Set<string>();
|
|
326
|
-
rules: LexerStateMatchRule[] = [];
|
|
327
|
-
|
|
328
|
-
push(...rules: LexerStateMatchRule[]) {
|
|
329
|
-
for (const rule of rules) {
|
|
330
|
-
if (RegexLib.IsRegex(rule.when)) {
|
|
331
|
-
if (!this.regexps.has((rule.when as RegExp).source)) {
|
|
332
|
-
this.rules.push(rule);
|
|
333
|
-
}
|
|
334
|
-
} else {
|
|
335
|
-
if (!this.strings.has(rule.when as string)) {
|
|
336
|
-
this.rules.push(rule);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
184
|
}
|