ewfmt
·I got to work on some embedded GUI projects. There are many tools to develop on various platforms; one of them is Embedded Wizard.
It has a custom language - Chora - that allows to write embedded code that interacts with the EW UI toolkit. Under the hood, Chora compiles to C.
While the language in itself is really powerful, it is niche. This means that there is not a lot of community provided DX tooling. This bugged me: I did not want to worry about code formatting - manually. I looked around and could not find a satisfying formatter.
So, I made one. It was quite the project.
Resources
I had a vague idea on where to start from based on some compilation uni class. However, most of this project comes from these resources:
- Chora reference: The docs in themselves
- Prettier printer by Philip Wadler: The algebra behind a formatter
- The hardest program I’ve ever written by Bob Nystrom: On how the dart formatter is made
- How to write a code formatter by Yorick Peterse: On how the inko formatter is made
- EBNF: Grammar description syntax
- Writing a tokenizer by @ndesmic: A tokenizer reference
- Writing An Interpreter In Go by Thorsten Ball: A reference book in Go
- C grammar: Inspiration based on the source material
Project structure
The problem was simple: “Take some code, and spit it back out given a set of structural rules”.
Initial formatter steps
To do this, take an AST and transform it into a format tree. Walk through the format tree and output the initial code with the correct new lines and white spaces. Simple enough.
A format tree representing:
var int foo = 3 + 4;
While quite a bit of work, this is what I wanted: to specify explicit rules for every possible statement and insert the appropriate white space.
To properly describe a format tree, I needed an AST. Since I could not find a Chora AST parser, I had to make one. I quite enjoyed the process since I needed to properly extract a grammar from the docs. By chance, some of it was already written.
Still, it took quite a while to get evrything properly working.
The Chora docs grammar syntax for a for-loop
I probably could have used a grammar converter tool to skip most of the work. Compilers are well researched and this type of problem has been solved before.
However, like most of my projects, I wanted to get my hands dirty and try to do it myself. I had time, so why not?
With the parser (and therefore lexer) added, the final steps to format a bit of code are as follows:
Steps to format code
Tech stack
This project is a pure Go CLI.
It was quick enough to parse strings and easy enough to work with.
The grammar
Here is the final grammar used by ewfmt to generate an AST.
