Module typir-langium

Typir-Langium: Typir integration for Langium

Typir-Langium is a framework for type checking of languages developed with Langium, the language workbench for developing textual domain-specific languages (DSLs) in the web.

Typir-Langium depends on Typir, the stand-alone library for type systems and type checking for software languages in the web, independent from any language workbench. Typir-Langium is a dedicated binding of Typir for languages and DSLs which are developed with Langium.

npm install typir-langium

Typir-Langium provides all features of Typir and adds some specifics for Langium projects:

  • Integration of Typir into the lifecycle of Langium, including:
    • For validations, you don't need to traverse the AST on your own, since Typir-Langium hooks into Langium's traversal during the validation phase.
    • Types which depend on AstNodes (e.g. user-defined functions or classes) are created and deleted according to Langium's build process.
  • Customizations of implementations for some Typir services, e.g. caches use Langium's DocumentCache
  • Additional APIs to register inference rules and validation rules in the usual Langium style (see below)

For an overview about the core features of Typir with a simple application example, see the root README.md of the Typir project.

Important design decision for Typir-Langium: Typir-Langium does not depend on langium/lsp, i.e. Typir-Langium can be used even for Langium-based DSLs which don't use LSP.

Integrate Typir as additional Langium service into your DSL (<MyDSLSpecifics> is explained later):

export type MyDSLAddedServices = {
// ...
typir: TypirLangiumServices<MyDSLSpecifics>,
// ...
}

In case of a multi-language project, this approach enables you to manage multiple type systems in parallel by having typir1: TypirLangiumServices, typir2: TypirLangiumServices and so on.

The Typir services are created in your module in this way:

{
// ...
typir: () => createTypirLangiumServices(shared, reflection, new MyDSLTypeSystem(), { /* customize Typir services here */ }),
// ...
}

After creating the Langium services (which contain the Typir serivces now) and storing them in a variable like langiumServices, the Typir services need to be initialized with initializeLangiumTypirServices(langiumServices, langiumServices.typir).

The actual type system for your Langium-based language is defined as an implementation of the interface LangiumTypeSystemDefinition:

export class MyDSLTypeSystem implements LangiumTypeSystemDefinition<MyDSLSpecifics> {
onInitialize(typir: TypirLangiumServices<MyDSLSpecifics>): void {
// define constant types and rules for conversion, inference and validation here
}

onNewAstNode(languageNode: AstNode, typir: TypirLangiumServices<MyDSLSpecifics>): void {
// define types and their rules which depend on the current AST respectively the given AstNode (as parsed by Langium from programs written by users of your language) here
}
}

<MyDSLSpecifics> is used to inform Typir-Langium about the generated DSL-specific TypeScript-types, which describe the current, DSL-specific AST:

export interface MyDSLSpecifics extends TypirLangiumSpecifics {
AstTypes: MyDSLAstType; // all AST types from the generated `ast.ts`
// ... more could be customized here ...
}

Beyond the APIs inherited from Typir core, Typir-Langium provides some additional APIs to ease type checking with Typir in Langium projects.

This includes an API to register validation rules for AstNode.$types, which is similar to the API of Langium for registering validation checks. Here is an excerpt from the LOX example:

typir.validation.Collector.addValidationRulesForAstNodes({
IfStatement: (node /* is of type IfStatement */, accept) => typir.validation.Constraints.ensureNodeIsAssignable(node.condition, typeBool, accept,
() => ({ message: "Conditions need to be evaluated to 'boolean'.", languageProperty: 'condition' })),
VariableDeclaration: ... ,
// ...
});

All properties of DiagnosticInfo from Langium are supported in Typir-Langium when creating validation issues. For example, this includes data to register code actions for validation issues which are created by Typir-Langium (see an example in LOX with test cases in lox-type-checking-operators.test.ts). Note that the properties node, property, and index are named languageNode, languageProperty, and languageIndex in Typir and these names are used in Typir-Langium as well.

In similar way, it is possible to register inference rules for AstNode.$types, as demonstrated in the LOX example:

typir.Inference.addInferenceRulesForAstNodes({
// ...
VariableDeclaration: (languageNode /* is of type VariableDeclaration */) => {
if (languageNode.type) {
return languageNode.type; // the user declared this variable with a type
} else if (languageNode.value) {
return languageNode.value; // the user didn't declare a type for this variable => do type inference of the assigned value instead!
} else {
return InferenceRuleNotApplicable; // this case is impossible, there is a validation in the Langium LOX validator for this case
}
},
Parameter: (languageNode /* is of type Parameter */) => languageNode.type,
// ...
});

Look at the examples in the examples/ folder of the repo (here). There we have some demo projects for you to get started.

MIT License

Classes

DefaultLangiumTypeCreator
DefaultLangiumTypeInferenceCollector
DefaultLangiumTypirValidator
DefaultLangiumValidationCollector
LangiumLanguageNodeInferenceCaching
LangiumLanguageService
LangiumProblemPrinter

Interfaces

LangiumTypeCreator
LangiumTypeInferenceCollector
LangiumTypeSystemDefinition
LangiumTypirValidator
LangiumValidationCollector
TypirLangiumSpecifics

Type Aliases

LangiumAstTypes
LangiumTypeInferenceRules
LangiumValidationRules
PartialTypirLangiumServices
TypirLangiumAddedServices
TypirLangiumServices

Functions

createDefaultTypirLangiumServicesModule
createLangiumSpecificTypirServicesModule
createTypirLangiumServices
createTypirLangiumServicesWithAdditionalServices
deleteAllDocuments
getDocumentKey
getDocumentKeyForDocument
getDocumentKeyForURI
initializeLangiumTypirServices
registerTypirValidationChecks