Skip to content

Commit

Permalink
Perform parser optimizations in production mode (#1688)
Browse files Browse the repository at this point in the history
  • Loading branch information
msujew authored Sep 30, 2024
1 parent 8faa4b8 commit d71b47b
Show file tree
Hide file tree
Showing 12 changed files with 40 additions and 12 deletions.
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

0 comments on commit d71b47b

Please sign in to comment.