Tutorial: Hacking the Nim compiler: Pragmas - nim-lang/Nim GitHub Wiki

Note: Old, use macros instead, but some information here is still useful

Introduction

As there are no tutorials (that I know of) on how to add new features to the nimrod compiler I have decided to make one, based on me implementing the requires pragma which will be used for Babel Packages.

As with many tasks there are many tools that are very helpful, I have used the nimgrep tool which is in the tools/ directory in Nimrod's repository, but I'm sure you know of other tools which can be very helpful!

First steps

The first thing I have decided to do was create a test file, it follows:

{.requires packageA "0.7" "0.9".}
echo("hi")

(It originally had a .. between the two string literals, I decided to get rid of that because I noticed that pragmas don't support it, I might come back to it.)

I then saved that file as "pragmaTest.nim" and compiled it with nimrod c pragmaTest.nim. This has caused pragmaTest.nim(1, 10) Error: invalid pragma: requires.

The next step was quite obvious, searching for "invalid pragma:", nimgrep --recursive --ext:nim "invalid\ pragma:", this only gives one result.

../Nimrod/rod/msgs.nim
  258:     errInvalidPragmaX: "invalid pragma: $1",

After some more intellectual grepping and looking through files, I noticed that the pragma() function in pragmas.nim takes an argument called validPragmas this lead me to semtypes.nim and semstmts.nim after searching for (yes, you've guessed it) pragma((please note this needs escaping when used as a regex).

There was many pragma calls, I have looked at most of them and since I wanted a "global"(not sure if that's the correct term) pragma, for example {.warning: "warning".}. The pragma function is called with many different valid pragma groups. There is among many others, stmtPragmas, which is what I wanted, it's defined in pragmas.nim.

Hacking the code!

I found where TSpecialWords is defined(wordrecg.nim) and added wRequires there, to the specialWords array below, and also to stmtPragmas. I then added wRequires to the case statement in the pragma function in pragmas.nim.

This is where the debug function came into play, it is a function that pretty prints a node in the AST, it is very useful. I added two debug calls one for the 'it' node and another one for the 'n' node.

I then bootstrapped by executing ./koch boot. After I got the beautiful "SUCCESS", I compiled pragmaTest.nim. And I got this output:

{
  "kind": "nkIdent",
  "ident": "requires"
}
{
  "kind": "nkPragma",
  "sons": [
    {
      "kind": "nkIdent",
      "ident": "requires"
    },
    {
      "kind": "nkIdent",
      "ident": "packageA"
    },
    {
      "kind": "nkStrLit",
      "strVal": "0.7"
    },
    {
      "kind": "nkStrLit",
      "strVal": "0.9"
    }
  ]
}