Skip to content

Commit

Permalink
Add parser error message provider service (#1108)
Browse files Browse the repository at this point in the history
  • Loading branch information
msujew authored Jul 7, 2023
1 parent b48ff13 commit c436598
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 12 deletions.
4 changes: 3 additions & 1 deletion packages/langium/src/default-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { DefaultIndexManager } from './workspace/index-manager';
import { DefaultWorkspaceManager } from './workspace/workspace-manager';
import { DefaultLexer } from './parser/lexer';
import { JSDocDocumentationProvider } from './documentation';
import { LangiumParserErrorMessageProvider } from './parser/langium-parser';

/**
* Context required for creating the default language-specific dependency injection module.
Expand All @@ -69,7 +70,8 @@ export function createDefaultModule(context: DefaultModuleContext): Module<Langi
CompletionParser: (services) => createCompletionParser(services),
ValueConverter: () => new DefaultValueConverter(),
TokenBuilder: () => new DefaultTokenBuilder(),
Lexer: (services) => new DefaultLexer(services)
Lexer: (services) => new DefaultLexer(services),
ParserErrorMessageProvider: () => new LangiumParserErrorMessageProvider()
},
lsp: {
CompletionProvider: (services) => new DefaultCompletionProvider(services),
Expand Down
44 changes: 33 additions & 11 deletions packages/langium/src/parser/langium-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,10 @@ export abstract class AbstractLangiumParser implements BaseParser {
constructor(services: LangiumServices) {
this.lexer = services.parser.Lexer;
const tokens = this.lexer.definition;
this.wrapper = new ChevrotainWrapper(tokens, services.parser.ParserConfig);
this.wrapper = new ChevrotainWrapper(tokens, {
...services.parser.ParserConfig,
errorMessageProvider: services.parser.ParserErrorMessageProvider
});
}

alternatives(idx: number, choices: Array<IOrAlt<any>>): void {
Expand Down Expand Up @@ -350,27 +353,22 @@ export interface IParserDefinitionError {
ruleName?: string
}

export class LangiumParserErrorMessageProvider implements IParserErrorMessageProvider {
export abstract class AbstractParserErrorMessageProvider implements IParserErrorMessageProvider {

buildMismatchTokenMessage({ expected, actual }: {
buildMismatchTokenMessage(options: {
expected: TokenType
actual: IToken
previous: IToken
ruleName: string
}): string {
const expectedMsg = expected.LABEL
? '`' + expected.LABEL + '`'
: expected.name.endsWith(':KW')
? `keyword '${expected.name.substring(0, expected.name.length - 3)}'`
: `token of type '${expected.name}'`;
return `Expecting ${expectedMsg} but found \`${actual.image}\`.`;
return defaultParserErrorProvider.buildMismatchTokenMessage(options);
}

buildNotAllInputParsedMessage({ firstRedundant }: {
buildNotAllInputParsedMessage(options: {
firstRedundant: IToken
ruleName: string
}): string {
return `Expecting end of file but found \`${firstRedundant.image}\`.`;
return defaultParserErrorProvider.buildNotAllInputParsedMessage(options);
}

buildNoViableAltMessage(options: {
Expand All @@ -395,6 +393,30 @@ export class LangiumParserErrorMessageProvider implements IParserErrorMessagePro

}

export class LangiumParserErrorMessageProvider extends AbstractParserErrorMessageProvider {

override buildMismatchTokenMessage({ expected, actual }: {
expected: TokenType
actual: IToken
previous: IToken
ruleName: string
}): string {
const expectedMsg = expected.LABEL
? '`' + expected.LABEL + '`'
: expected.name.endsWith(':KW')
? `keyword '${expected.name.substring(0, expected.name.length - 3)}'`
: `token of type '${expected.name}'`;
return `Expecting ${expectedMsg} but found \`${actual.image}\`.`;
}

override buildNotAllInputParsedMessage({ firstRedundant }: {
firstRedundant: IToken
ruleName: string
}): string {
return `Expecting end of file but found \`${firstRedundant.image}\`.`;
}
}

export interface CompletionParserResult {
tokens: IToken[]
elementStack: AbstractElement[]
Expand Down
2 changes: 2 additions & 0 deletions packages/langium/src/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ import type { InlayHintProvider } from './lsp/inlay-hint-provider';
import type { WorkspaceSymbolProvider } from './lsp/workspace-symbol-provider';
import type { NodeKindProvider } from './lsp/node-kind-provider';
import type { FuzzyMatcher } from './lsp/fuzzy-matcher';
import type { IParserErrorMessageProvider } from 'chevrotain';

/**
* The services generated by `langium-cli` for a single language. These are derived from the
Expand Down Expand Up @@ -106,6 +107,7 @@ export type LangiumDefaultServices = {
GrammarConfig: GrammarConfig
ValueConverter: ValueConverter
LangiumParser: LangiumParser
ParserErrorMessageProvider: IParserErrorMessageProvider
CompletionParser: LangiumCompletionParser
TokenBuilder: TokenBuilder
Lexer: Lexer
Expand Down

0 comments on commit c436598

Please sign in to comment.