Rockstar feat. Source Code Generators

Hasan Mahmud
8 min readDec 8, 2020

--

I recently watched a really interesting video from Dylan Beattie on the NDC called The Art of Code, where he talks about code that has no practical reason to exist except because it is fun, or beautiful, to write it. If you haven’t watched it, I seriously recommend it — it’s interesting and fun!

https://shadowmountain.org/hub/h-v-a1.html
https://shadowmountain.org/hub/h-v-a2.html
https://shadowmountain.org/hub/h-v-a3.html
https://shadowmountain.org/hub/h-v-a4.html
https://shadowmountain.org/hub/h-v-t5.html
https://shadowmountain.org/hub/h-v-t6.html
https://shadowmountain.org/hub/h-v-t7.html
https://shadowmountain.org/hub/h-v-t8.html
https://www.agwest.com/voc/h-v-a1.html
https://www.agwest.com/voc/h-v-a2.html
https://www.agwest.com/voc/h-v-a3.html
https://www.agwest.com/voc/h-v-a4.html
https://www.agwest.com/voc/h-v-t5.html
https://www.agwest.com/voc/h-v-t6.html
https://www.agwest.com/voc/h-v-t7.html
https://www.agwest.com/voc/h-v-t8.html
https://www.agwest.com/voc/video-bvb-v-zenit-match-liv-de1.html
https://www.agwest.com/voc/video-bvb-v-zenit-match-liv-de2.html
https://www.agwest.com/voc/video-bvb-v-zenit-match-liv-de3.html
https://www.agwest.com/voc/video-bvb-v-zenit-match-liv-de4.html
https://www.agwest.com/voc/video-bvb-v-zenit-match-liv-de5.html
https://www.agwest.com/voc/video-lazio-v-brugge-match-liv-uk1.html
https://www.agwest.com/voc/video-lazio-v-brugge-match-liv-uk2.html
https://www.agwest.com/voc/video-lazio-v-brugge-match-liv-uk3.html
https://www.agwest.com/voc/video-lazio-v-brugge-match-liv-uk4.html
https://www.agwest.com/voc/video-lazio-v-brugge-match-liv-uk5.html
https://www.agwest.com/voc/video-lazio-v-brugge-match-liv-uk6.html
https://shadowmountain.org/hub/video-bvb-v-zenit-match-liv-de1.html
https://shadowmountain.org/hub/video-bvb-v-zenit-match-liv-de2.html
https://shadowmountain.org/hub/video-bvb-v-zenit-match-liv-de3.html
https://shadowmountain.org/hub/video-bvb-v-zenit-match-liv-de4.html
https://shadowmountain.org/hub/video-bvb-v-zenit-match-liv-de5.html
https://shadowmountain.org/hub/video-lazio-v-brugge-match-liv-uk1.html
https://shadowmountain.org/hub/video-lazio-v-brugge-match-liv-uk2.html
https://shadowmountain.org/hub/video-lazio-v-brugge-match-liv-uk3.html
https://shadowmountain.org/hub/video-lazio-v-brugge-match-liv-uk4.html
https://shadowmountain.org/hub/video-lazio-v-brugge-match-liv-uk5.html
https://shadowmountain.org/hub/video-lazio-v-brugge-match-liv-uk6.html

The Art of Code — Dylan Beattie — YouTube

Towards the end of his talk, he introduces us to his own programming language. He created it in a bar and it’s since become famous worldwide: Rockstar.

Introducing, ROCKSTAR

While watching the talk, I remembered that I’ve been wanting to get started with source-code generators since the release of NET5.0 for another side project of mine, and what better than using Rockstar as a way to get started?

Introducing, the Rockstar Source Code Generator

Source-code generators are a new C# compiler feature recently introduced by Microsoft that lets developers inspect user code as part of the code compilation, and generate new C# source files that are added to the compilation. This is done via a new kind of code component that is called a Source Generator, that is added as an analyzer to any existing project. You use a generator in your project by either referencing a generator project or by adding it as a NuGet package. With that in mind, let’s start building our Rockstar to C# generator!

99 bottles of beer in Rockstar

I wanted the generator to allow me to embed Rockstar code in any existing C# project, and allow me to call it from normal C# code. So a natural place to “hide” such code is within comments. This way we can hide something as innocents as this comment on the left in our normal C# code-base.

As we don’t want to parse every single comment in our source-code as Rockstar code, let’s start by defining a suitable header format for identifying our code and giving a name to the class that will hold the generated code. Something appropriate as Let’s rock with (class name), to keep with the spirits.

Now to implementing the code generator. We start by importing a few NuGet packages as suggested on the official samples, and proceed to implement the ISourceGenerator interface and tag your generator with the [Generator] attribute:

The next step is to capture all comments from the input source-code syntax tree. A few google searches and I end up in a familiar blog — familiar because Dan is a colleague of mine at Curiosity. A few laughs after, and a bit of reading his post, code and playing with the Roslyn API, I’m happy to see that the API now provides an easy to use enumerator over all trivia in the parsed syntax tree, with the method DescendantTrivia() — this makes it easy to achieve what I need with a simple for loop:

We can use a simple regex to detect the right comment markers and extract both the class name and the source-code within the comment, and we are ready to go to the next step: transpiling Rockstar to C#, so we can inject it back into the compilation process using our generator.

Regex to the rescue (source: XKCD)

Time for transformation: Rockstar → Json → C#

The Rockstar website gives us a link to another related project by David Sit called sellout — that aims to implement a Rockstar to C# transpiler. The readme gives us a warning though: very much a work in process, and a quick inspection shows us that only variable initialization has been implemented so far. So either I’ll have to start from scratch, or maybe I can cheat a bit here and use something existing: the official Rockstar JavaScript interpreter Satriani.

Remembering a post from Oren Eini, in which he was introducing an interesting RavenDB feature of using Javascript code from within the C# code-base, I decide to take a look on how to run Javascript from my code generator, and luckily there is a fully functional Javascript interpreter called Jint, written in pure C#, that I can easily import in the generator project. So the plan is now:

  1. Extract the Rockstar code from the C# source-code comments
  2. Parse the Rockstar code using the Satriani auto-generated parser.
  3. Transform the syntax-tree into C# code
  4. Emit the newly generated source-code back to the Roslyn compiler

Regex came to our rescue with 1., and 2. is as simple as using the parser.js source code with Jint, and calling it on the extracted Rockstar code. We build a simple wrapper for this, and move on.

Running Javascript from C# is as easy as this, using Jint

For step 3, as the Satriani uses an interpreter after parsing, and we actually want to transpile the code to C# and not execute it immediately, we’ll have to handle the generated syntax-tree ourselves instead of using the JavaScript interpreter. Satriani’s PEG parser provides the starting point with a Json syntax tree that looks like this:

Syntax tree generated by PEG.js using Rockstar‘s official PEG parser

The final step is to convert this syntax tree to valid C# code. Starting by inspecting how the official interpreter works, it is easily to replicate the code in C# in a transpiler form: we can use a similar loop to the evaluate method, but instead of eagerly evaluating the code, we emit method calls to native C# code as required. For example, emitting the binary operation in C# is as simple as this:

The full source-code is available on GitHub for anyone to try (and will be soon also available on NuGet). With all in place, we can move on to the fun part!

It’s time for some FizzBuzz 🤘

I highly recommend watching this part of the video

Now that we have all the pieces required for the source-code generator — let’s put it together and see it in action. Using the nice new top-level programs introduced in C# 9.0, our C# FizzBuzz Rockstar program looks like this:

FizzBuzz in C# + Rockstar

And if we run it, it works just as we expected from a normal C# code:

Ready for some FizzBuzz!

We can even inspect the generated C# code, as for debugging the generator will dump all intermediate steps to your temp folder:

Auto-generated C# code from the Rockstar Fizzbuzz lyrics

All that is missing is explaining the Variable object that we had to build for compatibility with the official Rockstar specification. You can check the source-code on GitHub to understand how we “hacked” the expected behavior within C#. Next, I’ll need to add support for arrays and a few other remaining methods from the Rockstar specification — but all in all pretty good for a night of work 🤘

Also available as a Nuget Package — because why not :)

So that’s it — source-code generators is a quite neat feature from C# 9.0, and one that I’ve been wanting to get my hands dirty for a while — Rockstar provided the perfect excuse to take a few hours off and give it a try!

--

--