Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Perform parser optimizations in production mode #1688

Merged
merged 3 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion examples/arithmetics/src/language-server/generated/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { ArithmeticsGrammar } from './grammar.js';
export const ArithmeticsLanguageMetaData = {
languageId: 'arithmetics',
fileExtensions: ['.calc'],
caseInsensitive: true
caseInsensitive: true,
mode: 'development'
} as const satisfies LanguageMetaData;

export const ArithmeticsGeneratedSharedModule: Module<LangiumSharedCoreServices, LangiumGeneratedSharedCoreServices> = {
Expand Down
3 changes: 2 additions & 1 deletion examples/domainmodel/src/language-server/generated/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { DomainModelGrammar } from './grammar.js';
export const DomainModelLanguageMetaData = {
languageId: 'domain-model',
fileExtensions: ['.dmodel'],
caseInsensitive: false
caseInsensitive: false,
mode: 'development'
} as const satisfies LanguageMetaData;

export const parserConfig: IParserConfig = {
Expand Down
6 changes: 4 additions & 2 deletions examples/requirements/src/language-server/generated/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import { RequirementsGrammar, TestsGrammar } from './grammar.js';
export const RequirementsLanguageMetaData = {
languageId: 'requirements-lang',
fileExtensions: ['.req'],
caseInsensitive: false
caseInsensitive: false,
mode: 'development'
} as const satisfies LanguageMetaData;

export const TestsLanguageMetaData = {
languageId: 'tests-lang',
fileExtensions: ['.tst'],
caseInsensitive: false
caseInsensitive: false,
mode: 'development'
} as const satisfies LanguageMetaData;

export const RequirementsAndTestsGeneratedSharedModule: Module<LangiumSharedCoreServices, LangiumGeneratedSharedCoreServices> = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import { StatemachineGrammar } from './grammar.js';
export const StatemachineLanguageMetaData = {
languageId: 'statemachine',
fileExtensions: ['.statemachine'],
caseInsensitive: false
caseInsensitive: false,
mode: 'development'
} as const satisfies LanguageMetaData;

export const StatemachineGeneratedSharedModule: Module<LangiumSharedCoreServices, LangiumGeneratedSharedCoreServices> = {
Expand Down
1 change: 1 addition & 0 deletions packages/generator-langium/templates/core/.package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"watch": "tsc -b <%= tsconfig %> --watch",
"lint": "eslint src --ext ts",
"langium:generate": "langium generate",
"langium:generate:production": "langium generate --mode=production",
"langium:watch": "langium generate --watch"
},
"dependencies": {
Expand Down
5 changes: 4 additions & 1 deletion packages/langium-cli/src/generator/module-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { generatedHeader } from './node-util.js';
export function generateModule(grammars: Grammar[], config: LangiumConfig, grammarConfigMap: Map<Grammar, LangiumLanguageConfig>): string {
const grammarsWithName = grammars.filter(grammar => !!grammar.name);
const parserConfig = config.chevrotainParserConfig;
const mode = config.mode;
const hasIParserConfigImport = Boolean(parserConfig) || grammars.some(grammar => grammarConfigMap.get(grammar)?.chevrotainParserConfig !== undefined);
let needsGeneralParserConfig = undefined;

Expand Down Expand Up @@ -41,12 +42,14 @@ export function generateModule(grammars: Grammar[], config: LangiumConfig, gramm
grammarsWithName,
grammar => {
const config = grammarConfigMap.get(grammar)!;
const modeValue = mode === 'production' ? mode : 'development';
return expandToNode`

export const ${ grammar.name }LanguageMetaData = {
languageId: '${config.id}',
fileExtensions: [${config.fileExtensions && joinToNode(config.fileExtensions, e => appendQuotesAndDot(e), { separator: ', ' })}],
caseInsensitive: ${Boolean(config.caseInsensitive)}
caseInsensitive: ${Boolean(config.caseInsensitive)},
mode: '${modeValue}'
} as const satisfies LanguageMetaData;
`;
},
Expand Down
3 changes: 2 additions & 1 deletion packages/langium-cli/src/parser-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ function languageConfigToMetaData(config: LangiumLanguageConfig): LanguageMetaDa
return {
languageId: config.id,
fileExtensions: config.fileExtensions ?? [],
caseInsensitive: Boolean(config.caseInsensitive)
caseInsensitive: Boolean(config.caseInsensitive),
mode: 'development'
};
}

Expand Down
3 changes: 2 additions & 1 deletion packages/langium/src/grammar/generated/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import { LangiumGrammarGrammar } from './grammar.js';
export const LangiumGrammarLanguageMetaData = {
languageId: 'langium',
fileExtensions: ['.langium'],
caseInsensitive: false
caseInsensitive: false,
mode: 'development'
} as const satisfies LanguageMetaData;

export const LangiumGrammarParserConfig: IParserConfig = {
Expand Down
3 changes: 2 additions & 1 deletion packages/langium/src/grammar/internal-grammar-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,8 @@ export async function createServicesForGrammar<L extends LangiumServices = Langi
const languageMetaData = config.languageMetaData ?? {
caseInsensitive: false,
fileExtensions: [`.${grammarNode.name?.toLowerCase() ?? 'unknown'}`],
languageId: grammarNode.name ?? 'UNKNOWN'
languageId: grammarNode.name ?? 'UNKNOWN',
mode: 'development'
};
const generatedSharedModule: Module<LangiumGeneratedSharedCoreServices> = {
AstReflection: () => interpretAstReflection(grammarNode),
Expand Down
9 changes: 9 additions & 0 deletions packages/langium/src/languages/language-meta-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,17 @@
* terms of the MIT License, which is available in the project root.
******************************************************************************/

/**
* Metadata of a language.
*/
export interface LanguageMetaData {
languageId: string;
fileExtensions: readonly string[];
caseInsensitive: boolean;
/**
* Mode used to optimize code for development or production environments.
*
* In production mode, all Chevrotain lexer/parser validations are disabled.
*/
mode: 'development' | 'production';
}
9 changes: 7 additions & 2 deletions packages/langium/src/parser/langium-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,10 @@ export abstract class AbstractLangiumParser implements BaseParser {
constructor(services: LangiumCoreServices) {
this.lexer = services.parser.Lexer;
const tokens = this.lexer.definition;
const production = services.LanguageMetaData.mode === 'production';
this.wrapper = new ChevrotainWrapper(tokens, {
...services.parser.ParserConfig,
skipValidations: production,
errorMessageProvider: services.parser.ParserErrorMessageProvider
});
}
Expand Down Expand Up @@ -631,13 +633,16 @@ class ChevrotainWrapper extends EmbeddedActionsParser {
// This array is set in the base implementation of Chevrotain.
definitionErrors: IParserDefinitionError[];

constructor(tokens: TokenVocabulary, config?: IParserConfig) {
constructor(tokens: TokenVocabulary, config: IParserConfig) {
const useDefaultLookahead = config && 'maxLookahead' in config;
super(tokens, {
...defaultConfig,
lookaheadStrategy: useDefaultLookahead
? new LLkLookaheadStrategy({ maxLookahead: config.maxLookahead })
: new LLStarLookaheadStrategy(),
: new LLStarLookaheadStrategy({
// If validations are skipped, don't log the lookahead warnings
logging: config.skipValidations ? () => { } : undefined
}),
...config,
});
}
Expand Down
4 changes: 3 additions & 1 deletion packages/langium/src/parser/lexer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ export class DefaultLexer implements Lexer {
});
this.tokenTypes = this.toTokenTypeDictionary(tokens);
const lexerTokens = isTokenTypeDictionary(tokens) ? Object.values(tokens) : tokens;
const production = services.LanguageMetaData.mode === 'production';
this.chevrotainLexer = new ChevrotainLexer(lexerTokens, {
positionTracking: 'full'
positionTracking: 'full',
skipValidations: production
});
}

Expand Down
Loading