grammar-composer 0.6.2 → 0.7.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 +27 -19
- package/dist/parser/Builder.d.ts +3 -3
- package/dist/parser/Builder.d.ts.map +1 -1
- package/dist/parser/Builder.js +37 -37
- package/dist/parser/Builder.js.map +1 -1
- package/dist/parser/Grammar.d.ts +24 -24
- package/dist/parser/Grammar.d.ts.map +1 -1
- package/dist/parser/Grammar.js +11 -11
- package/dist/parser/Grammar.js.map +1 -1
- package/dist/parser/ParseError.js +6 -6
- package/dist/parser/ParseError.js.map +1 -1
- package/dist/parser/Parser.d.ts.map +1 -1
- package/dist/parser/Parser.js +36 -36
- package/dist/parser/Parser.js.map +1 -1
- package/dist/parser/StaticAnalysis.d.ts +3 -3
- package/dist/parser/StaticAnalysis.d.ts.map +1 -1
- package/dist/parser/StaticAnalysis.js +6 -6
- package/dist/parser/StaticAnalysis.js.map +1 -1
- package/dist/parser/{TerminalToText.d.ts → TerminalFormatter.d.ts} +2 -2
- package/dist/parser/TerminalFormatter.d.ts.map +1 -0
- package/dist/parser/{TerminalToText.js → TerminalFormatter.js} +2 -2
- package/dist/parser/TerminalFormatter.js.map +1 -0
- package/dist/tests/Test.js +6 -6
- package/dist/tests/Test.js.map +1 -1
- package/dist/tests/test-grammars/JsonGrammar.d.ts +3 -3
- package/dist/tests/test-grammars/JsonGrammar.d.ts.map +1 -1
- package/dist/tests/test-grammars/JsonGrammar.js +2 -2
- package/dist/tests/test-grammars/JsonGrammar.js.map +1 -1
- package/dist/tests/test-grammars/RegExpGrammar.d.ts +11 -11
- package/dist/tests/test-grammars/RegExpGrammar.d.ts.map +1 -1
- package/dist/tests/test-grammars/RegExpGrammar.js +2 -2
- package/dist/tests/test-grammars/RegExpGrammar.js.map +1 -1
- package/dist/tests/test-grammars/XmlGrammar.d.ts +1 -1
- package/dist/tests/test-grammars/XmlGrammar.d.ts.map +1 -1
- package/dist/tests/test-grammars/XmlGrammar.js +2 -2
- package/dist/tests/test-grammars/XmlGrammar.js.map +1 -1
- package/package.json +2 -2
- package/src/parser/Builder.ts +42 -42
- package/src/parser/Grammar.ts +36 -36
- package/src/parser/ParseError.ts +6 -6
- package/src/parser/Parser.ts +38 -38
- package/src/parser/StaticAnalysis.ts +20 -18
- package/src/parser/{TerminalToText.ts → TerminalFormatter.ts} +1 -1
- package/src/tests/Test.ts +6 -6
- package/src/tests/test-grammars/JsonGrammar.ts +2 -2
- package/src/tests/test-grammars/RegExpGrammar.ts +2 -2
- package/src/tests/test-grammars/XmlGrammar.ts +2 -2
- package/dist/parser/TerminalToText.d.ts.map +0 -1
- package/dist/parser/TerminalToText.js.map +0 -1
|
@@ -75,9 +75,9 @@ const quotedString = R.anyOf([
|
|
|
75
75
|
"'"
|
|
76
76
|
]);
|
|
77
77
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
78
|
-
//
|
|
78
|
+
// Unfolded nonterminal list
|
|
79
79
|
//////////////////////////////////////////////////////////////////////////////////////////////
|
|
80
|
-
export const
|
|
80
|
+
export const xmlGrammarUnfoldedNonterminalNames = [
|
|
81
81
|
'openingTagStart',
|
|
82
82
|
'tagEnd',
|
|
83
83
|
'declarationTagOpening',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"XmlGrammar.js","sourceRoot":"","sources":["../../../src/tests/test-grammars/XmlGrammar.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"XmlGrammar.js","sourceRoot":"","sources":["../../../src/tests/test-grammars/XmlGrammar.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "grammar-composer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Creates and generates parsers from composable grammar definitions. Includes advanced features like lexer-free parsing, selective packrat memoization and static analysis.",
|
|
5
5
|
"author": "Rotem Dan",
|
|
6
6
|
"license": "MIT",
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
"regexp-composer": "~0.6.1"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@types/node": "~26.4.
|
|
39
|
+
"@types/node": "~26.4.1",
|
|
40
40
|
"vitest": "~4.1.11"
|
|
41
41
|
}
|
|
42
42
|
}
|
package/src/parser/Builder.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isArray, isFunction, isString } from '../utilities/Utilities.js'
|
|
2
2
|
|
|
3
3
|
import { detectAndAnnotateOptionalNodes, detectAndErrorOnLeftRecursion } from './StaticAnalysis.js'
|
|
4
|
-
import { Grammar, Nonterminal,
|
|
4
|
+
import { Grammar, Nonterminal, GrammarNode, StringTerminal, Sequence, NonterminalReference, GrammarExpression } from './Grammar.js'
|
|
5
5
|
|
|
6
6
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
7
7
|
// Grammar builder method
|
|
@@ -12,7 +12,7 @@ export function buildGrammar<T extends GrammarDefinition>(
|
|
|
12
12
|
options?: GrammarBuilderOptions<T>): Grammar<T> {
|
|
13
13
|
|
|
14
14
|
options = {
|
|
15
|
-
|
|
15
|
+
unfoldedNonterminalNames: [],
|
|
16
16
|
...options
|
|
17
17
|
}
|
|
18
18
|
|
|
@@ -34,10 +34,10 @@ export function buildGrammar<T extends GrammarDefinition>(
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const productionContent = objectProperty.call(definitionObject)
|
|
37
|
-
const
|
|
38
|
-
const
|
|
37
|
+
const productionContentNode = grammarExpressionToNode(productionContent)
|
|
38
|
+
const isUnfoldedNonterminal = options.unfoldedNonterminalNames?.includes(key) === true
|
|
39
39
|
|
|
40
|
-
const newNonterminal = nonterminal(key,
|
|
40
|
+
const newNonterminal = nonterminal(key, productionContentNode, isUnfoldedNonterminal)
|
|
41
41
|
const newOptionalNonterminal = {
|
|
42
42
|
...newNonterminal,
|
|
43
43
|
optional: true,
|
|
@@ -57,7 +57,7 @@ export function buildGrammar<T extends GrammarDefinition>(
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
for (const [func, nonterminal] of nonterminalLookup) {
|
|
60
|
-
const preparedContent =
|
|
60
|
+
const preparedContent = prepareGrammarNode(
|
|
61
61
|
nonterminal.content,
|
|
62
62
|
nonterminalLookup,
|
|
63
63
|
optionalNonterminalLookup,
|
|
@@ -97,73 +97,73 @@ export function buildGrammar<T extends GrammarDefinition>(
|
|
|
97
97
|
)
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
-
function
|
|
101
|
-
|
|
100
|
+
function prepareGrammarNode(
|
|
101
|
+
rootNode: GrammarNode,
|
|
102
102
|
nonterminalLookup: Map<Function, Nonterminal>,
|
|
103
103
|
optionalNonterminalLookup: Map<Function, Nonterminal>,
|
|
104
104
|
getNewCacheId: () => number
|
|
105
|
-
):
|
|
106
|
-
function prepare(
|
|
107
|
-
const setCacheIdIfNeeded = (
|
|
108
|
-
if (
|
|
109
|
-
|
|
105
|
+
): GrammarNode {
|
|
106
|
+
function prepare(node: GrammarNode): GrammarNode {
|
|
107
|
+
const setCacheIdIfNeeded = (node: GrammarNode) => {
|
|
108
|
+
if (node.cached === true) {
|
|
109
|
+
node.cacheId = getNewCacheId()
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
return
|
|
112
|
+
return node
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
switch (
|
|
115
|
+
switch (node.type) {
|
|
116
116
|
case 'StringTerminal':
|
|
117
117
|
case 'Nonterminal': {
|
|
118
118
|
return setCacheIdIfNeeded({
|
|
119
|
-
...
|
|
119
|
+
...node
|
|
120
120
|
})
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
case 'PatternTerminal': {
|
|
124
124
|
return setCacheIdIfNeeded({
|
|
125
|
-
...
|
|
125
|
+
...node,
|
|
126
126
|
})
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
case 'Repetition': {
|
|
130
130
|
return setCacheIdIfNeeded({
|
|
131
|
-
...
|
|
132
|
-
content: prepare(
|
|
131
|
+
...node,
|
|
132
|
+
content: prepare(node.content),
|
|
133
133
|
})
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
case 'Sequence':
|
|
137
137
|
case 'Choice': {
|
|
138
138
|
return setCacheIdIfNeeded({
|
|
139
|
-
...
|
|
140
|
-
members:
|
|
139
|
+
...node,
|
|
140
|
+
members: node.members.map(member => prepare(member)),
|
|
141
141
|
})
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
case 'NonterminalReference': {
|
|
145
|
-
const reference =
|
|
145
|
+
const reference = node.reference
|
|
146
146
|
|
|
147
147
|
let nonterminal: Nonterminal | undefined
|
|
148
148
|
|
|
149
|
-
if (
|
|
149
|
+
if (node.optional) {
|
|
150
150
|
nonterminal = optionalNonterminalLookup.get(reference)
|
|
151
151
|
} else {
|
|
152
152
|
nonterminal = nonterminalLookup.get(reference)
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
if (!nonterminal) {
|
|
156
|
-
throw new Error(`Couldn't resolve function reference in grammar
|
|
156
|
+
throw new Error(`Couldn't resolve function reference in grammar node: ${JSON.stringify(node)}`)
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
-
if (
|
|
159
|
+
if (node.cached === true) {
|
|
160
160
|
return {
|
|
161
161
|
...nonterminal,
|
|
162
162
|
|
|
163
163
|
cached: true,
|
|
164
164
|
cacheId: getNewCacheId(),
|
|
165
165
|
|
|
166
|
-
|
|
166
|
+
canonicalNonterminal: nonterminal.canonicalNonterminal ?? nonterminal
|
|
167
167
|
}
|
|
168
168
|
} else {
|
|
169
169
|
return nonterminal
|
|
@@ -172,7 +172,7 @@ function prepareGrammarElement(
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
return prepare(
|
|
175
|
+
return prepare(rootNode)
|
|
176
176
|
}
|
|
177
177
|
|
|
178
178
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
@@ -192,7 +192,7 @@ function stringTerminal(content: string): StringTerminal {
|
|
|
192
192
|
}
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
function nonterminal(name: string, content:
|
|
195
|
+
function nonterminal(name: string, content: GrammarNode, unfolded: boolean): Nonterminal {
|
|
196
196
|
if (name.length < 1) {
|
|
197
197
|
throw new Error(`A nonterminal name must include at least 1 character.`)
|
|
198
198
|
}
|
|
@@ -204,11 +204,11 @@ function nonterminal(name: string, content: GrammarElement, unwrapped: boolean):
|
|
|
204
204
|
|
|
205
205
|
optional: false,
|
|
206
206
|
cached: false,
|
|
207
|
-
|
|
207
|
+
unfolded,
|
|
208
208
|
}
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
function sequence(members:
|
|
211
|
+
function sequence(members: GrammarNode[]): Sequence {
|
|
212
212
|
return {
|
|
213
213
|
type: 'Sequence',
|
|
214
214
|
members,
|
|
@@ -218,27 +218,27 @@ function sequence(members: GrammarElement[]): Sequence {
|
|
|
218
218
|
}
|
|
219
219
|
}
|
|
220
220
|
|
|
221
|
-
function
|
|
221
|
+
function unresolvedNonterminalReference(nonterminalReferenceFunction: Function): NonterminalReference {
|
|
222
222
|
return {
|
|
223
223
|
type: 'NonterminalReference',
|
|
224
|
-
reference,
|
|
224
|
+
reference: nonterminalReferenceFunction,
|
|
225
225
|
optional: false,
|
|
226
226
|
|
|
227
227
|
cached: false,
|
|
228
228
|
}
|
|
229
229
|
}
|
|
230
230
|
|
|
231
|
-
export function
|
|
232
|
-
if (isString(
|
|
233
|
-
return stringTerminal(
|
|
234
|
-
} else if (isArray(
|
|
235
|
-
const
|
|
231
|
+
export function grammarExpressionToNode(grammarExpression: GrammarExpression): GrammarNode {
|
|
232
|
+
if (isString(grammarExpression)) {
|
|
233
|
+
return stringTerminal(grammarExpression)
|
|
234
|
+
} else if (isArray(grammarExpression)) {
|
|
235
|
+
const memberNodes = grammarExpression.map(member => grammarExpressionToNode(member))
|
|
236
236
|
|
|
237
|
-
return sequence(
|
|
238
|
-
} else if (isFunction(
|
|
239
|
-
return
|
|
237
|
+
return sequence(memberNodes)
|
|
238
|
+
} else if (isFunction(grammarExpression)) {
|
|
239
|
+
return unresolvedNonterminalReference(grammarExpression)
|
|
240
240
|
} else {
|
|
241
|
-
return
|
|
241
|
+
return grammarExpression
|
|
242
242
|
}
|
|
243
243
|
}
|
|
244
244
|
|
|
@@ -246,7 +246,7 @@ export function productionToGrammarElement(production: Production): GrammarEleme
|
|
|
246
246
|
// Builder type definitions
|
|
247
247
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
248
248
|
export interface GrammarBuilderOptions<T> {
|
|
249
|
-
|
|
249
|
+
unfoldedNonterminalNames?: GrammarNonterminalNames<T>
|
|
250
250
|
}
|
|
251
251
|
|
|
252
252
|
export type GrammarNonterminalNames<T> = (keyof T)[]
|
package/src/parser/Grammar.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { isArray } from '../utilities/Utilities.js'
|
|
|
3
3
|
|
|
4
4
|
import { parse } from './Parser.js'
|
|
5
5
|
import { validatePatternCaptureGroups } from './StaticAnalysis.js'
|
|
6
|
-
import {
|
|
6
|
+
import { grammarExpressionToNode } from './Builder.js'
|
|
7
7
|
|
|
8
8
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
9
9
|
// Grammar class
|
|
@@ -28,7 +28,7 @@ export class Grammar<T> {
|
|
|
28
28
|
return parse(text, this)
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
get
|
|
31
|
+
get rootNode() {
|
|
32
32
|
return this.productions[this.startProductionName]
|
|
33
33
|
}
|
|
34
34
|
}
|
|
@@ -36,50 +36,50 @@ export class Grammar<T> {
|
|
|
36
36
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
37
37
|
// Exported grammar builder functions
|
|
38
38
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
39
|
-
export function zeroOrMore(content:
|
|
39
|
+
export function zeroOrMore(content: GrammarExpression): Repetition {
|
|
40
40
|
return {
|
|
41
41
|
type: 'Repetition',
|
|
42
|
-
content:
|
|
42
|
+
content: grammarExpressionToNode(content),
|
|
43
43
|
optional: true,
|
|
44
44
|
cached: false,
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export function oneOrMore(content:
|
|
48
|
+
export function oneOrMore(content: GrammarExpression): Repetition {
|
|
49
49
|
return {
|
|
50
50
|
type: 'Repetition',
|
|
51
|
-
content:
|
|
51
|
+
content: grammarExpressionToNode(content),
|
|
52
52
|
optional: false,
|
|
53
53
|
cached: false,
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
export function anyOf(...members:
|
|
57
|
+
export function anyOf(...members: GrammarExpression[]): Choice {
|
|
58
58
|
if (members.length === 0) {
|
|
59
59
|
throw new Error(`'anyOf' requires at least one member.`)
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
const
|
|
62
|
+
const memberNodes = members.map(member => grammarExpressionToNode(member))
|
|
63
63
|
|
|
64
64
|
return {
|
|
65
65
|
type: 'Choice',
|
|
66
|
-
members:
|
|
66
|
+
members: memberNodes,
|
|
67
67
|
optional: false,
|
|
68
68
|
exhaustive: false,
|
|
69
69
|
cached: false,
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
export function bestOf(...members:
|
|
73
|
+
export function bestOf(...members: GrammarExpression[]): Choice {
|
|
74
74
|
if (members.length === 0) {
|
|
75
75
|
throw new Error(`'bestOf' requires at least one member.`)
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
const
|
|
78
|
+
const memberNodes = members.map(member => grammarExpressionToNode(member))
|
|
79
79
|
|
|
80
80
|
return {
|
|
81
81
|
type: 'Choice',
|
|
82
|
-
members:
|
|
82
|
+
members: memberNodes,
|
|
83
83
|
optional: false,
|
|
84
84
|
exhaustive: true,
|
|
85
85
|
|
|
@@ -87,8 +87,8 @@ export function bestOf(...members: Production[]): Choice {
|
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
-
export function possibly<T extends
|
|
91
|
-
return { ...
|
|
90
|
+
export function possibly<T extends GrammarExpression>(content: GrammarExpression): T {
|
|
91
|
+
return { ...grammarExpressionToNode(content), optional: true } as T
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
export function pattern(pattern: Pattern): PatternTerminal {
|
|
@@ -113,20 +113,20 @@ export function pattern(pattern: Pattern): PatternTerminal {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
export function cached<T extends
|
|
117
|
-
return { ...
|
|
116
|
+
export function cached<T extends GrammarExpression>(content: GrammarExpression): T {
|
|
117
|
+
return { ...grammarExpressionToNode(content), cached: true } as T
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
export function uncached<T extends
|
|
121
|
-
return { ...
|
|
120
|
+
export function uncached<T extends GrammarExpression>(content: GrammarExpression): T {
|
|
121
|
+
return { ...grammarExpressionToNode(content), cached: false } as T
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
125
125
|
// Type definitions
|
|
126
126
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
127
|
-
export type
|
|
127
|
+
export type GrammarExpression = string | GrammarNode | (() => GrammarExpression) | GrammarExpression[]
|
|
128
128
|
|
|
129
|
-
export type
|
|
129
|
+
export type GrammarNode =
|
|
130
130
|
StringTerminal |
|
|
131
131
|
PatternTerminal |
|
|
132
132
|
Nonterminal |
|
|
@@ -135,60 +135,60 @@ export type GrammarElement =
|
|
|
135
135
|
Choice |
|
|
136
136
|
NonterminalReference
|
|
137
137
|
|
|
138
|
-
interface
|
|
138
|
+
interface GrammarNodeBase {
|
|
139
139
|
type: string
|
|
140
140
|
optional: boolean
|
|
141
141
|
|
|
142
142
|
cached: boolean
|
|
143
143
|
cacheId?: number
|
|
144
144
|
|
|
145
|
-
// The name of the grammar property this
|
|
146
|
-
// Used by the parser to refer to the
|
|
145
|
+
// The name of the grammar property this node was assigned to, if any.
|
|
146
|
+
// Used by the parser to refer to the node by name in error messages.
|
|
147
147
|
name?: string
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
export type Terminal = StringTerminal | PatternTerminal
|
|
151
151
|
|
|
152
|
-
export interface StringTerminal extends
|
|
152
|
+
export interface StringTerminal extends GrammarNodeBase {
|
|
153
153
|
type: 'StringTerminal'
|
|
154
154
|
content: string
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
export interface PatternTerminal extends
|
|
157
|
+
export interface PatternTerminal extends GrammarNodeBase {
|
|
158
158
|
type: 'PatternTerminal'
|
|
159
159
|
pattern: Pattern
|
|
160
160
|
regExp: RegExp
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
export interface Nonterminal extends
|
|
163
|
+
export interface Nonterminal extends GrammarNodeBase {
|
|
164
164
|
type: 'Nonterminal'
|
|
165
165
|
name: string
|
|
166
|
-
content:
|
|
167
|
-
|
|
166
|
+
content: GrammarNode
|
|
167
|
+
unfolded: boolean
|
|
168
168
|
|
|
169
169
|
// The canonical nonterminal as defined in the grammar. Clones created for
|
|
170
170
|
// optional references and cached references keep a reference to the original,
|
|
171
171
|
// so identity comparisons work across clones.
|
|
172
|
-
|
|
172
|
+
canonicalNonterminal?: Nonterminal
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
export interface Sequence extends
|
|
175
|
+
export interface Sequence extends GrammarNodeBase {
|
|
176
176
|
type: 'Sequence'
|
|
177
|
-
members:
|
|
177
|
+
members: GrammarNode[]
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
export interface Repetition extends
|
|
180
|
+
export interface Repetition extends GrammarNodeBase {
|
|
181
181
|
type: 'Repetition'
|
|
182
|
-
content:
|
|
182
|
+
content: GrammarNode
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
-
export interface Choice extends
|
|
185
|
+
export interface Choice extends GrammarNodeBase {
|
|
186
186
|
type: 'Choice'
|
|
187
|
-
members:
|
|
187
|
+
members: GrammarNode[]
|
|
188
188
|
exhaustive: boolean
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
-
export interface NonterminalReference extends
|
|
191
|
+
export interface NonterminalReference extends GrammarNodeBase {
|
|
192
192
|
type: 'NonterminalReference'
|
|
193
193
|
reference: Function
|
|
194
194
|
}
|
package/src/parser/ParseError.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Nonterminal, Terminal } from './Grammar.js'
|
|
2
2
|
import { buildCaretSpacing, expandTabs, getLineAndColumn } from '../utilities/LineAndColumn.js'
|
|
3
|
-
import { escapeChar,
|
|
3
|
+
import { escapeChar, TerminalFormatter } from './TerminalFormatter.js'
|
|
4
4
|
|
|
5
5
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|
|
6
6
|
// Parse error class
|
|
@@ -145,10 +145,10 @@ function isRedundantCandidate(candidate: TerminalCandidate, candidates: Terminal
|
|
|
145
145
|
|
|
146
146
|
// Compares nonterminals by their canonical grammar reference, because the same
|
|
147
147
|
// production can be represented by multiple cloned instances during a parse.
|
|
148
|
-
function stackIndexOf(productionStack: Nonterminal[],
|
|
149
|
-
const
|
|
148
|
+
function stackIndexOf(productionStack: Nonterminal[], nonterminal: Nonterminal): number {
|
|
149
|
+
const canonicalNonterminal = nonterminal.canonicalNonterminal ?? nonterminal
|
|
150
150
|
|
|
151
|
-
return productionStack.findIndex(nonterminal => (nonterminal.
|
|
151
|
+
return productionStack.findIndex(nonterminal => (nonterminal.canonicalNonterminal ?? nonterminal) === canonicalNonterminal)
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
function areTerminalsEqual(a: any, b: any): boolean {
|
|
@@ -193,7 +193,7 @@ function stringifyFailedTerminal(failedMatch: FailedMatch): string {
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
const stringifiedLengthLimit = 100
|
|
196
|
-
const terminalToText = new
|
|
196
|
+
const terminalToText = new TerminalFormatter(stringifiedLengthLimit)
|
|
197
197
|
|
|
198
198
|
return terminalToText.stringifyTerminal(terminal)
|
|
199
199
|
}
|
|
@@ -236,7 +236,7 @@ function findCommonProductionPrefix(productionStacks: Nonterminal[][]): Nontermi
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
function areSameNonterminal(a: Nonterminal, b: Nonterminal): boolean {
|
|
239
|
-
return (a.
|
|
239
|
+
return (a.canonicalNonterminal ?? a) === (b.canonicalNonterminal ?? b)
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
/////////////////////////////////////////////////////////////////////////////////////////////////
|