UNPKG

langium-cli

Version:

CLI for Langium - the language engineering tool

85 lines (80 loc) 3.62 kB
/****************************************************************************** * Copyright 2021 TypeFox GmbH * This program and the accompanying materials are made available under the * terms of the MIT License, which is available in the project root. ******************************************************************************/ import type { Grammar, IParserConfig, LangiumDocuments, LangiumParser, LanguageMetaData } from 'langium'; import type { LangiumConfig, LangiumLanguageConfig } from './package-types.js'; import { AstUtils, GrammarAST, prepareLangiumParser } from 'langium'; import type { LangiumGrammarServices} from 'langium/grammar'; import { createServicesForGrammar } from 'langium/grammar'; import { getFilePath } from './package.js'; export async function validateParser(grammar: Grammar, config: LangiumConfig, grammarConfigMap: Map<Grammar, LangiumLanguageConfig>, grammarServices: LangiumGrammarServices): Promise<Error | undefined> { const parserConfig: IParserConfig = { ...config.chevrotainParserConfig, ...grammarConfigMap.get(grammar)?.chevrotainParserConfig, skipValidations: false }; const services = await createServicesForGrammar({ grammarServices, grammar, languageMetaData: languageConfigToMetaData(grammarConfigMap.get(grammar)!), parserConfig }); let parser: LangiumParser | undefined; try { parser = prepareLangiumParser(services); // The finalization step invokes parser validation, which can lead to thrown errors parser.finalize(); return undefined; } catch (err) { if (parser && parser.definitionErrors.length > 0) { // Construct a message with tracing information let message = 'Parser definition errors detected:'; for (const defError of parser.definitionErrors) { message += '\n-------------------------------\n'; if (defError.ruleName) { const rule = findRule(defError.ruleName, grammar, grammarServices.shared.workspace.LangiumDocuments); if (rule && rule.$cstNode) { const filePath = getFilePath(AstUtils.getDocument(rule).uri.fsPath, config); const line = rule.$cstNode.range.start.line + 1; message += `${filePath}:${line} - `; } } message += defError.message; } return new Error(message); } if (err instanceof Error) { return err; } throw err; } } function languageConfigToMetaData(config: LangiumLanguageConfig): LanguageMetaData { return { languageId: config.id, fileExtensions: config.fileExtensions ?? [], caseInsensitive: Boolean(config.caseInsensitive), mode: 'development' }; } function findRule(name: string, grammar: Grammar, documents: LangiumDocuments): GrammarAST.ParserRule | undefined { for (const rule of grammar.rules) { if (rule.name === name && GrammarAST.isParserRule(rule)) { return rule; } } for (const document of documents.all) { const ast = document.parseResult.value; if (GrammarAST.isGrammar(ast)) { for (const rule of ast.rules) { if (rule.name === name && GrammarAST.isParserRule(rule)) { return rule; } } } } return undefined; }