Skip to content

Commit 0239db7

Browse files
authored
Allow hidden terminals reference in terminal lookahead (#1343)
Signed-off-by: Guillaume Fontorbe <[email protected]>
1 parent 067f9b6 commit 0239db7

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

packages/langium/src/grammar/validation/validator.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,6 +481,16 @@ export class LangiumGrammarValidator {
481481
if ('hidden' in parentRule && parentRule.hidden) {
482482
return;
483483
}
484+
485+
if (ruleCall.lookahead) {
486+
return;
487+
}
488+
489+
const terminalGroup = findLookAheadGroup(ruleCall);
490+
if (terminalGroup && terminalGroup.lookahead) {
491+
return;
492+
}
493+
484494
const ref = ruleCall.rule.ref;
485495
if (ast.isTerminalRule(ref) && ref.hidden) {
486496
accept('error', 'Cannot use hidden terminal in non-hidden rule', { node: ruleCall, property: 'rule' });
@@ -574,7 +584,7 @@ export class LangiumGrammarValidator {
574584
}
575585
}
576586

577-
// Collect imported terminals/keywords and their respectives imports
587+
// Collect imported terminals/keywords and their respective imports
578588
const importedTerminals = new MultiMap<string, ast.GrammarImport>();
579589
const importedKeywords = new MultiMap<string, ast.GrammarImport>();
580590

@@ -992,3 +1002,14 @@ function checkTypeUnionContainsOnlyParseRules(type: ast.UnionType): string[] {
9921002
return Array.from(new Set(errors));
9931003
}
9941004

1005+
function findLookAheadGroup(rule: AstNode | undefined): ast.TerminalGroup | undefined {
1006+
const terminalGroup = getContainerOfType(rule, ast.isTerminalGroup);
1007+
if (!terminalGroup) {
1008+
return undefined;
1009+
}
1010+
if (terminalGroup.lookahead) {
1011+
return terminalGroup;
1012+
} else {
1013+
return findLookAheadGroup(terminalGroup.$container);
1014+
}
1015+
}

packages/langium/test/grammar/grammar-validator.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -822,4 +822,22 @@ describe('Cross-reference to type union is only valid if all alternatives are AS
822822
property: 'rule'
823823
});
824824
});
825+
826+
test('Hidden terminals can be used in terminal lookahead', async () => {
827+
const validationResult = await validate(`
828+
hidden terminal WS: /\\s+/;
829+
terminal ID: /[_a-zA-Z][\\w_]*/;
830+
terminal TEST: ID (?=WS);`);
831+
832+
expectNoIssues(validationResult);
833+
});
834+
835+
test('Hidden terminals can be used in terminal lookahead regardless of terminal grouping', async () => {
836+
const validationResult = await validate(`
837+
hidden terminal WS: /\\s+/;
838+
terminal ID: /[_a-zA-Z][\\w_]*/;
839+
terminal TEST: ID (?=WS (WS (WS | WS)));`);
840+
841+
expectNoIssues(validationResult);
842+
});
825843
});

0 commit comments

Comments
 (0)