Skip to content

Commit 8c45e82

Browse files
authored
compiler: add v18 mode for arity checks (#592)
1 parent 3c34a59 commit 8c45e82

4 files changed

Lines changed: 37 additions & 29 deletions

File tree

packages/compiler/src/buildGrammar.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,7 @@ export function buildGrammars(
130130
visit(s.children[0]!);
131131
}
132132
rules.children.map((c: CstNode) => visit(c));
133-
const g = decl.build();
133+
const g = decl.build({v18: true});
134134
g.source = interval(node).trimmed();
135135
if (namespaceHas(namespace, grammarName)) {
136136
throw errors.duplicateGrammarDeclaration(g, namespace);

packages/ohm-js/src/GrammarDecl.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ export class GrammarDecl {
9393
}
9494

9595
// Creates a Grammar instance, and if it passes the sanity checks, returns it.
96-
build() {
96+
build({v18 = false} = {}) {
9797
const grammar = new Grammar(
9898
this.name,
9999
this.ensureSuperGrammar(),
@@ -114,7 +114,7 @@ export class GrammarDecl {
114114
Object.keys(grammar.rules).forEach(ruleName => {
115115
const {body} = grammar.rules[ruleName];
116116
try {
117-
body.assertChoicesHaveUniformArity(ruleName);
117+
body.assertChoicesHaveUniformArity(ruleName, v18);
118118
} catch (e) {
119119
grammarErrors.push(e);
120120
}

packages/ohm-js/src/pexprs-assertChoicesHaveUniformArity.js

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import * as pexprs from './pexprs-main.js';
66
// Operations
77
// --------------------------------------------------------------------
88

9+
// v18 (boolean, default false) is passed through to getArity().
10+
911
pexprs.PExpr.prototype.assertChoicesHaveUniformArity = abstract(
1012
'assertChoicesHaveUniformArity'
1113
);
@@ -17,54 +19,54 @@ pexprs.any.assertChoicesHaveUniformArity =
1719
pexprs.Param.prototype.assertChoicesHaveUniformArity =
1820
pexprs.Lex.prototype.assertChoicesHaveUniformArity =
1921
pexprs.UnicodeChar.prototype.assertChoicesHaveUniformArity =
20-
function (ruleName) {
22+
function (ruleName, v18 = false) {
2123
// no-op
2224
};
2325

24-
pexprs.Alt.prototype.assertChoicesHaveUniformArity = function (ruleName) {
26+
pexprs.Alt.prototype.assertChoicesHaveUniformArity = function (ruleName, v18 = false) {
2527
if (this.terms.length === 0) {
2628
return;
2729
}
28-
const arity = this.terms[0].getArity();
30+
const arity = this.terms[0].getArity(v18);
2931
for (let idx = 0; idx < this.terms.length; idx++) {
3032
const term = this.terms[idx];
31-
term.assertChoicesHaveUniformArity();
32-
const otherArity = term.getArity();
33+
term.assertChoicesHaveUniformArity(ruleName, v18);
34+
const otherArity = term.getArity(v18);
3335
if (arity !== otherArity) {
3436
throw errors.inconsistentArity(ruleName, arity, otherArity, term);
3537
}
3638
}
3739
};
3840

39-
pexprs.Extend.prototype.assertChoicesHaveUniformArity = function (ruleName) {
41+
pexprs.Extend.prototype.assertChoicesHaveUniformArity = function (ruleName, v18 = false) {
4042
// Extend is a special case of Alt that's guaranteed to have exactly two
4143
// cases: [extensions, origBody].
42-
const actualArity = this.terms[0].getArity();
43-
const expectedArity = this.terms[1].getArity();
44+
const actualArity = this.terms[0].getArity(v18);
45+
const expectedArity = this.terms[1].getArity(v18);
4446
if (actualArity !== expectedArity) {
4547
throw errors.inconsistentArity(ruleName, expectedArity, actualArity, this.terms[0]);
4648
}
4749
};
4850

49-
pexprs.Seq.prototype.assertChoicesHaveUniformArity = function (ruleName) {
51+
pexprs.Seq.prototype.assertChoicesHaveUniformArity = function (ruleName, v18 = false) {
5052
for (let idx = 0; idx < this.factors.length; idx++) {
51-
this.factors[idx].assertChoicesHaveUniformArity(ruleName);
53+
this.factors[idx].assertChoicesHaveUniformArity(ruleName, v18);
5254
}
5355
};
5456

55-
pexprs.Iter.prototype.assertChoicesHaveUniformArity = function (ruleName) {
56-
this.expr.assertChoicesHaveUniformArity(ruleName);
57+
pexprs.Iter.prototype.assertChoicesHaveUniformArity = function (ruleName, v18 = false) {
58+
this.expr.assertChoicesHaveUniformArity(ruleName, v18);
5759
};
5860

59-
pexprs.Not.prototype.assertChoicesHaveUniformArity = function (ruleName) {
61+
pexprs.Not.prototype.assertChoicesHaveUniformArity = function (ruleName, v18 = false) {
6062
// no-op (not required b/c the nested expr doesn't show up in the CST)
6163
};
6264

63-
pexprs.Lookahead.prototype.assertChoicesHaveUniformArity = function (ruleName) {
64-
this.expr.assertChoicesHaveUniformArity(ruleName);
65+
pexprs.Lookahead.prototype.assertChoicesHaveUniformArity = function (ruleName, v18 = false) {
66+
this.expr.assertChoicesHaveUniformArity(ruleName, v18);
6567
};
6668

67-
pexprs.Apply.prototype.assertChoicesHaveUniformArity = function (ruleName) {
69+
pexprs.Apply.prototype.assertChoicesHaveUniformArity = function (ruleName, v18 = false) {
6870
// The arities of the parameter expressions is required to be 1 by
6971
// `assertAllApplicationsAreValid()`.
7072
};

packages/ohm-js/src/pexprs-getArity.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ import * as pexprs from './pexprs-main.js';
55
// Operations
66
// --------------------------------------------------------------------
77

8+
// In v18, iteration expressions (*, +, ?) always have arity 1.
9+
// In v17, they have the same arity as their inner expression.
10+
811
pexprs.PExpr.prototype.getArity = abstract('getArity');
912

1013
pexprs.any.getArity =
@@ -14,32 +17,35 @@ pexprs.any.getArity =
1417
pexprs.Param.prototype.getArity =
1518
pexprs.Apply.prototype.getArity =
1619
pexprs.UnicodeChar.prototype.getArity =
17-
function () {
20+
function (v18 = false) {
1821
return 1;
1922
};
2023

21-
pexprs.Alt.prototype.getArity = function () {
24+
pexprs.Alt.prototype.getArity = function (v18 = false) {
2225
// This is ok b/c all terms must have the same arity -- this property is
2326
// checked by the Grammar constructor.
24-
return this.terms.length === 0 ? 0 : this.terms[0].getArity();
27+
return this.terms.length === 0 ? 0 : this.terms[0].getArity(v18);
2528
};
2629

27-
pexprs.Seq.prototype.getArity = function () {
30+
pexprs.Seq.prototype.getArity = function (v18 = false) {
2831
let arity = 0;
2932
for (let idx = 0; idx < this.factors.length; idx++) {
30-
arity += this.factors[idx].getArity();
33+
arity += this.factors[idx].getArity(v18);
3134
}
3235
return arity;
3336
};
3437

35-
pexprs.Iter.prototype.getArity = function () {
36-
return this.expr.getArity();
38+
pexprs.Iter.prototype.getArity = function (v18 = false) {
39+
if (v18) {
40+
return 1;
41+
}
42+
return this.expr.getArity(v18);
3743
};
3844

39-
pexprs.Not.prototype.getArity = function () {
45+
pexprs.Not.prototype.getArity = function (v18 = false) {
4046
return 0;
4147
};
4248

43-
pexprs.Lookahead.prototype.getArity = pexprs.Lex.prototype.getArity = function () {
44-
return this.expr.getArity();
49+
pexprs.Lookahead.prototype.getArity = pexprs.Lex.prototype.getArity = function (v18 = false) {
50+
return this.expr.getArity(v18);
4551
};

0 commit comments

Comments
 (0)