<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Making a Language on Thunderseethe's Devlog</title><link>https://thunderseethe.dev/series/making-a-language/</link><description>Recent content in Making a Language on Thunderseethe's Devlog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Wed, 18 Feb 2026 02:29:44 +0000</lastBuildDate><atom:link href="https://thunderseethe.dev/series/making-a-language/index.xml" rel="self" type="application/rss+xml"/><item><title>Making an LSP for great good</title><link>https://thunderseethe.dev/posts/lsp-base/</link><pubDate>Wed, 21 Jan 2026 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/lsp-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post brings together all our passes to build a language server.
It mainly relies on the output of the frontend passes (parsing, desugar, nameres, and types).&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>We&amp;rsquo;ve talked a big game about resilience this and interactive that.
With &lt;a 
 href="https://thunderseethe.dev/posts/nameres-base"
 
 >
 name resolution
 
&lt;/a>
 done, it&amp;rsquo;s finally time to put our money where our mouth is.
It&amp;rsquo;s time to tie our passes together into a compiler, but not just any compiler.
Sure, we &lt;em>could&lt;/em> string together a batch compiler if we really had to:&lt;/p></description></item><item><title>Resolving Names Once and for All</title><link>https://thunderseethe.dev/posts/nameres-base/</link><pubDate>Sat, 27 Dec 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/nameres-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post covers name resolution.
&lt;a 
 href="https://thunderseethe.dev/posts/desugar-base"
 
 >
 Desugaring
 
&lt;/a>
 left us with an &lt;code>Ast&amp;lt;String&amp;gt;&lt;/code> that we can&amp;rsquo;t yet feed to type inference.
Name resolution will turn that into a &lt;code>Ast&amp;lt;Var&amp;gt;&lt;/code> that is ready for type checking by figuring out what the names in our program mean.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>Why do we name things?
A silly question, perhaps.
No one had to tell me to name my pet rock Francis.
One look at his sedimentary exterior was all it took to christen him.&lt;/p></description></item><item><title>Desugaring the Relationship Between Concrete and Abstract Syntax</title><link>https://thunderseethe.dev/posts/desugar-base/</link><pubDate>Tue, 02 Dec 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/desugar-base/</guid><description>&lt;p>Previously, we, begrudgingly, &lt;a 
 href="https://thunderseethe.dev/posts/parser-base"
 
 >
 parsed some syntax into a Concrete Syntax Tree (CST)
 
&lt;/a>
.
With that tarpit deftly dodged, we can proceed to our next pass desugaring.
Desugaring removes syntax sugar and maps our CST onto our Abstract Syntax Tree (AST).
Our CST leaves us with a lot of cruft, such as &lt;code>|&lt;/code> or &lt;code>=&lt;/code>.
This stuff was important for telling head from tail in our initial source file, and we&amp;rsquo;ll want to have it around when we&amp;rsquo;re reporting diagnostics, but the rest of the compiler doesn&amp;rsquo;t really care about such mundane affairs.
Desugaring helps us strip away all the syntax and focus in on what&amp;rsquo;s important, lightening the cognitive load for following compiler passes.&lt;/p></description></item><item><title>Reproachfully Presenting Resilient Recursive Descent Parsing</title><link>https://thunderseethe.dev/posts/parser-base/</link><pubDate>Wed, 12 Nov 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/parser-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post covers parsing.
Parsing is the first pass of the compiler, so it doesn&amp;rsquo;t depend on anything from the previous posts.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>I must profess a certain disdain for the parsing tutorial.
I won&amp;rsquo;t insult you by pretending it&amp;rsquo;s fair or rational.
This may not come as a surprise, given that the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 Making a Language
 
&lt;/a>
 series has covered &lt;a 
 href="https://thunderseethe.dev/posts/types-base"
 
 >
 every
 
&lt;/a>
 &lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir"
 
 >
 part
 
&lt;/a>
 &lt;a 
 href="https://thunderseethe.dev/posts/simplify-base"
 
 >
 of the
 
&lt;/a>
 &lt;a 
 href="https://thunderseethe.dev/posts/closure-convert-base"
 
 >
 compiler
 
&lt;/a>
 &lt;a 
 href="https://thunderseethe.dev/posts/emit-base"
 
 >
 it can
 
&lt;/a>
 before parsing.
Parsing tutorials just feel so futile.
Thousands of tutorials written about parsing, and yet PL projects still die bikeshedding syntax.
What are the chances tutorial 1001 changes that?&lt;/p></description></item><item><title>Pushing Past the First Error During Type Inference</title><link>https://thunderseethe.dev/posts/types-base/</link><pubDate>Mon, 10 Nov 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/types-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>Today&amp;rsquo;s post builds on the previous &lt;a 
 href="https://thunderseethe.dev/posts/unification/"
 
 >
 type inference post
 
&lt;/a>
 for the base language.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/unification"
 
 >
 Last we left off
 
&lt;/a>
, we had a complete and working type inference system.
An admirable achievement and at the time our completed product.
I went off to write the remainder of the making a language series, and you went off to read it (I hope).
As I&amp;rsquo;ve written more of the language, my ambitions have focused.
Originally this series set out to write a compiler, pretty much any compiler would do and be challenging enough.
Now, however, it won&amp;rsquo;t be any old compiler, but a query-based compiler, supporting the &lt;a 
 href="https://microsoft.github.io/language-server-protocol/"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://microsoft.github.io/language-server-protocol/"
 data-goatcounter-title="Language Server Protocol (LSP)"
 data-goatcounter-referrer="Pushing Past the First Error During Type Inference"
 >
 Language Server Protocol (LSP)
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
.&lt;/p></description></item><item><title>Skipping the Backend by Emitting Wasm</title><link>https://thunderseethe.dev/posts/emit-base/</link><pubDate>Fri, 13 Jun 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/emit-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>Today&amp;rsquo;s post is preceded by the &lt;a 
 href="https://thunderseethe.dev/posts/closure-convert-base"
 
 >
 base closure conversion pass
 
&lt;/a>
.
Code emission turns our closure conversion IR into our executable target: WebAssembly.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>Today is a great day.
We stand together on the precipice of execution.
All the work we&amp;rsquo;ve done till now culminates in our final compilation pass: Code Generation.
Our compiler&amp;rsquo;s tires meet road, as we take our closure converted &lt;code>IR&lt;/code> and turn it into executable code, driving off into the sunset.&lt;/p></description></item><item><title>Closure Conversion Takes the Function out of Functional Programming</title><link>https://thunderseethe.dev/posts/closure-convert-base/</link><pubDate>Wed, 14 May 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/closure-convert-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>Today&amp;rsquo;s post is preceded by the &lt;a 
 href="https://thunderseethe.dev/posts/monomorph-base"
 
 >
 base monomorphization pass
 
&lt;/a>
.
Like monomorphization, closure conversion does not rely on anything from its prior pass.
It relies on the &lt;code>IR&lt;/code> (and accompanying types) introduced in &lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir"
 
 >
 lowering
 
&lt;/a>
.
We&amp;rsquo;ll review &lt;code>IR&lt;/code> before the action starts.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>Our &lt;a 
 href="https://thunderseethe.dev/posts/monomorph-base"
 
 >
 previous pass
 
&lt;/a>
, monomorphization, stripped polymorphism away from our intermediate representation (IR).
Today we&amp;rsquo;ve come to cut down an even closer confidant, functions.
How many friends must we lose on our conquest of compilation.
This may come as a shock, functions are entwined deeply in our language.
I mean it&amp;rsquo;s right there in the name, functional programming.
I don&amp;rsquo;t know what al programming is, and I don&amp;rsquo;t want to.&lt;/p></description></item><item><title>Casting out Polymorphism with Monomorphization</title><link>https://thunderseethe.dev/posts/monomorph-base/</link><pubDate>Sun, 11 May 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/monomorph-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>Today&amp;rsquo;s post is preceded by the &lt;a 
 href="https://thunderseethe.dev/posts/simplify-base/"
 
 >
 base simplify pass
 
&lt;/a>
.
That pass, however, is not a prerequisite to understanding monomorphization.
Monomorphization relies only on the &lt;code>IR&lt;/code> introduced in &lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir/"
 
 >
 lowering
 
&lt;/a>
.
We&amp;rsquo;ll review &lt;code>IR&lt;/code> before the action starts.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>As we press deeper into the compiler, we strip away high level features that stand between us and machine code.
Many of our language&amp;rsquo;s features have no direct instructions in the hardware, and we must either remove them or translate them into something that does.
The feature on today&amp;rsquo;s chopping block is polymorphism.&lt;/p></description></item><item><title>Back to Basics by Simplifying our IR</title><link>https://thunderseethe.dev/posts/simplify-base/</link><pubDate>Wed, 30 Apr 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/simplify-base/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language Series&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>Today&amp;rsquo;s post is preceded by the &lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir/"
 
 >
 base lowering pass
 
&lt;/a>
.
From that post we&amp;rsquo;ll need our &lt;code>IR&lt;/code>, and it&amp;rsquo;s accompanying data types.
These will be covered in a refresher below.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>Today we&amp;rsquo;re talking about a magical aspect of compilation: optimization.
Magic both in its ability to peel away abstractions, leaving only efficient machine code, and its inscrutable behavior.
Optimizers are known for being black boxes with a million knobs, each serving as butterfly wings flapping towards the final result.&lt;/p></description></item><item><title>Lowering Top Level Items</title><link>https://thunderseethe.dev/posts/lowering-items/</link><pubDate>Tue, 04 Mar 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/lowering-items/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post lowers top level functions from our &lt;a 
 href="https://thunderseethe.dev/posts/check-top-level-items"
 
 >
 prior pass
 
&lt;/a>
.
It extends the row language with support for items (top level functions) in our IR.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/lowering-rows-intro"
 
 >
 Last time
 
&lt;/a>
 saw us endeavoring upon a trilogy to bring rows crashing down from their high-flying AST nodes into the realities of our lowly IR.
Our goals this time are less highfalutin.
We&amp;rsquo;re going to be lowering items.
I can&amp;rsquo;t tell you how relieved I am to see this titled &amp;ldquo;.Items&amp;rdquo;, not &amp;ldquo;.Items[0]&amp;rdquo;.&lt;/p></description></item><item><title>The Heart of Lowered Rows</title><link>https://thunderseethe.dev/posts/lowering-rows-ast/</link><pubDate>Wed, 26 Feb 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/lowering-rows-ast/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post continues lowering rows from our &lt;a 
 href="https://thunderseethe.dev/posts/lowering-rows-ty"
 
 >
 previous post
 
&lt;/a>
.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/lowering-rows-ty"
 
 >
 Last time
 
&lt;/a>
 we upgraded &lt;code>lower_ty_scheme&lt;/code> to support rows and saw how we&amp;rsquo;d use it&amp;rsquo;s evidence to inform &lt;code>lower_ast&lt;/code>.
We&amp;rsquo;re getting to the heart of lowering rows this time: generating and applying our evidence terms.&lt;/p></description></item><item><title>The Types of Lowered Rows</title><link>https://thunderseethe.dev/posts/lowering-rows-ty/</link><pubDate>Tue, 18 Feb 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/lowering-rows-ty/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post continues lowering rows from our &lt;a 
 href="https://thunderseethe.dev/posts/lowering-rows-intro"
 
 >
 previous post
 
&lt;/a>
.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/lowering-rows-intro"
 
 >
 Last time
 
&lt;/a>
 we learned how we&amp;rsquo;re going to lower row types and made some row addendums for &lt;code>IR&lt;/code> and &lt;code>Type&lt;/code>.
Today, we&amp;rsquo;ll update &lt;code>lower_ty_scheme&lt;/code>, using those addendums, to generate types for &lt;code>Evidence&lt;/code>.&lt;/p>
&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Quick Refresher&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>Here&amp;rsquo;s a quick rundown of the stuff we&amp;rsquo;ll need from &lt;a 
 href="https://thunderseethe.dev/posts/row-types"
 
 >
 types/rows
 
&lt;/a>
.&lt;/p></description></item><item><title>Lowering Row Types, Evidently</title><link>https://thunderseethe.dev/posts/lowering-rows-intro/</link><pubDate>Tue, 11 Feb 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/lowering-rows-intro/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post undertakes lowering rows building on our &lt;a 
 href="https://thunderseethe.dev/posts/row-types"
 
 >
 previous pass
 
&lt;/a>
 that inferred row types.
It extends the &lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir"
 
 >
 lowering
 
&lt;/a>
 we did for the base language.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir"
 
 >
 Last time
 
&lt;/a>
, we lowered &lt;a 
 href="https://github.com/thunderseethe/making-a-language/tree/main/types/base"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://github.com/thunderseethe/making-a-language/tree/main/types/base"
 data-goatcounter-title="types/base"
 data-goatcounter-referrer="Lowering Row Types, Evidently"
 >
 types/base
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
 into our IR.
That was exciting, but I professed some anxieties that all we had really done is swap an &lt;code>Ast::&lt;/code> prefix for an &lt;code>IR::&lt;/code> prefix.
Today, we&amp;rsquo;re going to assuage those concerns by lowering &lt;a 
 href="https://github.com/thunderseethe/making-a-language/tree/main/types/rows"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://github.com/thunderseethe/making-a-language/tree/main/types/rows"
 data-goatcounter-title="types/rows"
 data-goatcounter-referrer="Lowering Row Types, Evidently"
 >
 types/rows
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
.
A more seismic lowering.
Recall that &lt;a 
 href="https://thunderseethe.dev/posts/row-types"
 
 >
 row types
 
&lt;/a>
 provide data types for our language.
Rows are great in the surface language and the type checker but start to lose their luster once we need to represent them in memory.&lt;/p></description></item><item><title>Escaping the Typechecker, an Implementation</title><link>https://thunderseethe.dev/posts/lowering-base-impl/</link><pubDate>Tue, 04 Feb 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/lowering-base-impl/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post builds on the &lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir"
 
 >
 previous lowering post
 
&lt;/a>
.
Now that we have some more theory about lowering we undertake Implementation this time around.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>Armed with the knowledge of &lt;code>IR&lt;/code> and &lt;code>Type&lt;/code> from &lt;a 
 href="https://thunderseethe.dev/posts/lowering-base-ir"
 
 >
 last time
 
&lt;/a>
, we can finally write some code:&lt;/p>
&lt;div class="highlight">&lt;pre tabindex="0" style="color:#b0c4de;background-color:#282c34;-moz-tab-size:2;-o-tab-size:2;tab-size:2;">&lt;code class="language-rs" data-lang="rs">&lt;span style="display:flex;">&lt;span>&lt;span style="color:#c678dd">fn&lt;/span> &lt;span style="color:#00b1f7">lower&lt;/span>(
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c1abea">ast&lt;/span>: &lt;span style="color:#76a9f9">Ast&lt;/span>&lt;span style="color:#c7bf54">&amp;lt;&lt;/span>&lt;span style="color:#c1abea">TypedVar&lt;/span>&lt;span style="color:#c7bf54">&amp;gt;&lt;/span>, 
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c1abea">scheme&lt;/span>: &lt;span style="color:#76a9f9">ast&lt;/span>::&lt;span style="color:#c1abea">TypeScheme&lt;/span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>) -&amp;gt; (&lt;span style="color:#b756ff;font-weight:bold">IR&lt;/span>, &lt;span style="color:#c1abea">Type&lt;/span>) {
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#c678dd">let&lt;/span> (&lt;span style="color:#c1abea">ir_ty&lt;/span>, &lt;span style="color:#c1abea">types&lt;/span>) &lt;span style="color:#c7bf54">=&lt;/span> &lt;span style="color:#c1abea">lower_ty_scheme&lt;/span>(&lt;span style="color:#c1abea">scheme&lt;/span>);
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span> &lt;span style="color:#00b1f7">todo!&lt;/span>()
&lt;/span>&lt;/span>&lt;span style="display:flex;">&lt;span>}
&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>One line down.
That&amp;rsquo;s great progress (especially compared to last post)!&lt;/p></description></item><item><title>Lowering our AST to Escape the Typechecker</title><link>https://thunderseethe.dev/posts/lowering-base-ir/</link><pubDate>Tue, 28 Jan 2025 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/lowering-base-ir/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post covers turning our typed AST into our intermediate representation for our base language.
It builds on the outputs of the &lt;a 
 href="https://thunderseethe.dev/posts/type-inference"
 
 >
 previous pass
 
&lt;/a>
 where we inferred types for the base language.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>We&amp;rsquo;ve been in &lt;a 
 href="https://thunderseethe.dev/posts/check-top-level-items"
 
 >
 type checking
 
&lt;/a>
 so long it&amp;rsquo;s becoming a tar pit deep enough to rival picking a parser.
Our only hope of escape is to delve deeper, lest we find ourselves fretting over the endlessly enticing type checker features available to adjoin.
We&amp;rsquo;re always free to return to our type checker older and wiser.
But this series is called making a language, not type check until our motivation evaporates.&lt;/p></description></item><item><title>Checking Types of Top Level Functions</title><link>https://thunderseethe.dev/posts/check-top-level-items/</link><pubDate>Fri, 05 Jul 2024 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/check-top-level-items/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post covers type checking for top level functions.
It extends the row language with top level functions and type checking.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/row-types"
 
 >
 Last season
 
&lt;/a>
, boy how time flies, we added support for algebraic datatypes using row types.
With &lt;strong>both&lt;/strong> product and sum types, our type inference must be near completion.
It&amp;rsquo;s a little lacking in scope though.
We don&amp;rsquo;t have a way to call top-level functions.&lt;/p></description></item><item><title>Rowing Afloat Datatype Boats</title><link>https://thunderseethe.dev/posts/row-types/</link><pubDate>Sat, 21 Oct 2023 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/row-types/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This post covers type inference for row types, a method for adding data types to our language.
It extends the base language with support for row types and their constructs.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/unification"
 
 >
 Last episode
 
&lt;/a>
 we assembled a simple type inference engine end to end.
Powerful enough to check both functions &lt;em>and&lt;/em> integers, without any annotations at all.
Perfect as it is, our type inference (and language) lacks one teensy feature.
It doesn&amp;rsquo;t have any data types.
We&amp;rsquo;ll rectify that on today&amp;rsquo;s episode by adding support for row types.&lt;/p></description></item><item><title>Tying up Type Inference</title><link>https://thunderseethe.dev/posts/unification/</link><pubDate>Sat, 01 Jul 2023 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/unification/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This is the capstone of type inference we built towards with &lt;a 
 href="https://thunderseethe.dev/posts/bidirectional-constraint-generation"
 
 >
 constraint generation
 
&lt;/a>
.&lt;/p>
&lt;/div>
&lt;/details>

&lt;h2 id="constraint-solving">
 Constraint Solving
 &lt;a class="heading-link" href="#constraint-solving">
 &lt;i class="fa fa-link" aria-hidden="true" title="Link to heading">&lt;/i>
 &lt;span class="sr-only">Link to heading&lt;/span>
 &lt;/a>
&lt;/h2>
&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/bidirectional-constraint-generation"
 
 >
 On last week&amp;rsquo;s episode
 
&lt;/a>
 we generated a set of constraints with our bidirectional type system.
Now that we&amp;rsquo;ve got our set of constraints, we can attempt to solve them.
So what does it mean to solve a constraint? A constraint is something that has to be true about our types.
If we can prove whatever our constraint wants true, we have solved the constraint.
Since our &lt;code>Constraint&lt;/code> datatype is just type equality, we can solve all our constraints by proving their types equal.
If we fail to prove two types equal, we have a type error, and we can bail out early.&lt;/p></description></item><item><title>Turning our AST Into Type Constraints</title><link>https://thunderseethe.dev/posts/bidirectional-constraint-generation/</link><pubDate>Sat, 24 Jun 2023 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/bidirectional-constraint-generation/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>Today&amp;rsquo;s post builds on the previous &lt;a 
 href="https://thunderseethe.dev/posts/type-inference/"
 
 >
 type inference post
 
&lt;/a>
 for the base language.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>&lt;a 
 href="https://thunderseethe.dev/posts/type-inference/"
 
 >
 Last time
 
&lt;/a>
, we laid out the AST and Type for the language we are building. We also got a bird&amp;rsquo;s-eye view of our type inference algorithm: constraint generation, constraint solving, substitute our solved types. This time we&amp;rsquo;re implementing the constraint generation portion of our type inference algorithm.&lt;/p></description></item><item><title>Typechecking a Language Without a Parser</title><link>https://thunderseethe.dev/posts/type-inference/</link><pubDate>Sat, 17 Jun 2023 00:00:00 +0000</pubDate><guid>https://thunderseethe.dev/posts/type-inference/</guid><description>&lt;details class="accessory">
 &lt;summary>&lt;div class="title">Making a Language&lt;/div>&lt;/summary>
 &lt;div class="inner">&lt;p>This post is part of the &lt;a 
 href="https://thunderseethe.dev/series/making-a-language"
 
 >
 making a language series
 
&lt;/a>
.
A series that teaches you how to implement a programming language using Rust.&lt;/p>
&lt;p>This is the first post in the series, talking about type inference for a simple functional language.&lt;/p>
&lt;/div>
&lt;/details>

&lt;p>I&amp;rsquo;d like to design a language, more specifically implement a compiler for a programming language I&amp;rsquo;ve made up.
This is not the first time I&amp;rsquo;ve wanted to do this.
In fact, I&amp;rsquo;ve had the &lt;a 
 href="https://github.com/thunderseethe/waht"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://github.com/thunderseethe/waht"
 data-goatcounter-title="itch"
 data-goatcounter-referrer="Typechecking a Language Without a Parser"
 >
 itch
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
 &lt;a 
 href="https://github.com/thunderseethe/panera"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://github.com/thunderseethe/panera"
 data-goatcounter-title="quite a"
 data-goatcounter-referrer="Typechecking a Language Without a Parser"
 >
 quite a
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
 &lt;a 
 href="https://github.com/thunderseethe/brainfuck_interpreter"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://github.com/thunderseethe/brainfuck_interpreter"
 data-goatcounter-title="few"
 data-goatcounter-referrer="Typechecking a Language Without a Parser"
 >
 few
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
 &lt;a 
 href="https://github.com/thunderseethe/false_interpreter"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://github.com/thunderseethe/false_interpreter"
 data-goatcounter-title="times"
 data-goatcounter-referrer="Typechecking a Language Without a Parser"
 >
 times
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
 &lt;a 
 href="https://github.com/thunderseethe/tiger"
 
 
 target="_blank" 
 rel="noopener" 
 data-goatcounter-click="https://github.com/thunderseethe/tiger"
 data-goatcounter-title="before"
 data-goatcounter-referrer="Typechecking a Language Without a Parser"
 >
 before
 
 &lt;i class="fa-solid fa-arrow-up-right-from-square">&lt;/i>
 
&lt;/a>
.
I can&amp;rsquo;t tell you why I keep returning to this venture when I&amp;rsquo;ve failed at it so many times.
What I can tell you is why I always fail.
Every time I begin a sparkly new project with fresh eyes and quickly whip together a lexer.&lt;/p></description></item></channel></rss>