Writing 12 programming languages in 2023, part 2
Heyyyy, long time no see. I'm still working on this project, even though I haven't checked in here. Hope this entry finds you well. I should probably just get into the language, but I feel a certain obligation to account for my time.
Before that, a short recap of the project:
- I think I want to work on programming languages. I used to think that I would have to get a PhD to do this, but instead I've decided to just do it.
Even if I decide I don't want to work on programming languages, I can't know without trying. - It's hard to get a job working on a programming language. Languages are high leverage tools and network effect is the most important factor in picking one for a project, so there are relatively few jobs working on them compared to websites and stuff. I get to do some language-type stuff in my job (for which I'm very lucky!), but if I want to work on more impactful language stuff I need to develop the requisite skills outside of my paid work time.
- To that end, I've devised a project wherein I:
- Read Beautiful Racket, a book about writing small languages
- Write 12 small languages in the year 2023
- Write about the project here
As of last time I had read about half of Beautiful Racket.
The timeline since last article
Here is the timeline since then:
- Feb 2, Published the last post
- Feb 18, Arielle's website project
- Mar 8, Finished the book (but it took longer than I might have wanted)
- Mar 8 - Mar 23, Try to write an article about the book, but what? Think I should really be working on the language. Feel bad.
- Mar 11, Get distracted developing a PAO memory system
- Mar 14 - Mar 24, Stuck in text editor anxiety hell
- Mar 26, Actually start working on the language
- Apr 9, Today (Now it's April 13th actually, wasn't able to edit on the 9th!)
I don't have much more to say about it than that actually. Sometimes I need a break. Also it's hard to work on stuff I care about. Maybe some day I'll write a post about that.
Okay, on to the language.
Overview of AMAL
Background
Arielle has a personal website, mostly for her writing work. She wanted to put a poem on the front page of the website. She didn't want the poem to just sit there though, she wanted it to be a spectacle. She wanted it to look as though she was typing the poem out letter-by-letter for whoever visited the site.
She came to me for advice. I thought we could accomplish this effect with CSS animations. It turned out to be too much of a pain in the butt. We ended up just recording her typing out the poem and turning that into a GIF.
The idea stuck in my head though. Why shouldn't there be an ergonomic animated markup? Thus, AMAL
: a language for animated markup (in Markdown
, for the non-animated parts).
Design
AMAL
, or the Arielle Markdown Animation Library is, essentially, a preprocessor of Markdown
that provides syntax for using CSS
animations. CSS
animations can be hard to write, so the idea is that AMAL
comes with a library of prewritten animations which can be plopped into any Markdown
text. AMAL
also provides users the ability to change elements of animations or use entirely custom animations.
For example, this piece of AMAL
:
@ type-and-erase Hello! @
Produces this HTML
and CSS
animation:
Animation arguments can be placed between the name of the animation and the body of the text, like so:
@type-and-erase animation-duration: 4s Hello!@
This produces CSS
with the specified animation-duration
Here is a breakdown of an AMAL
expression:
The implementation plan
My plan for implementing AMAL
rests on the fact that HTML
can (usually) be embedded in Markdown
.
I will:
- Convert
AMAL
expressions to the associatedHTML
andCSS
- Let everything else pass through unchanged
- Pass the resulting string to the existing Markdown package to turn into
HTML
I don't love that this means the language has to go through two passes: AMAL
-> Markdown
(with embedded HTML
) -> HTML
. It seems like I should be able to convert it all to HTML
in one shot. Given the time constraints though, I think this is the prudent way forward.
Unfortunately, even given this design, I am not finished.
Turns out that writing programming languages is hard
I admit that I didn't exactly set myself up for success by starting six days before the end of the month. Since then I've been working pretty hard on the language! (ask Arielle) Unfortunately I'm not done, and not just because I haven't fleshed out the animation library. The language doesn't work at all! The example above uses handwritten HTML
!
Turns out that designing and writing a novel(-ish!) language is harder than copying languages from a book. Oops. I expected this but uh, well, I was optimistic. So I don't have a language (yet). What I do have is a parser.
Parser problems
We can think about a programming language as a recipe. Each step produces output that feeds into a later step. The first step in this analogy would be opening the recipe (sending code off to compile). The last step in this analogy would be eating (the compiled program doing whatever it's supposed to do).
Parsing is the mise en place of writing a language. It's prepping the ingredients for the more involved cooking coming up. Expansion (in the case of writing a language in Racket) is the actual cooking. So I've got my bowls full of carrots, celery, onions, etc…, but I still need to actually turn them into soup.
I had a hell of a time figuring out how to slice my carrots. Eventually I settled on the design in The implementation plan, but I spent a lot of time thinking about different plans, implementing them, then testing them only to find that they wouldn't work for one reason or another. You can read my inane ramblings in the work log if you want more background, but ultimately I had to relearn a few lessons I am always relearning:
- Spend more time than feels comfortable on design. Try to validate ideas in the design phase!
- Spend more time than feels comfortable reading. Reading is great. It gives me so many ideas. It often feels like a waste of time. It's almost never a waste of time.
- Test at a granularity that feels superfluous while building. I'm able to skip this more in domains where I feel comfortable, but working on a language in Racket I really don't know what's going on without a short feedback loop.
Next steps
So I still have to cook the soup.
Which is to say, give meaning to the collection of ingredients I've assembled.
Which is to say, write the expander.
I hope to have a language that people can actually use by next month. But I wanted to put something up here in the mean time. It's easy to get discouraged when I'm not making progress as fast as I'd like and think about quitting. Publishing makes that a little bit harder :)