Rockstar feat. Source Code Generators
Be the Rockstar Developer you wish, from within your .NET source-code
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!
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!
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 ended up in a familiar blog — familiar because Dan is a colleague of mine at Curiosity. A few laughs later, and after 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.
Time for transformation: Rockstar → Json → C#
Extract the Rockstar code from the C# source-code comments
Parse the Rockstar code using the Satriani auto-generated parser.
Transform the syntax-tree into C# code
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.
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 🤘
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:
And if we run it, it works just as we expected from a normal C# code:
We can even inspect the generated C# code, as for debugging the generator will dump all intermediate steps to your temp folder:
All that’s missing now is to explain 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 night’s work 🤘
So that’s it — source-code generators are a 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!