← Back to Kevin's newslettersPublished: 2025 June 3

How do you prototype a nice language?

I’ve spent the past month prototyping my codeCAD language. However, while I’ve made tons of zero-to-one-type progress (an EBNF grammar, parser, function definitions, evaluation, and numeric solving!), the current possible demos are all terribly underwhelming — think the game programmer’s “triangle with color gradient” or the hardware engineer’s “PCB with a single blinking LED”.

However, even once I’m further along I suspect the demos will be fairly underwhelming — I’m not one-shot prompting my way to production G-code or building a slick augmented reality, Minority Report UI.

Rather, I’m after a particular kind of software hygge: Loads instantly, doesn’t crash, and fits nicely in the hand.

The objective is a feeling, and there’s no point trying to convince people — either the software exists and evokes the feeling, or it doesn’t.

Pitching it feels as nonsensical to me as pitching the deliciousness of an unbaked cake (which is why you haven’t heard about my crunchy tiramisu).

Unfortunately, this perspective makes prototyping tricky: How much baking is required to test an idea?

For example: One idea I’m exploring is “bidirectional editing”, so geometry can be manipulated using either:

If you graphically drag a point around, the coordinates in the source code should automatically update. If you edit the source code, the graphical UI should automatically update.

A simple way to test this idea is to throw a <textarea> in the UI that displays the corresponding source code. But to me, that feels terrible because I never want to be coding in some janky, in-browser <textarea> — I want to be working with source code in Emacs, with all of my familiar key bindings, color schemes, autocomplete, and decades of cozy practice.

That’s the core appeal of a textual programming language.

But doing this properly is an absolute boatload of work:

How much of this needs to be built to evaluate whether bidirectional editing “fits nicely in the hand”?

It’s a fine line balancing between the reasonable “this is a prototype, we can fix the awkward parts later” and the tautological “the idea is good if we ignore all the bad stuff”.

Language design resources

While I’ve toyed with some programming language-ish projects before (a microcontroller configuration solver and relational spreadsheet), this is my first time building a language starting from a grammar and implementing stuff like binding, function resolution, and evaluation.

While there’s tons of 101-level resources for “building your first LISP” and evaluating arithmetic expressions like “1 + 2 / 5”, I haven’t found as much that gets in the fiddly details of more complex language semantics.

The most useful book I’ve found is Nystrom’s Crafting Interpreters.

I roughly followed its approach to building a lil’ tree-walking interpreter, but with Instaparse for parsing and some of the data format and processing machinery from Clojure tools.analyzer.

So far I’ve punted on doing proper (whitespace and comment preserving) unparsing in favor of brute force canonicalizing abstract-syntax-tree -> string rendering, but I expect I’ll need to flesh that out along with LSP support sooner rather than later.

I considered replacing Instaparse with Tree-sitter to leg into the latter’s better performance and potential ecosystem benefits (the “universal formatting engine” Topiary; Combobulate structured editing).

However, I decided against it for now as I feel like it’s worth trying to grapple with the challenges myself using a familiar tool (Clojure), rather than picking up frameworks and hoping I can mold them into the to-be-determined experience I’m trying to provide.

I have been reading around to learn about unified approaches for building a language with first-party support for editor tooling — where the LSP engine isn’t a from-scratch duplication of the compiler/interpreter’s analyzer, but is rather integrated as part of a single codebase.

(Aside: While a language implementation and editor tooling may make different trade offs around, e.g., throughput, latency, and tolerance of malformed inputs, I feel like a unified approach is more sustainable for single-author art project language.)

Some prior art I’ve seen there:

Anyway, if you know of any programming language implementations (or bidirectional editing work) that I should study, please let me know!

Misc. stuff