1.4.4 • Published 4 months ago

langium-visitor v1.4.4

Weekly downloads
-
License
MPL-2.0
Repository
github
Last release
4 months ago

Langium Visitor

A CLI tool to generate visitor classes for a Langium project. The generator will generate two different abstract visitors:

  • Visitor: A visitor that can visit all the nodes of the AST.
  • ValidationVisitor: A visitor enabling Langium validation.

Installation

npm install -D langium-visitor

Usage

Generate the visitor files

langium-visitor

Or modify the package.json file of your Langium project to add a script:

"scripts": {
  "langium:visitor": "langium-visitor"
}

To correctly work, the langium-visitor command must be run after the langium:generate command. Indeed, the langium-visitor command will use the generated "src/language/generated/grammar.ts" file to generate the visitor classes. The generated files will be placed in the "src/semantics" directory.

Plug the visitor files in your Langium project

To allow your Langium project to use the visitor files, you need to import them in your project as a module. For that, you need to add the following lines in your "src/language/-module.ts" file:

import { <LanguageName>AcceptWeaver } from '../semantics/<language-id>-accept-weaver.js';
import { <LanguageName>CustomVisitor } from './your/path/language-id-visitor.ts';
import { <LanguageName>CustomValidationVisitor } from './your/path/language-id-custom-validation-visitor.ts';
import { registerVisitorAsValidator } from '../semantics/<language-id>-visitor.js';

...

export type <LanguageName>AddedServices = {
    visitors: {
      <LanguageName>AcceptWeaver: <LanguageName>AcceptWeaver
      <LanguageName>CustomVisitor: <LanguageName>CustomVisitor
      <LanguageName>CustomValidationVisitor: <LanguageName>CustomValidationVisitor
    }
}

...

export const <LanguageName>Module: Module<<LanguageName>Services, PartialLangiumServices & <LanguageName>AddedServices> = {
    visitors: {
      <LanguageName>AcceptWeaver: (services) => new <LanguageName>AcceptWeaver(services)
      <LanguageName>CustomVisitor: () => new <LanguageName>CustomVisitor()
      <LanguageName>CustomValidationVisitor: () => new <LanguageName>CustomValidationVisitor()
    }
};

...

// On the create services function, just after "shared.ServiceRegistry.register(<LanguageName>);"
HelloWorld.HelloWorldAcceptWeaver; // This is to instantiate the accept weaver
registerVisitorAsValidator(HelloWorld.visitors.HelloWorldTypeChecker, HelloWorld); // This is to register the validation visitor to the validation registry of Langium

The instantiation and registration of the validation is done by the registerVisitorAsValidator function. For basic visitors, you have to do it manually by calling <LanguageName>Module.visitors.<LanguageName>CustomVisitor where you want to use the visitor.

Create a new concrete Visitor

To create a new concrete Visitor, you just need to create a new class that implements the Visitor interface or extends the ValidationVisitor abstract class. If the main goal of this visitor is to program dynamic semantics, it is recommended to place your concrete visitor in the src/cli directory to follow Langium's convention. The ValidationVisitor provides a protected validationAccept function that can be used to accept an ASTNode, as in the default Langium validator. An example can be found in the examples directory.

CLI Arguments

ArgumentDescriptionDefault ValueOptional
--out <path>The output directory for the generated filessrc/semanticsYes
--grammar <path>The path to the grammar fileoutput path specified in the Langium config file + /grammar.tsYes
--ast <path>The path to the AST fileoutput path specified in the Langium config file + /ast.tsYes
--config <path>The path to the Langium config filelangium-config.jsonYes

How does this work?

The purpose of the accept-weaver is to dynamically add a new method accept to the Langium generated (concrete) types. The weaver is executed when each time a Langium document goes in "IndexedReferences" state, but use a cache to avoid reweaving the same AST nodes multiple times. However, this method only exists at runtime, so TypeScript will throw errors when trying to access it. To fix this, the generator also creates for each type a type with the same properties of its equivalent Langium type, but also with an accept method. The only other difference is that instead of containing/referencing other Langium's types, they contain/reference the equivalent types generated by the generator. These types are in the visitor file. So by casting a Langium type to its equivalent visitor type (duck-typing), we can statically access the accept method we woven earlier. Accept methods are not woven to abstract types. We consider any type that doesn't have properties and has subtypes to be an abstract type.

1.4.4

4 months ago

1.4.3

4 months ago

1.4.2

4 months ago

1.4.1

4 months ago

1.4.0

4 months ago

1.3.0

5 months ago

1.2.1

5 months ago

1.2.0

5 months ago

1.1.6

5 months ago

1.1.5

5 months ago

1.1.4

5 months ago

1.1.3

5 months ago

1.1.2

5 months ago

1.1.1

6 months ago

1.1.0

6 months ago

1.0.1

6 months ago

1.0.0

6 months ago