ohm-js 17.2.1 → 17.4.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/dist/ohm-extras.cjs +568 -471
- package/dist/ohm-extras.js +568 -471
- package/dist/ohm.cjs +511 -464
- package/dist/ohm.cjs.map +1 -1
- package/dist/ohm.js +512 -465
- package/dist/ohm.min.js +1 -1
- package/extras/VisitorFamily.js +9 -9
- package/extras/index.d.ts +7 -11
- package/extras/index.mjs +1 -0
- package/extras/recoverSourceOrder.js +48 -0
- package/extras/semantics-toAST.js +1 -1
- package/index.d.ts +24 -4
- package/package.json +4 -4
- package/src/Builder.js +8 -8
- package/src/CaseInsensitiveTerminal.js +3 -3
- package/src/Grammar.js +69 -70
- package/src/GrammarDecl.js +5 -5
- package/src/IndentationSensitive.js +6 -6
- package/src/InputStream.js +3 -0
- package/src/Interval.js +19 -7
- package/src/MatchResult.js +14 -16
- package/src/MatchState.js +17 -17
- package/src/PosInfo.js +7 -7
- package/src/Semantics.js +43 -43
- package/src/Trace.js +19 -19
- package/src/buildGrammar.js +4 -4
- package/src/common.js +9 -9
- package/src/errors.js +36 -36
- package/src/main.js +3 -3
- package/src/nodes.js +4 -4
- package/src/ohm-cmd.js +5 -5
- package/src/pexprs-allowsSkippingPrecedingSpace.js +2 -2
- package/src/pexprs-assertAllApplicationsAreValid.js +11 -11
- package/src/pexprs-assertChoicesHaveUniformArity.js +9 -9
- package/src/pexprs-assertIteratedExprsAreNotNullable.js +7 -7
- package/src/pexprs-eval.js +40 -36
- package/src/pexprs-getArity.js +6 -6
- package/src/pexprs-introduceParams.js +5 -5
- package/src/pexprs-isNullable.js +9 -9
- package/src/pexprs-main.js +12 -4
- package/src/pexprs-outputRecipe.js +15 -15
- package/src/pexprs-substituteParams.js +6 -6
- package/src/pexprs-toArgumentNameList.js +20 -20
- package/src/pexprs-toDisplayString.js +5 -5
- package/src/pexprs-toFailure.js +12 -12
- package/src/pexprs-toString.js +20 -20
- package/src/semanticsDeferredInit.js +8 -8
- package/src/unicode.js +54 -0
- package/src/util.js +3 -3
- package/src/version.js +1 -1
- package/dist/ohm-grammar.js.new +0 -0
- package/src/UnicodeCategories.js +0 -30
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/*
|
|
2
|
+
To find iter nodes that are derived from the same repetition expression, we
|
|
3
|
+
look for adjacent iter nodes that have the same source interval and the same
|
|
4
|
+
number of children.
|
|
5
|
+
|
|
6
|
+
A few things to note:
|
|
7
|
+
- The children of `*` and `+` nodes can't be nullable, so the associated iter
|
|
8
|
+
nodes always consume some input, and therefore consecutive nodes that have
|
|
9
|
+
the same interval must come from the same repetition expression.
|
|
10
|
+
- We *could* mistake `a? b?` for (a b)?`, if neither of them comsume any input.
|
|
11
|
+
However, for the purposes of this module, those two cases are equivalent
|
|
12
|
+
anyways, since we only care about finding the correct order of the non-iter
|
|
13
|
+
nodes, and both interpretations yield the same order.
|
|
14
|
+
*/
|
|
15
|
+
const isIterSibling = (refNode, n) => {
|
|
16
|
+
return (
|
|
17
|
+
n.isIteration() &&
|
|
18
|
+
n.source.startIdx === refNode.source.startIdx &&
|
|
19
|
+
n.source.endIdx === refNode.source.endIdx &&
|
|
20
|
+
n.children.length === refNode.children.length
|
|
21
|
+
);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function recoverSourceOrder(nodes, depth = 0) {
|
|
25
|
+
const ans = [];
|
|
26
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
27
|
+
const n = nodes[i];
|
|
28
|
+
if (!n.isIteration()) {
|
|
29
|
+
ans.push(n);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// We found an iter node, now find its siblings.
|
|
34
|
+
const siblings = [n];
|
|
35
|
+
// Find the first node that's *not* part of the current list.
|
|
36
|
+
for (let j = i + 1; j < nodes.length && isIterSibling(n, nodes[j]); j++) {
|
|
37
|
+
siblings.push(nodes[j]);
|
|
38
|
+
i = j;
|
|
39
|
+
}
|
|
40
|
+
const cousins = [];
|
|
41
|
+
const numRows = siblings[0].children.length;
|
|
42
|
+
for (let row = 0; row < numRows; row++) {
|
|
43
|
+
cousins.push(...siblings.map(sib => sib.children[row]));
|
|
44
|
+
}
|
|
45
|
+
ans.push(...recoverSourceOrder(cousins, depth + 1));
|
|
46
|
+
}
|
|
47
|
+
return ans;
|
|
48
|
+
}
|
package/index.d.ts
CHANGED
|
@@ -165,28 +165,48 @@ export interface Matcher {
|
|
|
165
165
|
* Result of Grammar#match
|
|
166
166
|
*/
|
|
167
167
|
export interface MatchResult {
|
|
168
|
+
matcher: Matcher;
|
|
169
|
+
input: string;
|
|
170
|
+
|
|
168
171
|
/**
|
|
169
172
|
* True iff match succeeded
|
|
170
173
|
*/
|
|
171
|
-
succeeded():
|
|
174
|
+
succeeded(): this is SucceededMatchResult;
|
|
172
175
|
|
|
173
176
|
/**
|
|
174
177
|
* True iff match did not succeed
|
|
175
178
|
*/
|
|
176
|
-
failed():
|
|
179
|
+
failed(): this is FailedMatchResult;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export interface SucceededMatchResult extends MatchResult {}
|
|
177
183
|
|
|
184
|
+
export interface FailedMatchResult extends MatchResult {
|
|
178
185
|
/**
|
|
179
186
|
* If match failed contains an error message indicating where and
|
|
180
187
|
* why the match failed. This message is suitable for end users of a
|
|
181
188
|
* language (i.e., people who do not have access to the grammar source).
|
|
182
189
|
*/
|
|
183
|
-
message
|
|
190
|
+
message: string;
|
|
184
191
|
|
|
185
192
|
/**
|
|
186
193
|
* If match failed contains an abbreviated version of this.message that
|
|
187
194
|
* does not include an excerpt from the invalid input.
|
|
188
195
|
*/
|
|
189
|
-
shortMessage
|
|
196
|
+
shortMessage: string;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Returns the position at which the error should be reported. This is used
|
|
200
|
+
* to construct `message` and `shortMessage`.
|
|
201
|
+
*/
|
|
202
|
+
getRightmostFailurePosition(): number;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Return a string summarizing the expected contents of the input stream
|
|
206
|
+
* at the rightmost failure position. This is used to construct `message`
|
|
207
|
+
* and `shortMessage`.
|
|
208
|
+
*/
|
|
209
|
+
getExpectedText(): string;
|
|
190
210
|
|
|
191
211
|
/**
|
|
192
212
|
* If this MatchResult is a failure, returns an Interval indicating
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ohm-js",
|
|
3
|
-
"version": "17.
|
|
3
|
+
"version": "17.4.0",
|
|
4
4
|
"description": "An object-oriented language for parsing and pattern matching",
|
|
5
5
|
"repository": "https://github.com/ohmjs/ohm",
|
|
6
6
|
"keywords": [
|
|
@@ -79,6 +79,7 @@
|
|
|
79
79
|
"James Meng <35415298+jamesmengo@users.noreply.github.com>",
|
|
80
80
|
"Julien Gonzalez <hello@spinjs.com>",
|
|
81
81
|
"Justin Chase <justin.m.chase@gmail.com>",
|
|
82
|
+
"Karl Weber <me@kow.fm>",
|
|
82
83
|
"Leslie Ying <acetophore@users.noreply.github.com>",
|
|
83
84
|
"Luca Guzzon <luca.guzzon@gmail.com>",
|
|
84
85
|
"Mike Niebling <(none)>",
|
|
@@ -110,16 +111,15 @@
|
|
|
110
111
|
"ava": "^6.0.0",
|
|
111
112
|
"ava-spec": "^1.1.1",
|
|
112
113
|
"dedent": "^0.7.0",
|
|
113
|
-
"husky": "^4.2.5",
|
|
114
114
|
"jsdom": "^9.9.1",
|
|
115
115
|
"json": "^9.0.6",
|
|
116
116
|
"markscript": "^0.5.0",
|
|
117
117
|
"node-static": "^0.7.11",
|
|
118
|
+
"prettier": "^3.6.2",
|
|
118
119
|
"rollup": "^2.63.0",
|
|
119
120
|
"terser": "^5.15.1",
|
|
120
121
|
"uvu": "^0.5.6",
|
|
121
|
-
"walk-sync": "^2.2.0"
|
|
122
|
-
"watchlist": "^0.3.1"
|
|
122
|
+
"walk-sync": "^2.2.0"
|
|
123
123
|
},
|
|
124
124
|
"engines": {
|
|
125
125
|
"node": ">=0.12.1"
|
package/src/Builder.js
CHANGED
|
@@ -21,7 +21,7 @@ export class Builder {
|
|
|
21
21
|
if (superGrammar) {
|
|
22
22
|
// `superGrammar` may be a recipe (i.e. an Array), or an actual grammar instance.
|
|
23
23
|
gDecl.withSuperGrammar(
|
|
24
|
-
superGrammar instanceof Grammar ? superGrammar : this.fromRecipe(superGrammar)
|
|
24
|
+
superGrammar instanceof Grammar ? superGrammar : this.fromRecipe(superGrammar)
|
|
25
25
|
);
|
|
26
26
|
}
|
|
27
27
|
if (defaultStartRule) {
|
|
@@ -45,8 +45,8 @@ export class Builder {
|
|
|
45
45
|
let source;
|
|
46
46
|
if (gDecl.source && metaInfo && metaInfo.sourceInterval) {
|
|
47
47
|
source = gDecl.source.subInterval(
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
metaInfo.sourceInterval[0],
|
|
49
|
+
metaInfo.sourceInterval[1] - metaInfo.sourceInterval[0]
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
gDecl[action](ruleName, formals, body, description, source);
|
|
@@ -141,7 +141,7 @@ export class Builder {
|
|
|
141
141
|
|
|
142
142
|
app(ruleName, optParams) {
|
|
143
143
|
if (optParams && optParams.length > 0) {
|
|
144
|
-
optParams = optParams.map(function(param) {
|
|
144
|
+
optParams = optParams.map(function (param) {
|
|
145
145
|
return param instanceof pexprs.PExpr ? param : this.fromRecipe(param);
|
|
146
146
|
}, this);
|
|
147
147
|
}
|
|
@@ -153,10 +153,10 @@ export class Builder {
|
|
|
153
153
|
// `this.currentDecl` and `this.currentRuleName` being set.
|
|
154
154
|
splice(beforeTerms, afterTerms) {
|
|
155
155
|
return new pexprs.Splice(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
156
|
+
this.currentDecl.superGrammar,
|
|
157
|
+
this.currentRuleName,
|
|
158
|
+
beforeTerms.map(term => this.fromRecipe(term)),
|
|
159
|
+
afterTerms.map(term => this.fromRecipe(term))
|
|
160
160
|
);
|
|
161
161
|
}
|
|
162
162
|
|
|
@@ -48,9 +48,9 @@ export class CaseInsensitiveTerminal extends PExpr {
|
|
|
48
48
|
|
|
49
49
|
toFailure(grammar) {
|
|
50
50
|
return new Failure(
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
this,
|
|
52
|
+
this.obj.toFailure(grammar) + ' (case-insensitive)',
|
|
53
|
+
'description'
|
|
54
54
|
);
|
|
55
55
|
}
|
|
56
56
|
|
package/src/Grammar.js
CHANGED
|
@@ -12,8 +12,8 @@ const SPECIAL_ACTION_NAMES = ['_iter', '_terminal', '_nonterminal', '_default'];
|
|
|
12
12
|
|
|
13
13
|
function getSortedRuleValues(grammar) {
|
|
14
14
|
return Object.keys(grammar.rules)
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
.sort()
|
|
16
|
+
.map(name => grammar.rules[name]);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
// Until ES2019, JSON was not a valid subset of JavaScript because U+2028 (line separator)
|
|
@@ -34,11 +34,11 @@ export class Grammar {
|
|
|
34
34
|
if (optDefaultStartRule) {
|
|
35
35
|
if (!(optDefaultStartRule in rules)) {
|
|
36
36
|
throw new Error(
|
|
37
|
-
|
|
37
|
+
"Invalid start rule: '" +
|
|
38
38
|
optDefaultStartRule +
|
|
39
39
|
"' is not a rule in grammar '" +
|
|
40
40
|
name +
|
|
41
|
-
"'"
|
|
41
|
+
"'"
|
|
42
42
|
);
|
|
43
43
|
}
|
|
44
44
|
this.defaultStartRule = optDefaultStartRule;
|
|
@@ -109,7 +109,6 @@ export class Grammar {
|
|
|
109
109
|
_checkTopDownActionDict(what, name, actionDict) {
|
|
110
110
|
const problems = [];
|
|
111
111
|
|
|
112
|
-
// eslint-disable-next-line guard-for-in
|
|
113
112
|
for (const k in actionDict) {
|
|
114
113
|
const v = actionDict[k];
|
|
115
114
|
const isSpecialAction = SPECIAL_ACTION_NAMES.includes(k);
|
|
@@ -139,10 +138,10 @@ export class Grammar {
|
|
|
139
138
|
if (problems.length > 0) {
|
|
140
139
|
const prettyProblems = problems.map(problem => '- ' + problem);
|
|
141
140
|
const error = new Error(
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
141
|
+
[
|
|
142
|
+
`Found errors in the action dictionary of the '${name}' ${what}:`,
|
|
143
|
+
...prettyProblems,
|
|
144
|
+
].join('\n')
|
|
146
145
|
);
|
|
147
146
|
error.problems = problems;
|
|
148
147
|
throw error;
|
|
@@ -155,9 +154,9 @@ export class Grammar {
|
|
|
155
154
|
// All special actions have an expected arity of 0, though all but _terminal
|
|
156
155
|
// are expected to use the rest parameter syntax (e.g. `_iter(...children)`).
|
|
157
156
|
// This is considered to have arity 0, i.e. `((...args) => {}).length` is 0.
|
|
158
|
-
return SPECIAL_ACTION_NAMES.includes(actionName)
|
|
159
|
-
0
|
|
160
|
-
this.rules[actionName].body.getArity();
|
|
157
|
+
return SPECIAL_ACTION_NAMES.includes(actionName)
|
|
158
|
+
? 0
|
|
159
|
+
: this.rules[actionName].body.getArity();
|
|
161
160
|
}
|
|
162
161
|
|
|
163
162
|
_inheritsFrom(grammar) {
|
|
@@ -248,7 +247,7 @@ export class Grammar {
|
|
|
248
247
|
sb.append('{');
|
|
249
248
|
|
|
250
249
|
let first = true;
|
|
251
|
-
|
|
250
|
+
|
|
252
251
|
for (const ruleName in this.rules) {
|
|
253
252
|
const {body} = this.rules[ruleName];
|
|
254
253
|
if (first) {
|
|
@@ -295,10 +294,10 @@ export class Grammar {
|
|
|
295
294
|
if (formals.length !== app.args.length) {
|
|
296
295
|
const {source} = this.rules[app.ruleName];
|
|
297
296
|
throw errors.wrongNumberOfParameters(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
297
|
+
app.ruleName,
|
|
298
|
+
formals.length,
|
|
299
|
+
app.args.length,
|
|
300
|
+
source
|
|
302
301
|
);
|
|
303
302
|
}
|
|
304
303
|
return app;
|
|
@@ -317,63 +316,63 @@ export class Grammar {
|
|
|
317
316
|
// `digit`, and is implicitly the super-grammar of any grammar whose super-grammar
|
|
318
317
|
// isn't specified.
|
|
319
318
|
Grammar.ProtoBuiltInRules = new Grammar(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
},
|
|
353
|
-
// Union of Lt (titlecase), Lm (modifier), and Lo (other), i.e. any letter not in Ll or Lu.
|
|
354
|
-
unicodeLtmo: {
|
|
355
|
-
body: new pexprs.UnicodeChar('Ltmo'),
|
|
356
|
-
formals: [],
|
|
357
|
-
description: 'a Unicode character in Lt, Lm, or Lo',
|
|
358
|
-
primitive: true,
|
|
359
|
-
},
|
|
360
|
-
|
|
361
|
-
// These rules are not truly primitive (they could be written in userland) but are defined
|
|
362
|
-
// here for bootstrapping purposes.
|
|
363
|
-
spaces: {
|
|
364
|
-
body: new pexprs.Star(new pexprs.Apply('space')),
|
|
365
|
-
formals: [],
|
|
366
|
-
},
|
|
367
|
-
space: {
|
|
368
|
-
body: new pexprs.Range('\x00', ' '),
|
|
369
|
-
formals: [],
|
|
370
|
-
description: 'a space',
|
|
371
|
-
},
|
|
319
|
+
'ProtoBuiltInRules', // name
|
|
320
|
+
undefined, // supergrammar
|
|
321
|
+
{
|
|
322
|
+
any: {
|
|
323
|
+
body: pexprs.any,
|
|
324
|
+
formals: [],
|
|
325
|
+
description: 'any character',
|
|
326
|
+
primitive: true,
|
|
327
|
+
},
|
|
328
|
+
end: {
|
|
329
|
+
body: pexprs.end,
|
|
330
|
+
formals: [],
|
|
331
|
+
description: 'end of input',
|
|
332
|
+
primitive: true,
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
caseInsensitive: {
|
|
336
|
+
body: new pexprs.CaseInsensitiveTerminal(new pexprs.Param(0)),
|
|
337
|
+
formals: ['str'],
|
|
338
|
+
primitive: true,
|
|
339
|
+
},
|
|
340
|
+
lower: {
|
|
341
|
+
body: new pexprs.UnicodeChar('Ll'),
|
|
342
|
+
formals: [],
|
|
343
|
+
description: 'a lowercase letter',
|
|
344
|
+
primitive: true,
|
|
345
|
+
},
|
|
346
|
+
upper: {
|
|
347
|
+
body: new pexprs.UnicodeChar('Lu'),
|
|
348
|
+
formals: [],
|
|
349
|
+
description: 'an uppercase letter',
|
|
350
|
+
primitive: true,
|
|
372
351
|
},
|
|
352
|
+
// Union of Lt (titlecase), Lm (modifier), and Lo (other), i.e. any letter not in Ll or Lu.
|
|
353
|
+
unicodeLtmo: {
|
|
354
|
+
body: new pexprs.UnicodeChar('Ltmo'),
|
|
355
|
+
formals: [],
|
|
356
|
+
description: 'a Unicode character in Lt, Lm, or Lo',
|
|
357
|
+
primitive: true,
|
|
358
|
+
},
|
|
359
|
+
|
|
360
|
+
// These rules are not truly primitive (they could be written in userland) but are defined
|
|
361
|
+
// here for bootstrapping purposes.
|
|
362
|
+
spaces: {
|
|
363
|
+
body: new pexprs.Star(new pexprs.Apply('space')),
|
|
364
|
+
formals: [],
|
|
365
|
+
},
|
|
366
|
+
space: {
|
|
367
|
+
body: new pexprs.Range('\x00', ' '),
|
|
368
|
+
formals: [],
|
|
369
|
+
description: 'a space',
|
|
370
|
+
},
|
|
371
|
+
}
|
|
373
372
|
);
|
|
374
373
|
|
|
375
374
|
// This method is called from main.js once Ohm has loaded.
|
|
376
|
-
Grammar.initApplicationParser = function(grammar, builderFn) {
|
|
375
|
+
Grammar.initApplicationParser = function (grammar, builderFn) {
|
|
377
376
|
ohmGrammar = grammar;
|
|
378
377
|
buildGrammar = builderFn;
|
|
379
378
|
};
|
package/src/GrammarDecl.js
CHANGED
|
@@ -27,7 +27,7 @@ export class GrammarDecl {
|
|
|
27
27
|
// TODO: The conditional expression below is an ugly hack. It's kind of ok because
|
|
28
28
|
// I doubt anyone will ever try to declare a grammar called `BuiltInRules`. Still,
|
|
29
29
|
// we should try to find a better way to do this.
|
|
30
|
-
this.name === 'BuiltInRules' ? Grammar.ProtoBuiltInRules : Grammar.BuiltInRules
|
|
30
|
+
this.name === 'BuiltInRules' ? Grammar.ProtoBuiltInRules : Grammar.BuiltInRules
|
|
31
31
|
);
|
|
32
32
|
}
|
|
33
33
|
return this.superGrammar;
|
|
@@ -95,10 +95,10 @@ export class GrammarDecl {
|
|
|
95
95
|
// Creates a Grammar instance, and if it passes the sanity checks, returns it.
|
|
96
96
|
build() {
|
|
97
97
|
const grammar = new Grammar(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
98
|
+
this.name,
|
|
99
|
+
this.ensureSuperGrammar(),
|
|
100
|
+
this.rules,
|
|
101
|
+
this.defaultStartRule
|
|
102
102
|
);
|
|
103
103
|
// Initialize internal props that are inherited from the super grammar.
|
|
104
104
|
grammar._matchStateInitializer = grammar.superGrammar._matchStateInitializer;
|
|
@@ -125,12 +125,12 @@ const applyDedent = new pexprs.Apply('dedent');
|
|
|
125
125
|
const newAnyBody = new pexprs.Splice(BuiltInRules, 'any', [applyIndent, applyDedent], []);
|
|
126
126
|
|
|
127
127
|
export const IndentationSensitive = new Builder()
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
128
|
+
.newGrammar('IndentationSensitive')
|
|
129
|
+
.withSuperGrammar(BuiltInRules)
|
|
130
|
+
.define('indent', [], new Indentation(true), INDENT_DESCRIPTION, undefined, true)
|
|
131
|
+
.define('dedent', [], new Indentation(false), DEDENT_DESCRIPTION, undefined, true)
|
|
132
|
+
.extend('any', [], newAnyBody, 'any character', undefined)
|
|
133
|
+
.build();
|
|
134
134
|
|
|
135
135
|
Object.assign(IndentationSensitive, {
|
|
136
136
|
_matchStateInitializer(state) {
|
package/src/InputStream.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {Interval} from './Interval.js';
|
|
2
2
|
|
|
3
3
|
const MAX_CHAR_CODE = 0xffff;
|
|
4
|
+
export const MAX_CODE_POINT = 0x10ffff;
|
|
4
5
|
|
|
5
6
|
export class InputStream {
|
|
6
7
|
constructor(source) {
|
|
@@ -46,6 +47,8 @@ export class InputStream {
|
|
|
46
47
|
|
|
47
48
|
This is intended to be a locale-invariant comparison, which means it may not obey
|
|
48
49
|
locale-specific expectations (e.g. "i" => "İ").
|
|
50
|
+
|
|
51
|
+
See also https://unicode.org/faq/casemap_charprop.html#casemap
|
|
49
52
|
*/
|
|
50
53
|
for (idx = 0; idx < s.length; idx++) {
|
|
51
54
|
const actual = this.next();
|
package/src/Interval.js
CHANGED
|
@@ -8,11 +8,23 @@ import * as util from './util.js';
|
|
|
8
8
|
|
|
9
9
|
export class Interval {
|
|
10
10
|
constructor(sourceString, startIdx, endIdx) {
|
|
11
|
-
|
|
11
|
+
// Store the full source in a non-enumerable property, so that when
|
|
12
|
+
// grammars and other objects are printed in the REPL, it's not
|
|
13
|
+
// cluttered with multiple copies of the same long string.
|
|
14
|
+
Object.defineProperty(this, '_sourceString', {
|
|
15
|
+
value: sourceString,
|
|
16
|
+
configurable: false,
|
|
17
|
+
enumerable: false,
|
|
18
|
+
writable: false,
|
|
19
|
+
});
|
|
12
20
|
this.startIdx = startIdx;
|
|
13
21
|
this.endIdx = endIdx;
|
|
14
22
|
}
|
|
15
23
|
|
|
24
|
+
get sourceString() {
|
|
25
|
+
return this._sourceString;
|
|
26
|
+
}
|
|
27
|
+
|
|
16
28
|
get contents() {
|
|
17
29
|
if (this._contents === undefined) {
|
|
18
30
|
this._contents = this.sourceString.slice(this.startIdx, this.endIdx);
|
|
@@ -78,13 +90,13 @@ export class Interval {
|
|
|
78
90
|
throw errors.intervalSourcesDontMatch();
|
|
79
91
|
}
|
|
80
92
|
assert(
|
|
81
|
-
|
|
82
|
-
|
|
93
|
+
this.startIdx >= that.startIdx && this.endIdx <= that.endIdx,
|
|
94
|
+
'other interval does not cover this one'
|
|
83
95
|
);
|
|
84
96
|
return new Interval(
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
97
|
+
this.sourceString,
|
|
98
|
+
this.startIdx - that.startIdx,
|
|
99
|
+
this.endIdx - that.startIdx
|
|
88
100
|
);
|
|
89
101
|
}
|
|
90
102
|
|
|
@@ -103,7 +115,7 @@ export class Interval {
|
|
|
103
115
|
}
|
|
104
116
|
}
|
|
105
117
|
|
|
106
|
-
Interval.coverage = function(firstInterval, ...intervals) {
|
|
118
|
+
Interval.coverage = function (firstInterval, ...intervals) {
|
|
107
119
|
let {startIdx, endIdx} = firstInterval;
|
|
108
120
|
for (const interval of intervals) {
|
|
109
121
|
if (interval.sourceString !== firstInterval.sourceString) {
|
package/src/MatchResult.js
CHANGED
|
@@ -8,13 +8,13 @@ import {Interval} from './Interval.js';
|
|
|
8
8
|
|
|
9
9
|
export class MatchResult {
|
|
10
10
|
constructor(
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
11
|
+
matcher,
|
|
12
|
+
input,
|
|
13
|
+
startExpr,
|
|
14
|
+
cst,
|
|
15
|
+
cstOffset,
|
|
16
|
+
rightmostFailurePosition,
|
|
17
|
+
optRecordedFailures
|
|
18
18
|
) {
|
|
19
19
|
this.matcher = matcher;
|
|
20
20
|
this.input = input;
|
|
@@ -25,22 +25,20 @@ export class MatchResult {
|
|
|
25
25
|
this._rightmostFailures = optRecordedFailures;
|
|
26
26
|
|
|
27
27
|
if (this.failed()) {
|
|
28
|
-
|
|
29
|
-
common.defineLazyProperty(this, 'message', function() {
|
|
28
|
+
common.defineLazyProperty(this, 'message', function () {
|
|
30
29
|
const detail = 'Expected ' + this.getExpectedText();
|
|
31
30
|
return (
|
|
32
31
|
util.getLineAndColumnMessage(this.input, this.getRightmostFailurePosition()) + detail
|
|
33
32
|
);
|
|
34
33
|
});
|
|
35
|
-
common.defineLazyProperty(this, 'shortMessage', function() {
|
|
34
|
+
common.defineLazyProperty(this, 'shortMessage', function () {
|
|
36
35
|
const detail = 'expected ' + this.getExpectedText();
|
|
37
36
|
const errorInfo = util.getLineAndColumn(
|
|
38
|
-
|
|
39
|
-
|
|
37
|
+
this.input,
|
|
38
|
+
this.getRightmostFailurePosition()
|
|
40
39
|
);
|
|
41
40
|
return 'Line ' + errorInfo.lineNum + ', col ' + errorInfo.colNum + ': ' + detail;
|
|
42
41
|
});
|
|
43
|
-
/* eslint-enable no-invalid-this */
|
|
44
42
|
}
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -69,9 +67,9 @@ export class MatchResult {
|
|
|
69
67
|
}
|
|
70
68
|
|
|
71
69
|
toString() {
|
|
72
|
-
return this.succeeded()
|
|
73
|
-
'[match succeeded]'
|
|
74
|
-
'[match failed at position ' + this.getRightmostFailurePosition() + ']';
|
|
70
|
+
return this.succeeded()
|
|
71
|
+
? '[match succeeded]'
|
|
72
|
+
: '[match failed at position ' + this.getRightmostFailurePosition() + ']';
|
|
75
73
|
}
|
|
76
74
|
|
|
77
75
|
// Return a string summarizing the expected contents of the input stream when
|
package/src/MatchState.js
CHANGED
|
@@ -66,8 +66,8 @@ export class MatchState {
|
|
|
66
66
|
posInfo.exit();
|
|
67
67
|
|
|
68
68
|
this.rightmostFailurePosition = Math.max(
|
|
69
|
-
|
|
70
|
-
|
|
69
|
+
this.rightmostFailurePosition,
|
|
70
|
+
this._rightmostFailurePositionStack.pop()
|
|
71
71
|
);
|
|
72
72
|
|
|
73
73
|
if (optNode) {
|
|
@@ -208,9 +208,9 @@ export class MatchState {
|
|
|
208
208
|
}
|
|
209
209
|
|
|
210
210
|
_getRightmostFailureOffset() {
|
|
211
|
-
return this.rightmostFailurePosition >= 0
|
|
212
|
-
this.posToOffset(this.rightmostFailurePosition)
|
|
213
|
-
-1;
|
|
211
|
+
return this.rightmostFailurePosition >= 0
|
|
212
|
+
? this.posToOffset(this.rightmostFailurePosition)
|
|
213
|
+
: -1;
|
|
214
214
|
}
|
|
215
215
|
|
|
216
216
|
// Returns the memoized trace entry for `expr` at `pos`, if one exists, `null` otherwise.
|
|
@@ -267,8 +267,8 @@ export class MatchState {
|
|
|
267
267
|
const memoRecRightmostFailurePosition =
|
|
268
268
|
this.inputStream.pos + memoRec.rightmostFailureOffset;
|
|
269
269
|
this.rightmostFailurePosition = Math.max(
|
|
270
|
-
|
|
271
|
-
|
|
270
|
+
this.rightmostFailurePosition,
|
|
271
|
+
memoRecRightmostFailurePosition
|
|
272
272
|
);
|
|
273
273
|
if (
|
|
274
274
|
this.recordedFailures &&
|
|
@@ -279,8 +279,8 @@ export class MatchState {
|
|
|
279
279
|
}
|
|
280
280
|
|
|
281
281
|
this.inputStream.examinedLength = Math.max(
|
|
282
|
-
|
|
283
|
-
|
|
282
|
+
this.inputStream.examinedLength,
|
|
283
|
+
memoRec.examinedLength + origPos
|
|
284
284
|
);
|
|
285
285
|
|
|
286
286
|
if (memoRec.value) {
|
|
@@ -358,7 +358,7 @@ export class MatchState {
|
|
|
358
358
|
let rightmostFailures;
|
|
359
359
|
if (this.recordedFailures) {
|
|
360
360
|
rightmostFailures = Object.keys(this.recordedFailures).map(
|
|
361
|
-
|
|
361
|
+
key => this.recordedFailures[key]
|
|
362
362
|
);
|
|
363
363
|
}
|
|
364
364
|
const cst = this._bindings[0];
|
|
@@ -366,13 +366,13 @@ export class MatchState {
|
|
|
366
366
|
cst.grammar = this.grammar;
|
|
367
367
|
}
|
|
368
368
|
return new MatchResult(
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
369
|
+
this.matcher,
|
|
370
|
+
this.input,
|
|
371
|
+
this.startExpr,
|
|
372
|
+
cst,
|
|
373
|
+
this._bindingOffsets[0],
|
|
374
|
+
this.rightmostFailurePosition,
|
|
375
|
+
rightmostFailures
|
|
376
376
|
);
|
|
377
377
|
}
|
|
378
378
|
|