grammar-well 2.1.0 → 2.3.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.
Files changed (134) hide show
  1. package/README.md +74 -1
  2. package/build/generator/artifacts/basic.d.ts +1 -1
  3. package/build/generator/artifacts/basic.js.map +1 -1
  4. package/build/generator/artifacts/lexer.d.ts +2 -2
  5. package/build/generator/artifacts/lexer.js +1 -1
  6. package/build/generator/artifacts/lexer.js.map +1 -1
  7. package/build/generator/artifacts/lr.d.ts +5 -5
  8. package/build/generator/artifacts/lr.js +2 -2
  9. package/build/generator/artifacts/lr.js.map +1 -1
  10. package/build/generator/generator.d.ts +3 -3
  11. package/build/generator/generator.js +3 -3
  12. package/build/generator/generator.js.map +1 -1
  13. package/build/generator/grammars/index.d.ts +2 -2
  14. package/build/generator/grammars/index.js +2 -2
  15. package/build/generator/import-resolvers/auto.d.ts +1 -1
  16. package/build/generator/import-resolvers/browser.d.ts +1 -1
  17. package/build/generator/import-resolvers/browser.js.map +1 -1
  18. package/build/generator/import-resolvers/dictionary.d.ts +1 -1
  19. package/build/generator/import-resolvers/dictionary.js.map +1 -1
  20. package/build/generator/import-resolvers/filesystem.d.ts +1 -1
  21. package/build/generator/index.d.ts +3 -3
  22. package/build/generator/index.js +3 -3
  23. package/build/generator/state.d.ts +1 -1
  24. package/build/generator/stringify/common.d.ts +2 -2
  25. package/build/generator/stringify/common.js.map +1 -1
  26. package/build/generator/stringify/exports/javascript.d.ts +1 -1
  27. package/build/generator/stringify/exports/json.d.ts +1 -1
  28. package/build/generator/stringify/exports/registry.d.ts +6 -6
  29. package/build/generator/stringify/exports/typescript.d.ts +1 -1
  30. package/build/generator/stringify/grammar/v2.d.ts +1 -1
  31. package/build/generator/stringify/javascript.d.ts +2 -2
  32. package/build/generator/stringify/javascript.js.map +1 -1
  33. package/build/index.d.ts +7 -7
  34. package/build/index.js +7 -7
  35. package/build/lexers/character-lexer.d.ts +1 -1
  36. package/build/lexers/stateful-lexer.d.ts +1 -1
  37. package/build/lexers/token-buffer.d.ts +3 -3
  38. package/build/lexers/token-buffer.js +2 -2
  39. package/build/lexers/token-buffer.js.map +1 -1
  40. package/build/parser/algorithms/cyk.d.ts +2 -2
  41. package/build/parser/algorithms/earley.d.ts +15 -12
  42. package/build/parser/algorithms/earley.js +29 -17
  43. package/build/parser/algorithms/earley.js.map +1 -1
  44. package/build/parser/algorithms/lrk/algorithm.d.ts +2 -2
  45. package/build/parser/algorithms/lrk/algorithm.js +31 -21
  46. package/build/parser/algorithms/lrk/algorithm.js.map +1 -1
  47. package/build/parser/algorithms/lrk/canonical-collection.d.ts +10 -10
  48. package/build/parser/algorithms/lrk/canonical-collection.js +73 -49
  49. package/build/parser/algorithms/lrk/canonical-collection.js.map +1 -1
  50. package/build/parser/algorithms/lrk/stack.d.ts +8 -18
  51. package/build/parser/algorithms/lrk/stack.js +11 -24
  52. package/build/parser/algorithms/lrk/stack.js.map +1 -1
  53. package/build/parser/algorithms/lrk/typings.d.ts +16 -0
  54. package/build/parser/algorithms/lrk/typings.js +2 -0
  55. package/build/parser/algorithms/lrk/typings.js.map +1 -0
  56. package/build/parser/algorithms/noop.d.ts +7 -0
  57. package/build/parser/algorithms/noop.js +9 -0
  58. package/build/parser/algorithms/noop.js.map +1 -0
  59. package/build/parser/parse.d.ts +1 -1
  60. package/build/parser/parse.js +3 -1
  61. package/build/parser/parse.js.map +1 -1
  62. package/build/typings/ast.d.ts +1 -1
  63. package/build/typings/generator.d.ts +4 -4
  64. package/build/typings/index.d.ts +8 -8
  65. package/build/typings/index.js +4 -4
  66. package/build/typings/runtime.d.ts +3 -3
  67. package/build/utility/format.js +3 -3
  68. package/build/utility/general.d.ts +2 -2
  69. package/build/utility/general.js +1 -1
  70. package/build/utility/general.js.map +1 -1
  71. package/build/utility/index.d.ts +4 -4
  72. package/build/utility/index.js +4 -4
  73. package/build/utility/lint.d.ts +1 -1
  74. package/build/utility/monarch.d.ts +1 -1
  75. package/build/utility/parsing.d.ts +2 -2
  76. package/build/utility/parsing.js.map +1 -1
  77. package/build/utility/text-format.d.ts +3 -3
  78. package/build/utility/text-format.js +4 -4
  79. package/build/utility/text-format.js.map +1 -1
  80. package/build/version.json +1 -1
  81. package/package.json +13 -11
  82. package/src/generator/artifacts/basic.ts +6 -4
  83. package/src/generator/artifacts/lexer.ts +6 -4
  84. package/src/generator/artifacts/lr.ts +10 -7
  85. package/src/generator/generator.ts +17 -11
  86. package/src/generator/grammars/index.ts +2 -2
  87. package/src/generator/grammars/v1.ts +1 -1
  88. package/src/generator/grammars/v2.ts +1 -1
  89. package/src/generator/import-resolvers/auto.ts +3 -3
  90. package/src/generator/import-resolvers/browser.ts +5 -2
  91. package/src/generator/import-resolvers/dictionary.ts +5 -2
  92. package/src/generator/import-resolvers/filesystem.ts +1 -1
  93. package/src/generator/index.ts +3 -3
  94. package/src/generator/state.ts +1 -1
  95. package/src/generator/stringify/common.ts +6 -3
  96. package/src/generator/stringify/exports/javascript.ts +1 -1
  97. package/src/generator/stringify/exports/json.ts +1 -1
  98. package/src/generator/stringify/exports/registry.ts +4 -4
  99. package/src/generator/stringify/exports/typescript.ts +1 -1
  100. package/src/generator/stringify/grammar/v2.ts +1 -1
  101. package/src/generator/stringify/javascript.ts +12 -8
  102. package/src/index.ts +7 -7
  103. package/src/lexers/character-lexer.ts +1 -1
  104. package/src/lexers/stateful-lexer.ts +1 -1
  105. package/src/lexers/token-buffer.ts +16 -3
  106. package/src/parser/algorithms/cyk.ts +4 -4
  107. package/src/parser/algorithms/earley.ts +67 -36
  108. package/src/parser/algorithms/lrk/algorithm.ts +40 -25
  109. package/src/parser/algorithms/lrk/canonical-collection.ts +84 -55
  110. package/src/parser/algorithms/lrk/stack.ts +12 -37
  111. package/src/parser/algorithms/lrk/typings.ts +13 -0
  112. package/src/parser/algorithms/noop.ts +11 -0
  113. package/src/parser/parse.ts +11 -9
  114. package/src/typings/ast.ts +1 -1
  115. package/src/typings/generator.ts +4 -4
  116. package/src/typings/index.ts +8 -8
  117. package/src/typings/runtime.ts +3 -3
  118. package/src/utility/format.ts +4 -4
  119. package/src/utility/general.ts +4 -3
  120. package/src/utility/index.ts +4 -4
  121. package/src/utility/lint.ts +1 -1
  122. package/src/utility/monarch.ts +1 -1
  123. package/src/utility/parsing.ts +3 -2
  124. package/src/utility/text-format.ts +6 -6
  125. package/src/version.json +1 -1
  126. package/tsconfig.tsbuildinfo +1 -1
  127. package/build/parser/algorithms/lrk/closure.d.ts +0 -10
  128. package/build/parser/algorithms/lrk/closure.js +0 -26
  129. package/build/parser/algorithms/lrk/closure.js.map +0 -1
  130. package/build/parser/algorithms/lrk/state.d.ts +0 -12
  131. package/build/parser/algorithms/lrk/state.js +0 -2
  132. package/build/parser/algorithms/lrk/state.js.map +0 -1
  133. package/src/parser/algorithms/lrk/closure.ts +0 -37
  134. package/src/parser/algorithms/lrk/state.ts +0 -10
@@ -1,8 +1,11 @@
1
- import { ASTGrammarSymbolLiteral, ASTGrammarSymbolNonTerminal, ASTGrammarSymbolRegex, ASTGrammarSymbolToken, GeneratorGrammarSymbol } from "../../typings/index.js";
2
- import { GeneratorState } from "../state.js";
1
+ import type { ASTGrammarSymbolLiteral, ASTGrammarSymbolNonTerminal, ASTGrammarSymbolRegex, ASTGrammarSymbolToken, GeneratorGrammarSymbol } from "../../typings/index.ts";
2
+ import { GeneratorState } from "../state.ts";
3
3
 
4
4
  export class CommonGenerator {
5
- constructor(public state: GeneratorState) { }
5
+ public state: GeneratorState;
6
+ constructor(state: GeneratorState) {
7
+ this.state = state;
8
+ }
6
9
 
7
10
  static NewLine(indent: number) {
8
11
  return '\n' + ' '.repeat(indent * 4);
@@ -1,4 +1,4 @@
1
- import { JavaScriptGenerator } from "../javascript.js";
1
+ import { JavaScriptGenerator } from "../javascript.ts";
2
2
 
3
3
  export function CJSOutput(generator: JavaScriptGenerator) {
4
4
  const exportName = generator.name();
@@ -1,4 +1,4 @@
1
- import { JavaScriptGenerator } from "../javascript.js";
1
+ import { JavaScriptGenerator } from "../javascript.ts";
2
2
 
3
3
  export function JSONFormatter(generator: JavaScriptGenerator) {
4
4
  return JSON.stringify({ state: generator.state.export(), output: generator.options });
@@ -1,8 +1,8 @@
1
1
 
2
- import { JavaScriptGenerator } from "../javascript.js";
3
- import { CJSOutput, ESMOutput } from "./javascript.js";
4
- import { JSONFormatter } from "./json.js";
5
- import { TypescriptFormat } from "./typescript.js";
2
+ import { JavaScriptGenerator } from "../javascript.ts";
3
+ import { CJSOutput, ESMOutput } from "./javascript.ts";
4
+ import { JSONFormatter } from "./json.ts";
5
+ import { TypescriptFormat } from "./typescript.ts";
6
6
 
7
7
 
8
8
  export const ExportsRegistry = {
@@ -1,4 +1,4 @@
1
- import { JavaScriptGenerator } from "../javascript.js";
1
+ import { JavaScriptGenerator } from "../javascript.ts";
2
2
 
3
3
  export function TypescriptFormat(generator: JavaScriptGenerator) {
4
4
  const exportName = generator.name();
@@ -1,4 +1,4 @@
1
- import { ASTConfig, ASTDirectives, ASTGrammar, ASTGrammarProduction, ASTGrammarSymbol, ASTImport, ASTLexer, ASTLexerState, ASTLexerStateImportRule, ASTLexerStateMatchRule, ASTLexerStateNonMatchRule, GeneratorGrammarSymbol } from "../../../typings/index.js";
1
+ import type { ASTConfig, ASTDirectives, ASTGrammar, ASTGrammarProduction, ASTGrammarSymbol, ASTImport, ASTLexer, ASTLexerState, ASTLexerStateImportRule, ASTLexerStateMatchRule, ASTLexerStateNonMatchRule, GeneratorGrammarSymbol } from "../../../typings/index.ts";
2
2
 
3
3
  export class V2GrammarString {
4
4
  source: string = '';
@@ -1,9 +1,9 @@
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";
1
+ import type { Dictionary, GeneratorOutputOptions, GeneratorGrammarProductionRule } from "../../typings/index.ts";
2
+ import { BasicGrammarTable } from "../artifacts/basic.ts";
3
+ import { LexerArtifact } from "../artifacts/lexer.ts";
4
+ import { LRParseTableBuilder } from "../artifacts/lr.ts";
5
+ import { GeneratorState } from "../state.ts";
6
+ import { CommonGenerator } from "./common.ts";
7
7
 
8
8
  const PostProcessors = {
9
9
  "join": "({data}) => data.join('')",
@@ -13,8 +13,12 @@ const PostProcessors = {
13
13
  };
14
14
 
15
15
  export class JavaScriptGenerator {
16
-
17
- constructor(public state: GeneratorState, public options: GeneratorOutputOptions) { }
16
+ public state: GeneratorState;
17
+ public options: GeneratorOutputOptions;
18
+ constructor(state: GeneratorState, options: GeneratorOutputOptions) {
19
+ this.state = state;
20
+ this.options = options;
21
+ }
18
22
 
19
23
  name() {
20
24
  return this.options.name || 'GWLanguage';
package/src/index.ts CHANGED
@@ -1,7 +1,7 @@
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
+ export * from './generator/generator.ts';
2
+ export * from './generator/import-resolvers/auto.ts';
3
+ export { StatefulLexer } from './lexers/stateful-lexer.ts';
4
+ export * from './parser/parse.ts';
5
+ export * from './utility/parsing.ts';
6
+ export * from './typings/index.ts';
7
+ export * from './utility/index.ts';
@@ -1,4 +1,4 @@
1
- import { RuntimeLexer } from "../typings/index.js";
1
+ import type { RuntimeLexer } from "../typings/index.ts";
2
2
 
3
3
  export class CharacterLexer implements RuntimeLexer {
4
4
  private buffer: string | any[] = '';
@@ -1,4 +1,4 @@
1
- import { RuntimeLexerStateMatchRule, ASTLexerStateNonMatchRule, RuntimeLexer, RuntimeLexerConfig, StatefulLexerStateDefinition } from "../typings/index.js";
1
+ import type { RuntimeLexerStateMatchRule, ASTLexerStateNonMatchRule, RuntimeLexer, RuntimeLexerConfig, StatefulLexerStateDefinition } from "../typings/index.ts";
2
2
 
3
3
  export class StatefulLexer implements RuntimeLexer {
4
4
  private start: string;
@@ -1,4 +1,4 @@
1
- import { RuntimeLexer, RuntimeLexerToken, TQRestorePoint } from '../typings/index.js';
1
+ import type { RuntimeLexer, RuntimeLexerToken, TQRestorePoint } from '../typings/index.ts';
2
2
 
3
3
  export class TokenBuffer {
4
4
  private history: RuntimeLexerToken[] = [];
@@ -6,6 +6,9 @@ export class TokenBuffer {
6
6
 
7
7
  private $historyIndex = -1;
8
8
 
9
+ public lexer: RuntimeLexer;
10
+ private tokenProcessor?: (token: RuntimeLexerToken) => RuntimeLexerToken;
11
+
9
12
  get offset() { return this.active?.offset || 0 }
10
13
  get line() { return this.active?.line || 0 }
11
14
  get column() { return this.active?.column || 0; }
@@ -15,7 +18,13 @@ export class TokenBuffer {
15
18
  return { historyIndex: this.$historyIndex, offset: this.offset };
16
19
  }
17
20
 
18
- constructor(public lexer: RuntimeLexer, private tokenProcessor?: (token: RuntimeLexerToken) => RuntimeLexerToken) { }
21
+ constructor(
22
+ lexer: RuntimeLexer,
23
+ tokenProcessor?: (token: RuntimeLexerToken) => RuntimeLexerToken
24
+ ) {
25
+ this.lexer = lexer;
26
+ this.tokenProcessor = tokenProcessor;
27
+ }
19
28
 
20
29
  reset(buffer: string) {
21
30
  this.lexer.feed(buffer);
@@ -92,7 +101,11 @@ export class TokenBuffer {
92
101
  }
93
102
 
94
103
  class TokenIterator {
95
- constructor(private buffer: TokenBuffer) { }
104
+ private buffer: TokenBuffer;
105
+
106
+ constructor(buffer: TokenBuffer) {
107
+ this.buffer = buffer;
108
+ }
96
109
 
97
110
  next() {
98
111
  const token = this.buffer.next()
@@ -1,7 +1,7 @@
1
- import { RuntimeGrammarProductionRule, RuntimeGrammarRuleSymbol, RuntimeParserClass, RuntimeLexerToken } from "../../typings/index.js";
2
- import { TokenBuffer } from "../../lexers/token-buffer.js";
3
- import { Matrix } from "../../utility/general.js";
4
- import { ParserUtility } from "../../utility/parsing.js";
1
+ import type { RuntimeGrammarProductionRule, RuntimeGrammarRuleSymbol, RuntimeParserClass, RuntimeLexerToken } from "../../typings/index.ts";
2
+ import { TokenBuffer } from "../../lexers/token-buffer.ts";
3
+ import { Matrix } from "../../utility/general.ts";
4
+ import { ParserUtility } from "../../utility/parsing.ts";
5
5
 
6
6
  export function CYK(language: RuntimeParserClass & { tokens: TokenBuffer }, _options = {}) {
7
7
  const { grammar } = language.artifacts;
@@ -1,16 +1,18 @@
1
- import { Dictionary, RuntimeGrammarProductionRule, RuntimeLexerToken, RuntimeParserClass } from "../../typings/index.js";
2
- import { TokenBuffer } from "../../lexers/token-buffer.js";
3
- import { TextFormatter } from "../../utility/text-format.js";
4
- import { ParserUtility } from "../../utility/parsing.js";
1
+ import type { Dictionary, RuntimeGrammarProductionRule, RuntimeLexerToken, RuntimeParserClass } from "../../typings/index.ts";
2
+ import { TokenBuffer } from "../../lexers/token-buffer.ts";
3
+ import { TextFormatter } from "../../utility/text-format.ts";
4
+ import { ParserUtility } from "../../utility/parsing.ts";
5
5
 
6
6
  export interface EarleyParserOptions {
7
7
  keepHistory?: boolean;
8
+ postProcessing?: 'eager' | 'lazy';
8
9
  }
9
10
 
10
11
  export function Earley(language: RuntimeParserClass & { tokens: TokenBuffer }, options: EarleyParserOptions = {}) {
11
12
  const { tokens } = language;
12
13
  const { rules, start } = language.artifacts.grammar;
13
- const column = new Column(rules, 0);
14
+ const StateClass = options.postProcessing === 'eager' ? EagerState : LazyState;
15
+ const column = new Column(rules, 0, StateClass);
14
16
  const table: Column[] = [column];
15
17
  column.wants[start] = [];
16
18
  column.predict(start);
@@ -27,7 +29,7 @@ export function Earley(language: RuntimeParserClass & { tokens: TokenBuffer }, o
27
29
 
28
30
  current++;
29
31
 
30
- const nextColumn = new Column(rules, current);
32
+ const nextColumn = new Column(rules, current, StateClass);
31
33
  table.push(nextColumn);
32
34
 
33
35
  const literal = token.value;
@@ -58,9 +60,12 @@ export function Earley(language: RuntimeParserClass & { tokens: TokenBuffer }, o
58
60
  results.push(data);
59
61
  }
60
62
  }
61
- const clone = results.length > 1;
62
- for (let i = 0; i < results.length; i++) {
63
- results[i] = PostProcess(results[i], clone);
63
+
64
+ if (StateClass == LazyState) {
65
+ const clone = results.length > 1;
66
+ for (let i = 0; i < results.length; i++) {
67
+ results[i] = PostProcess(results[i], clone);
68
+ }
64
69
  }
65
70
  return { results, info: { table } };
66
71
  }
@@ -76,28 +81,35 @@ function PostProcess(ast: PreAST | RuntimeLexerToken, clone?: boolean) {
76
81
  }
77
82
 
78
83
  class Column {
79
- data: any;
80
- states: State[] = [];
81
- wants: Dictionary<State[]> = Object.create(null);// states indexed by the non-terminal they expect
82
- scannable: State[] = [];// list of states that expect a token
83
- completed: Dictionary<State[]> = Object.create(null); // states that are nullable
84
+ public data: any;
85
+ public states: State[] = [];
86
+ public wants: Dictionary<State[]> = Object.create(null);
87
+ public scannable: State[] = [];
88
+ public completed: Dictionary<State[]> = Object.create(null);
89
+ public index: number;
90
+ private rules: Dictionary<RuntimeGrammarProductionRule[]>;
91
+ private StateClass: Concrete<typeof State>;
84
92
 
85
93
  constructor(
86
- private rules: Dictionary<RuntimeGrammarProductionRule[]>,
87
- public index: number
88
- ) { }
94
+ rules: Dictionary<RuntimeGrammarProductionRule[]>,
95
+ index: number,
96
+ StateClass: Concrete<typeof State>
97
+ ) {
98
+ this.rules = rules;
99
+ this.index = index;
100
+ this.StateClass = StateClass;
101
+ }
89
102
 
90
103
 
91
104
  process() {
92
105
  let w = 0;
93
106
  let state: State;
94
107
 
95
- // eslint-disable-next-line no-cond-assign
96
- while (state = this.states[w++]) { // nb. we push() during iteration
108
+ while (state = this.states[w++]) {
97
109
  if (state.isComplete) {
98
110
  state.finish();
99
111
  const { wantedBy } = state;
100
- for (let i = wantedBy.length; i--;) { // this line is hot
112
+ for (let i = wantedBy.length; i--;) {
101
113
  this.complete(wantedBy[i], state);
102
114
  }
103
115
 
@@ -136,7 +148,7 @@ class Column {
136
148
  return;
137
149
 
138
150
  for (const rule of this.rules[exp]) {
139
- this.states.push(new State(rule, 0, this.index, this.wants[exp]));
151
+ this.states.push(new this.StateClass(rule, 0, this.index, this.wants[exp]));
140
152
  }
141
153
  }
142
154
 
@@ -156,22 +168,31 @@ class Column {
156
168
  }
157
169
  }
158
170
 
159
- class State {
160
- isComplete: boolean;
161
- data: any = [];
162
- left: State;
163
- right: State | StateToken;
171
+ abstract class State {
172
+ public isComplete: boolean;
173
+ public data: any = [];
174
+ public left: State;
175
+ public right: State | StateToken;
176
+ public rule: RuntimeGrammarProductionRule;
177
+ public dot: number;
178
+ public reference: number;
179
+ public wantedBy: State[];
180
+
164
181
  constructor(
165
- public rule: RuntimeGrammarProductionRule,
166
- public dot: number,
167
- public reference: number,
168
- public wantedBy: State[]
182
+ rule: RuntimeGrammarProductionRule,
183
+ dot: number,
184
+ reference: number,
185
+ wantedBy: State[]
169
186
  ) {
187
+ this.rule = rule;
188
+ this.dot = dot;
189
+ this.reference = reference;
190
+ this.wantedBy = wantedBy;
170
191
  this.isComplete = this.dot === rule.symbols.length;
171
192
  }
172
193
 
173
194
  nextState(child: State | StateToken) {
174
- const state = new State(this.rule, this.dot + 1, this.reference, this.wantedBy);
195
+ const state = new (this.constructor as any)(this.rule, this.dot + 1, this.reference, this.wantedBy);
175
196
  state.left = this;
176
197
  state.right = child;
177
198
  if (state.isComplete) {
@@ -182,13 +203,10 @@ class State {
182
203
  }
183
204
 
184
205
 
185
- finish() {
186
- this.data = [this.rule, this.data, { reference: this.reference, dot: this.dot }];
187
- }
206
+ abstract finish(): void;
188
207
 
189
208
  protected build() {
190
209
  const children = [];
191
- // eslint-disable-next-line @typescript-eslint/no-this-alias
192
210
  let node: State = this;
193
211
  do {
194
212
  children[node.dot - 1] = node.right.data;
@@ -198,6 +216,18 @@ class State {
198
216
  }
199
217
  }
200
218
 
219
+ class EagerState extends State {
220
+ finish() {
221
+ this.data = ParserUtility.PostProcess(this.rule, this.data, { reference: this.reference, dot: this.dot });
222
+ }
223
+ }
224
+
225
+ class LazyState extends State {
226
+ finish() {
227
+ this.data = [this.rule, this.data, { reference: this.reference, dot: this.dot }];
228
+ }
229
+ }
230
+
201
231
  interface StateToken {
202
232
  data: any,
203
233
  token: any,
@@ -205,4 +235,5 @@ interface StateToken {
205
235
  reference: number
206
236
  }
207
237
 
208
- type PreAST = [RuntimeGrammarProductionRule, (RuntimeLexerToken | PreAST)[], { reference: number, dot: number }];
238
+ type PreAST = [RuntimeGrammarProductionRule, (RuntimeLexerToken | PreAST)[], { reference: number, dot: number }];
239
+ type Concrete<T extends abstract new (...args: any) => any> = new (...args: ConstructorParameters<T>) => InstanceType<T>;
@@ -1,37 +1,52 @@
1
- import { RuntimeParserClass } from "../../../typings/index.js";
2
- import { TokenBuffer } from "../../../lexers/token-buffer.js";
3
- import { ParserUtility } from "../../../utility/parsing.js";
4
- import { CanonicalCollection } from "./canonical-collection.js";
5
- import { LRStack } from "./stack.js";
1
+ import type { RuntimeParserClass } from "../../../typings/index.ts";
2
+ import { TokenBuffer } from "../../../lexers/token-buffer.ts";
3
+ import { ParserUtility } from "../../../utility/parsing.ts";
4
+ import { CanonicalCollection } from "./canonical-collection.ts";
5
+ import { Stack } from "./stack.ts";
6
+ import type { State } from "./typings.ts";
6
7
 
7
8
  export function LRK(language: RuntimeParserClass & { tokens: TokenBuffer }, options = {}) {
8
9
  const { grammar } = language.artifacts;
9
10
  const { tokens } = language;
10
- const { states, rules: rules } = new CanonicalCollection(grammar);
11
- const stack = new LRStack();
12
- const s = states.get('0.0');
13
- stack.append(s.rule.name);
14
- stack.shift(s);
11
+ const { start } = new CanonicalCollection(grammar);
12
+ const stateStack = new Stack<State>();
13
+ const inputStack = new Stack<any>();
14
+ stateStack.push(start);
15
+
15
16
  let token;
16
17
 
17
- while (token = tokens.next()) {
18
- for (const [symbol, state] of stack.current.state.actions) {
19
- if (ParserUtility.SymbolMatchesToken(symbol, token)) {
20
- stack.append(symbol);
21
- stack.shift(states.get(state));
22
- stack.current.value = token;
23
- break;
24
- }
18
+ tokenloop: while (token = tokens.next()) {
19
+ const match = stateStack.current.actions.find(a => ParserUtility.SymbolMatchesToken(a.symbol, token));
20
+
21
+ if (match) {
22
+ inputStack.push(token);
23
+ stateStack.push(match.state);
24
+ } else {
25
+ throw new Error("Syntax Error: Unexpected Token");
25
26
  }
26
- while (stack.current.state?.isFinal) {
27
- const rule = rules.fetch(stack.current.state.reduce);
28
- stack.reduce(rule);
29
- stack.current.value = ParserUtility.PostProcess(rule, stack.current.children.map(v => v.value));
30
- const s = stack.previous.state.goto.get(rule.name);
31
- stack.shift(states.get(s));
32
27
 
28
+ while (stateStack.current.reduce) {
29
+ const rule = stateStack.current.reduce;
30
+ const value = inputStack.pop(rule.symbols.length);
31
+ stateStack.pop(rule.symbols.length);
32
+ inputStack.push(ParserUtility.PostProcess(rule, value));
33
+ const nextState = stateStack.current.goto[rule.name];
34
+
35
+ if (!nextState)
36
+ break tokenloop;
37
+
38
+ stateStack.push(nextState);
33
39
  }
34
40
  }
35
41
 
36
- return { results: [stack.current.value] }
42
+ if (stateStack.size > 1) {
43
+ throw new Error("Syntax Error: Unexpected End of Input");
44
+ }
45
+ const peek = tokens.next();
46
+ if (peek) {
47
+ console.log(peek)
48
+ throw new Error("Syntax Error: Expected End of Input");
49
+ }
50
+
51
+ return { results: [inputStack.current[0]] }
37
52
  }
@@ -1,79 +1,108 @@
1
- import { RuntimeGrammarProductionRule, RuntimeGrammarRuleSymbol, RuntimeParserClass } from "../../../typings/index.js";
2
- import { ParserUtility } from "../../../utility/parsing.js";
3
- import { BiMap } from "./bimap.js";
4
- import { ClosureBuilder } from "./closure.js";
5
- import { State } from "./state.js";
1
+ import type { RuntimeGrammarProductionRule, RuntimeGrammarRuleSymbol, RuntimeParserClass } from "../../../typings/index.ts";
2
+ import { ParserUtility } from "../../../utility/parsing.ts";
3
+ import { TextFormatter } from "../../../utility/text-format.ts";
4
+ import { BiMap } from "./bimap.ts";
5
+ import type { LRItem, State } from "./typings.ts";
6
6
 
7
7
  export class CanonicalCollection {
8
- states: Map<string, State> = new Map();
9
- rules: BiMap<RuntimeGrammarProductionRule> = new BiMap();
10
- terminals: BiMap<RuntimeGrammarRuleSymbol> = new BiMap();
8
+ public start: State;
9
+ public rules: BiMap<RuntimeGrammarProductionRule> = new BiMap();
10
+ public grammar: RuntimeParserClass['artifacts']['grammar'];
11
+ private cache: { [key: string]: State } = {};
11
12
 
12
- private closure: ClosureBuilder;
13
13
  constructor(
14
- public grammar: RuntimeParserClass['artifacts']['grammar']
14
+ grammar: RuntimeParserClass['artifacts']['grammar']
15
15
  ) {
16
+ this.grammar = grammar;
16
17
  const augmented = {
17
18
  name: Symbol() as unknown as string,
18
19
  symbols: [this.grammar.start]
19
20
  }
20
- this.grammar['rules'][augmented.name] = [augmented];
21
- this.closure = new ClosureBuilder(this.grammar);
21
+ this.grammar.rules[augmented.name] = [augmented];
22
22
  this.rules.id(augmented);
23
- this.addState(this.grammar['rules'][augmented.name][0], 0);
24
- this.linkStates('0.0');
23
+ this.start = this.generateState([{ rule: augmented, dot: 0 }]);
25
24
  }
26
25
 
27
- private addState(rule: RuntimeGrammarProductionRule, dot: number) {
28
- const id = this.getStateId(rule, dot);
29
- if (this.states.has(id))
30
- return;
26
+ private generateState(kernel: LRItem[]): State {
27
+ const id = this.canonicalStateId(kernel);
28
+ if (this.cache[id])
29
+ return this.cache[id];
31
30
 
32
- const state: State = {
33
- items: [],
34
- isFinal: false,
35
- actions: new Map(),
36
- goto: new Map(),
37
- reduce: null,
38
- rule: rule
31
+ this.cache[id] = { id };
32
+ if (kernel.length == 1 && kernel[0].rule.symbols.length == kernel[0].dot) {
33
+ this.cache[id].reduce = kernel[0].rule;
34
+ return this.cache[id];
39
35
  }
40
36
 
41
- state.items.push({ rule, dot });
42
- if (rule.symbols.length == dot)
43
- state.isFinal = true;
37
+ const items = [...kernel];
38
+ const visited = new Set<string>();
39
+ const refs: { [key: string]: RuntimeGrammarRuleSymbol } = {}
40
+ const actions: { [key: string]: LRItem[] } = {};
41
+ const goto: { [key: string]: LRItem[] } = {};
42
+ for (let i = 0; i < items.length; i++) {
43
+ const { rule, dot } = items[i];
44
+ const id = this.canonicalLRItemId(items[i]);
45
+ if (dot == rule.symbols.length)
46
+ throw new Error('Reduce Conflict on state: ' + id + `\n${items.map(v => TextFormatter.GrammarRule(v.rule, v.dot)).join('\n')}`);
44
47
 
45
- this.states.set(id, state);
48
+ if (visited.has(id))
49
+ continue;
50
+ visited.add(id);
51
+ const symbol = rule.symbols[dot];
52
+ const name = this.canonicalSymbolId(symbol);
53
+ refs[name] = symbol;
46
54
 
47
- state.items.push(...this.closure.get(rule.symbols[dot] as string))
48
-
49
- if (!state.isFinal)
50
- for (const { rule, dot } of state.items) {
51
- this.addState(rule, dot + 1);
55
+ if (symbol && !ParserUtility.SymbolIsTerminal(symbol)) {
56
+ const prods = this.grammar.rules[symbol] || [];
57
+ for (const rule of prods) {
58
+ items.push({ rule, dot: 0 });
59
+ }
60
+ goto[name] = goto[name] || [];
61
+ goto[name].push({ rule, dot: dot + 1 });
62
+ } else {
63
+ actions[name] = actions[name] || [];
64
+ actions[name].push({ rule, dot: dot + 1 });
52
65
  }
53
- }
66
+ }
67
+ this.cache[id].actions = [];
68
+ this.cache[id].goto = {};
54
69
 
55
- private linkStates(id: string, completed: Set<string> = new Set()) {
56
- completed.add(id);
57
- const state = this.states.get(id);
58
- if (!state.isFinal) {
59
- for (const { rule, dot } of state.items) {
60
- const symbol = rule.symbols[dot];
61
- const itemStateId = this.getStateId(rule, dot + 1);
62
- if (ParserUtility.SymbolIsTerminal(symbol) && typeof symbol != 'symbol') {
63
- state.actions.set(symbol, itemStateId);
64
- } else {
65
- state.goto.set(symbol, itemStateId);
66
- }
70
+ for (const key in actions) {
71
+ this.cache[id].actions.push({ symbol: refs[key], state: this.generateState(actions[key]) })
72
+ }
67
73
 
68
- if (!completed.has(itemStateId))
69
- this.linkStates(itemStateId, completed);
70
- }
71
- } else {
72
- state.reduce = this.rules.id(state.rule);
74
+ for (const key in goto) {
75
+ this.cache[id].goto[refs[key] as string] = this.generateState(goto[key]);
73
76
  }
77
+
78
+ return this.cache[id];
79
+ }
80
+
81
+ private canonicalStateId(items: LRItem[]): string {
82
+ return items
83
+ .map(item => this.canonicalLRItemId(item))
84
+ .sort()
85
+ .join('|');
86
+ }
87
+
88
+ private canonicalLRItemId(item: LRItem) {
89
+ return `${this.rules.id(item.rule)}:${item.dot}`;
74
90
  }
75
91
 
76
- private getStateId(rule: RuntimeGrammarProductionRule, dot: number) {
77
- return this.rules.id(rule) + '.' + dot;
92
+ private canonicalSymbolId(symbol: RuntimeGrammarRuleSymbol) {
93
+ if (typeof symbol === 'symbol')
94
+ return `SY:START`;
95
+ if (typeof symbol === 'string')
96
+ return `NT:${symbol}`;
97
+ if (typeof symbol == 'function')
98
+ return `FN:${symbol.toString()}`;
99
+ if (!symbol)
100
+ return
101
+ if (symbol instanceof RegExp)
102
+ return `RG:${symbol.source}`;
103
+ if ("token" in symbol)
104
+ return `TK:${symbol.token}`;
105
+ if ("literal" in symbol)
106
+ return `LT:${symbol.literal}`;
78
107
  }
79
- }
108
+ }