Skip to content

Commit d2d4ace

Browse files
authored
Fix 'oneof' in syntax-directed operations (#637)
1 parent 95954d3 commit d2d4ace

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

src/lint/utils.ts

+11
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,10 @@ export function rhsMatches(a: RightHandSide | OneOfList, b: RightHandSide | OneO
7373
}
7474
return symbolSpanMatches(aHead, bHead);
7575
}
76+
case SyntaxKind.OneOfList:
77+
return oneOfListMatches(a, b as OneOfList);
7678
default:
79+
// @ts-expect-error: Callers might pass other kinds of nodes.
7780
throw new Error('unknown rhs type ' + a.constructor.name);
7881
}
7982
}
@@ -171,6 +174,14 @@ function argumentListMatches(a: ArgumentList, b: ArgumentList) {
171174
);
172175
}
173176

177+
function oneOfListMatches(a: OneOfList, b: OneOfList) {
178+
if (a.terminals === undefined || b.terminals === undefined) {
179+
throw new Error('OneOfList must have terminals');
180+
}
181+
// The terminals in a must be a subset of the terminals in b.
182+
return a.terminals.every(ae => b.terminals!.find(be => ae.text === be.text));
183+
}
184+
174185
// this is only for use with single-file grammars
175186
export function getLocationInGrammarFile(file: SourceFile, pos: number) {
176187
const posWithoutWhitespace = skipTrivia(file.text, pos, file.text.length);

test/errors.js

+69
Original file line numberDiff line numberDiff line change
@@ -1106,6 +1106,31 @@ ${M} </pre>
11061106
);
11071107
});
11081108

1109+
it('unknown oneof', async () => {
1110+
await assertError(
1111+
positioned`
1112+
<emu-grammar type="definition">
1113+
Foo :: one of \`a\` \`b\` \`c\`
1114+
</emu-grammar>
1115+
1116+
<emu-clause id="sec-example" type="sdo">
1117+
<h1>Static Semantics: Example</h1>
1118+
<dl class='header'></dl>
1119+
<emu-grammar>
1120+
Foo :: ${M}one of \`d\` \`e\`
1121+
</emu-grammar>
1122+
<emu-alg>
1123+
1. Return *true*.
1124+
</emu-alg>
1125+
</emu-clause>`,
1126+
{
1127+
ruleId: 'grammar-shape',
1128+
nodeType: 'emu-grammar',
1129+
message: 'could not find definition for rhs "d e"',
1130+
},
1131+
);
1132+
});
1133+
11091134
it('negative', async () => {
11101135
await assertErrorFree(`
11111136
<emu-grammar type="definition">
@@ -1167,5 +1192,49 @@ ${M} </pre>
11671192
},
11681193
);
11691194
});
1195+
1196+
it('negative: oneof', async () => {
1197+
await assertErrorFree(`
1198+
<emu-grammar type="definition">
1199+
Foo :: one of \`a\` \`b\` \`c\`
1200+
</emu-grammar>
1201+
1202+
<emu-clause id="sec-example" type="sdo">
1203+
<h1>Static Semantics: Example</h1>
1204+
<dl class='header'></dl>
1205+
<emu-grammar>
1206+
Foo :: one of \`a\` \`b\` \`c\`
1207+
</emu-grammar>
1208+
<emu-alg>
1209+
1. Return *true*.
1210+
</emu-alg>
1211+
</emu-clause>
1212+
`);
1213+
});
1214+
1215+
it('negative: oneof (subset)', async () => {
1216+
await assertErrorFree(`
1217+
<emu-grammar type="definition">
1218+
Foo :: one of \`a\` \`b\` \`c\` \`d\`
1219+
</emu-grammar>
1220+
1221+
<emu-clause id="sec-example" type="sdo">
1222+
<h1>Static Semantics: Example</h1>
1223+
<dl class='header'></dl>
1224+
<emu-grammar>
1225+
Foo :: one of \`a\` \`b\`
1226+
</emu-grammar>
1227+
<emu-alg>
1228+
1. Return *true*.
1229+
</emu-alg>
1230+
<emu-grammar>
1231+
Foo :: one of \`c\` \`d\`
1232+
</emu-grammar>
1233+
<emu-alg>
1234+
1. Return *false*.
1235+
</emu-alg>
1236+
</emu-clause>
1237+
`);
1238+
});
11701239
});
11711240
});

0 commit comments

Comments
 (0)