Custom language plugin development for IntelliJ IDEA — Part 04

Shan Mahanama
4 min readNov 11, 2018

--

From the last article of this series, I explained some fundamental concepts you have to know when developing plugins. From this article, I’m planning to explain the Lexer and Parser generation. So without further ado, let's start.

Prerequisites

Please clone the following repo if you don't have it already. You need to checkout the v0.2.0 tag if you intend to follow this tutorial step by step.

https://github.com/Shan1024/Simple-Intellij-Plugin

Token type and element type classes

Token Type class

Create a new class called SimpleTokenType.java in org.shan.psi package and copy the following content to it. This class will represent leaf nodes of PSI tree as I mentioned in the previous article.

Element Type class

Create another class called SimpleElementType.java in org.shan.psi package and copy the following content to it. This class will represent internal nodes of PSI tree as I mentioned in the previous article.

So now the project structure should look like this -

Project Structure

Generating the parser

Ballerina.bnf

We have already created a Ballerina.bnf file in one of the previous articles. Now we need to modify the Ballerina.bnf file to add more attributes to it which will be used to generate the Parser.

So now comes one of the most awaited moments, which is generating the parser :)

This is really a very simple process. You just have to right click on the Ballerina.bnf file and select Generate Parser Code menu item like shown below.

Generating parser code

This will generate the parser and all related PSI interfaces and classes in gen directory.

Location of the generated parser and other related classes

Now we need to mark gen directory as a generated source root (otherwise code completion, etc will not work when we use these classes later). To do this, right click on gen directory and select Mark Directory as -> Generated Source Root.

If you look at the generated directory and classes, you can see how the attributes which we have added to the Ballerina.bnf have been used.

Deciphering parser attributes :)

Generating the Lexer

So now it’s time to generate the Lexer. To do this, we use a flex.

Ballerina.flex

Create a new file called Ballerina.flex in the grammar package and copy the following content to it. I’ve added some comments so it is easier to understand what is going on.

Now comes another most awaited moment — Lexer generation :)

Generating the lexer is also very straightforward process like generating the parser.

Right click on the Ballerina.flex file and select Generate JFlex Generator. Before trying this, read the next few instructions as well.

Generating the Lexer

Note — When you run the generator for the first time, you will be prompted to select the download location for a library and a skeleton file needed for this operation. Create a flex directory in the resources directory and select it when prompted. This is not a mandatory step, but it will be easier if you save these files inside the project.

Selecting download location
Downloaded files

The lexer will be generated in the gen directory as well similar to the parser. The package where the lexer is generated is the package which we have defined at the top of the Ballerina.flex file.

Generated Lexer

We have successfully generated the lexer and the parser. So now what?

Now we need to let the IntelliJ platform know that we have a lexer and parser which we would like to use when generating the PSI tree for the files with the extension `s`.

You must be wondering how to do that by now. The answer is the plugin.xml file which provides various extension points which we can use when implementing plugins.

But unfortunately, this article is becoming a bit lengthier than I expected. So I’ll discuss this process in the next article.

Please find the source code which correspond to this article at https://github.com/Shan1024/Simple-Intellij-Plugin/releases/tag/v0.3.0.

Hope you enjoyed this article. See you soon… :)

--

--