<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
  xmlns:content="http://purl.org/rss/1.0/modules/content/"
  xmlns:dc="http://purl.org/dc/elements/1.1/"
  xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
  <channel>
    <title>Vidar Hokstad</title>
    <link>http://hokstad.com/</link>
    <description>Vidar Hokstad</description>
    <pubDate>Mon, 04 Nov 2013 22:00:00 +0000</pubDate>
    <item>
      <title>Docker Postfix container w/Virtual Hosts support</title>
      <link>http://hokstad.com/docker/postfix</link>
      <description>&lt;p&gt;Just wanted to point you to a short post I just published on my consulting site:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://hokstadconsulting.com/docker/postfix&quot;&gt;Simple Docker Postfix container&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It provides a very basic Postfix setup that's ready for handling multiple
domains and forwarding.&lt;/p&gt;
</description>
      <category>docker</category>
      <category>postfix</category>
      <category>consulting</category>
      <pubDate>Wed, 13 Apr 2016 05:50:00 +0000</pubDate>
      <dc:date>2016-04-13T05:50:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 45</title>
      <link>http://hokstad.com/compiler/45-send</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Send&lt;/h2&gt;

&lt;p&gt;One of the great &quot;joys&quot; of trying to compile Ruby is of course the level of
dynamism. Especially when trying, as I am, to make the compiler as static as
possible.&lt;/p&gt;

&lt;p&gt;One of the culprits is the ability to send messages to objects that may be
composed dynamically (e.g. formatting strings), and that may or may not even
exist at compile time.&lt;/p&gt;

&lt;p&gt;So far we've avoided this. There are two issues here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;We need to be able to handle methods with names that are not present in the application at compile time. Currently we put everything into vtables, and to know how to allocate slots we need to know the names at compile time.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We need to be able to look up methods by name, and do something with the information.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Matz' Ruby implementation does this with a hash table of methods. And we will
too. This does, however, &lt;em&gt;not&lt;/em&gt; mean we'll ditch the vtables. The vtables are
essential to get fast method calls for methods we call by names statically known,
which for most applications will likely be the vast majority.&lt;/p&gt;

&lt;p&gt;Even for method calls where the target method was not defined at compile time
this works, by pre-allocating a vtable slot.&lt;/p&gt;

&lt;p&gt;Instead what we will do is add redundant information for the methods known at
compile time, and augment this with the ability to add new methods down the line.&lt;/p&gt;

&lt;p&gt;The initial motivation for this is the work towards self-hosting, and the
compiler itself, foolishly or not, uses &lt;code&gt;#send&lt;/code&gt; to call the &lt;code&gt;#parse_XXX&lt;/code&gt;
methods in &lt;code&gt;Parser&lt;/code&gt; for example.&lt;/p&gt;

&lt;h2&gt;CS101 - Hash tables&lt;/h2&gt;

&lt;p&gt;The last time I wrote a hash table implementation from scratch was more than 20
years ago, in my introductory data structures and algorithms course. I read the
book on a long train journey and mostly ignored the lessons. Apart from frustrating
everyone by insisting on doing a &lt;a href=&quot;https://en.wikipedia.org/wiki/Eight_queens_puzzle&quot;&gt;N-Queens&lt;/a&gt;
exercise in &lt;a href=&quot;http://strlen.com/amiga-e&quot;&gt;Amiga-E&lt;/a&gt; (a wonderful language by the
amazing &lt;a href=&quot;http://strlen.com&quot;&gt;Wouter van Oortmerssen&lt;/a&gt;, though unfortunately
rather esoteric even back in '94)&lt;/p&gt;

&lt;p&gt;Thankfully, making a simple hash table is, well, simple.&lt;/p&gt;

&lt;p&gt;We'll do a very basic &lt;a href=&quot;https://en.wikipedia.org/wiki/Linear_probing&quot;&gt;linear scan&lt;/a&gt;
hash table. If you've forgotten your CS courses and is too lazy to click the wikipedia
link, that means that once we've calculated which slot an entry should ideally go in,
if it is occupied, we linearly probe the other slots until we find an empty one.&lt;/p&gt;

&lt;p&gt;There are all kinds of upsides and downsides from various methods for scanning/probing,
and from using scans instad of alternative structures, but the point as usual is
simplicity first. &lt;em&gt;Especially&lt;/em&gt; in this case as we won't even know the access patterns
until things are complete enough to do proper benchmarks.&lt;/p&gt;

&lt;h3&gt;A hash function, and comparisons&lt;/h3&gt;

&lt;p&gt;Firstly, let us implement &lt;code&gt;#hash&lt;/code&gt;. The documentation for &lt;code&gt;Object#hash&lt;/code&gt; says this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Generates a Fixnum hash value for this object. This function must have the property that a.eql?(b) implies a.hash == b.hash.

The hash value is used along with eql? by the Hash class to determine if two objects reference the same hash key. Any hash value that exceeds the capacity of a Fixnum will be truncated before being used.

The hash value for an object may not be identical across invocations or implementations of Ruby. If you need a stable identifier across Ruby invocations and implementations you will need to generate one with a custom method.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is thankfully easy to match, and we'll do it with the &lt;a href=&quot;http://cr.yp.to/cdb/cdb.txt&quot;&gt;DJB hash function used in amongst others CDB&lt;/a&gt;. It's simple, and reasonably efficient:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# DJB hash&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5381&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;each_byte&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;33&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You'll note we use a multiply by 33 instead of the &lt;code&gt;((h &amp;lt;&amp;lt; 5) + h)&lt;/code&gt; in the description. The
real reason for this is that I haven't implemented &lt;code&gt;&amp;lt;&amp;lt;&lt;/code&gt; yet. But in our case, given Ruby's
pathological amount of method calls, &lt;code&gt;h * 33&lt;/code&gt; is actually even likely to be faster than &lt;code&gt;((h &amp;lt;&amp;lt; 5) + h)&lt;/code&gt;
until we actually add some fairly advanced optimization (so ca. 2030 at my current pace).&lt;/p&gt;

&lt;p&gt;Note that our function is &lt;strong&gt;not&lt;/strong&gt; entirely equivalent to the original djb hash function, as
the original assumes truncation to a 32 bit value. It has little practical implication here
given that we will be using a modulo of it in the actual code.&lt;/p&gt;

&lt;p&gt;We'll also add &lt;code&gt;String#eql?&lt;/code&gt;, which in this case is just an alias for &lt;code&gt;#==&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;eql?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/6b01ee3&quot;&gt;6b01ee3&lt;/a&gt;)&lt;/p&gt;

&lt;h3&gt;Handle modulus&lt;/h3&gt;

&lt;p&gt;Since I happen to know we'll want a working modulus operator (because we'll want to take the
hash value of a string, and take the modulus of the hash value and the capacity of the Array
we'll store the hash table in to find out where to start probing), that's what we'll fix next.&lt;/p&gt;

&lt;p&gt;We start out gently in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/3f24489&quot;&gt;3f24489&lt;/a&gt; by adding it to the operator table in &lt;code&gt;operators.rb&lt;/code&gt;, and
in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e6bb8c7&quot;&gt;e6bb8c7&lt;/a&gt; we add the &lt;code&gt;mod&lt;/code&gt; keyword to the s-expression syntax to give us something to
implement it with.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/88066af&quot;&gt;88066af&lt;/a&gt; we implement the &lt;code&gt;mod&lt;/code&gt; keyword:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_arithmetic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_arithmetic&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dividend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sarl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dividend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;idivl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;divisor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
         &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_mod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Piece of cake as &lt;code&gt;div&lt;/code&gt; already does the calculation, we just need to actually
save the modulus that's already calculated.&lt;/p&gt;

&lt;h3&gt;Then starts the pain - or &quot;% is the devil&quot;&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;%&lt;/code&gt; is one of the most heinous abominations of Ruby syntax. I'm &lt;strong&gt;not&lt;/strong&gt; talking
about the modulus operator. I'm talking about the &lt;strong&gt;other&lt;/strong&gt; &lt;code&gt;%&lt;/code&gt;. The evil twin.&lt;/p&gt;

&lt;p&gt;You have met it. It's the &lt;code&gt;%&lt;/code&gt; that starts quoted strings og all kinds. We've
&quot;stolen&quot; one of the codes for the s-expression syntax.&lt;/p&gt;

&lt;p&gt;Only &lt;code&gt;%&lt;/code&gt; is really horrendously ambiguous. For example, consider what this
expression should parse as:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In a sane, just world, this would be a syntax error.&lt;/p&gt;

&lt;p&gt;Nah. Too obvious, isn't it? Can't be anything but &lt;code&gt;&quot;x&quot;&lt;/code&gt;. Uh? What?!?&lt;/p&gt;

&lt;p&gt;As it happens, in contexts where it can't validly be the infix modulus opeator,
&lt;code&gt;%&lt;/code&gt; starts a quoted string &lt;strong&gt;even when the following character is a space&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;For characters outside of a specific set of exceptions with special meaning,
&lt;code&gt;%&lt;/code&gt; will treat the character immediately following as the &quot;quote&quot; character
that will start and terminate the given string. So above, we're basically using
space as the equivalent of a quote.&lt;/p&gt;

&lt;p&gt;(If you have ever seen that &lt;em&gt;used&lt;/em&gt; other than as a way of terrorising language
implementors or other unsuspecting &lt;del&gt;developers&lt;/del&gt; victims, I want to know)&lt;/p&gt;

&lt;p&gt;Of course this broke the parser, as we've consistently gone for simplicity first...&lt;/p&gt;

&lt;p&gt;First of all, let's get some test cases in place (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8473eaecb&quot;&gt;8473eaecb&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;gherkin codehilite&quot;&gt;&lt;code&gt;
    
        &lt;span class=&quot;nt&quot;&gt;@mod&lt;/span&gt;
            &lt;span class=&quot;kn&quot;&gt;Scenario Outline&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; Simple expressions
                    &lt;span class=&quot;nf&quot;&gt;Given &lt;/span&gt;the expression &lt;span class=&quot;nv&quot;&gt;&amp;lt;expr&amp;gt;&lt;/span&gt;
                    &lt;span class=&quot;nf&quot;&gt;When &lt;/span&gt;I parse it with the full parser
                    &lt;span class=&quot;nf&quot;&gt;Then &lt;/span&gt;the parse tree should become &lt;span class=&quot;nv&quot;&gt;&amp;lt;tree&amp;gt;&lt;/span&gt;
    
            &lt;span class=&quot;nn&quot;&gt;Examples&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;expr&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;tree&lt;/span&gt;                 &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;notes&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;&lt;/span&gt;     &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;[:do,&quot;x&quot;]&lt;/span&gt;            &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;[:do,[:+,:a,&quot;x&quot;]]&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;[:do,[:%,1,2]]&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;&quot;1&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;2&quot;&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;[:do,[:%,1,2]]&lt;/span&gt;       &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;        &lt;span class=&quot;p&quot;&gt;|&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then we fix it. As it happens the fix is simple. As horrendous as this
syntax looks, at least the cases we're concerned with now are just a
matter of distinguishing between a prefix and infix operator, and the
shunting yard parser has a mechanism for that. First we change the
operator table (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/c276794&quot;&gt;c276794&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;operators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;operators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;97&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Operators&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;ss&quot;&gt;:prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;ss&quot;&gt;:prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
       &lt;span class=&quot;s2&quot;&gt;&quot;!&quot;&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;!&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;ss&quot;&gt;:prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;%&quot;&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;%&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;ss&quot;&gt;:infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;%&quot;&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:infix_or_postfix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;%&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;ss&quot;&gt;:infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:quoted_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
       &lt;span class=&quot;s2&quot;&gt;&quot;/&quot;&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;      &lt;span class=&quot;ss&quot;&gt;:infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt;         &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
         &lt;span class=&quot;ss&quot;&gt;:infix_or_postfix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;*&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;   &lt;span class=&quot;ss&quot;&gt;:infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This basically makes the parser accept both versions in their
respective contexts.&lt;/p&gt;

&lt;p&gt;Then we need to handle it. As it happens we can use the opportunity
for some minor cleanup. We already added code to special case the
operator case of '%', and that's actually what broke the modulo
operator case. So now we rip that out, and add a helper &lt;code&gt;#get_quoted_exp&lt;/code&gt;
to let the parser choose whether to call back in and parse a quoted
expression (and make use of that helper one other place as well) (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/3815fb2&quot;&gt;3815fb2&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tokens&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;143&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;143&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Tokens&lt;/span&gt;
           &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_quoted_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;unget&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;unget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;%&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unget&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Quoted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse_defexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#, nil]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_raw&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;peek&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;sc&quot;&gt;?'&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Quoted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse_defexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;},&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;get_quoted_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;DIGITS&lt;/span&gt;
             &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Number&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ALPHA&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?@&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?$&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?:&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?_&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;182&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;11&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;187&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;Tokens&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
             &lt;span class=&quot;c1&quot;&gt;# Special cases - two/three character operators, and character constants&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;peek&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?%&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Quoted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@parser&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse_defexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note that in the operator case, the rest of that code have already 'eaten' the
'%' so we need an option to unget it.&lt;/p&gt;

&lt;p&gt;We also expose the &lt;code&gt;#get_quoted_exp&lt;/code&gt; helper in &lt;code&gt;tokenizeradapter.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And finally in &lt;code&gt;shunting.rb&lt;/code&gt; we trigger on &lt;code&gt;quoted_exp&lt;/code&gt; and call back into the
tokenizer via the adapter (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/3815fb2&quot;&gt;3815fb2&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parse_quoted_exp&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@tokenizer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_quoted_exp&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;shunt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ostack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inhibit&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[])&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;possible_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# was the last token a possible function name?&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;opstate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:prefix&lt;/span&gt;         &lt;span class=&quot;c1&quot;&gt;# IF we get a single arity operator right now, it is a prefix operator&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;90&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;94&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;module&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;OpPrec&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
                   &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Block not allowed here&quot;&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sym&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:quoted_exp&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;vi&quot;&gt;@out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parse_quoted_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
                 &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rp&lt;/span&gt;
                   &lt;span class=&quot;vi&quot;&gt;@out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lastlp&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Finally we can implement the '%' operator in Fixnum (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/9f6f151&quot;&gt;9f6f151&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fixnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Fixnum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Integer&lt;/span&gt;
         &lt;span class=&quot;sx&quot;&gt;%s(assign @value 0)&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#    %s(printf &quot;%i\n&quot; (callm other __get_raw))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign r (callm other __get_raw))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign m (mod @value r))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if (eq (gt m 0) (lt r 0))
    +         (assign m (add m r)))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(__get_fixnum m)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note the last &lt;code&gt;if&lt;/code&gt; expression, which is used because the x86 instruction set and Ruby disagrees on how to
handle modulo operations with negative numbers, and I opted to stick with code similar to what gcc outputs
for C rather than encode the Ruby behaviour in the s-exp syntax. I may yet change my opinion on that - we'll
see, but for now this works.&lt;/p&gt;

&lt;h2&gt;Minor Array fixes&lt;/h2&gt;

&lt;p&gt;In addition to the above, in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/928fe97&quot;&gt;928fe97&lt;/a&gt; I add support for &lt;code&gt;Array.new(capacity)&lt;/code&gt; and &lt;code&gt;Array#capacity&lt;/code&gt;, as well
as make &lt;code&gt;Array#[]=&lt;/code&gt; work for the basic cases, as this will be needed for the &lt;code&gt;Hash&lt;/code&gt; implementation below.&lt;/p&gt;

&lt;h2&gt;Creating the class hash table&lt;/h2&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/913a3de&quot;&gt;913a3de&lt;/a&gt; you will find an initial implementation of &lt;code&gt;Hash&lt;/code&gt;. Notably, this implementation is pure Ruby,
and (basic, simple) programs will not even necessarily break if you load this implementation in MRI and
proceed to use it. It also maintains insertion order, like MRI 1.9+, which aids in testing vs. MRI.&lt;/p&gt;

&lt;p&gt;It does, however, lack most methods, but it should be sufficient for us for the next steps. It is worth noting,
though, that it is certainly still inefficient in eg. the interaction with &lt;code&gt;Array&lt;/code&gt;, and there's plenty of
scope for improvement in the future.&lt;/p&gt;

&lt;p&gt;I'll leave figuring the hash implementation out as an exercise for the reader (or ask in the comments),
as there's nothing specific to the compiler in that one and it should be quite simple: Basically I maintan
an array of slots consisting of pointers - one to the key, one to the value, and a linked list to maintain
insertion order. Then on setting and reading the hash table, we calculate the hash of the key, look up the
first applicable slot, then we loop over the hash table until we've found a matching key, possibly wrapping
around, or we find an empty slot.&lt;/p&gt;

&lt;p&gt;If the table is too small, we re-allocate the array and re-insert all the key/value pairs.&lt;/p&gt;

&lt;p&gt;We could do this more efficiently for special cases like the vtable where we don't need the insertion
order, for example, but as usual, efficiency for later.&lt;/p&gt;

&lt;h3&gt;Creating a hash table of String =&amp;gt; Symbol&lt;/h3&gt;

&lt;p&gt;But in the interest of (some) efficiency as in this case it &lt;em&gt;also&lt;/em&gt; brings us closer to feature-completeness,
I will first make one further improvement to Symbol handling.&lt;/p&gt;

&lt;p&gt;Since we now have a Hash table, we can store a hash mapping Symbol &lt;strong&gt;names&lt;/strong&gt; to Symbol &lt;strong&gt;instances&lt;/strong&gt;, and
thus gain the two main advantages &lt;code&gt;Symbol&lt;/code&gt; is meant to have: Ability to treat object identity as equality
(in other words: compare pointers rather than string values in our case), and secondly reusing the same
object instance each time the symbol is mentioned.&lt;/p&gt;

&lt;p&gt;We'll use this to make the cost of the class method tables less excessive.&lt;/p&gt;

&lt;p&gt;Firstly, to make &lt;code&gt;Symbol&lt;/code&gt; work with these changes, it was necessary to move it later in the bootstrap of the
runtime (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/fc674f3&quot;&gt;fc674f3&lt;/a&gt;). This is one of the things I find most interesting with working on this compiler:
Slowly teasing out a minimal core of Ruby and figuring out how to bootstrap &lt;em&gt;just&lt;/em&gt; the lower level facilities
and bootstrap. That's going to be an interesting subject in its own right at some point.&lt;/p&gt;

&lt;p&gt;Secondly we implement &lt;code&gt;Object#object_id&lt;/code&gt; as simply returning &lt;code&gt;%s(__get_fixnum self)&lt;/code&gt;. So (and this should not
be relied on), &lt;code&gt;#object_id&lt;/code&gt; in our case is actually the fixnum version of the pointer to the object.&lt;/p&gt;

&lt;p&gt;We strictly don't need this, but it's used by my test case, and also lets me isolate the s-expression parts
further, implementing Object identity comparisons (note: these actually belongs in Comparable, but we don't
do &lt;code&gt;include&lt;/code&gt; and friends yet). (In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/38ca5270e3&quot;&gt;38ca5270e3&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;These leave us with a very small manageable set of changes to &lt;code&gt;Symbol&lt;/code&gt;. Small enough to just include the
whole rudimentary &lt;code&gt;Symbol&lt;/code&gt; class here (changes can be seen in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/9abb565&quot;&gt;9abb565&lt;/a&gt;, and followup in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/077dcf3&quot;&gt;077dcf3&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Symbol&lt;/span&gt;
       &lt;span class=&quot;vi&quot;&gt;@symbols&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The above is our symbol-name to &lt;code&gt;Symbol&lt;/code&gt; hash table.&lt;/p&gt;

&lt;p&gt;Cleaned it up to use proper String objects for the name
(though &lt;code&gt;#to_s&lt;/code&gt; should probably use &lt;code&gt;#dup&lt;/code&gt;, which I don't
think we've implemented yet)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# FIXME: Should be private, but we don't support that yet&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;hash&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;c1&quot;&gt;# FIXME&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# The compiler should turn &quot;:foo&quot; into Symbol.__get_symbol(&quot;foo&quot;).&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Alternatively, the compiler can do this _once_ at the start for&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# any symbol encountered in the source text, and store the result.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@symbols&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;nil?&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;## FIXME: Doing !sym instead fails w/method missing&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@symbols&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;sx&quot;&gt;%s(defun __get_symbol (name) (callm Symbol __get_symbol ((__get_string name))))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here is the fun: Look up the symbol; if not present in the hash table,
create a new one, and return it.&lt;/p&gt;

&lt;p&gt;One notable thing: MRI recently added garbage collection of symbols. The
above actively works counter to garbage collection of symbols - once we
get to add a GC we'll want to deal with that by letting the GC handle
certain structures, such as  this hash, as &quot;weak&quot; references that can be
broken. It's an extra complexity, but far away.&lt;/p&gt;

&lt;h2&gt;Bootstrapping the values&lt;/h2&gt;

&lt;p&gt;Eventually we are going to use two separate types of hash tables:
&lt;code&gt;Symbol&lt;/code&gt; =&amp;gt; offset in vtable for statically allocated methods, and
&lt;code&gt;Symbol&lt;/code&gt; =&amp;gt; address of method for runtime defined methods. This will
keep the class specific hash tables small at the cost of one extra hash
table lookup in &lt;code&gt;#send&lt;/code&gt;, but &lt;code&gt;#send&lt;/code&gt; will always be slow compared to the
direct vtable lookup anyway.&lt;/p&gt;

&lt;p&gt;This time we will only actually implement the former, and only handle
cases of &quot;#send&quot; called with method names we've statically seen. This
actually covers a substantial proportion of the use of &lt;code&gt;#send&lt;/code&gt;. The big
exception is cases where a method is both dynamically &lt;em&gt;defined&lt;/em&gt; and
dynamically &lt;em&gt;used&lt;/em&gt; by string composition or by requiring files at load
time (which we don't support yet). Most importantly at this stage it
handles the specific case of bootstrapping the compiler itself.&lt;/p&gt;

&lt;p&gt;We'll declare it out of bounds for the compiler itself to use &lt;code&gt;#send&lt;/code&gt;
before a suitable point in the bootstrap process, where we call a compiler
generated function to bootstrap this hash table.&lt;/p&gt;

&lt;p&gt;Calling &lt;code&gt;#send&lt;/code&gt; before that will trigger a runtime error.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/5a269ec&quot;&gt;5a269ec&lt;/a&gt; I add a new file &lt;code&gt;lib/core/class_ext.rb&lt;/code&gt; that implements
the send &quot;send&quot; logic, and the code to bootstrap these values. This goes
in a separate file for the simple reason that it needs to be loaded &lt;em&gt;after&lt;/em&gt;
&lt;code&gt;Symbol&lt;/code&gt; and various other things have gotten bootstrapped, but the basics
of &lt;code&gt;Class&lt;/code&gt; are needed much earlier.&lt;/p&gt;

&lt;p&gt;First of all, this is how the send happens:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# This is called by __send__&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__send_for_obj__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;voff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method_to_voff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;voff&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING: __send__ bypassing vtable (name not statically known at compile time) not yet implemented.\n&quot;)&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(if sym (printf &quot;WARNING:    Method: '%s'\n&quot; (callm (callm sym to_s) __get_raw)))&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING:    symbol address = %p\n&quot; sym)&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING:    object = %p\n&quot; obj)&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING:    class '%s'\n&quot; (callm (callm self name) __get_raw))&lt;/span&gt;
          &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# We can't inline this in the call, as our updated callm&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# doesn't allow method/function calls in the method slot&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# for simplicity, for now anyway.&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(assign raw (callm voff __get_raw))&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(callm obj (index self raw) ((splat args)))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;There's not that much new or different here. Mainly we look up the method
name in the new hash table (which should not be public, but we'll worry
about that later). Secondly, if the vtable offset is known - which will
be the case for all methods we've seen statically mentioned - we attempt
to convert the stored &lt;code&gt;Fixnum&lt;/code&gt; to a raw integer, retrieve the address from
the vtable, and do a &lt;code&gt;callm&lt;/code&gt; with the address instead of a method name.&lt;/p&gt;

&lt;p&gt;This latter part is new, and we'll have a look at how to handle that shortly,
but first the last part of &lt;code&gt;lib/core/class_ext.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Populate the Class.method_to_voff hash based on the __vtable_names&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# table that gets generated by the compiler.&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(let (i max)
       (assign i 0)
       (assign max __vtable_size)
       (assign h (callm Class method_to_voff))
       (while (lt i max)
          (do
             (if (ne (index __vtable_names i) 0)
                (callm h []= ((__get_symbol (index __vtable_names i)) (__get_fixnum i)))
                )
              (assign i (add i 1))
          )
       )
    )&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is fairly straight forward: We iterate over a table name &lt;code&gt;__vtable_names&lt;/code&gt;
that the compiler will henceforth output, and for &lt;code&gt;__vtable_size&lt;/code&gt; entries we
obtain a &lt;code&gt;Symbol&lt;/code&gt; object, and then add a mapping from the ymbol to the according
offset to the &lt;code&gt;Class.method_to_voff&lt;/code&gt; hash table.&lt;/p&gt;

&lt;p&gt;This table was actually added in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e6bb8c75&quot;&gt;e6bb8c75&lt;/a&gt; - I think that method in &lt;code&gt;Compiler&lt;/code&gt;
should be reasonable self-explanatory - basically outputs an array of pointers to
constant strings.&lt;/p&gt;

&lt;h2&gt;Handling callm with computed addresses&lt;/h2&gt;

&lt;p&gt;Previously &lt;code&gt;%s(callm ...)&lt;/code&gt; have only supported names. Now it needs to supports
&lt;code&gt;%s(callm object &amp;lt;some expression resulting in method address&amp;gt; ...)&lt;/code&gt; too.&lt;/p&gt;

&lt;p&gt;We handle this as follows. Firstly, we (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/46bb9d0&quot;&gt;46bb9d0&lt;/a&gt;) we check if the method
is provided by name (as a &lt;code&gt;Symbol&lt;/code&gt;), and only use the old logic if it is:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;off&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@vtableoffsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then further down, we conditionally compile the actual call differently:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# NOTE: The expression in &quot;method&quot; can not&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# include a function call, as it'll clobber&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# %ebx&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;I'm not quite pleased with the complexity of &lt;code&gt;compile_call.rb&lt;/code&gt;, but it'll do for now.&lt;/p&gt;

&lt;h2&gt;Parting words&lt;/h2&gt;

&lt;p&gt;And that's in. Doing &lt;code&gt;#send&lt;/code&gt; now works. And we have a somewhat working &lt;code&gt;Hash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Not bad.&lt;/p&gt;

&lt;p&gt;And with this I will start doing what I've mentioned for a while now and switch to
writing shorter, more focused entries on specific features rather than these huge
parts. And feature branches instead of branches focused on a specific part....&lt;/p&gt;

&lt;p&gt;Hopefully it will get things moving a bit quicker.&lt;/p&gt;

&lt;p&gt;(This also signals that I'll be more open to outside contributions and suggestions,
though I recognise this probably isn't the easiest codebase to jump into, despite the
copious amount of writing I've done about it's internals)
&lt;/some&gt;&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Sun, 26 Jul 2015 05:00:00 +0000</pubDate>
      <dc:date>2015-07-26T05:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 44</title>
      <link>http://hokstad.com/compiler/44</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Further misadventures on the way to self-hosting&lt;/h2&gt;

&lt;h3&gt;In which we continue the circuitous approach towards parsing s-expressions&lt;/h3&gt;

&lt;p&gt;As you may or may not remember (it's taking a while, after all), the
immediate purpose is to use the limited s-expression part of the parser
to ferret out the first batch of problems standing beween us and fully
self-hosting the compiler.&lt;/p&gt;

&lt;p&gt;For that purpose, I've now put together a tiny test driver and the
minimal dependencies of the s-expression parser, and this part we
will look at 1) changes to reduce coupling (which means we're
cheating by  delaying certain types of fixes by moving the troublesome
code out of the immediate dependencies of the s-expression parser)
and 2) changes to make that code compile, and hopefully even run.&lt;/p&gt;

&lt;p&gt;I'll give you a spoiler right now, and tell you that at the end of
this there will be &lt;em&gt;at least&lt;/em&gt; one more roadblock: Implementing
dynamic method dispatch (looking up a method by name for &lt;code&gt;#send&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;At the time of writing I don't know if that will be the &lt;em&gt;only&lt;/em&gt;
outstanding issue (probably not), but it's most likely the &lt;em&gt;biggest&lt;/em&gt;
of the remaining issues to get the s-expression parser to work by
itself, since call parser methods by name.&lt;/p&gt;

&lt;p&gt;(Whether or not it's a good idea to do that is another matter, but
for now it'll stay since we need to cover that bit anyway).&lt;/p&gt;

&lt;h2&gt;Improving 'require' and the driver&lt;/h2&gt;

&lt;p&gt;An immediate problem presented itself when trying to compile code
that require'd other code expecting a different load path. I'm not quite
reading to start dealing with the pain (in terms of ahead-of-time, semi-statically)
compiling code that dynamically messes with &lt;code&gt;$:&lt;/code&gt;, but adding options to set the
load path, and improving/fixing some of the path issues with the current
implementation of &lt;code&gt;require&lt;/code&gt;, as well as improving the option passing in the
driver code seems like a good idea.&lt;/p&gt;

&lt;p&gt;Time to start cleaning up the driver for the compiler ever so slightly. In
&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/91aa84d&quot;&gt;91aa84d&lt;/a&gt; I started by making the driver bail out without trying to
assemble if the compilation fails, as that's been driving me crazy for a while.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/4b62af4&quot;&gt;4b62af4&lt;/a&gt; I added slightly better load/include path handling. In &lt;code&gt;driver.rb&lt;/code&gt;,
I added support for &quot;-I&quot; to indicate the initial include path (we do not support
&lt;code&gt;$:&lt;/code&gt; etc. yet). That is supported in &lt;code&gt;parser.rb&lt;/code&gt; by quite straight forward code to
mangle the paths and identify the actual files as needed, and to ensure the core
library still loads.&lt;/p&gt;

&lt;h3&gt;Improving nested symbol resolution&lt;/h3&gt;

&lt;p&gt;What was revealed once I added the above, was that I took too many shortcuts
for resolving &lt;code&gt;Foo::Bar&lt;/code&gt; back in part 41:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;199&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`compile_deref': Unable to resolve: Scanner::ScannerString statically (FIXME) (RuntimeError)
    from ./compiler.rb:540:in `&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'
    from ./compiler.rb:114:in `get_arg'&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;370&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`compile_eval_arg'

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We're going to attack this first by improving the debugging of symbol table
content.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a8b23a9&quot;&gt;a8b23a9&lt;/a&gt; I added the &lt;code&gt;--dumpsymtab&lt;/code&gt; option, which makes use of new
&lt;code&gt;#dump&lt;/code&gt; methods added to &lt;code&gt;Scope&lt;/code&gt; with specializations for &lt;code&gt;GlobalScope&lt;/code&gt;
and &lt;code&gt;ClassScope&lt;/code&gt; in &lt;code&gt;debugscope.rb&lt;/code&gt;, which recursively processes the
symbol table.&lt;/p&gt;

&lt;p&gt;What that that revealed was the result of the ugly shortcut of conflating
the low level output of assembler level symbols with Ruby-level constant
nesting, as a result of hacking our way through this without a detailed
up front design.&lt;/p&gt;

&lt;p&gt;Thankfully that's not all that hard to fix at this stage - we already
did the most important work with the introduction of &lt;code&gt;build_class_scopes&lt;/code&gt;
in part 41, which ensures that the right information is available - that's
what made the &lt;code&gt;--dumpsymtabs&lt;/code&gt; option easy to provide.&lt;/p&gt;

&lt;p&gt;All we need to do is to actually look up what we &lt;em&gt;should&lt;/em&gt; be looking up:
the name of the inner constant, instead of the synthetic assembly level
name, so that it is found in the scope chain instead of ending up being
forwarded all the way up to &lt;code&gt;GlobalScope&lt;/code&gt; (which still has the ugly
synthetic variable name - that needs to go eventually, and not be exposed
to Ruby).&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;ClassScope&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e4eafcc&quot;&gt;e4eafcc&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;const&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;__&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@next&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@next&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;While doing a global looking in &lt;code&gt;compiler.rb&lt;/code&gt; we'll actually look up these ugly compound names
for now, and then add them to the list (&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e4eafcc&quot;&gt;e4eafcc&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;__&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;
           &lt;span class=&quot;vi&quot;&gt;@global_constants&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Handling &quot;include&quot;&lt;/h3&gt;

&lt;p&gt;For now we're just stubbing it out, together with protected. See &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/f0dfb45&quot;&gt;f0dfb45&lt;/a&gt; which basically just
adds them without doing anything of substance...&lt;/p&gt;

&lt;h3&gt;Handling splat =&amp;gt; array conversion&lt;/h3&gt;

&lt;p&gt;Now to the big one for this round. The remaining other issues I dealt with for this part all fell
out of addressing the splat handling.&lt;/p&gt;

&lt;p&gt;This is one of the long-standing tensions between efficiency and getting required Ruby functionality.&lt;/p&gt;

&lt;p&gt;This does what you'd expect with MRI, of course:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Length:&quot;&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Members:&quot;&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But on entering &lt;code&gt;foo&lt;/code&gt; at the moment, &lt;code&gt;args&lt;/code&gt; is a c-style array. It works if we dip into the s-expression syntax:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Length:&quot;&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;%s(callm self puts ((__get_fixnum numargs)))&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Members:&quot;&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;%s(callm self puts ((index args 0)))&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;%s(callm self puts ((index args 1)))&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;%s(callm self puts ((index args 2)))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(never mind that it outputs a length of 5 - that reflects &lt;code&gt;self&lt;/code&gt; and space for a pointer to a block).&lt;/p&gt;

&lt;p&gt;To handle this, we need to add support for turning &lt;code&gt;args&lt;/code&gt; into an actual Ruby array.&lt;/p&gt;

&lt;p&gt;There's a wrinkle: So far we've used this as a shortcut for quickly pushing
members onto the call stack if we subsequently turn around and call another
method with it. Either we need to continue supporting that (it will be
sufficient if the second example above still works, but there are
other alternatives)&lt;/p&gt;

&lt;p&gt;One solution is to allocate arguments in a Ruby array, but that has terrible
overhead, and complicates interoperability with C. Another is to allocate a
Ruby Array in the method, optionally using some method to determine if the
array is likely to be used.&lt;/p&gt;

&lt;p&gt;For now, I have chosen to add code in the method to convert splat arguments
to a real Ruby array, and to take the pain of rewriting code that used
index/numargs on splat arguments.&lt;/p&gt;

&lt;p&gt;A problem which instantly materialize is that calling &lt;code&gt;Class#new&lt;/code&gt; &lt;strong&gt;can not&lt;/strong&gt;
directly or indirectly require calls to &lt;code&gt;Class#new&lt;/code&gt; in order to complete. If
it does, we get infinite recursion, obviously (or rather, recursion until we
run out of stack).&lt;/p&gt;

&lt;p&gt;Unfortunately this is tricky: &lt;code&gt;Class#new&lt;/code&gt; currently uses a splat argument,
which in the most obvious naive implementation of turning splat arguments into
a real Ruby Array itself triggers a &lt;code&gt;Class#new&lt;/code&gt; call (in the form of &lt;code&gt;Array.new&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;&lt;code&gt;Array#initialize&lt;/code&gt; further assigns &lt;code&gt;Fixnum&lt;/code&gt;'a to instance variables, and this
too triggers &lt;code&gt;Class#new&lt;/code&gt; to instantiate said &lt;code&gt;Fixnum&lt;/code&gt;'s.&lt;/p&gt;

&lt;p&gt;We either needs to shortcircuit this in the case of an empty splat array, and
add a way of constructing  an empty &lt;code&gt;Array&lt;/code&gt;, or find some other way of short-circuiting
this recursion.&lt;/p&gt;

&lt;p&gt;(We're going to deal with the fallout of figuring out a more reasonable
ordering of the bootstrapping of the core classes for some time to come).&lt;/p&gt;

&lt;h3&gt;Let's look at the code&lt;/h3&gt;

&lt;p&gt;You'll find this entire change in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/d9ac43d75&quot;&gt;d9ac43d75&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm not going to go over every tiny little bit, but let's examine the most
important pieces.&lt;/p&gt;

&lt;p&gt;First of all, this is a bit on the sidelines, but a major reason to
complete the splat support was to handle literal arrays. There's now a new
method &lt;code&gt;Compiler#compile_array&lt;/code&gt; to handle that simply by turning them into
&lt;code&gt;Array[]&lt;/code&gt; calls:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Compile a literal Array initalization&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# FIXME: An alternative is another &quot;transform&quot; step&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;initializers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                      &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:[]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initializers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                      &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Next, in &lt;code&gt;transform.rb&lt;/code&gt; the work starts by modifying methods with splat arguments.
First we rename the argument to &lt;code&gt;__splat&lt;/code&gt; (at some point I'll probably change
this to hide them from the Ruby code entirely):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;rescue&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__splat&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then we introduce a new local variable (hence the location of this transformation
rule in &lt;code&gt;rewrite_let_env&lt;/code&gt;) with the original name of the argument, and assign
the result of a call to &lt;code&gt;__splay_to_Array_&lt;/code&gt; to it:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;rest_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;           &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__splat_to_Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;rest_func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rest_func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;One immediate thing is worth observing: We could certainly defer this call
as long as possible, to hope to avoid the conversion in e.g. cases of early return.&lt;/p&gt;

&lt;p&gt;At some point that will be worth exploring, but note also that this could/should
fall out automatically if we later add suitable optimization passes. For now
it's by far easiest to just put it at the beginning of the method.&lt;/p&gt;

&lt;p&gt;This of course means we need to implement &lt;code&gt;__splat_to_Array&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;sx&quot;&gt;%s(defun __splat_to_Array (r na)
    +   (let (splat pos data max)
    +    (assign splat (callm Array __new))
    +    (assign pos 0)
    +    (assign max (sub na 2))
    +    (callm splat __grow (max))
    +    (while (lt pos max)
    +       (do
    +          (callm splat __set (pos (index r pos)))
    +          (assign pos (add pos 1))
    +          )
    +        )
    +  splat
    +  ))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is roughly equivalent to (pseudo-Ruby):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__splat_to_Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# na is &quot;numargs&quot;; r is the c-style splat array.&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__new&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Subtract two for &quot;self&quot; and a &amp;amp;block argument we always allocate space for&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__grow&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;max&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;There are a few odd things here. For starters, we do this using the
s-expression syntax because nearly &quot;everything&quot; otherwise would potentially
trigger attempts to allocate objects, and &lt;code&gt;Class#new&lt;/code&gt; uses splats. This
also means we can't use &lt;code&gt;Class#new&lt;/code&gt;, as discussed above.&lt;/p&gt;

&lt;p&gt;So I've introduced &lt;code&gt;Class#__new&lt;/code&gt; as a lower level method that you should
never-ever use in Ruby code (and which we'll find some way of hiding later).
I also had to modify &lt;code&gt;Array&lt;/code&gt; extensively to avoid even using &lt;code&gt;Fixnum&lt;/code&gt;'s,
since we're for the time being at least using objects rather than
type-tagged integers.&lt;/p&gt;

&lt;p&gt;The rest pretty much falls out of that. &lt;code&gt;Class#__new&lt;/code&gt; and &lt;code&gt;Class#__alloc&lt;/code&gt;
(used by &lt;code&gt;Class#__new&lt;/code&gt;) looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Clients that need to be able to allocate a completely clean-slate empty&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# object, should call &amp;lt;tt&amp;gt;__alloc&amp;lt;/tt&amp;gt;.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__alloc&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign ob (__array @instance_size))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign (index ob 0) self)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
     
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Clients that want to be able to create and initialize a basic version of&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# an object without normal initializtion should call &amp;lt;tt&amp;gt;__new&amp;lt;/tt&amp;gt;. See&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# &amp;lt;tt&amp;gt;__splat_to_array&amp;lt;/tt&amp;gt;&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__new&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__alloc&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__initialize&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;These should be pretty self-explanatory. Note that the new &lt;code&gt;Class#new&lt;/code&gt; calls &lt;code&gt;__alloc&lt;/code&gt;, but &lt;em&gt;not&lt;/em&gt; &lt;code&gt;__initialize&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A &lt;em&gt;very&lt;/em&gt; basic initial version of &lt;code&gt;Array&lt;/code&gt; is now first introduced in &lt;code&gt;lib/core/core.rb&lt;/code&gt;. It needs to be introduced
that early for bootstrapping reasons, since it needs to exist when &lt;code&gt;Class#new&lt;/code&gt; is first called. This showcases
&lt;code&gt;__initialize&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Array&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# __get_fixum should technically be safe to call, but lets not tempt fate&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# NOTE: The order of these is important, as it is relied on elsewhere&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__initialize&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign @len 0)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign @ptr 0)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign @capacity 0)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#FIXME: Private; Used by splat handling&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__len&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@len&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__ptr&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@ptr&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And here's &lt;code&gt;__grow&lt;/code&gt; that's used internally to ensure the &lt;code&gt;Array&lt;/code&gt; is big enough. Normally it should not be called
directly, but we make an exception for the splat code:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__grow&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newlen&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: This is just a guestimate of a reasonable rule for&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# growing. Too rapid growth and it wastes memory; to slow and&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# it is, well, slow to append to.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: This called __get_fixnum, which means it fails when called&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# from __new_empty. May want to create new method to handle the whol&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# basic nasty splat allocation&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# @capacity = (newlen * 4 / 3) + 4&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign @capacity (add (div (mul newlen 4) 3) 4))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if (ne @ptr 0)
    +         (assign @ptr (realloc @ptr (mul @capacity 4)))
    +         (assign @ptr (malloc (mul @capacity 4)))
    +         )&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And &lt;code&gt;__set&lt;/code&gt; is a low level method to assign to the array and extend, that makes assumptions
we can't safely make in general (that is, it expects an expansion by at most one element at
a time. Frankly rewriting &lt;code&gt;__splat_to_Array&lt;/code&gt; to set length once and omit it here would probably
be worth it, but some other time:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#FIXME: Private. Assumes idx &amp;lt; @len &amp;amp;&amp;amp; idx &amp;gt;= 0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;idx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;obj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if (ge idx @len) (assign @len (add idx 1)))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign (index @ptr idx) obj)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Most of the rest of the changes, apart from &lt;code&gt;compile_calls.rb&lt;/code&gt;, are changes to the library
code (particularly &lt;code&gt;Array&lt;/code&gt; to accommodate the splat handling changes and/or take advantage of
them). &lt;code&gt;compile_calls.rb&lt;/code&gt;, though has seen a huge rewrite. Rather than go through the diff,
it's easier to walk through the new version.&lt;/p&gt;

&lt;p&gt;Both method and our &quot;c-level&quot; function calls now use the same method-chanin to push arguments onto
the stack. It starts with this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;caller_save&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;detect&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:splat&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;compile_args_nosplat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;compile_args_splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &quot;nosplat&quot; case is simple, and pretty much what
we used to do:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_args_nosplat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The tricky bit is the splat handling, which I'm by no
means happy with, and it will probably need significant
simplification:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_args_splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Because Ruby evaluation order is left to right,&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# we need to first figure out how much space we need on&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# the stack.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# We do that by first building up an expression that&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# adds up the static elements of the parameter list&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# and the result of retrieving 'Array#length' from&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# each splatted array.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# (FIXME: Note that we're not actually type-checking&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# what is *actually* passed)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;num_fixed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;exprlist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:splat&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# We do this, rather than Array#length, because the class may not&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# have been created yet. This *requires* Array's @len ivar to be&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# in the first ivar;&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# FIXME: should enforce this.&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;exprlist&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;num_fixed&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;num_fixed&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exprlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pop&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BEGIN Calculating argument count for splat&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;END Calculating argument count for splat; numargs is now in &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The comments in the part above hopefully speaks for itself. For e.g.
&lt;code&gt;foo(*a, b, *c)&lt;/code&gt; it basically does the equivalent of &lt;code&gt;a.length + c.length + n&lt;/code&gt;
where n is the number of non-splat arguments.&lt;/p&gt;

&lt;p&gt;Next we save the count we found, and then allocate space on the stack:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Moving stack pointer to start of argument array:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# We assume this may get borked during argument evaluation&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# esp now points to the start of the arguments; ebx holds numargs,&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# and end_of_arguments(%esp) also holds numargs&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then we start at the bottom of the allocated stack segment, and evaluate arguments and save the result, working our ways up the stack, except if we find a splat argument,
we call &lt;code&gt;compile_args_copysplat&lt;/code&gt; to take care of that:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BEGIN Pushing arguments:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# We'll use indir to put arguments onto the stack without clobbering esp:&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;BEGIN args.each do |a|&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:splat&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;compile_args_copysplat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;END args.each&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;END Pushing arguments&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then we yield to handle the actual call for various types of calls, and then adjust the stack:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Re-adjusting stack post-call:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;imull&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;That leaves &lt;code&gt;compile_args_copysplat&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# For a splat argument, push it onto the stack,&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# forwards relative to register &quot;indir&quot;.&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# FIXME: This method is almost certainly much&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# less efficient than it could be.&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_args_copysplat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SPLAT&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splatcnt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;splatcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;testl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Notice the ugliness that comes next: We need to sort-of
the case where the &lt;code&gt;Array&lt;/code&gt; class itself simply hasn't
been created yet at all (which will only &quot;work&quot; if the
splat arguments in question are not actually &lt;em&gt;used&lt;/em&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;c1&quot;&gt;# If Array class ptr has not been allocated yet:&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;je&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;I really hope there's a nicer/cleaner/faster way of
doing this, but what's driving me crazy below is the
addressing modes for x86. For m68k, you can get away
with some indirect gymnastics which makes
stuff like this far simpler:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;br&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;testl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splatcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;splatcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;je&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;br&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# x86 will be the death of me.&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(%&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;indir&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splatcnt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;I'm sure there are better ways of doing it for x86 too
(and certainly for x64; one day we'll get around to doing
a 64-bit backend).&lt;/p&gt;

&lt;h2&gt;Parting words&lt;/h2&gt;

&lt;p&gt;And that's it. This brings me to the point where the
main obvious hindrance (I'm sure others will pop up) is
the lack of proper support for &lt;code&gt;send&lt;/code&gt;, and so that
is what I'll cover in part 45.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Tue, 17 Mar 2015 00:35:00 +0000</pubDate>
      <dc:date>2015-03-17T00:35:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 43</title>
      <link>http://hokstad.com/compiler/43-eigenclasses</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Eigenclasses&lt;/h2&gt;

&lt;p&gt;Eigenclasses, or meta-classes in Ruby are effectively regular classes that gets &quot;injected&quot; in the inheritance
chain, but hidden when calling &lt;code&gt;#super&lt;/code&gt; and &lt;code&gt;#class&lt;/code&gt; (Ruby is sneaky like that; I'm not convinced
I like that part). For more on eigenclasses &lt;a href=&quot;http://viewsourcecode.org/why/hacking/seeingMetaclassesClearly.html&quot;&gt;there's _why's excellent old article&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Fixing this is deceptively easy, at least for the basic case. Lets get this example working first:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;baz&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;baz&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Hello world&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;def self.bar&lt;/code&gt; basically means (using the convention that &quot;#klass&quot; refers to the &lt;em&gt;real&lt;/em&gt; class of the
object, rather than whatever &lt;code&gt;#class&lt;/code&gt; returns):&lt;/p&gt;

&lt;p&gt;&quot;if self.klass is not an eigenclass, then make it one (create a new subclass of self.klass that
is marked as an eigenclass). Define &lt;code&gt;#bar&lt;/code&gt; as a method on self.klass&quot;. Note that &quot;self&quot; in this case
is the &lt;code&gt;Class&lt;/code&gt; object &lt;code&gt;Foo&lt;/code&gt;, so &lt;code&gt;Foo.klass&lt;/code&gt; will be &lt;code&gt;Class&lt;/code&gt;, and the new eigenclass that we define a method on will be a subclass of &lt;code&gt;Class&lt;/code&gt;, not a subclass of &lt;code&gt;Foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Similarly, the alternative syntax (which we'll get back to later) of &quot;class &amp;lt;&lt;self end basically means define an eigenclass for and open a scope it. doesn seem so simple now does diagrams please. first of all consider that we are currently trying to handle the case defining it is above method where need introduced not mess up object everyone else. conceptually this same as when instance. class instance after but i tested latter there likely be missing bits. let say have src=&quot;/images/gviz/dot_9d72c0be72ac8b33a59208caf7357fc1.png&quot; this:=&quot;&quot;&gt;&lt;/self&gt;&lt;/p&gt;

&lt;p&gt;(where green represents &lt;code&gt;Class&lt;/code&gt; objects)&lt;/p&gt;

&lt;p&gt;This represents this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Now we want to do the &lt;code&gt;def self.bar&lt;/code&gt; from above. The resulting objects should look like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/gviz/dot_4548754c427272e02c6a2c108c893bfd.png&quot; class=&quot;gviz&quot;&gt;&lt;/p&gt;

&lt;h3&gt;For illustration: The non-class case&lt;/h3&gt;

&lt;p&gt;Consider if we instead did:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        
        &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In that case, we'd expect &lt;code&gt;#bar&lt;/code&gt; to get defined on an Eigenclass that pops into the hierarchy like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/gviz/dot_063fc7179b0bc387e39e7ccf91bdfe6a.png&quot; class=&quot;gviz&quot;&gt;&lt;/p&gt;

&lt;p&gt;Notice how the Eigenclass for the non-class case gets introduced as the new class of the &lt;em&gt;instance&lt;/em&gt;.
The object isn't &quot;really&quot; an instance of &lt;code&gt;Foo&lt;/code&gt; any more, but an instance of the eigenclass, which
again is inherited from &lt;code&gt;Foo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Conceptually it's exactly the same. It's just a matter of which object we introduced a new method on,
and therefore which object we attached an eigenclass to.&lt;/p&gt;

&lt;p&gt;We'll not deal with this case any further in this part. We'll wrap that up later. Especially as instance
specific eigenclasses is rare (because they should be used sparingly: they are expensive, causing a
&lt;code&gt;Class&lt;/code&gt; object per object you attach methods to).&lt;/p&gt;

&lt;h3&gt;Implementation&lt;/h3&gt;

&lt;p&gt;First we get &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/51c003f&quot;&gt;51c003f&lt;/a&gt; out of the way, which simply expands the &lt;code&gt;Scope&lt;/code&gt; class slightly to forward
and provide defaults for more cases. Most of these will be made use of later.&lt;/p&gt;

&lt;p&gt;Then let's start to hook in the actual eigenclass treatment. We're now aiming for handle the
&lt;code&gt;def self.foo&lt;/code&gt; case, which the parser will deliver as &lt;code&gt;[:defm, [:self, :foo], ...]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;All of the following is in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8ad4e6f&quot;&gt;8ad4e6f&lt;/a&gt;&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_defm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;class_scope&lt;/span&gt;
     
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;compile_eigenclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:defm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;compile_eigenclass&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_eigenclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;=== Eigenclass start&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                                   &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__new_class_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;klass_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;klass_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                                  &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lscope&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_local_var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# FIXME: This uses lexical scoping, which will be wrong in some contexts.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local_name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; eigenclass&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;exps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;compile_do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_local_var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;=== Eigenclass end&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Basically, we create a new class object, save the pointer to it as a local variable temporarily,
and alias &lt;code&gt;self&lt;/code&gt;. We then assign a name to the class, and compile methods in that new context.&lt;/p&gt;

&lt;p&gt;This is all fairly similar to &lt;code&gt;compile_class&lt;/code&gt;, and there might be opportunities to combine the
two more later (and there's almost certainly holes/bugs in &lt;code&gt;compile_eigenclass&lt;/code&gt; as it stands.&lt;/p&gt;

&lt;p&gt;There's also one big inefficiency: If you define multiple methods, you get multiple eigenclasses
chained. That's ok. It's just wasteful, and potentially slow. It's easier to fix that once I
get around to adding an easier way of identifying an eigenclass.&lt;/p&gt;

&lt;p&gt;But what is the &lt;code&gt;let&lt;/code&gt; method above?&lt;/p&gt;

&lt;h3&gt;A convenience method for local variables&lt;/h3&gt;

&lt;p&gt;Basically, I needed a simple way of defining a local scope, and allocating stack space for it.
&lt;code&gt;compile_let&lt;/code&gt; did that, but only for code in tree form. So  the new &lt;code&gt;let&lt;/code&gt; is a rewrite that
extracts out that part of the code, and leaves &lt;code&gt;compile_let&lt;/code&gt; a tiny little stub:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;zip&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;lscope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LocalVarScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_regs_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_regs_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      
      &lt;span class=&quot;c1&quot;&gt;# Compiles a let expression.&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Takes the current scope, a list of variablenames as well as a list of arguments. &lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ls&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;compile_do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Before we move on to some minor supporting changes in the runtime library, there was
one bug  that slowed me down substantially I want to briefly mention:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;compile_assign&lt;/code&gt; was the only user of what at some point became a severely broken
mechanism for saving register content. With the proper register allocation there's
no excuse for it any more, and so &lt;code&gt;Emitter#save_register&lt;/code&gt; has to go. The problem
was that if you indicated a register should be saved, it didn't properly mark it
as freed up again, and so we got spurious &lt;code&gt;pushl&lt;/code&gt;'s onto the stack in positions
which meant you could push and pop values in the wrong order The replacement in
`compile_assign is sometimes less efficient, but also less broken.&lt;/p&gt;

&lt;p&gt;It also cuts some lines out of &lt;code&gt;emitter.rb&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;Runtime library changes&lt;/h3&gt;

&lt;p&gt;The bootstrapping of the object model is still a bit messy. One aspect that has been
there &quot;forever&quot; but which became more obvious when working on this part, is the chicken
and egg problem with &lt;code&gt;Class&lt;/code&gt; and &lt;code&gt;Object&lt;/code&gt;. With the support for re-opening classes,
we have the mechanism for making the situation better.&lt;/p&gt;

&lt;p&gt;This change in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1e1ce21&quot;&gt;1e1ce21&lt;/a&gt; improved by explicitly &quot;manually&quot; link &lt;code&gt;Class&lt;/code&gt; into the list
of subclasses of &lt;code&gt;Object&lt;/code&gt;. This means &lt;code&gt;Class&lt;/code&gt; will properly inherit methods of &lt;code&gt;Object&lt;/code&gt;
after all, and let us clean up &lt;code&gt;Class&lt;/code&gt; next.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# At this point we have a &quot;fixup to make as part of bootstrapping:&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#  Class was created *before* Object existed, which means it is not linked into the&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#  subclasses array. As a result, unless we do this, Class will not inherit methods&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#  that are subsquently added to Object below. This *must* be the first thing to happen&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#  in Object, before defining any methods etc:&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;sx&quot;&gt;%s(assign (index self 4) Class)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The above let us strip out the suprfluous &lt;code&gt;Class#==&lt;/code&gt; and depend on &lt;code&gt;Object#==&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/4c0c349&quot;&gt;4c0c349&lt;/a&gt;.
At the same time (and same commit) we fix &lt;code&gt;Class#to_s&lt;/code&gt; and &lt;code&gt;Class#inspect&lt;/code&gt; to use the ugly &lt;code&gt;Class#name&lt;/code&gt;. We also &quot;manually&quot; set the class of &lt;code&gt;Class&lt;/code&gt; to &lt;code&gt;Class&lt;/code&gt;, and it's name to the raw string &quot;Class&quot;&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;These changes leave us with what's needed to compile almost all of the tokenizer code
pretty much unmodified, and so we're no rapidly closing on the initial goal of compiling the s-exp
subset of the parser. We'll look at the next batch of changes for that next.&lt;/p&gt;

&lt;p&gt;However I will make a change going forwards. After part 44 or 45, rather than batching up
changes and trying to cover specific subjects, I'll be pushing out changes as soon as I
have something ready to commit, and will mention the commits I think are worth while
discussing in much shorter posts. I'll then follow it up with longer articles covering
specific areas of the compiler or larger changes more rarely as I think I have something
more worthwhile about a specific component.&lt;/p&gt;

&lt;p&gt;The main reason is that it takes a lot of effort to write these larger posts - 2-3 times as
long as actually making the changes (including time to restructure some of the commits to
make more sense for the articles), and frankly I want to make faster progress on actually
being able to &lt;em&gt;use&lt;/em&gt; the compiler.&lt;/p&gt;

&lt;p&gt;This will also simplify my git handling substantially - currently I manage two repos in
addition to my local working copies - one for my drafts, and the public one on Github.
Going forwards I'll push changes to the Github repo right away. Branches will also no
longer reflect a specific article.&lt;/p&gt;

&lt;p&gt;I hope this will lead to more interesting development rather than fewer, though recent
parts of this series have been very much a mixed bag of commits that are only related by
the what goal I've been working towards rather than what code they've touched anyway.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Mon, 02 Feb 2015 02:05:00 +0000</pubDate>
      <dc:date>2015-02-02T02:05:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 42</title>
      <link>http://hokstad.com/compiler/42-reopening-classes</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Re-opening class definitions&lt;/h2&gt;

&lt;p&gt;The main reason for handling re-opening of class-definitions at this stage, is for a simple
reason:&lt;/p&gt;

&lt;p&gt;We're going to attack eigenclasses soon, and being able to handle class re-opening makes
that a lot simpler in addition to being needed in and of itself too.&lt;/p&gt;

&lt;p&gt;Part of the reason is that I made the choice way back &lt;a href=&quot;/writing-a-compiler-in-ruby-bottom-up-step-19&quot;&gt;in part 19&lt;/a&gt; to use
&lt;a href=&quot;http://en.wikipedia.org/wiki/Virtual_method_table&quot;&gt;vtables&lt;/a&gt; as the basic method for dispatch, and
while vtables make for fast method calls, there's extra book-keeping required if we allow
re-defining a method, which Ruby of course does.&lt;/p&gt;

&lt;p&gt;But how does that affect eigenclasses?&lt;/p&gt;

&lt;h3&gt;A quick refresher on vtables, and how this fits with Ruby&lt;/h3&gt;

&lt;p&gt;As you may or may not remember, this involves an array in the class object with a pointer to
each method. This is what an instance, and its class (which is itself an instance of &lt;code&gt;Class&lt;/code&gt;)
looks like today:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/gviz/dot_57b99232074718f66a67cf5e70fde71e.png&quot; class=&quot;gviz&quot;&gt;&lt;/p&gt;

&lt;p&gt;(the left column represents the &quot;slot&quot; in the object structure. With our current 32-bit
backend, this is a multiple of 4 bytes offset from the start of the structure)&lt;/p&gt;

&lt;p&gt;This is the standard approach for virtual method dispatch in languages like C++. There it is
easier than in Ruby for a few reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;The class hierarchies are rarely as deep, since they're not all rooted in a
single class (&lt;code&gt;Object&lt;/code&gt; previously, these days &lt;code&gt;BasicObject&lt;/code&gt;). Furthermore, not all methods are virtual,
and member functions that are not virtual do not typically get vtable slots.
This substantially reduces the likely maximum size of the vtables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You're not expected to be able to safely call any method on any object. If you do stupid
stuff like statically casting objects to incompatible types, your application will crash
when you call the wrong methods on it. But in Ruby, that's expected to be &quot;safe&quot; (as in,
the worst case is a &lt;code&gt;method_missing&lt;/code&gt;. This means a vtable in C++ only needs to contain
space for virtual member functions up to and including the current class. New ones added
in sub-classes does not impact the size.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You're not expected to be able to re-open classes and make further definitions, and
certainly not allowed to define the same method multiple times for the same class (with
the result of overwriting past versions)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It's this last one that makes re-opening classes and Eigenclasses tangled up for us. Consider
these two variants:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Here self == Foo&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# Here self == Foo's eigenclass&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Here self == Foo again&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
       
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
       
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;While in the latter case it's not as explicit, in both cases we're handling first class &lt;code&gt;Foo&lt;/code&gt;,
then opening &lt;code&gt;Foo&lt;/code&gt;'s eigenclass, then handling class &lt;code&gt;Foo&lt;/code&gt; again. While we can optimize
away some cruft here later, to merge processing of adjacent definitions (so that e.g. defining
&lt;code&gt;self.foo&lt;/code&gt; and &lt;code&gt;self.bar&lt;/code&gt; right after each other maintains the same scope), that's extra
complexity that does not solve the wider issue.&lt;/p&gt;

&lt;h3&gt;Re-opening classes with vtables&lt;/h3&gt;

&lt;p&gt;There is one obvious issue with trying to re-open a class with vtables: What about sub-classes?&lt;/p&gt;

&lt;p&gt;Consider our earlier example fleshed out a bit more:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/gviz/dot_9807d27d7cc497715b7f69eb2217361f.png&quot; class=&quot;gviz&quot;&gt;&lt;/p&gt;

&lt;p&gt;What do we now have to do if we want to override, say, vtable slot 2 in &lt;code&gt;Foo&lt;/code&gt;? Well, that depends on &lt;code&gt;Bar&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;Bar&lt;/code&gt; has overridden vtable slot 2, then we just update &lt;code&gt;Foo&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;Bar&lt;/code&gt; has &lt;strong&gt;not&lt;/strong&gt; overridden vtable slot 2, then we need to update &lt;code&gt;Foo&lt;/code&gt; &lt;strong&gt;and&lt;/strong&gt; &lt;code&gt;Bar&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;So we need to expand the &lt;code&gt;Class&lt;/code&gt; instance variables to let us find the sub-classes of any given class. As an example, I've added in a &lt;code&gt;Baz&lt;/code&gt; class which is a second subclass of Foo. So this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    
        &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        
        &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Baz&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        
        &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;turns into this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/images/gviz/dot_847d963c262048e2847fbf376872faf1.png&quot; class=&quot;gviz&quot;&gt;&lt;/p&gt;

&lt;p&gt;This leaves us with these steps to set a vtable slot:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does this class have sub-classes?&lt;/li&gt;
&lt;li&gt;If yes

&lt;ul&gt;
&lt;li&gt;Find the current vtable entry for the current class, lets call it &quot;cur&quot;, and the new entry &quot;new&quot;, and the vtable slot entry &quot;slot&quot;&lt;/li&gt;
&lt;li&gt;For each subclass &quot;c&quot;:

&lt;ul&gt;
&lt;li&gt;if c[slot] == cur (the slot has not been overridden)

&lt;ul&gt;
&lt;li&gt;Recurse and check all subclasses of &quot;c&quot;.&lt;/li&gt;
&lt;li&gt;Set c[slot] = new&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;if c[slot] != cur

&lt;ul&gt;
&lt;li&gt;the slot has been overridden, so we don't do anything else for this class&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Override the current slot for this class&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;(Instead of using a pointer to the first subclass, and a chained linked list like this, we could use a hash table or array, and we might very well
do that at some point, but not now).&lt;/p&gt;

&lt;h3&gt;Test case&lt;/h3&gt;

&lt;p&gt;I've added a test case in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/02021ad&quot;&gt;02021ad&lt;/a&gt; which simply exercises the basic scenarios by creating a class and two sub-classes - one for which a method is
overridden - and then re-opens the base class and overrides one of the original methods.&lt;/p&gt;

&lt;h3&gt;Globals&lt;/h3&gt;

&lt;p&gt;One of the first things to overhaul is the method I introduced way back at the start of this series to keep track of &lt;em&gt;functions&lt;/em&gt; we want to output.&lt;/p&gt;

&lt;p&gt;While Ruby does not have functions, we turn every method we find statically into something that looks much more like a function, and name it
in a reasonably human-friendly way in part to make it easier to debug the assembler output.&lt;/p&gt;

&lt;p&gt;You can check out most of this (all of the handful of lines) yourself, apart from the new &lt;code&gt;globals.rb&lt;/code&gt; which contains the meat in this method (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b88a31b&quot;&gt;b88a31b&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# Returns the actual name&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@global_functions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;__&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;suffix&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# add the method to the global list of functions defined so far&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# with its &quot;munged&quot; name.&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@global_functions&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;function&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fname&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;All this does is append __&lt;some number&gt; to a desired global function name and return the (possibly munged)
name.&lt;/p&gt;

&lt;p&gt;The reason we need to do this is that we now of course can have &lt;em&gt;multiple&lt;/em&gt; &lt;code&gt;Foo#bar&lt;/code&gt; methods at various
stages of the execution.&lt;/p&gt;

&lt;h3&gt;New class object vs. re-opening&lt;/h3&gt;

&lt;p&gt;I also snuck in another minor change in the preceding commit (&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b88a31b&quot;&gt;b88a31b&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;To allow re-opening classes, we need to not blindly create new class objects as we did before (though we're still assuming the class and its name
is/was possible to determine statically. This is the change, which basically wraps an if check around the old version:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__new_class_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;klass_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ssize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                             &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]],&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                             &lt;span class=&quot;c1&quot;&gt;# then&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                             &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                              &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__new_class_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;klass_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ssize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                             &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                            &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Updating the class objects / vtable&lt;/h3&gt;

&lt;p&gt;Next up we assign two extra instance variable slots in the class objects:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# slot 4 is reserved for subclasses&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# slot 5 is reserved for next_sibling&lt;/span&gt;
      &lt;span class=&quot;no&quot;&gt;CLASS_IVAR_NUM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You'll find the remaining bits in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/4733be0&quot;&gt;4733be0&lt;/a&gt;, and we'll look at &lt;code&gt;lib/core/class.rb&lt;/code&gt; in more detail.&lt;/p&gt;

&lt;p&gt;Firstly, this part of &lt;code&gt;__new_class_object&lt;/code&gt; is new:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;c1&quot;&gt;# Sub-classes&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eq&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Link in as subclass:&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Basically it simply links this class into the list of sub-classes for it's superclass, by
prepending it to the head.&lt;/p&gt;

&lt;p&gt;The more interesting bit is &lt;code&gt;__set_vtable&lt;/code&gt;. This was previously the over-simplistic:&lt;/p&gt;

&lt;pre class=&quot;clj codehilite&quot;&gt;&lt;code&gt;
&lt;span class=&quot;w&quot;&gt;    &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;%s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defun&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__set_vtable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;vtable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;assign&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
      &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Now it looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(defun __set_vtable (vtable off ptr)
       (let (p)
        (assign p (index vtable 4))
        (while (sexp p)
           (do
              (if (eq (index p off) (index vtable off)) (__set_vtable p off ptr))
              (assign p (index p 5))
           )
        )
      (assign (index vtable off) ptr)
    ))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This boils down to this &quot;pseudo-Ruby&quot; which follows the algorithm sketched out earlier:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subclasses&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__set_vtable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;next_sibling&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
       &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ptr&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And that's it!&lt;/p&gt;

&lt;p&gt;Next up: Eigenclasses.
&lt;/some&gt;&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Sun, 07 Dec 2014 02:00:00 +0000</pubDate>
      <dc:date>2014-12-07T02:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 41</title>
      <link>http://hokstad.com/compiler/41-further-steps-towards-self-hosting</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Messy further steps towards self-hosting&lt;/h2&gt;

&lt;p&gt;This part is going to be a hodge-podge of changes, as I walk through a good chunk of changes needed to
prepare to compile the tokenization code in &lt;code&gt;tokenizer.rb&lt;/code&gt;, and improves what we can handle from &lt;code&gt;scanner.rb&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I'm going to start by briefly talking about this commit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; [part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/d0ee180&quot;&gt;d0ee180&lt;/a&gt;] Refactoring of tokenizer&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This commit breaks &lt;code&gt;tokenizer.rb&lt;/code&gt; into several separate files. And that was the starting point for this
part. To identify what I had to do, I broke apart the &lt;code&gt;Tokenizer&lt;/code&gt; module, and wrote a few small scripts
to see what compiled, and what crashed. E.g:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'selfhost/atom'&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'selfhost/scanner'&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Scanner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Tokens&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(I haven't checked in the &quot;selfhost&quot; directory - the files there are mostly like the broken up &lt;code&gt;tokenizer.rb&lt;/code&gt;)&lt;/p&gt;

&lt;p&gt;The purpose was to tweak the classes however much I needed to compile them, then fix or tweak until
I got them mostly working, based on whatever errors I run into.&lt;/p&gt;

&lt;p&gt;The purpose of this is of course to get one step closer to the first big &quot;selfhosting&quot; goal of being
able to run the s-expression parser.&lt;/p&gt;

&lt;p&gt;Rather than following the entire process, which was simple yet tedious, I'll walk through the most
important commits, and simply list the others.&lt;/p&gt;

&lt;h2&gt;A number of minor tweaks&lt;/h2&gt;

&lt;p&gt;I'm going to skip over these, other than mentioning the commits. They are all important, but trivial.
If you have any questions about them, I'm happy to answer comments:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8fe7103&quot;&gt;8fe7103&lt;/a&gt;] Add FalseClass#to_s&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/79d39f4&quot;&gt;79d39f4&lt;/a&gt;] Add TrueClass#to_s&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e31a44e&quot;&gt;e31a44e&lt;/a&gt;] Added first stab at NilClass#==&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/814b520&quot;&gt;814b520&lt;/a&gt;] Naive / incomplete (base 10 only) version of String#to_i&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/2f8ecb7&quot;&gt;2f8ecb7&lt;/a&gt;] Absent #is_a? etc., adding explicit nil check in Fixnum#== as a temporary hack to get the parser closer to self-hosted&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7ae9623&quot;&gt;7ae9623&lt;/a&gt;] Replace += with &amp;lt;&amp;lt; in tokenizer and scanner; partly because it may be more efficient, partly because it removes an obstacle to self-hosting&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/6f1c5a1&quot;&gt;6f1c5a1&lt;/a&gt;] Let get_arg transparently convert true/false to :true, :false&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7429885&quot;&gt;7429885&lt;/a&gt;] Fixed handling of quoted strings in asm output&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/72d255e&quot;&gt;72d255e&lt;/a&gt;] Prevent 'require' loops by 'registering' the required file as empty at the outset&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/ffda923&quot;&gt;ffda923&lt;/a&gt;] Added String#+&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a1af1fb&quot;&gt;a1af1fb&lt;/a&gt;] Assume :assign outside %s() returns an object&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Valid return addresses for empty methods&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7b4cf91&quot;&gt;7b4cf91&lt;/a&gt;] Ensure a valid return value for empty method (caused String#to_i to seg fault)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Until now, if a method did not specify a return value, we'd leave garbage in &lt;code&gt;%eax&lt;/code&gt;. Ruby does in fact
require &lt;code&gt;nil&lt;/code&gt; to be returned in most instances where there's not a sane last expression value to depend
on.&lt;/p&gt;

&lt;h2&gt;The case of the argumentative not operator&lt;/h2&gt;

&lt;p&gt;For a while I was baffled at why the not-operator methods required an extra argument, and used
workarounds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e2f6b37&quot;&gt;e2f6b37&lt;/a&gt;] Another workaround for not operator requiring arguments&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/d734bb4&quot;&gt;d734bb4&lt;/a&gt;] Added dummy/trivial not operator for String&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here I fixed it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1d54cec&quot;&gt;1d54cec&lt;/a&gt;] Fix situation where not operator methods needed an argument&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The specific line that fixes it was this from &lt;code&gt;transform.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
         &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Previously this was done unconditionally, which meant that if e[2] was already an empty array, we
wrapped it in another array and unintentionally gave a method call an extra, though invalid, argument.&lt;/p&gt;

&lt;h2&gt;Range class&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a18cdef&quot;&gt;a18cdef&lt;/a&gt;] Add first trivial version of Range class + rewrite :range nodes in AST to Range.new(...)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The tokenizer classes relies on ranges in a number of locations. This commit takes a first tiny stab at
a basic version of the Range class, and also adds support for literal ranges (1..5), through this bit added to &lt;code&gt;transform.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rewrite_range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;depth_first&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:range&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:Range&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;ss&quot;&gt;:next&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Quirks of parsing Ruby&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/dbfe020&quot;&gt;dbfe020&lt;/a&gt;] Function/method calls with arguments inside () or without parentheses have different needs for the priority of the call operator; we need to push a variation with a different priority onto the operator stack if we detect a method call without an opening parenthesis (caveat: Ruby has rules regarding whitespace here too, that I believe we're currently &lt;em&gt;not&lt;/em&gt; taking into account)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;What this is talking about (unfortunately the commit is really messy and includes unrelated whitespace and documentation changes etc - I was sloppy; sorry about that), is for example the difference between these expressions:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;45&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Prior to this change, these were handled differently. The synthetic &quot;call&quot; operator used by the shunting
yard parser needs a high priority to bind tightly to the function arguments. But in the absence of parentheses, this means it bound too tightly to the tokens immediately following, so that the latter example above would be treated as &lt;code&gt;foo(45) + 5&lt;/code&gt; because the call operator was given higher precedence than &lt;code&gt;+&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This was resolved by introducing a second call operator, and in the instance where we are handling functions without a leading parenthesis, that operator (with much lower priority) is pushed onto the operator stack instead:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;possible_func&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;reduce&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ostack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;ostack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;opcall&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;     &lt;span class=&quot;n&quot;&gt;ostack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@opcall2&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Correctly compiling &quot;||&quot;&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/456a989&quot;&gt;456a989&lt;/a&gt;] Improved comments / label names for #compile_if and fixed rather broken 'or' logic&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/c288585&quot;&gt;c288585&lt;/a&gt;] Rewrite compile_or to deal properly with shortcut logic, and in process do slight refactor to split out common functionality also used by compile_if and compile_while&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;As it turned out, my previous attempt at implementing &lt;code&gt;||&lt;/code&gt; was completely broken. I don't know what
I was thinking. All evidence is that I was not.&lt;/p&gt;

&lt;p&gt;The original &quot;||&quot; implementation basically turned &lt;code&gt;&amp;lt;left&amp;gt; || &amp;lt;right&amp;gt;&lt;/code&gt; into &lt;code&gt;if &amp;lt;left&amp;gt;; false; else &amp;lt;right&amp;gt;; end&lt;/code&gt;. Which sort-of works, except it discards the result from &lt;code&gt;&amp;lt;left&amp;gt;&lt;/code&gt;, which obviously isn't
acceptable.&lt;/p&gt;

&lt;p&gt;The first commit above improves that every so slightly by changing the implementation into the equivalent of this pseudo code:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;n&quot;&gt;__left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__left&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;__left&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
         &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But that really was not a very satisfying solution. So the next commit changes it drastically, and
also refactors &lt;code&gt;#compile_if&lt;/code&gt; and &lt;code&gt;#compile_while&lt;/code&gt;, and at the same time takes a stab at handling
our minimal static typing in a reasonable way. Here's how &lt;code&gt;#compile_or&lt;/code&gt; changed:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;compile_or: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; || &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: Eek. need to make sure variables are assigned for these. Turn it into a rewrite?&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;l_or&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_or&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_jmp_on_false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l_or&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;l_end_or&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;_end_or&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_end_or&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.. or:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_or&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;or_ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_end_or&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_all&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;combine_types&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;or_ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Which does roughly this, as pseudo-code:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_or&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;goto&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_end_or&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;_or:
        &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;_end_or:

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;You'll note this is not optimal, we can improve on it by adding code to avoid one of the branches,
but this was a decent shortcut to let it still share code with &lt;code&gt;#compile_if&lt;/code&gt; and &lt;code&gt;#compile_while&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#compile_jmp_on_false&lt;/code&gt; and &lt;code&gt;#combine_types&lt;/code&gt; are worth a quick look. &lt;code&gt;#compile_jmp_on_false&lt;/code&gt; extracts
part of &lt;code&gt;#compile_if&lt;/code&gt; as follows:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_jmp_on_false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:object&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nil&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;je&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;je&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp_on_false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;target&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;As you can see, the main reason it has been given its own method is to handle the case where we
check the truthyness of an object.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#combine_types&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;combine_types&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This was also extracted from &lt;code&gt;#compile_if&lt;/code&gt;, and is responsible for ensuring the weaken the type
information. Which is the fancy way of saying that if the type of the left hand expression matches
that of the right hand expression, we return that type. Otherwise, we return &quot;nil&quot; in the type field,
which in our current incarnation means &quot;we have no clue, this could be anything&quot; which means we
won't take any object-specific action elsewhere.&lt;/p&gt;

&lt;h2&gt;Resolving Foo::Bar&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt; [part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/3a7e275&quot;&gt;3a7e275&lt;/a&gt;] Add default implementations for new &lt;code&gt;Scope#add_constant&lt;/code&gt; and &lt;code&gt;Scope#find_constant&lt;/code&gt;&lt;/li&gt;
&lt;li&gt; [part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/6ceb215&quot;&gt;6ceb215&lt;/a&gt;] Turn '::' into internal operator :deref, and add machinery to pre-build scope chain and traverse it to resolve class constant names at compile time where possible&lt;/li&gt;
&lt;li&gt; [part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/960f1b0&quot;&gt;960f1b0&lt;/a&gt;] Make use of new inner classes support to bring test case closer to real Scanner implementation&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Next up we need to handle inner classes. The first step is to actually capture &lt;code&gt;Foo::Bar&lt;/code&gt; as different to &lt;code&gt;Foo.bar&lt;/code&gt;, as it was previously. We do this by introducing the internal &lt;code&gt;:deref&lt;/code&gt; operator in the parse tree in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/6ceb215&quot;&gt;6ceb215&lt;/a&gt; in &lt;code&gt;operators.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;::&quot;&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;s2&quot;&gt;&quot;::&quot;&lt;/span&gt;        &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Oper&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;100&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:deref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:infix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The next step is a major change to build a sequence of class scope objects. Consider the case where
I open a class, define a method that refers to an as yet undefined class. Then later I re-open the
class and define the earlier class as an inner class:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;hello&lt;/span&gt;
         &lt;span class=&quot;no&quot;&gt;Bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Bar&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;To handle this case, &lt;code&gt;ClassScope&lt;/code&gt; objects must persist across open/close of a class, and they do.
However, to compile this to static references, I also must identify any references and resolve them,
to be able to distinguish a possible &lt;code&gt;::Bar&lt;/code&gt; from &lt;code&gt;::Foo::Bar&lt;/code&gt; without being forced to do runtime
lookups (we still need to be able to fall back to dynamic constant lookup at some point in the future).&lt;/p&gt;

&lt;p&gt;So lets take a look at the code, in &lt;code&gt;transform.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;build_class_scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@global_scope&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;exps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:defm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ClassScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_vtable_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# add method into vtable of class-scope to associate with class&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;depth_first&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;              &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_ivar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?@&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Firstly, above, we deal with method definitions, by identifying instance variables that are plainly mentioned (we still don't support dynamically generated ivars).&lt;/p&gt;

&lt;p&gt;Then this bit was extracted from &lt;code&gt;compile_class&lt;/code&gt; as we may as well allocate these earlier:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:attr_accessor&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# This is a bit presumptious, assuming noone are stupid enough to overload&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# attr_accessor, attr_reader without making them do more or less the same thing.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# but the right thing to do is actually to call the method.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# In any case there is no actual harm in allocating the vtable&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# entry.`&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# We may do a quick temporary hack to synthesize the methods,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# though, as otherwise we need to implement the full define_method&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# etc.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_vtable_entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;entry&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And then we handle the case of the &lt;code&gt;class&lt;/code&gt; or &lt;code&gt;module&lt;/code&gt; blocks themselves, by creating the
&lt;code&gt;ClassScope&lt;/code&gt; objects that will hold the scope information, and recursing, as well as finally
recursing for all other AST node types:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:class&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:module&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;superc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ClassScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@vtableoffsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@global_scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;add_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;build_class_scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;build_class_scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And at the top level in &lt;code&gt;transform.rb&lt;/code&gt; we hook this step in early, starting by initializing the
&lt;code&gt;GlobalScope&lt;/code&gt; object, so we have something to hook the class scopes into:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;preprocess&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# The global scope is needed for some rewrites&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@global_scope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GlobalScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@vtableoffsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;build_class_scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;There are a number of smaller supporting changes, but lets just look at &lt;code&gt;compile_deref&lt;/code&gt; that
handles the new internal &lt;code&gt;:deref&lt;/code&gt; node as a starting point:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_deref&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Unable to resolve: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; statically (FIXME)&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ClassScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This simply delegates to the new &lt;code&gt;find_constant&lt;/code&gt; methods in the scope classes, which for &lt;code&gt;ClassScope&lt;/code&gt;
recurses and builds a multi-level class name (e.g. &lt;code&gt;Foo__Bar&lt;/code&gt;) - in &lt;code&gt;classcope.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;find_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;const&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@next&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;find_constant&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;__&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@next&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Rewriting :incr&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b3edea5&quot;&gt;b3edea5&lt;/a&gt;] Rewrite :incr internal operator into += method call&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;There's not much to say about this. The whole change simply adds a small bit to &lt;code&gt;treeoutput.rb&lt;/code&gt;
that on coming across &lt;code&gt;[:incr, :foo]&lt;/code&gt; insteads translates it into &lt;code&gt;[:callm, :foo, :&quot;+&quot;, right hand expression&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;is_a?&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e19a85d&quot;&gt;e19a85d&lt;/a&gt;] Support for #is_a?; also needed to add default Object#==, since comparison of object references is used in the #is_a? implementation&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This implements a very basic &lt;code&gt;#is_a?&lt;/code&gt; implementation that simply loops up the &lt;code&gt;superclass&lt;/code&gt; chain.&lt;/p&gt;

&lt;p&gt;It required the implementation itself, but also adding a basic &lt;code&gt;Object#==&lt;/code&gt; that does pointer based
comparison, and &lt;code&gt;Class#superclass&lt;/code&gt; itself.&lt;/p&gt;

&lt;h2&gt;attr_reader / accessor / writer&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt; [part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/af00ab3&quot;&gt;af00ab3&lt;/a&gt;] Filter out leading nil's where E[node.position, ....] is called and node does not have a position set&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The above is a one-liner that helps debugging by ensuring the position doesn't get accidentally set to nil.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; [part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/ee85225&quot;&gt;ee85225&lt;/a&gt;] Quick and dirty attr_accessor / attr_reader / attr_writer implementation and minor bug fix (array index e[1] =&amp;gt; e[2])&lt;/li&gt;
&lt;li&gt; [part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/83f0333&quot;&gt;83f0333&lt;/a&gt;] Made use of attr_reader / writer / accessor, and fixed += operator to bring test Scanner version closer in line with the real Scanner&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;A while back I was holding back on this awaiting a full &lt;code&gt;define_method&lt;/code&gt; implementation, so I could do this in pure Ruby, but since I pulled back on that, it's time for a simple implementation since it helps actually get closer to compile the unmodified scanner. The bulk of is this in &lt;code&gt;transform.rb&lt;/code&gt;,  which simply injects one or two method definitions:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# Then let's do the quick hack:&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;syms&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;slice!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;syms&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mname&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;mname&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:attr_reader&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:attr_accessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;              &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:defm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mname&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:attr_writer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:attr_accessor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;              &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:defm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mname&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;@&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mname&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Refactoring&lt;/h3&gt;

&lt;p&gt;I won't comment further on these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/0084643&quot;&gt;0084643&lt;/a&gt;] Refactored *Scope classes into separate files&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/d9d9d2b&quot;&gt;d9d9d2b&lt;/a&gt;] Refactoring: Split compiler driver out into separate file&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7fe231b&quot;&gt;7fe231b&lt;/a&gt;] Refactored out code related to compiling function and method calls&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/2da30b5&quot;&gt;2da30b5&lt;/a&gt;] Refactoring&lt;/li&gt;
&lt;li&gt;[part-41 &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/083d0b5&quot;&gt;083d0b5&lt;/a&gt;] Additional refactoring&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;Next steps&lt;/h2&gt;

&lt;p&gt;My current plans (subject to changes):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Part 42 will cover re-opening classes&lt;/li&gt;
&lt;li&gt;Part 43 will cover Eigenclasses.&lt;/li&gt;
&lt;li&gt;Part 44 will wrap up a few niggling issues with compiling the tokenization code, such as named block arguments (&amp;amp;block), possibly Struct, and any other small issues required for self-hosting&lt;/li&gt;
&lt;li&gt;Part 45 will start to attack ParserBase. The most likely subject is &lt;code&gt;#send&lt;/code&gt; and according method lookup
machinery (this also affects the main &lt;code&gt;Compiler&lt;/code&gt; class). There's also the issue of exceptions, though I'm unsure if I want to deal with that yet, as well as &lt;code&gt;#include&lt;/code&gt;'ing modules.&lt;/li&gt;
&lt;li&gt;Part 46-50 - by this point I expect to wrap up self-hosting of the s-expression parser, and start attacking the operator precedence parser. At this point we should have gotten rid of the worst hindrances for full self-hosting, ad I hope to get there by part 50.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;These may be hopelessly optimistic:&lt;/p&gt;

&lt;h3&gt;Parts 51-60 or so:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Parse (possibly not correctly) all of Rubyspec.&lt;/li&gt;
&lt;li&gt;Run mspec (for Rubyspec)&lt;/li&gt;
&lt;li&gt;Case studies of compiling (and fixing issues with) specific applications.&lt;/li&gt;
&lt;li&gt;Yanking out &quot;gas&quot; and generate asm opcodes directly. JIT to support &lt;code&gt;eval()&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Refactoring towards better support for retargeting to another backend&lt;/li&gt;
&lt;li&gt;Start on an x86-64 backend&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Part 61-70 or so:&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Optimization and re-targeting&lt;/li&gt;
&lt;li&gt;Rubyspec compliance&lt;/li&gt;
&lt;li&gt;A &quot;review&quot;/revisit of the major components
&lt;/left&gt;&lt;/right&gt;&lt;/left&gt;&lt;/right&gt;&lt;/left&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Wed, 12 Nov 2014 01:00:00 +0000</pubDate>
      <dc:date>2014-11-12T01:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 40</title>
      <link>http://hokstad.com/compiler/40-untangling-expect</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Untangling Expect&lt;/h2&gt;

&lt;p&gt;Next up in my attempt to self-host parts of the parser, is &lt;code&gt;Scanner#expect&lt;/code&gt;.
This was no fun, and this part again recounts a long string of attempts at
addressing relatively small annoying issues that will seem disjoint and
probably confusing, but possibly useful in showing some of the debugging
approaches.&lt;/p&gt;

&lt;h3&gt;Diving in&lt;/h3&gt;

&lt;p&gt;The immediate problem with &lt;code&gt;Scanner#expect&lt;/code&gt; is this curious line:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Tokens&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Keyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;It calls into &lt;code&gt;Tokens::Keyword&lt;/code&gt; for no obvious reason. Because when we
dig into &lt;code&gt;Tokens::Keyword&lt;/code&gt;, we find that &lt;code&gt;Tokens::Keyword.expect&lt;/code&gt; simply
calls &lt;code&gt;Atom.expect&lt;/code&gt; and compares the result with what it got passed in.&lt;/p&gt;

&lt;p&gt;So in our case, the only result of going that route, instead of falling
through to the rest of &lt;code&gt;Scanner#expect&lt;/code&gt; is basically to turn the
expected string into a &lt;code&gt;Symbol&lt;/code&gt; on returning it.&lt;/p&gt;

&lt;p&gt;Now, first of all, we don't need to call &lt;code&gt;Tokens::Keyword.expect&lt;/code&gt; for that.
I'm not quite sure why I did that. Secondly, the &quot;proper&quot; thing to do here
is to just return a &lt;code&gt;String&lt;/code&gt; anyway, or specifically a &lt;code&gt;ScannerString&lt;/code&gt;, as
that includes the &lt;em&gt;position&lt;/em&gt;, allowing for better error reporting.&lt;/p&gt;

&lt;p&gt;The only place I find that depend on a specific value returned from &lt;code&gt;expect&lt;/code&gt;
is a line that uses &lt;code&gt;ParserBase#expect&lt;/code&gt; with three symbols, which again call
&lt;code&gt;Scanner#expect&lt;/code&gt; with each in turn (I'm itching to optimize, but it's not
for now), and uses that to determine what expression to return (&lt;code&gt;:if&lt;/code&gt;,
&lt;code&gt;:while&lt;/code&gt;, or &lt;code&gt;:rescue&lt;/code&gt; nodes). But that piece of code actually calls
&lt;code&gt;#to_sym&lt;/code&gt; on the result...&lt;/p&gt;

&lt;p&gt;So, we're going to clean up &lt;code&gt;Scanner#expect&lt;/code&gt; to simply call &lt;code&gt;#to_s&lt;/code&gt; on
objects that don't respond to &lt;code&gt;#expect&lt;/code&gt;, and treat it as we do strings
in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/f190425&quot;&gt;f190425&lt;/a&gt; :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;respond_to?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Tokens&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Keyword&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ScannerString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_byte&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;102&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;103&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Scanner&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;And the problems pile up...&lt;/h2&gt;

&lt;p&gt;Firstly, our number of arguments check does not handle an explicit block argument
as optional.&lt;/p&gt;

&lt;p&gt;Comment out that for now, and I get &quot;Method missing: Symbol#==&quot; when testing &lt;code&gt;Scanner#expect&lt;/code&gt;
by calling &lt;code&gt;expect(:rescue)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I've added one in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/4292c34&quot;&gt;4292c34&lt;/a&gt; - it's trivial, just comparing the string values
This version is inefficient; part of the value of &lt;code&gt;Symbol&lt;/code&gt; in Ruby is that it does not
need to have the cost of &lt;code&gt;String&lt;/code&gt; for comparisions, but it's functionally sufficient
for now. A better way of handling it is to ensure &lt;code&gt;Symbol&lt;/code&gt; objects are unique per symbol
(so we can depend on just a pointer comparison), or at least obtain a unique id for
any given string and compare that (which would be closer to how MRI is doing it); we'll
revisit that again some day (not soon).&lt;/p&gt;

&lt;p&gt;Next up, I stub out &lt;code&gt;String#is_a?&lt;/code&gt;, since &lt;code&gt;Scanner#expect&lt;/code&gt; depends on it. I just make
it return &lt;code&gt;true&lt;/code&gt;, which will obviously cause problems later. We don't yet have
exactly what we need to implement it properly. See &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/284d493&quot;&gt;284d493&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then I ran into a segmentation fault. Some poking reveals several possible causes.&lt;/p&gt;

&lt;p&gt;One clear candidate is that &lt;code&gt;String#initialize&lt;/code&gt; by default uses a null pointer,
but that'd force us to check for null all over the place. And indeed, &lt;code&gt;String#length&lt;/code&gt;
doesn't. Rather than adding null checks all over, we fix &lt;code&gt;String#initialize&lt;/code&gt; in
&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7b5805b&quot;&gt;7b5805b&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Default nil from blocks&lt;/h3&gt;

&lt;p&gt;We also need to add &lt;em&gt;something&lt;/em&gt; to &lt;code&gt;String#reverse&lt;/code&gt; so what's returned is at
a bare minimum a viable object. The obvious answer here would be to implement it,
and we will, but first we should solve the reason this crashes:&lt;/p&gt;

&lt;p&gt;As it turns out, when we compile an empty array of expressions, we return junk:
Whatever is in &lt;code&gt;%eax&lt;/code&gt;. Thankfully this is trivial to fix the most obvious
cases of. In &lt;code&gt;Compiler#compile_do&lt;/code&gt; we do this (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/c359ea7ca&quot;&gt;c359ea7ca&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;751&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c34b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dfcd253&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;649&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;649&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
     
       &lt;span class=&quot;c1&quot;&gt;# Compiles a do-end block expression.&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;String#reverse&lt;/h3&gt;

&lt;p&gt;Great! Now we fail on &lt;code&gt;NilClass#length&lt;/code&gt; due to the empty &lt;code&gt;String#reverse&lt;/code&gt;. So lets
add a basic version. Not the most inspired, nor most Ruby-ish implementation,
but it has the benefit that it works with the current state of the compiler (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/9a363ee&quot;&gt;9a363ee&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cbba12&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d118d91&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;130&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;130&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;
     
     
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;reverse&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chr&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;buf&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;String#&amp;lt;&amp;lt;&lt;/h3&gt;

&lt;p&gt;The next error I ran into was this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;WARNING: __send__ bypassing vtable (name not statically known at compile time) not yet implemented.
WARNING:    Method: '&amp;amp;lt;6a5ffde) since we don't have support for method aliases (method aliases are actually quite
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;straight forward to implement in this case: We 'just' need to update the vtable pointers; the only
complication is that since this effectively means re-opening the class, it may have been sub-classed,
in which case we need to update the sub-classes vtables as well; we'll deal with this properly once
we &quot;have to&quot; deal with class re-opening).&lt;/p&gt;

&lt;h3&gt;String#count&lt;/h3&gt;

&lt;p&gt;The scanner uses &lt;code&gt;String.count(character)&lt;/code&gt; to count the number of instances of LF (ASCII 10) to
determine how to adjust the line number. We don't care about this for now, so I just give it
an argument that defaults to nil, and make it return 1 (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/f41af6b&quot;&gt;f41af6b&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Now my test program runs all the way through, but it doesn't do much.&lt;/p&gt;

&lt;h2&gt;Adding String#each_byte, and the fallout&lt;/h2&gt;

&lt;p&gt;The big deal is the missing &lt;code&gt;String#each_byte&lt;/code&gt; which the &lt;code&gt;Scanner&lt;/code&gt; class uses to check the stream
against each byte in the expected string. We fill in a basic version like this (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b7879ee&quot;&gt;b7879ee&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b89ae2c&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;51&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dba30&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;82&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;82&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;each_byte&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;  &lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
   
&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Boom. Back to segmentation faults. The most obvious culprit is &lt;code&gt;yield&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Replacing the &lt;code&gt;yield&lt;/code&gt; with &lt;code&gt;__closure__.call(self[i])&lt;/code&gt;, using what should eventually be a
&quot;hidden&quot; internal variable name for the block argument, we quickly run into a different
error, but one that makes it clear that &lt;code&gt;yield&lt;/code&gt; doesn't work. This is another unfortunate
regression. As it turns out we can now reduce &lt;code&gt;yield&lt;/code&gt; to this, though:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# Yield to the supplied block&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;yield&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compile_callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__closure__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But while this makes &lt;code&gt;yield&lt;/code&gt; and &lt;code&gt;__closure__.call()&lt;/code&gt; equivalent, it does not make it work
with an argument.&lt;/p&gt;

&lt;h2&gt;Splat handling, again ##&lt;/h2&gt;

&lt;p&gt;This is one of those little overcomplicated bits that badly needs to be re-thought. Basically,
whenever we come across &lt;code&gt;*rest&lt;/code&gt; in a method, we do a raw copy of it onto the stack for the
call we expect to currently be preparing for.&lt;/p&gt;

&lt;p&gt;Except &lt;code&gt;*rest&lt;/code&gt; can occur anywhere. And it can be used for things that does not refer to the
argument list from the calling function. Except that will fail horribly.&lt;/p&gt;

&lt;p&gt;Basically this is a hack that is quickly overstaying its welcome. Particularly because the
current solution is error prone. We'll give it this one last chance, before getting rid of it.&lt;/p&gt;

&lt;p&gt;There are two glaring problems with the current code: Firstly, it doesn't handle the case
where there are no arguments properly. Secondly, I actually confused the parameters provided
to the method/function being called, with the arguments provided to the method we're currently
in.&lt;/p&gt;

&lt;p&gt;This has worked, sort of, as long as the methods have sufficiently similar signatures, which
is why I haven't spotted it previously.&lt;/p&gt;

&lt;p&gt;I've fixed it like this (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/58c4373&quot;&gt;58c4373&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;65&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cf0f9&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a7c1b46&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# (needs proper register allocation)&lt;/span&gt;
                         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# &quot;reg&quot; is set to numargs - (number of non-splat arguments to the *method we're in*)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The above is the critical bit that takes the correct argument length.&lt;/p&gt;

&lt;p&gt;And this changes the loop that copies, so that we jump to the end and do the check
against the end condition &lt;em&gt;first&lt;/em&gt; to handle the case of zero arguments to copy:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;35&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
           
           &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;lc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# So we can handle the zero argument case&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;ls&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# So we can jump straight to condition&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jne&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jne&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# At this point, dest points to the position *after* the&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# splat arguments. Subtracting the stack pointer, and shifting&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# right twice gives us the number of splat arguments&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sarl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; end&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The above also depends on some minor changes to the classes in &lt;code&gt;scope.rb&lt;/code&gt;, which now have
finally gotten a shared superclass. &lt;code&gt;FuncScope&lt;/code&gt; have had a &lt;code&gt;#method&lt;/code&gt; method that returns the
&lt;code&gt;Function&lt;/code&gt; object. The change introduced &lt;code&gt;#method&lt;/code&gt; methods in all the scope classes, so that
we can get at the method in question to figure out the argument length (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/58c4373&quot;&gt;58c4373&lt;/a&gt; too)&lt;/p&gt;

&lt;p&gt;We also need to &quot;fix&quot; &lt;code&gt;compile_call&lt;/code&gt;, as we're &quot;abusing it&quot; to implement &lt;code&gt;yield&lt;/code&gt;, and it
also needs to handle splats (we are long overdue a refactoring of &lt;code&gt;compile_call&lt;/code&gt; and &lt;code&gt;compile_callm&lt;/code&gt;,
so we'll give that a gentle nudge by factoring out a tiny bit of code from it as well).&lt;/p&gt;

&lt;p&gt;Here is the change that includes invoking &lt;code&gt;handle_splat&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8b013ef15a&quot;&gt;8b013ef15a&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d77bf08&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f09da08&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;489&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;489&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Push arguments onto the stack&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;push_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# Compiles a function call.&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# Takes the current scope, the function to call as well as the arguments&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# to call the function with.&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;504&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;15&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;513&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
    
         &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;caller_save&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;handle_splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ARGS: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;; &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;push_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;scratch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
             &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Yet more is needed to make this work properly, as we did not handle arguments to &lt;code&gt;Proc#call&lt;/code&gt;
previously.&lt;/p&gt;

&lt;h2&gt;Fixing Proc&lt;/h2&gt;

&lt;p&gt;I will repeat the entirety of the &quot;new&quot; &lt;code&gt;Proc&lt;/code&gt; here, as it's not very large. The main change
is that instead of continuing to expand the &lt;code&gt;__new_proc&lt;/code&gt; function, I've followed the approach
taken in many of the other classes and added a &lt;code&gt;#__set_raw&lt;/code&gt; method, with the intent of
eventually preventing access to this method from regular Ruby.&lt;/p&gt;

&lt;p&gt;Other than that, the main difference, and the point of changing the class, is to make use of
the fixed splat support to allow arguments, and at the same time attack another problem
we'd run into shortly: &lt;code&gt;self&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &quot;old &lt;code&gt;Proc&lt;/code&gt; executed the block with &lt;code&gt;self&lt;/code&gt; bound to the instance of &lt;code&gt;Proc&lt;/code&gt; itself, which
does not work very well if the block tries to run methods on the object it was defind in.
So now we pass in the value that should be bound to &lt;code&gt;self&lt;/code&gt; as well.&lt;/p&gt;

&lt;p&gt;Also note the warning at the end of &lt;code&gt;#call&lt;/code&gt;. This has a very good reason, which will be
addressed in the next section.&lt;/p&gt;

&lt;p&gt;You can find this in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/226e24f&quot;&gt;226e24f&lt;/a&gt;&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Proc&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@env&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# self in block&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;c1&quot;&gt;# We do this here rather than allow it to be&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# set in initialize because we want to&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# eventually &quot;seal&quot; access to this method&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# away from regular Ruby code&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__set_raw&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@addr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@env&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(call @addr (@s 0 @env (splat arg)))&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# WARNING: Do not do extra stuff here. If this is a 'proc'/bare block&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# code after the %s(call ...) above will not get executed.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;sx&quot;&gt;%s(defun __new_proc (addr env self)
    (let (p)
       (assign p (callm Proc new))
       (callm p __set_raw (addr env self))
       p
    ))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;There's also a minor change to &lt;code&gt;transform.rb&lt;/code&gt; to ensure &lt;code&gt;__new_proc&lt;/code&gt; is called with a
&lt;code&gt;self&lt;/code&gt; value to assign to the &lt;code&gt;Proc&lt;/code&gt; object:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;22&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f3efb&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;406&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ca30&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
                 &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__closure__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__env__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                 &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
             &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__new_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__tmp_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__env__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__new_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__tmp_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__env__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We have two minor little bits to add after this: &lt;code&gt;Fixnum#!&lt;/code&gt; and &lt;code&gt;String#ord&lt;/code&gt; which I've
added in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a93f95e&quot;&gt;a93f95e&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And then it's on to one more larger change before we're done:&lt;/p&gt;

&lt;h2&gt;Return from blocks&lt;/h2&gt;

&lt;p&gt;Ruby semantics is that a &quot;return&quot; from a block exits the method that calls the block.
That doesn't currently work for us, because a block gets compiled into a C-style function
that takes some extra arguments.&lt;/p&gt;

&lt;p&gt;A solution is to put the return address into the environment, and treat a return as a
&lt;code&gt;goto __env__.__return_address__&lt;/code&gt; of sorts.&lt;/p&gt;

&lt;p&gt;Another complication is that when you use &lt;code&gt;lambda&lt;/code&gt; to create &lt;code&gt;Proc&lt;/code&gt; object, a return
inside the block does seemingly not exit the defining method. But another way of seeing
it, it that the return &lt;em&gt;does&lt;/em&gt; exit &lt;code&gt;Proc#call&lt;/code&gt;. This is a useful realisation, since for
the time being at least, we've been creating &lt;code&gt;Proc&lt;/code&gt; objects for simplicity.&lt;/p&gt;

&lt;p&gt;There are a few ways around this difference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a different class for &quot;plain&quot; blocks that can handle the call accordingly.&lt;/li&gt;
&lt;li&gt;Don't create a class for &quot;plain&quot; blocks, at all, but pass around a &quot;raw&quot; tuple of the address and environment of some sort.&lt;/li&gt;
&lt;li&gt;Change how we &lt;em&gt;create&lt;/em&gt; he &lt;code&gt;Proc&lt;/code&gt; objects, so that the return address for &quot;proper&quot; &lt;code&gt;Proc&lt;/code&gt; objects explicitly instantiated, or
created via &lt;code&gt;lambda&lt;/code&gt;, gets the following instruction in &lt;code&gt;Proc#call&lt;/code&gt; set as its address for explicit returns.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;I'm sure there are other options too.&lt;/p&gt;

&lt;p&gt;One additional complication: If you return a block as a &lt;code&gt;Proc&lt;/code&gt;, and it has a &lt;code&gt;return&lt;/code&gt; inside,
it will raise a &lt;code&gt;LocalJumpError&lt;/code&gt; exception, so ideally we should be able to recognize this case,
though we will defer that for later.&lt;/p&gt;

&lt;p&gt;We'll opt for storing what we need to return out of the defining scope on creation of the object.
We'll also make a block act as the &lt;code&gt;proc&lt;/code&gt; keyword (which we don't currently support). Note that
there are additional complications: We're meant to &lt;code&gt;nil&lt;/code&gt; out missing arguments, and ignore excess
arguments rather than do strict argument checking as well. Those will have to wait.&lt;/p&gt;

&lt;p&gt;The approach chosen will absent additional work make things go &lt;em&gt;badly haywire&lt;/em&gt; if we commit the
sin of returning a &lt;code&gt;Proc&lt;/code&gt; by returning a bare block / or &lt;code&gt;Proc.new&lt;/code&gt;/&lt;code&gt;proc&lt;/code&gt; result (which we also
doesn't support yet), since we can't yet detect it.&lt;/p&gt;

&lt;p&gt;First of all, we will add a new low level operation: &lt;code&gt;:stackframe&lt;/code&gt;, which will return the contents
of &lt;code&gt;%ebp&lt;/code&gt;. By restoring &lt;code&gt;%ebp&lt;/code&gt; to that of the defining method, we can do a normal &lt;code&gt;leave&lt;/code&gt; then
&lt;code&gt;ret&lt;/code&gt; sequence, and the stack pointer will be correctly adjusted, and the return address of the
next instruction in the containing method will be used. Conversely, for non-&lt;code&gt;proc&lt;/code&gt; blocks, a
normal return will still be done, resulting in a return to &lt;code&gt;Proc#call&lt;/code&gt;, which will again just
return out in the &lt;em&gt;calling&lt;/em&gt; scope.&lt;/p&gt;

&lt;p&gt;Apart from adding it to &lt;code&gt;@@keywords&lt;/code&gt; in &lt;code&gt;Compiler&lt;/code&gt;, &lt;code&gt;#compile_stackframe&lt;/code&gt; consists of just this (in
&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e39ae721f48ed&quot;&gt;e39ae721f48ed&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_stackframe&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Stack frame&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Above I've eluded to special handling of &lt;code&gt;:return&lt;/code&gt; for &lt;code&gt;:proc&lt;/code&gt;'s. We do this in a new
low level operation called &lt;code&gt;:preturn&lt;/code&gt; that you can se below. In a little bit we'll then go
through changes to transformations in &lt;code&gt;transform.rb&lt;/code&gt; that rewrites &lt;code&gt;:return&lt;/code&gt; nodes to &lt;code&gt;:preturn&lt;/code&gt;
as needed. But first &lt;code&gt;#compile_preturn&lt;/code&gt; (still in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e39ae721f48ed&quot;&gt;e39ae721f48ed&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# &quot;Special&quot; return for `proc` and bare blocks&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# to exit past Proc#call.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_preturn&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;preturn&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# We load the return address pre-saved in __stackframe__ on creation of the proc.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# __stackframe__ is automatically added to __env__ in `rewrite_let_env`&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__env__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;leave&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ret&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_all&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;__stackframe__&lt;/code&gt; here is hardcoded to offset 0 of &lt;code&gt;__env__&lt;/code&gt; which isn't particularly clean,
but it works. So first we reload &lt;code&gt;%ebp&lt;/code&gt; from what is effectively &lt;code&gt;__env__[0]&lt;/code&gt;, then we pop
the return value off the stack, and do a normal return. Simple and fast.&lt;/p&gt;

&lt;p&gt;Here's our new &lt;code&gt;#compile_proc&lt;/code&gt;... At the moment it's a pointless waste as it is pretty much
identical to &lt;code&gt;#compile_lambda&lt;/code&gt;. It will make more sense later, given the differences in how
&lt;code&gt;proc&lt;/code&gt; and &lt;code&gt;lambda&lt;/code&gt; affect treatment of checking argument count etc. (&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e39ae721f48ed&quot;&gt;e39ae721f48ed&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# To compile `proc`, and anonymous blocks&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# See also #compile_lambda&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_defun&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__closure__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[]]&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Some minor additional static typing&lt;/h3&gt;

&lt;p&gt;To make accessing captured variables (variables defined outside of the block, but
used inside it) work with our recent typing, we need to define the contents of
&lt;code&gt;__env__&lt;/code&gt; apart from the stack frame to be of type &lt;code&gt;:object&lt;/code&gt;. To do this reasonably
cleanly, we add a tiny &lt;code&gt;#lookup_type&lt;/code&gt; method which for now is a bit of a hack,
but that allow us to expand the type lookups later (&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e39ae721f48ed&quot;&gt;e39ae721f48ed&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# For our limited typing we will in some cases need to do proper lookup.&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# For now, we just want to make %s(index __env__ xxx) mostly treated as&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# objects, in order to ensure that variables accesses that gets rewritten&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# to indirect via __env__ gets treated as object. The exception is&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# for now __env__[0] which contains a stackframe pointer used by&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# :preturn.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;lookup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__env__&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;For now this is only used in &lt;code&gt;#compile_index&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lookup_type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Transformations&lt;/h3&gt;

&lt;p&gt;The above is still not enough to &lt;em&gt;use&lt;/em&gt; &lt;code&gt;:preturn&lt;/code&gt; and &lt;code&gt;:proc&lt;/code&gt;. For starters,
in a number of places we now check for both &lt;code&gt;:lambda&lt;/code&gt; an &lt;code&gt;:proc&lt;/code&gt; nodes.&lt;/p&gt;

&lt;p&gt;Additionally, in the event we get a &lt;code&gt;:proc&lt;/code&gt;, we call a new method to rewrite
the body of the &lt;code&gt;:proc&lt;/code&gt; to replace and &lt;code&gt;:return&lt;/code&gt; nodes with &lt;code&gt;:preturn&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;(&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e39ae721f48ed&quot;&gt;e39ae721f48ed&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:proc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;body&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rewrite_proc_return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;#rewrite_proc_return&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rewrite_proc_return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;depth_first&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:skip&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:return&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:preturn&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And in &lt;code&gt;#rewrite_let_env&lt;/code&gt; we add &lt;code&gt;__stackframe__&lt;/code&gt; to the &lt;code&gt;__env__&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;c1&quot;&gt;# For &quot;preturn&quot;. see Compiler#compile_preturn&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;aenv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__stackframe__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_a&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;env&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__stackframe__&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In addition there are a few minor changes to correctly pick up variable references that were left out.&lt;/p&gt;

&lt;p&gt;Finally, in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/927f173&quot;&gt;927f173&lt;/a&gt; I make a minor change to actually generate &lt;code&gt;:proc&lt;/code&gt; nodes
from bare blocks. I've not yet added support for the &lt;code&gt;proc&lt;/code&gt; keyword itself,
though that should be trivial.&lt;/p&gt;

&lt;h2&gt;Some final changes&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e535b77&quot;&gt;e535b77&lt;/a&gt; contains a number of test case updates to cover &lt;em&gt;some&lt;/em&gt; of the above changes, as well
as a bug fix that caused a number of vasted lines special casing on single-argument function/method
calls. It also contains some minor refactoring to start reducing the coupling of the shunting yard
parser to the higher level Ruby parser (eventually I'd like to extract a useful generic component
from it, but the separation is also intended to make the next step of self-hosting easier).&lt;/p&gt;

&lt;h2&gt;The current state of the test scanner&lt;/h2&gt;

&lt;p&gt;You can find &lt;code&gt;features/inputs/scanner6.rb&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/36e3da5&quot;&gt;36e3da5&lt;/a&gt;. This is the exact bastardized / cut down
version of the scanner that compiles after the above changes. When run it tests &lt;code&gt;#peek&lt;/code&gt;, &lt;code&gt;#get&lt;/code&gt;, &lt;code&gt;#unget&lt;/code&gt;
and &lt;code&gt;#expect&lt;/code&gt; (for some limited values of &quot;tests&quot; - many things will still not work). Compile and
echo a suitable string in:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./compile features/inputs/scanner6.rb
[...]
$ echo &quot;forescue&quot; | /tmp/scanner6
Got: 102 (PEEK)
Got: f (GET)
Got: o (GET2)
rescue
f
o
o
DONE
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Parting words&lt;/h2&gt;

&lt;p&gt;The output from the scanner test code is hardly impressive for the amount of work put in so far, but
more and more of the foundation is in place now, and as you can see from this part, apart from some
hairy moments dealing with things like &lt;code&gt;proc&lt;/code&gt; and yield, an increasing number of the fixes are a
matter of small additions to our highly under-developed version of the Ruby standard library rather
than gnarly low level compiler code.&lt;/p&gt;

&lt;p&gt;As a result I expect progress towards self-hosting to be faster for each coming part.&lt;/p&gt;

&lt;p&gt;There's certainly still plenty of gnarly low level compiler code &lt;em&gt;left&lt;/em&gt; to do, such as re-opening of
classes, proper handling of method-missing and &lt;code&gt;send&lt;/code&gt;, as well as &lt;code&gt;attr_accessor/reader/writer&lt;/code&gt;,
&lt;code&gt;define_method&lt;/code&gt; (again...), &lt;code&gt;module&lt;/code&gt;, class methods and &lt;code&gt;include&lt;/code&gt;. (I'm sure there are many more
that I'm repressing too...), but even much of that should be simpler than what we've gone through
over the last couple of parts.&lt;/p&gt;

&lt;p&gt;The next part too will be fairly messy, but then we'll have soother sailing for a few rounds as I'll be covering more focused features again.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Wed, 05 Nov 2014 01:00:00 +0000</pubDate>
      <dc:date>2014-11-05T01:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Eight Docker Development Patterns</title>
      <link>http://hokstad.com/docker/patterns</link>
      <description>&lt;p&gt;In the past I've written about my &lt;a href=&quot;/the-home-cloud&quot;&gt;&quot;home cloud&quot;&lt;/a&gt; that used to be
&lt;a href=&quot;http://openvz.org&quot;&gt;OpenVz&lt;/a&gt; containers, and &lt;a href=&quot;/rebuilding-the-build-server-on-every-build&quot;&gt;how I've come to advocate rebuilding the &quot;build server&quot; for every build&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://docker.io&quot;&gt;Docker&lt;/a&gt; has quickly become one of my favorite enabling tools for
this overall philosophy of creating repeatable builds that results in as-static-as-possible server
environments.&lt;/p&gt;

&lt;p&gt;Here I will outline some patterns that have started to show up repeatedly in my use
of Docker. I don't expect any of them to be particularly novel or any big surprises,
but I hope some can be useful, and I would very much like to hear from others about
patterns you come across while working with Docker.&lt;/p&gt;

&lt;p&gt;A foundation for all of my Docker experiments, is keeping state that should persist in
volumes, so that the Docker containers themselves can be re-created at will without
data loss (unless I've been naughty and modified container state without updating the
Dockerfile's - and regularly rebuilding the containers helps stop that bad habit).&lt;/p&gt;

&lt;p&gt;The examples Dockerfiles below are all focused on that: Creating containers where the
containers themselves can be replaced at any time without having to think about it.&lt;/p&gt;

&lt;p&gt;The more regularly the containers are recreated; the more habitual this becomes, the
more it reinforces a habit of avoiding state outside of clearly defined locations
that are explicitly persisted.&lt;/p&gt;

&lt;h2&gt;1. The Shared Base Container(s)&lt;/h2&gt;

&lt;p&gt;Docker encourages &quot;inheritance&quot; so this should not come as a surprise - it is a
fundamental aspect of effectively using Docker, not least because it contributes
to reducing the time it takes to build new containers by not having to re-execute
steps as often. Docker does a good job - sometimes too good - of trying to cache
intermediate steps, but it is easy to lose out on opportunities for sharing
when not being explicit about it.&lt;/p&gt;

&lt;p&gt;One of the first things that became apparent on migrating my various containers to
Docker was the amount of redundant setup.&lt;/p&gt;

&lt;p&gt;I run separate containers for most projects that I expect to ever deploy anywhere, at
least the moment it needs any long running processes, or needs any specific packages
beyond my &quot;standard&quot; set, so I have many containers, and the set is rapidly growing.&lt;/p&gt;

&lt;p&gt;To the point where I'm considering moving towards trying to run &quot;everything&quot;
(including the few desktop apps I depend on) in Docker in order to make mybase environment
entirely disposable.&lt;/p&gt;

&lt;p&gt;So I quickly started extracting my basic setups into base containers for various
purposes. Here's my current &quot;devbase&quot; Dockerfile:&lt;/p&gt;

&lt;pre class=&quot;sh codehilite&quot;&gt;&lt;code&gt;
    FROM debian:wheezy
    RUN apt-get update
    RUN apt-get &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;ruby ruby-dev build-essential git
    RUN apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; libopenssl-ruby libxslt-dev libxml2-dev
    
    &lt;span class=&quot;c&quot;&gt;# For debugging&lt;/span&gt;
    RUN apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; gdb strace
    
    &lt;span class=&quot;c&quot;&gt;# Set up my user&lt;/span&gt;
    RUN useradd vidarh &lt;span class=&quot;nt&quot;&gt;-u&lt;/span&gt; 1000 &lt;span class=&quot;nt&quot;&gt;-s&lt;/span&gt; /bin/bash &lt;span class=&quot;nt&quot;&gt;--no-create-home&lt;/span&gt;
    
    RUN gem &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; /usr/bin bundler
    RUN gem &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; /usr/bin rake
    
    WORKDIR /home/vidarh/
    ENV HOME /home/vidarh
    
    VOLUME &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;/home&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;
    USER vidarh
    EXPOSE 8080

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;There's nothing much special to note about it - it installs some specific tools I tend
to like to always have available. These will presumably be different for most people.
The distribution choice is pretty arbitrary. The one thing about it worth considering
is to specify a specific tag to avoid surprises if/when you rebuild a container (and
I need to get better at that too - I do it for the distributions, but I too rarely
tag my own containers).&lt;/p&gt;

&lt;p&gt;It exposes port 8080 by default, since that's where I usually expose my web apps,
which is what I usually use these containers for.&lt;/p&gt;

&lt;p&gt;It adds a user for me, and forces the userid to the user id I have on my server, and
doesn't create a /home directory. This latter is because I bind mount a shared /home
from the host. Which brings us to the next pattern:&lt;/p&gt;

&lt;h2&gt;2. The Shared Volume Dev Container&lt;/h2&gt;

&lt;p&gt;All of my dev containers share at least one volume with the host: /home. This is
for ease of development. For many apps it lets me leave the apps running with a
suitable file-system-change based code-reloader in dev mode, so that the containers
encapsulate the OS/distro-level dependencies, and help verify that the app-as-bundled
works in a pristine environment, without making me restart/rebuild the VM fully
on every code change. Meanwhile &lt;em&gt;I can&lt;/em&gt;, and &lt;em&gt;do&lt;/em&gt; restart them fairly frequently
to ensure that nothing slips past.&lt;/p&gt;

&lt;p&gt;For the rest, it lets me just restart (rather than rebuild) the container to pick
up code changes.&lt;/p&gt;

&lt;p&gt;For test/staging and production containers I would in most cases avoid sharing code
via volumes, and instead use &quot;ADD&quot; to add the code in question to the Docker
container itself.&lt;/p&gt;

&lt;p&gt;Here is the Dockerfile for my &quot;homepage&quot; dev container, for example, which contains
my homegrown personal wiki, that draws on the already shared /home volume from
my &quot;devbase&quot; container, and so showcases the shared base and how I &lt;em&gt;use&lt;/em&gt; the
shared /home volume:&lt;/p&gt;

&lt;pre class=&quot;sh codehilite&quot;&gt;&lt;code&gt;
    FROM vidarh/devbase
    WORKDIR /home/vidarh/src/repos/homepage
    ENTRYPOINT bin/homepage web

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(note, I really should version tag my devbase container)&lt;/p&gt;

&lt;p&gt;And for my dev-version of my blog:&lt;/p&gt;

&lt;pre class=&quot;sh codehilite&quot;&gt;&lt;code&gt;
    FROM vidarh/devbase
    
    WORKDIR /
    USER root
    
    &lt;span class=&quot;c&quot;&gt;# For Graphivz integration&lt;/span&gt;
    RUN apt-get update
    RUN apt-get &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;graphviz xsltproc imagemagick
    
    USER vidarh
    WORKDIR /home/vidarh/src/repos/hokstad-com
    ENTRYPOINT bundle &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;rackup &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; 8080

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Because they pull in the code from a shared repository, and are based on a shared base
container, these containers are in general extremely fast to rebuild when I add/modify/remove
dependencies, which I find important in order to ensure I don't get tempted to resort to
workarounds that leave undocumented dependencies.&lt;/p&gt;

&lt;p&gt;Even so, there are certainly things
I'd like to improve on. Even though the base for the above are lightweight, they could
certainly be much more so: Most of what are in these containers remain unused. Since
Docker uses copy-on-write overlays, this does not result in a huge overhead, but it does
still mean I am not truly capturing the bare minimal requirements, nor minimizing the
attack- or error-surface as much as possible. (I'm not so concerned about attack surface
for these specific cases, as e.g. my blog does not maintain any important state in the
&quot;live&quot; version that's not sitting in two git repositories in two other locations, and
it gets overwritten on every push I do; but it's the principle)&lt;/p&gt;

&lt;h2&gt;3. The Dev Tools Container&lt;/h2&gt;

&lt;p&gt;This may be most attractive for those of us who like to rely on ssh to a screen session
to work on code, and less for the IDE crowd, but for me, one of the nice things about
the above setup is that it lets me separate out editing and test-executing parts of code
from running the in-development application.&lt;/p&gt;

&lt;p&gt;One of the annoying thing in the past for me with dev-systems have been that dev and
production dependencies and &lt;em&gt;development tool&lt;/em&gt; dependencies easily get co-mingled. You
can try to keep them apart, but unless these setups are genuinely kept separated, it is
all too easy to create undocumented dependencies by e.g. in a bind during debugging
apt-get'ing strace or tcpdump - or even emacs - in an environment that does not really
need it, and pull in a boatload of dependencies for the various tools at the same time.&lt;/p&gt;

&lt;p&gt;In the past I had this driven home after spending weeks &quot;reverse engineering&quot; the
dependencies of an application that had accreted all kinds of undocumented dependencies
due to co-mingling of dev-environment, testing and initial prototype deployment
environment.&lt;/p&gt;

&lt;p&gt;While there are many ways of solving this by ensuring you do regular test-deployments,
combined with the patterns above I have a solution I quite like because it prevents the
problem from arising in the first place:&lt;/p&gt;

&lt;p&gt;I have a separate container that contains my Emacs installation, and various other tools
that I like to have available. I still try to keep it sparse, but the point is, my screen
session can live in this container, and coupled with &quot;autossh&quot; set up on my laptop, there's
pretty much always a running connection to it, where I can edit code that is shared &quot;live&quot;
with my other dev containers.&lt;/p&gt;

&lt;p&gt;This container is also one where I allow the occasional transgression of installing
packages directly (with the caveat that if I want to keep them around, I need to put them
in my Dockerfile, or they'll get blown away next time I rebuild) because it only affects
debugging and development.&lt;/p&gt;

&lt;p&gt;Currently it looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FROM vidarh/devbase
RUN apt-get update
RUN apt-get -y install openssh-server emacs23-nox htop screen

# For debugging
RUN apt-get -y install sudo wget curl telnet tcpdump

# For 32-bit experiments
RUN apt-get -y install gcc-multilib 

# Man pages and &quot;most&quot; viewer:
RUN apt-get install -y man most

RUN mkdir /var/run/sshd
ENTRYPOINT /usr/sbin/sshd -D

VOLUME [&quot;/home&quot;]
EXPOSE 22
EXPOSE 8080
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Combined with the shared &quot;/home&quot;, this gets me a sufficiently functional little
place to ssh into. I'm sure I'll augment it as I use it more, but for now it has
proven quite sufficient for my needs.&lt;/p&gt;

&lt;h2&gt;4. The Test In A Different Environment containers&lt;/h2&gt;

&lt;p&gt;One aspect of Docker I particularly love is the ease with which I can test my code in
different environments. For example, when I upgraded my &lt;a href=&quot;/compiler&quot;&gt;Ruby compiler project&lt;/a&gt;
to handle Ruby 1.9 (much overdue), I created this trivial little Dockerfile to let me
spawn a shell in a Ruby 1.8 environment after I'd transitioned my main dev environment
to 1.9:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FROM vidarh/devbase
RUN apt-get update
RUN apt-get -y install ruby1.8 git ruby1.8-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Of course you can achieve a similar effect with rbenv etc.. But I've always found those
tools annoying as I prefer to deploy as much as possible with distro-packages (as painful
as that has been with Ruby in the past), not least because it makes it easier for &lt;em&gt;others&lt;/em&gt;
to use my code if I ensure that works smoothy.&lt;/p&gt;

&lt;p&gt;Having a docker container that I can just &quot;docker run&quot; when I need a different environment
for a few minutes solves the problem neatly, and also has the benefit that it is not
constrained to things like Ruby that have pre-packaged custom tools to deal with versioning.&lt;/p&gt;

&lt;p&gt;I could also achieve it with full VM's, as is the case for many of the things I describe,
but I can start the above docker containers in far less time.&lt;/p&gt;

&lt;h2&gt;5. The Build Container&lt;/h2&gt;

&lt;p&gt;Most of what I write are in interpreted languages these days, but even then there are often
useful &quot;build&quot; steps that are expensive enough that I'd prefer not to execute them all the
time.&lt;/p&gt;

&lt;p&gt;An example is running &quot;bundler&quot; for Ruby applications. Bundler updates cached dependencies
for Rubygems (and optionally full gem files, or even unpacked contents) and it can take
some time to run for a larger app.&lt;/p&gt;

&lt;p&gt;It also often requires dependencies that are not needed at runtime for the application.
E.g. installing gems that rely on native extensions can often depend on so many packages
- often without documenting exactly which - that it's easier to just start by pulling in
all of build-essential and it's dependencies. At the same time, while you can make bundler
do all the work up-front, I &lt;em&gt;really&lt;/em&gt; don't want to run it in the host environment that
may or may not be compatible with the containers I want to deploy in.&lt;/p&gt;

&lt;p&gt;A solution for this is to create a build container. You can create a separate Dockerfile
if the dependencies are different, or you can reuse the main app Dockerfile and just
override the command to run your desired build commands. E.g. the Dockerfile may look
like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FROM myapp
RUN apt-get update
RUN apt-get install -y build-essential [assorted dev packages for libraries]
VOLUME [&quot;/build&quot;]
WORKDIR /build
CMD [&quot;bundler&quot;, &quot;install&quot;,&quot;--path&quot;,&quot;vendor&quot;,&quot;--standalone&quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then run this while mounting your build/source directory in the containers &quot;/build&quot; directory
whenever you have updated your dependencies. Replace as suitable.&lt;/p&gt;

&lt;p&gt;The point is that you can decouple &lt;em&gt;build&lt;/em&gt; of your applications, or parts of it from the
final &lt;em&gt;packaging&lt;/em&gt;, while still encapsulating both processes and their dependencies in Docker
containers by breaking the process into two or more containers.&lt;/p&gt;

&lt;p&gt;(I often check in the build artefacts, to be 100% certain I can reproduce the final packaging
steps; an alternative is to do a full end-to-end build and test on a regular basis as well,
to make sure the split accurately reflects th full process)&lt;/p&gt;

&lt;h2&gt;6. The Installation Container&lt;/h2&gt;

&lt;p&gt;This is not my own, but really deserves a mention. The excellent &lt;a href=&quot;https://github.com/jpetazzo/nsenter&quot;&gt;nsenter and docker-enter tools&lt;/a&gt;
comes with an installation option that is a nice step forward from the popular but terrifying
&quot;curl [some url you have no control over] | bash&quot; pattern. It does this by providing a Docker
container that implements the &quot;Build Container&quot; pattern from above, but goes one step further. It deserves
a look.&lt;/p&gt;

&lt;p&gt;This is the last portion of the Dockerfile, from after it has downloaded and built a suitable version of
nsenter (my one caveat is no integrity check of the downloaded archive):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ADD installer /installer
CMD /installer
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&quot;installer&quot; looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#!/bin/sh
if mountpoint -q /target; then
       echo &quot;Installing nsenter to /target&quot;
       cp /nsenter /target
       echo &quot;Installing docker-enter to /target&quot;
       cp /docker-enter /target
else
       echo &quot;/target is not a mountpoint.&quot;
       echo &quot;You can either:&quot;
       echo &quot;- re-run this container with -v /usr/local/bin:/target&quot;
       echo &quot;- extract the nsenter binary (located at /nsenter)&quot;
fi
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;While the potential is still there for a malicious attacker to try to exploit potential privilege
escalation problems with containers, the attack surface is at least substantially smaller.&lt;/p&gt;

&lt;p&gt;But the most likely immediate win for most of us with this pattern is to avoid the risk of
&lt;a href=&quot;https://github.com/MrMEEE/bumblebee-Old-and-abbandoned/issues/123&quot;&gt;wellmeaning developers who occasionally make very dangerous mistakes in installation scripts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I really love this approach. And hopefully it will help curtail the abomination that is
&quot;curl [something] | bash&quot;, (but even if it doesn't, at least we can easily contain that within containers too...)&lt;/p&gt;

&lt;h2&gt;7. The Default-Service-In-A-Box Containers&lt;/h2&gt;

&lt;p&gt;While I relatively quickly if I get &quot;serious&quot; with an app will prep suitable containers to handle the database
etc. for the project, I find it invaluable to have a series of &quot;basic&quot; infrastructure containers sitting there,
with suitable tweaks for me to be able to spin up e.g. the database of my choice, or queueuing system of choice
with suitable default settings.&lt;/p&gt;

&lt;p&gt;Of course you can get &quot;mostly there&quot; by just trying &quot;docker run [some-app-name]&quot; and cross your fingers that
there's a great alternative in the Docker index, and often there is. But I like to vet them first, and figure
out e.g. how they handle data, and then I will be more likely to add my own tweaked version to my own &quot;library&quot;.&lt;/p&gt;

&lt;p&gt;E.g. I have one sitting around for Beanstalkd:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FROM debian:wheezy
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get -q update
RUN apt-get -y install build-essential
ADD http://github.com/kr/beanstalkd/archive/v1.9.tar.gz /tmp/
RUN cd /tmp &amp;amp;amp;&amp;amp;amp; tar zxvf v1.9.tar.gz
RUN cd /tmp/beanstalkd-1.9/ &amp;amp;amp;&amp;amp;amp; make
RUN cp /tmp/beanstalkd-1.9/beanstalkd /usr/local/bin/
EXPOSE 11300
CMD [&quot;/usr/local/bin/beanstalkd&quot;,&quot;-n&quot;]
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;(For e.g. Postgres I have a vastly more complicated one that amongst others also set up persistent volumes for
data, configuration etc.)&lt;/p&gt;

&lt;p&gt;My goal is to be able to go &quot;ok, I'm going to need memcached, postgres and beanstalk&quot; and three quick &quot;docker run&quot;'s
later have three containers up and running that are tweaked to my environment and personal preferences for a default
environment, and ready to go. Setting up &quot;standard&quot; infrastructure components should be a 1 minute job rather than
take away from the development itself.&lt;/p&gt;

&lt;h2&gt;8. The Infrastructure / Glue Containers&lt;/h2&gt;

&lt;p&gt;Many of these patterns focus on the development environment (and this means there's many more to discuss
some other time for production environments), but there is one big category missing:&lt;/p&gt;

&lt;p&gt;Containers whose purpose is to glue your environment together into a cohesive whole. This is an under-explored
area for my part so far, but I will mention one particular example:&lt;/p&gt;

&lt;p&gt;To enable easy access to my containers, I have a small little haproxy container. I have a wildcard DNS entry
pointing at my home server, and an iptable entry opening up access to my haproxy container. The Dockerfile
is nothing special:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FROM debian:wheezy
ADD wheezy-backports.list /etc/apt/sources.list.d/
RUN apt-get update
RUN apt-get -y install haproxy
ADD haproxy.cfg /etc/haproxy/haproxy.cfg
CMD [&quot;haproxy&quot;, &quot;-db&quot;, &quot;-f&quot;, &quot;/etc/haproxy/haproxy.cfg&quot;]
EXPOSE 80
EXPOSE 443
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The fun part here is the haproxy.cfg, which is generated by a script that generates backend sections like this from the output of &quot;docker ps&quot;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;backend test
    acl authok http_auth(adminusers)
    http-request auth realm Hokstad if !authok
    server s1 192.168.0.44:8084
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and a bunch of acls and use_backend statements in the frontend definition that dispatches [hostname].mydomain to the right backend.backend test.&lt;/p&gt;

&lt;p&gt;If I wanted to be fancy, I'd deploy something like &lt;a href=&quot;https://github.com/airbnb/synapse&quot;&gt;AirBnB's Synapse&lt;/a&gt;,
but it has far more options than I need for my dev use.&lt;/p&gt;

&lt;p&gt;For my home environment, this makes up most of my infrastructure needs. While at work I'm rolling out an increasing
array of infrastructure containers whose purpose is to make deployment of the actual applications a breeze as I'm transitioning a
full private cloud system towards Docker.&lt;/p&gt;
</description>
      <category>docker</category>
      <category>devops</category>
      <category>cloud</category>
      <category>patterns</category>
      <pubDate>Wed, 22 Oct 2014 02:00:00 +0000</pubDate>
      <dc:date>2014-10-22T02:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 39</title>
      <link>http://hokstad.com/compiler/39-to-be-or-not-to-be-nil</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;To be or not to be nil&lt;/h2&gt;

&lt;p&gt;One of the big elephants sauntering around the room for a long time has been
the issue of how to handle the specifics of how Ruby handles &lt;code&gt;nil&lt;/code&gt;, &lt;code&gt;true&lt;/code&gt; and
&lt;code&gt;false&lt;/code&gt;. To a lesser extent this issue also affects numbers, but it is those
three values that are most critical right now.&lt;/p&gt;

&lt;p&gt;The reason is control flow. So far, we've treated these values the way C does:
&lt;code&gt;nil&lt;/code&gt; is simply the null pointer; &lt;code&gt;true&lt;/code&gt; is any non-zero value, and false is zero
(and thus for most practical intents the same as &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The problem, of course, is that this is not the way it is in Ruby. &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt;
and &lt;code&gt;nil&lt;/code&gt; are values distinct from the numbers, and they compare with each others
and with other values in different ways than in C.&lt;/p&gt;

&lt;p&gt;They are also &lt;em&gt;objects&lt;/em&gt;. Which means we lose out on some of the simplest ways of
doing comparisons and turning the comparison results into a value. We may find
people doing things like &lt;code&gt;if &amp;lt;some expression&amp;gt;.nil?&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nil&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; both evaluate to false in a conditional, but &lt;code&gt;nil != false&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So far &quot;faking it&quot; have worked, because with a few exceptions like the ones above,
the C and Ruby variations are relatively compatible. But it's not a lasting solution.&lt;/p&gt;

&lt;p&gt;There is another problem: If we change basic contructs like the s-expression &lt;code&gt;if&lt;/code&gt; to
work on Ruby objects, we'll find it hard to implement the &quot;plumbing&quot; under Ruby.&lt;/p&gt;

&lt;h2&gt;Introducing some static typing&lt;/h2&gt;

&lt;p&gt;Don't bring out the pickaxe just yet (&lt;em&gt;groan&lt;/em&gt;). As it happens, our compiler compiles
two very different languages: The s-expression inspired low level language used both as
the compilation target for Ruby and implementation language for low level features,
and Ruby itself.&lt;/p&gt;

&lt;p&gt;The former language is de facto &lt;em&gt;typeless&lt;/em&gt;, like &lt;a href=&quot;http://en.wikipedia.org/wiki/BCPL&quot;&gt;BCPL&lt;/a&gt;:
We pass values around with wild abandon, and we even clobber Ruby local variables
and instance variables with it, but what meaning these values have depends entirely
on &lt;em&gt;usage&lt;/em&gt; rather than the type of the variable (as in C) or a type attached to
the value itself, like in Ruby.&lt;/p&gt;

&lt;p&gt;And as it happens, here lies both the problem and solution to our conundrum from
above:&lt;/p&gt;

&lt;p&gt;If only the compiler can know when it is dealing with real Ruby values, and when
it is dealing with something else, then, e.g. &lt;code&gt;compile_if&lt;/code&gt; can generate different
code in these situations.&lt;/p&gt;

&lt;p&gt;Not only that: We will need this information when we eventually get tired of leaking
memory and start adding a garbage collector - otherwise we're stuck with a
conservative collector, so we get twice the benefit.&lt;/p&gt;

&lt;p&gt;It will also help us contain the &quot;leakage&quot; of untyped values into Ruby, by letting
us define and narrow the rules for when and where and how we're allowed to work
with them.&lt;/p&gt;

&lt;p&gt;As it happens, we don't need a very complicated type-system: For now we can get
away with knowing if a reasonable subset of constructs returns either an &lt;em&gt;object&lt;/em&gt;
or may contain &lt;em&gt;anything&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That's it. That's the grand total of the static typing we'll introduce this time.&lt;/p&gt;

&lt;p&gt;However the changes start laying the groundwork for more static typing that we
can use for optimizations and sanity checks. Ultimately I wish to relegate the
&quot;s-expression plumbing&quot; to a very restricted space.&lt;/p&gt;

&lt;p&gt;Apart from just categorizing stuff into two types, there's another limitation too
for now: Where we act on type information, we will treat all variables as typed to
objects, and all return variables from method calls to be typed as objects. We
will implicitly assume that the s-expression syntax will be contained, though we
are not yet verifying that. In some cases this will be outright wrong. E.g. this
explicitly prevents &lt;code&gt;if foo; bar; end&lt;/code&gt; from working correctly if &lt;code&gt;foo&lt;/code&gt; is not an
object, and happens to contain 0, and in any number of similar instances, so it
is likely introducing some regressions (I caught one while writing this - there are
probably more).&lt;/p&gt;

&lt;h2&gt;Introducing Value&lt;/h2&gt;

&lt;p&gt;First, let's put some basic test cases in place. You'll find them in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/d22b95f&quot;&gt;d22b95f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then lets start putting our new typing into place. Let's start with a &lt;code&gt;Value&lt;/code&gt; class
to hold a possibly typed value (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/3ec81cb&quot;&gt;3ec81cb&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'delegate'&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;# Used to hold a possiby-typed value&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Currently, valid values for &quot;type&quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# are :object or nil.&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Value&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SimpleDelegator&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:type&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;c1&quot;&gt;# Evil. Since we explicitly check for Symbol some places&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;__getobj__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;To simplify refactoring, we have it be a delegator, so we only selectively add/change
behaviour as needed. For now, the only new thing is that &lt;code&gt;#type&lt;/code&gt; will return the associated
type tag, or nil. We only support &lt;code&gt;:object&lt;/code&gt; for now, to indicate we know the value to be a
pointer to a Ruby object.&lt;/p&gt;

&lt;p&gt;I'm not going to go through ever detail of the changes in &lt;code&gt;compiler.rb&lt;/code&gt;. You can find the full set
in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/0ded9c1&quot;&gt;0ded9c1&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Apart from a number of changes to return objects of the new &lt;code&gt;Value&lt;/code&gt; class, the main things
to notice are as follows:&lt;/p&gt;

&lt;p&gt;We add &lt;code&gt;:false&lt;/code&gt;, &lt;code&gt;:true&lt;/code&gt;, and &lt;code&gt;:nil&lt;/code&gt; to &lt;code&gt;@global_constants&lt;/code&gt; to prevent them from being treated
as method calls:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@global_constants&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:false&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@global_constants&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:true&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@global_constants&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:nil&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Next up is this change in &lt;code&gt;compile_if&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp_on_false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:object&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;nil&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;je&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;false&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;je&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp_on_false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;What's happening here is that instead of assuming an untyped value,
we check to see if we know we have an object. If we do, and we come across
&quot;if result; ...; else ...; end&quot;, we change the code to effectively do the equivalent of:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# if block&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# else block&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;There's an equivalent change for &lt;code&gt;compile_while&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Furthermore there's a few minor additional changes to &lt;code&gt;scope.rb&lt;/code&gt; to prevent true/false/nil from
being treated as method calls in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/52f31ad3&quot;&gt;52f31ad3&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We also need to check in &lt;code&gt;transform.rb&lt;/code&gt; that we're not trying to treat true, false and nil as
local variables. See &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/f2af5fc&quot;&gt;f2af5fc&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Changes to the runtime&lt;/h2&gt;

&lt;p&gt;In order to make these changes work, we also need to modify the runtime in various ways.
Most obviously, we need to actually make &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;nil&lt;/code&gt; real objects. We do that in
&lt;code&gt;lib/core/core.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'core/true'&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;TrueClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# FIXME: MRI does not allow creating an object of TrueClass&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'core/false'&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;FalseClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# FIXME: MRI does not allow creating an object of FalseClass&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'core/nil'&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NilClass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# FIXME: MRI does not allow creating an object of NilClass.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
     &lt;span class=&quot;c1&quot;&gt;# OK, so perhaps this is a bit ugly...&lt;/span&gt;
     &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
     
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;59&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;66&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
     &lt;span class=&quot;no&quot;&gt;STDOUT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
     &lt;span class=&quot;no&quot;&gt;ARGV&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;
     &lt;span class=&quot;no&quot;&gt;Enumerable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;#Here because modules doesn't work yet&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# FIXME: Should be an object of NilClass&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# FIXME: Should be an object of TrueClass&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: Should be an object of FalseClass&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;These depends on very basic initial implementations of &lt;code&gt;TrueClass&lt;/code&gt;, &lt;code&gt;FalseClass&lt;/code&gt; and
&lt;code&gt;NilClass&lt;/code&gt; - see &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/c356591&quot;&gt;c356591&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another change is in &lt;code&gt;lib/core/fixnum.rb&lt;/code&gt;, where all the comparison operators needs to change:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(eq @value (callm other __get_raw))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if (eq @value (callm other __get_raw)) true false)&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is because &lt;code&gt;%s(eq ..)&lt;/code&gt; etc. does not handle typing yet (and they may not necessarily
ever need it), so we use our newly &lt;code&gt;typed %s(if ..)&lt;/code&gt; coupled with explicitly returning the
right objects instead of the numeric values we'd previously get.&lt;/p&gt;

&lt;p&gt;It is important to do this in particular as one of the changes I snuck past in &lt;code&gt;compiler.rb&lt;/code&gt;
assumes that method calls returns Ruby objects.&lt;/p&gt;

&lt;p&gt;Almost done now, but there's also a minor change to &lt;code&gt;lib/core/object.rb&lt;/code&gt; to remove the horribly
hacky &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; &lt;em&gt;methods&lt;/em&gt; we used previously.&lt;/p&gt;

&lt;h2&gt;To be or not to be and more?&lt;/h2&gt;

&lt;p&gt;As it happens, we have a few more things to do: &lt;code&gt;%s(and ..)&lt;/code&gt; and &lt;code&gt;%s(or ...)&lt;/code&gt; needs to take
type information into account to be able to generate proper code for e.g.:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In our new world, &lt;code&gt;a and b&lt;/code&gt; (or &lt;code&gt;a &amp;amp;amp;&amp;amp;amp; b&lt;/code&gt;) will always be true, because both &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt;
have integer values that are non-null. Similarly &lt;code&gt;a or c&lt;/code&gt; / &lt;code&gt;a || c&lt;/code&gt; will always be true as well,
since both values will be seen to evaluate to true.&lt;/p&gt;

&lt;p&gt;First of all, I've added a test case to catch this, in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1dfe043&quot;&gt;1dfe043&lt;/a&gt;. But one of our other test
cases shows a regression as well. &lt;code&gt;features/inputs/strcmp.rb&lt;/code&gt; now gives wrong results, because
we previously relied on being able to use &quot;plain Ruby&quot; &lt;code&gt;if&lt;/code&gt; to check the result of a call to
&lt;code&gt;strcmp&lt;/code&gt; that we stored in a local variable. But for now at least, we're assuming variables
contain objects. We'll likely want to refine that, but for now we'll apply a workaround that
will work (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/32ddcde&quot;&gt;32ddcde&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(assign res (if (strcmp @buffer (callm other __get_raw)) false true))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;By explicitly assigning with the values &lt;code&gt;false&lt;/code&gt; or &lt;code&gt;true&lt;/code&gt;, from the result of a value that
will get an indeterminate type, it will work again.&lt;/p&gt;

&lt;p&gt;But lets fix &quot;&amp;amp;&amp;amp;&quot;/&quot;and&quot;. Firstly we need to actually store the return value from &lt;code&gt;compile_eval_arg&lt;/code&gt;
for &lt;code&gt;if_arm&lt;/code&gt; and &lt;code&gt;else_arm&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/2ae727d&quot;&gt;2ae727d&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;if_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ifret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;if_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_end_if_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;elseret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Secondly, we need to determine type based on them. Most importantly, we can only
safely return a type that is shared by both of them if both &lt;code&gt;if&lt;/code&gt; and &lt;code&gt;else&lt;/code&gt; are
present (also in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/2ae727d&quot;&gt;2ae727d&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# We only return a specific type if there's either only an &quot;if&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# expression, or both the &quot;if&quot; and &quot;else&quot; expressions have the&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# same type.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ifret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;elseret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ifret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;elseret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ifret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Other than that, we're simply just adding our missing &lt;code&gt;compile_or&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;(EDIT: This implementation is broken; a correct version will be in part 41)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And that's it for this time.
&lt;/some&gt;&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Tue, 30 Sep 2014 04:00:00 +0000</pubDate>
      <dc:date>2014-09-30T04:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 38</title>
      <link>http://hokstad.com/compiler/38-super</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;p&gt;I've been lazy again. Just today I realized that not only has it been two
months since last post, but I still have one more post queued than I thought.
I hope to clean up the next post in 2-3 weeks time, and another one in the
following 2-3 weeks. I've actually just started preparing part 42..&lt;/p&gt;

&lt;h2&gt;Super&lt;/h2&gt;

&lt;p&gt;This time, I'm going to cover a small, simple change again for a change. Make
this compile:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScannerString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;String&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Which means implementing &lt;code&gt;super&lt;/code&gt;. Conceptually this is easy. Consider that &quot;under the
hood&quot;, a method call effectively compiles to roughly the following pseudo code (imagine
we're compiling to C instead of assembler). &quot;self.bar(baz)&quot; becomes:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__class_pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset_of_bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(this assumes the method has a vtable slot, but we don't handle ones that don't yet, anyway)&lt;/p&gt;

&lt;p&gt;We want to translate this into something like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__class_pointer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__super_class_pointer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset_of_bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;](&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In other words: We find the pointer to the Class object, and then we need to look up the
super-class of that class.&lt;/p&gt;

&lt;h3&gt;A quick aside about eigenclasses&lt;/h3&gt;

&lt;p&gt;If you're experienced with Ruby, you've probably at least heard of eigenclasses or metaclasses.&lt;/p&gt;

&lt;p&gt;An eigenclass in Ruby is a class that is private to the &lt;em&gt;instance&lt;/em&gt;. This may look like a
complicating factor, especially since if you call &lt;code&gt;#class&lt;/code&gt; on an object after defining a
method on the eigenclass, you still get the same class as before. But what actually happens
is that the eigenclass is added into the inheritance chain, but &quot;hidden&quot; from certain types of lookup.&lt;/p&gt;

&lt;p&gt;For method calls, everything is as before, so we continue to ignore eigenclasses (at this
point it looks like I'll cover that in part 42 or 43)&lt;/p&gt;

&lt;h3&gt;Getting the superclass&lt;/h3&gt;

&lt;p&gt;First things first: We currently don't actually &lt;em&gt;store&lt;/em&gt; a pointer to the super-class anywhere.&lt;/p&gt;

&lt;p&gt;In &lt;code&gt;lib/core/class.rb&lt;/code&gt;, we handle the storage (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b05160c&quot;&gt;b05160c&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We then increase &lt;code&gt;ClassScope::CLASS_IVAR_NUM&lt;/code&gt; in &lt;code&gt;scope.rb&lt;/code&gt;. At the same time, we add a &lt;code&gt;#method&lt;/code&gt;
method that will be needed to get the &lt;em&gt;name&lt;/em&gt; of the method we're currently compiling, in order
to compile a call to the super-class version of the method correctly.&lt;/p&gt;

&lt;h3&gt;compile_super and friends&lt;/h3&gt;

&lt;p&gt;Next, we add the function/method &lt;strong&gt;name&lt;/strong&gt; &lt;code&gt;Function&lt;/code&gt;, which includes a few changes to actually
pass it when it is known. But the real work gets done by &lt;code&gt;Compiler#compile_super&lt;/code&gt; which we'll
look at shortly, and this new line in &lt;code&gt;#compile_call&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/cd29057&quot;&gt;cd29057&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:super&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is because super-calls will look like receiver-less method-calls, which are handled by
compile_call.&lt;/p&gt;

&lt;p&gt;And here's &lt;code&gt;#compile_super&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# Compiles a super method call&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;super &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;=&amp;gt; super &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;= super &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;It pulls the name of the surrounding method, and then calls &lt;code&gt;#compile_callm&lt;/code&gt;, with an added
new flag. Other than that it's debugging/tracing only. The new flag to &lt;code&gt;#compile_callm&lt;/code&gt; is
&lt;code&gt;do_load_super&lt;/code&gt;. &lt;code&gt;#compile_callm&lt;/code&gt; changes like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;do_load_super&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;and this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;n&quot;&gt;load_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Load self.class into %eax&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;do_load_super&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;and finally, &lt;code&gt;#load_super&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Load the super-class pointer&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load_super&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_instance_var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Basically &lt;code&gt;#load_super&lt;/code&gt; depends on the hardcoded slot for the super class pointer as an instance
variable. Note: We could alternatively expose this pointer as a instance variable of some sort,
but this keeps it anonymous and inaccessible (keep in mind that asking for the super-class is
&lt;em&gt;different&lt;/em&gt; to following this field, as following the inheritance chain from Ruby excludes
eigenclasses, and also modules.&lt;/p&gt;

&lt;h2&gt;Are we there yet?&lt;/h2&gt;

&lt;p&gt;Not quite. We're going to make string take an optional argument to &lt;code&gt;#initialize&lt;/code&gt; too, in order
to be able to handle the example I started with.&lt;/p&gt;

&lt;p&gt;Here is the change we make (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/55d076e&quot;&gt;55d076e&lt;/a&gt;). See the comments inline.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# NOTE&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Changing this to '= &quot;&quot;' is likely to fail, as it&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# gets translated into '__get_string(&quot;&quot;)', which&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# will do (callm String new), leading to a loop that&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# will only terminate when the stack blows up.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Setting it &quot;= &amp;lt;some other default&amp;gt;&quot; may work, but&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# will be prone to order of bootstrapping the core&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# classes.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# @buffer contains the pointer to raw memory&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# used to contain the string.&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# &lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# 0 outside of the s-expression eventually will&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# be an FixNum instance instead of the actual&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# value 0.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign @buffer 0)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if (lt numargs 3)
    +         (assign @buffer 0)
    +         (do 
    +            (assign len (callm (index str 0) length))
    +            (callm self __copy_raw ((callm (index str 0) __get_raw) len)))
    +        )&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Next time&lt;/h2&gt;

&lt;p&gt;Next time it will be time to fix &quot;nil&quot;. And since we're going there, maybe &quot;true&quot; and &quot;false&quot; too.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Sun, 28 Sep 2014 13:50:00 +0000</pubDate>
      <dc:date>2014-09-28T13:50:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 37</title>
      <link>http://hokstad.com/compiler/37-default-arguments</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;(I will be at the &lt;a href=&quot;http://brightonruby.com/&quot;&gt;Brighton Ruby Conference&lt;/a&gt; on Monday July 20th
if you're attending and follow my series or just want to talk about Ruby in general,
I'm happy to have a chat)&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;Default arguments&lt;/h2&gt;

&lt;p&gt;First order of business today is to get rid of this abomination from last time:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;c1&quot;&gt;# FIXME: ScannerString is broken -- need to handle String.new with an argument&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#  - this again depends on handling default arguments&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ScannerString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__set_raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Essentially we want to be able to do both &lt;code&gt;String.new&lt;/code&gt; and &lt;code&gt;String.new &quot;foo&quot;&lt;/code&gt;,
and then inherit &lt;code&gt;String&lt;/code&gt; with &lt;code&gt;ScannerString&lt;/code&gt;, and use &lt;code&gt;super&lt;/code&gt; to pass a &lt;code&gt;String&lt;/code&gt;
argument straight through to the super class constructory, so we can change
the code above to:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ScannerString&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This shouldn't be too hard: We pass the argument count to methods, and&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;something&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;.. is equivalent to (pseudo code):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
             &lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
               &lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;something&quot;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;here&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;we&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;really&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;an&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;exception&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The overheads Ruby imposes for all the nice high level stuff should start to become apparent now...&lt;/p&gt;

&lt;p&gt;We don't have support for &lt;code&gt;raise&lt;/code&gt; yet, but we can at least output a message for the &lt;code&gt;else&lt;/code&gt; case too while
we're at it. Of course, the more arguments, the more convoluted the above will get, but it's not &lt;em&gt;hard&lt;/em&gt; -
we have %s(numargs) to get at the argument count, and we should be able to do this pretty much just with
high level constructs.&lt;/p&gt;

&lt;h2&gt;A first naive approach&lt;/h2&gt;

&lt;p&gt;My first attempt was something like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;default&quot;&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;%s(if (gt numargs 4) (printf &quot;ERROR: wrong number of arguments (%d for 1)\n&quot; (sub numargs 2))
           (if (lt numargs 3) (printf &quot;ERROR: wrong number of arguments (%d for 1)\n&quot; (sub numargs 2))
            (if (le numargs 3) (assign arg2 (__get_string &quot;default&quot;))))
             )&lt;/span&gt;
    
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Spot the mistake? It is slightly tricky. The problem is not in this function itself, but in
how the arguments get allocated: Since the &lt;em&gt;caller&lt;/em&gt; allocates space on the stack for the arguments,
if &lt;code&gt;arg2&lt;/code&gt; is not being passed, then there's no slot for it, so we can't assign anything to it.&lt;/p&gt;

&lt;p&gt;One way out of this is to allocate a &lt;em&gt;local&lt;/em&gt; variable, and copy &lt;em&gt;either&lt;/em&gt; the default value &lt;em&gt;or&lt;/em&gt;
or the passed in argument to the local variable, and then rewrite all references to &lt;code&gt;arg2&lt;/code&gt; to
&lt;code&gt;local_arg2&lt;/code&gt; in the rest of the function.&lt;/p&gt;

&lt;p&gt;Another variation is to instead of doing the rewrite, change the &lt;code&gt;Function#get_arg&lt;/code&gt; method to
allow us to &quot;redirect&quot; requests for the argument afterwards. We can do this similarly to
how we reference &lt;code&gt;numargs&lt;/code&gt;, by treating them as negative offsets&lt;/p&gt;

&lt;h2&gt;Parsing&lt;/h2&gt;

&lt;p&gt;We were getting ahead of ourselves. First lets update the parser. In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7bca9f3&quot;&gt;7bca9f3&lt;/a&gt; I've added
this to &lt;code&gt;parse_arglist&lt;/code&gt;. Previously we just ignored the result of the call to the
shunting yard parser. Now we keep it, and treat the argument differently if we have a
default value:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;=&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;nolfws&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@shunting&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;parse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;,&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This change breaks a number of test cases, so there's also a series of updates to
&lt;code&gt;features/parser.feature&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To make this work, we also need to slightly change &lt;code&gt;transform.rb&lt;/code&gt; to actually handle
these arrays in the argument list (which brings up the question of whether or not
it might not be cleaner to modify the parser to store them uniformly, but lets leave
that for later).&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rewrite_let_env&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;depth_first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:defm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;kind_of?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;}]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Creating our own local variables&lt;/h2&gt;

&lt;p&gt;Note that I'm not particularly happy with the approach I'm about to describe. It feels a bit
dirty. Not so much the concept, but the implementation. I'd love suggestions for cleanups.&lt;/p&gt;

&lt;p&gt;But first, there's a test case in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/f25101b&quot;&gt;f25101b&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we turn our attention to &lt;code&gt;function.rb&lt;/code&gt;. &lt;code&gt;Function&lt;/code&gt; and &lt;code&gt;Arg&lt;/code&gt; objects are instantiated
from the data in the parse tree, and we now need to handle the arguments with &lt;code&gt;:default&lt;/code&gt;
in them.&lt;/p&gt;

&lt;p&gt;We start by simply adding a &lt;code&gt;@default&lt;/code&gt; in &lt;code&gt;Arg&lt;/code&gt; (In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1a09e19&quot;&gt;1a09e19&lt;/a&gt; ). You'll note I've also
added a &lt;code&gt;@lvar&lt;/code&gt; that is not being set immediately, as this value will depend on the
function object. But as the comment says, this will be used to let us &quot;switch&quot; this &lt;code&gt;Arg&lt;/code&gt;
object from referring to refer to a local variable that will effectively (and intentionally)
alias the original in the case of defaults.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Arg&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rest&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# The local variable offset for this argument, if it &lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# has a default&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lvar&lt;/span&gt;
    
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;modifiers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# @rest indicates if we have&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# a variable amount of parameters&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@rest&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modifiers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;include?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modifiers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:default&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;modifiers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In &lt;code&gt;Function&lt;/code&gt;, we add a &lt;code&gt;@defaultvars&lt;/code&gt; that keeps track of how many extra local variable
slots we need to allocate. In &lt;code&gt;Function#initialize&lt;/code&gt; we change the initalization of the
&lt;code&gt;Arg&lt;/code&gt; objects, and once we've created it, we assign a local variable slot for this argument.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@defaultvars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lvar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@defaultvars&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@defaultvars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We then initialize &lt;code&gt;@defaults_assigned&lt;/code&gt; to false. This is a new instance variable that will
act as a &quot;switch&quot;. When it is false, compiling request for an argument with a default will
refer to the argument itself. So we're not yet aliasing. At this stage, we need to be careful -
if we read the argument without checking &lt;code&gt;numargs&lt;/code&gt;, we may be reading random junk from the stack.&lt;/p&gt;

&lt;p&gt;Once we switch it to &lt;code&gt;true&lt;/code&gt;, we're telling the &lt;code&gt;Function&lt;/code&gt; object that we wish to redirect requests
for arguments that have defaults to their freshly created local variables. We'll see how this
is done when changing &lt;code&gt;Compiler&lt;/code&gt; shortly.&lt;/p&gt;

&lt;p&gt;Let's now look at &lt;code&gt;get_arg&lt;/code&gt; and some new methods, in reverse order of the source, &lt;code&gt;Function#get_arg&lt;/code&gt;
first:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Previously, we made this a constant for non-variadic&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# functions. The problem is that we need to be able&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# to trigger exceptions for calls with the wrong number&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# of arguments, so we need this always.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:lvar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The above is basically a bug fix. It was a short-sighted optimization (I knew there was a reason
why I don't like premature optimizations, but every now and again they are just too tempting)
which worked great until actually getting the semantics right.&lt;/p&gt;

&lt;p&gt;And this is the start of the part I'm not particularly happy with:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_lvar_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@defaults_assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?#&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Expected lvar - &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; / &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?#&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Basically, if the &lt;code&gt;@defaults_assigned&lt;/code&gt; &quot;switch&quot; has been flipped, &lt;em&gt;or&lt;/em&gt; we &lt;em&gt;explicitly&lt;/em&gt; request
a &quot;fake argument&quot;, we call &lt;code&gt;get_lvar_arg&lt;/code&gt; to try to look it up. If we find it, great. If not,
we check for a normal variable. We feel free to throw an exception for debugging purposes if
we're requesting a &quot;fake argument&quot;, as they should only ever be created by the compiler itself,
and should always exist if they've been created. The &quot;fake argument&quot; here is &quot;#argname&quot; if the
arguments name is &quot;argname&quot;. I chose to use the &quot;#&quot; prefix as it can't legally occur in an
argument name, and so it's safe. It's still ugly, though.&lt;/p&gt;

&lt;p&gt;Next a helper to process the argument list and yield the ones with defaults, and &quot;flip the switch&quot;
when done:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;process_defaults&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# FIXME: Should check that there are no &quot;gaps&quot; without defaults?&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@defaults_assigned&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Last but not least, we do the lookup of our &quot;fake argument&quot;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# For arguments with defaults only, return the [:lvar, arg.lvar] value&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_lvar_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?#&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Expected to have a lvar assigned for &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lvar&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:lvar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Using our own local variables&lt;/h2&gt;

&lt;p&gt;in &lt;code&gt;Compiler#output_functions&lt;/code&gt; (still in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1a09e19&quot;&gt;1a09e19&lt;/a&gt;), we add a bit to actually handle
the default argument:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rest?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;varfreq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;varfreq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defaultvars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;defaultvars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; 
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;              &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;process_defaults&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Default argument for &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; at position &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                &lt;span class=&quot;n&quot;&gt;compile_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:lt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                           &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;default&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                           &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;#&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;              &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;c1&quot;&gt;# FIXME: Also check *minium* and *maximum* number of arguments too.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This piece basically allocates a new stack frame for local variables, and then iterates
through the arguments with defaults; we then compile code equivalent to &lt;code&gt;if numargs &amp;amp;lt; [offset]; #arg = [default value]; else #arg = arg; end&lt;/code&gt; where &quot;arg&quot; is the name of the current argument.&lt;/p&gt;

&lt;h2&gt;Adding checks for minimum and maximum number of arguments&lt;/h2&gt;

&lt;p&gt;What should have been utterly trivial, given the above, turned into a couple of annoying debugging
sessions, due to bugs that were in fact exposed once I started checking the argument numbers...&lt;/p&gt;

&lt;p&gt;But let us start with the actual checks:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;minargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;minargs&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;n&quot;&gt;compile_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:lt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;minargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                     &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                             &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ArgumentError: In %s - expected a minimum of %d arguments, got %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                              &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;minargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]],&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rest?&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;maxargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;maxargs&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;            &lt;span class=&quot;n&quot;&gt;compile_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:gt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                       &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; 
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                               &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ArgumentError: In %s - expected a maximum of %d arguments, got %d&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                                &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maxargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]],&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;These should be reasonably straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If the number of passed arguments is below a calculated minimum (we'll look at &lt;code&gt;Function#minargs&lt;/code&gt; shortly), we &lt;code&gt;printf&lt;/code&gt; an error.&lt;/li&gt;
&lt;li&gt;If the number of passed arguments is below a calculated maximum, we'll &lt;code&gt;printf&lt;/code&gt; another error - unless there's a &quot;splat&quot; (*arg) in the argument list, in which case the number of arguments is unbounded.&lt;/li&gt;
&lt;li&gt;For now, I've just used 1/0 to trigger an floating point exception as a convenient way of exiting. I could have used &lt;code&gt;int 1&lt;/code&gt; or &lt;code&gt;int 3&lt;/code&gt;, which are intended for debugging, but this is temporary until implementing proper exceptions, and I've not surfaced access to the &lt;code&gt;int&lt;/code&gt; instruction to the mid-layer of the compiler, so this is a lazy temporary alternative.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;In &lt;code&gt;Function&lt;/code&gt; (&lt;code&gt;function.rb&lt;/code&gt;), this is &lt;code&gt;#minargs&lt;/code&gt; and &lt;code&gt;#maxargs&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;minargs&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rest?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@defaultvars&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;maxargs&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;rest?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;99999&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(We could leave #maxargs undefined for cases where &lt;code&gt;#rest?&lt;/code&gt; returns true, but really, we could
just as well try to set a reasonable maximum - if it gets ridiculously high, it likely indicates
 a messed up stack again)&lt;/p&gt;

&lt;h2&gt;Fixing saving of caller saved registers&lt;/h2&gt;

&lt;p&gt;One thing that I wasted quite a bit of time with when adding the min/max argument checks was that this
triggered a few lingering bugs/limitations of the current register handling.&lt;/p&gt;

&lt;p&gt;The main culprit was the &lt;code&gt;[:div, 1, 0]&lt;/code&gt; part. As it happens, because this forces use of &lt;code&gt;%edx&lt;/code&gt; (if you
remember, this is because on i386, &lt;code&gt;idivl&lt;/code&gt; explicitly depends on &lt;code&gt;%edx&lt;/code&gt;), which is a caller saved
register, our lack of proper handling of caller saved registers caused spurious errors.&lt;/p&gt;

&lt;p&gt;The problem is that &lt;code&gt;Emitter#with_register&lt;/code&gt; is only safe as long as nothing triggers forced evictions
of registers within the code it uses. This code is going to need further refactoring to make it safer.
For now I've added a few changes to make the current solution more resilient (at the cost of sometimes
making it generate even less efficient code, but it should long since have been clear that efficiency
is secondary until everything is working).&lt;/p&gt;

&lt;p&gt;The most important parts of this change is in &lt;code&gt;Emitter&lt;/code&gt; and &lt;code&gt;RegAlloc&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/3997a31&quot;&gt;3997a31&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Firstly, we add a &lt;code&gt;Emitter#caller_save&lt;/code&gt;, like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;caller_save&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;to_push&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_caller_saved&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:will_push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;to_push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;free!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;to_push&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;alloc!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This depends on an improvement of &lt;code&gt;#evict_caller_saved&lt;/code&gt; that returns the registers that needs to be
saved on the stack, because they've been allocated &quot;outside&quot; of the variable caching (for cached
variables, we can &quot;just&quot; spill them back into their own storage locations, and reload them later,
if they are referenced again). We then push them onto the stack, and explicitly free them, yield
to let the upper layers do what it wants (such as generate a method call), and pop them back off
the stack.&lt;/p&gt;

&lt;p&gt;There's likely lots to be gained from cleaning up the entire method call handling once the dust
settles and things are a bit closer to semantically complete - we'll get back to that eventually,
I promise.&lt;/p&gt;

&lt;p&gt;The new version of &lt;code&gt;evict_caller_saved&lt;/code&gt; looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;evict_caller_saved&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;will_push&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;to_push&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;will_push&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@caller_saved&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;evict_by_cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@by_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;block_given?&lt;/span&gt;
    
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;member?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;will_push&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Allocated via with_register when crossing call boundary: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;to_push&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to_push&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Basically, we iterate through the list of caller-save reigsters, and if we've indicated we
intend to push the values on the stack, we return a list of what needs to be pushed. Otherwise
we raise an error, as we risk losing/overwriting an allocated register.&lt;/p&gt;

&lt;p&gt;You will see &lt;code&gt;Emitter#caller_save&lt;/code&gt; in use in &lt;code&gt;compiler.rb&lt;/code&gt; in &lt;code&gt;#compile_call&lt;/code&gt; and &lt;code&gt;#compile_callm&lt;/code&gt;,
where it simply wraps the code that evaluates the argument list and calls themselves.&lt;/p&gt;

&lt;p&gt;Other than that, I've made some minor hacky changes to make &lt;code&gt;#compile_assign&lt;/code&gt;, &lt;code&gt;#compile_index&lt;/code&gt; and
&lt;code&gt;#compile_bindex&lt;/code&gt; more resilient against these problems.&lt;/p&gt;

&lt;h2&gt;Splats and numarg revisited&lt;/h2&gt;

&lt;p&gt;The last, missing little piece is that it surfaced a bug in the handling of numargs with splats.
In particular, once I added the min/max checks, the call to a class's &lt;code&gt;#initialize&lt;/code&gt; triggered
the errors, because this is done with &lt;code&gt;ob.initialize(*args)&lt;/code&gt; in &lt;code&gt;lib/core/class.rb&lt;/code&gt;, and it didn't
set numargs correctly.&lt;/p&gt;

&lt;p&gt;I'm not going into this change in detail, as it's a few lines of modifications to &lt;code&gt;splat.rb&lt;/code&gt;,
&lt;code&gt;compiler.rb&lt;/code&gt; and &lt;code&gt;emitter.rb&lt;/code&gt;. The significant part of the change is that the splat handling
now expects to overwrite &lt;code&gt;%ebx&lt;/code&gt;, as it should, and &lt;code&gt;Emitter#with_stack&lt;/code&gt; will now set &lt;code&gt;%ebx&lt;/code&gt;
outright &lt;em&gt;unless&lt;/em&gt; it is called after the splat handling, in which case it will &lt;em&gt;add&lt;/em&gt; the number
of &quot;fixed&quot; arguments to the existing &quot;splat argument count&quot; in &lt;code&gt;%ebx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;(We'll still need to go back and fix the splat handling, as we're still not creating a proper
array, and the current support &lt;em&gt;only&lt;/em&gt; works for method calls)&lt;/p&gt;

&lt;h2&gt;Reflections on optimizations&lt;/h2&gt;

&lt;p&gt;While working on this, it struck me that a future optimization to consider is different entry-points
for different variations of the method. While the caller does not really &quot;know&quot; exactly which method
will be called, the caller &lt;em&gt;does&lt;/em&gt; know how many arguments it has, and so knows that either there is
an implementation of a method that &lt;em&gt;can&lt;/em&gt; take that number of arguments, or it will trigger an &lt;code&gt;ArgumentError&lt;/code&gt;
(or should do when we add exceptions).&lt;/p&gt;

&lt;p&gt;Thus, if we allocate vtable slots based on the number of provided arguments too, then static/compile-time
lookups will fail for method calls where no known possible combination of method name / number of
arguments is known at compile time, and it will fall back to the slow path (which we've not yet
implemented).&lt;/p&gt;

&lt;p&gt;The question of course is how much it would bloa the vtables. However this approach can also reduce
the cost of the code, as we can jump past the numargs checks for the version where all arguments
are specified etc.&lt;/p&gt;

&lt;p&gt;Another approach is to decide on rules for &quot;padding&quot; the argument space allocated, so that the most
common cases, of, say 1-2 default arguments can be supported without resorting to extra local variables.
This saves some assignments.&lt;/p&gt;

&lt;h2&gt;Next time&lt;/h2&gt;

&lt;p&gt;... we'll fix &lt;code&gt;super&lt;/code&gt;. Well, add it, as currently it ends up being treated as a regular method call.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>tutorial</category>
      <pubDate>Sat, 19 Jul 2014 19:27:00 +0000</pubDate>
      <dc:date>2014-07-19T19:27:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 36</title>
      <link>http://hokstad.com/compiler/36-scanning-for-problems</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Scanning for problems&lt;/h2&gt;

&lt;p&gt;Where we left off last time, we'd just barely scratched the surface of what it will take to self-host the &lt;code&gt;Scanner&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This time we'll keep digging into that. I will skip or gloss over fixes to some bugs etc., and focus mostly on the bits
that are filling in intentional omissions from earlier that are now finally coming back to bite us, with the exception
of some particularly interesting (to me at least) bugs.&lt;/p&gt;

&lt;p&gt;One of the bugfixes were actually pushed out with the previous branch. See &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e6ae4ba&quot;&gt;e6ae4ba&lt;/a&gt; - this is worth at least
a cursory note as it got the order in which we determined the size of an object instance vs. where I actually
counted up the number of immediately visible instance variables wrong. Ouch.&lt;/p&gt;

&lt;p&gt;By the time this version is out, I'll also have merged a bunch of fixes to make the code work with Ruby 1.9, finally.&lt;/p&gt;

&lt;p&gt;But back to the &lt;code&gt;Scanner&lt;/code&gt; code. This part ended up a lot more convoluted than I'd planned. I've skipped over some of
the details of my debugging, as it got tedious to write and probably twice as much to read, with lots of jumping
back and forth. Th&lt;/p&gt;

&lt;p&gt;For the purposes of this series, I've added &lt;code&gt;features/inputs/scanner4.rb&lt;/code&gt; which is a variation of the &lt;code&gt;Scanner&lt;/code&gt;
code and some minor test code that I will make work in this article. I'll walk through a few issues with it at
the end.&lt;/p&gt;

&lt;h2&gt;ScannerString&lt;/h2&gt;

&lt;p&gt;In &lt;code&gt;scanner.rb&lt;/code&gt; we define &lt;code&gt;Scanner::ScannerString&lt;/code&gt;. &lt;code&gt;ScannerString&lt;/code&gt; is &quot;just&quot; a subclass of &lt;code&gt;String&lt;/code&gt; that allows
us to have the scanner attach a &lt;code&gt;Position&lt;/code&gt; to a token, which again allows us to add position information to the
syntax tree for error reporting and debugging.&lt;/p&gt;

&lt;p&gt;For this part we will lift &lt;code&gt;ScannerString&lt;/code&gt; out of the &lt;code&gt;Scanner&lt;/code&gt; class as embedded classes is not yet supported.&lt;/p&gt;

&lt;p&gt;The next issue is our lack of &lt;code&gt;attr_accessor&lt;/code&gt;. So we end up with this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ScannerString&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;String&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# Instance variables in inherited classes did not work&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Note: It's still awkward to use &quot;nil&quot;, so we cop out for now.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;c1&quot;&gt;# &quot;=&quot; was not handled correctly for vtable thunks?&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newp&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;newp&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@position&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Compiling even this, however, proves a challenge, as per the inline comments above. The latter
was just a trivial issue with the name handling. Test cases in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8cd9c18&quot;&gt;8cd9c18&lt;/a&gt; and a one character fix (!) in
&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/55b9d23&quot;&gt;55b9d23&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The former was trickier - I messed up in some subtle ways when I added the instance variable support that I
missed by not testing with instance variables in sub-classes. I added a test case for this in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e828033&quot;&gt;e828033&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In fixing this, I muddied things up a bit, and I've been too lazy to untangle the changes, as while tracking
down these issues, I added some initial support for &lt;code&gt;#inspect&lt;/code&gt; and getting hold of class names. We'll finish
up that next, to not leave changes hanging.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/ca6f420&quot;&gt;ca6f420&lt;/a&gt; there are some minor changes in &lt;code&gt;GlobalScope&lt;/code&gt; that follows from the changes in &lt;code&gt;ClassScope&lt;/code&gt; -
I'll ignore those - read the commit. The meat is in &lt;code&gt;ClassScope&lt;/code&gt; in &lt;code&gt;scope.rb&lt;/code&gt; (and later we'll look at changes
to &lt;code&gt;compiler.rb&lt;/code&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;186&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;194&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ClassScope&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# slot 0 is reserved for the vtable pointer for _all_ classes.&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# slot 1 is reserved for @instance_size for objects of class Class&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;CLASS_IVAR_NUM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# slot 2 is reserved for @name&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;CLASS_IVAR_NUM&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next_scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;next_scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@next&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;next_scope&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@superclass&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@vtable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@vtableoffsets&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offsets&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@instance_vars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:@__class__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# FIXME: Do this properly&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@ivaroff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@superclass&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_size&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@instance_vars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@superclass&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@__class__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# FIXME: Do this properly&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@class_vars&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The bump in &lt;code&gt;CLASS_IVAR_NUM&lt;/code&gt; is due to adding &lt;code&gt;Class#name&lt;/code&gt; as mentioned above. More
interestingly we now rectify a long standing omission: The scope chain did not keep
track of superclass. We could look it up separately as needed, I guess, but we did
not do that either. We now pass in a scope object that represents
the super class.&lt;/p&gt;

&lt;p&gt;We then assign &lt;code&gt;@ivaroff&lt;/code&gt; to represent the &lt;em&gt;offset&lt;/em&gt; that instance variables for this
class start at. This bug is well into the &quot;embarrassing&quot; category. Without this, when
we subclass a class, and add instance variables, the instance variables will get
overlapping offsets, and overwrite each other. Oops.&lt;/p&gt;

&lt;p&gt;Lastly, we set &lt;code&gt;@instance_vars&lt;/code&gt; to start with &lt;code&gt;@__class__&lt;/code&gt; if there is no super class
provided, to guarantee that we have a place to stash the class pointer (we could alternatively
do this by setting &lt;code&gt;@ivaroff&lt;/code&gt; to 1 in the same situation).&lt;/p&gt;

&lt;p&gt;Next we ensure &lt;code&gt;@ivaroff&lt;/code&gt; is included when we calculate the instance size, so we actually
allocate enough memory for the instances too, unlike before (double-oops...)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;210&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;221&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ClassScope&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
     
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;instance_size&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@instance_vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@instance_vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@ivaroff&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Lastly, we ensure we return the right offset from the instance pointer in &lt;code&gt;ClassScope&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;239&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;250&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;14&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ClassScope&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@instance_vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;add_ivar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@instance_vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ivar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# This will show the name of the current class, the superclass name, the instance variable &lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# name, the offset of the instance variable relative to the current class &quot;base&quot;, and the&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# instance variable offset for the current class which comes in quite handy when debugging&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# object layout:&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;#&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# STDERR.puts [:ivar, @name, @superclass ? @superclass.name : &quot;&quot;,a, offset, @ivaroff].inspect&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ivar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;offset&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@ivaroff&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This isn't &lt;em&gt;quite&lt;/em&gt; enough. We also need to update &lt;code&gt;compile_class&lt;/code&gt; in &lt;code&gt;compiler.rb&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;First we obtain the pointer to the super class, and use that to properly initialize the
class scope:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;635&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;635&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;=== class &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; ===&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ClassScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@vtableoffsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;superc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@classes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;ClassScope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@vtableoffsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;superc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note that there's another shortcut here: Ultimately
we need to compute this too, as people can do nasty stuff like dynamically picking a class,
assigning it to a constant, and subclassing that, so even if we have something that &lt;em&gt;looks&lt;/em&gt; like
a class &lt;strong&gt;name&lt;/strong&gt;, what we actually have is actually an expression that evaluates to the &lt;code&gt;Class&lt;/code&gt;
object of the class that should be the superclass. I don't remember if the parser will even allow
that at the moment, and I'm not in the mood to fix even the &quot;simple&quot; case of someone assigning
stuff to constants and expecting me to treat it as a class, so we'll continue to ignore this for
now and stumble over it later.&lt;/p&gt;

&lt;p&gt;Then we fix up the assignment to the &lt;code&gt;Class&lt;/code&gt; instance for the new class. The inline comment
says it all, really:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;679&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;681&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__new_class_object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;klass_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;superclass&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ssize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]])&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@global_constants&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;
     
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:@instance_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# In the context of &quot;cscope&quot;, &quot;self&quot; refers to the Class object of the newly instantiated class.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# Previously we used &quot;@instance_size&quot; directly instead of [:index, :self, 1], but when fixing instance&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# variable handling and adding offsets to avoid overwriting instance variables in the superclass,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# this broke, as obviously we should not be able to directly mess with the superclass's instance&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# variables, so we're intentionally violating encapsulation here.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;instance_size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# We need to store the &quot;raw&quot; name here, rather than a String object,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# as String may not have been initialized yet&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;cscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But all of that is not enough to fix our test-case (&lt;code&gt;features/inputs/ivar.rb&lt;/code&gt;) as it turns out -
now the instances variables of &lt;code&gt;Foo&lt;/code&gt; are undefined in instances of &lt;code&gt;Bar&lt;/code&gt;, since &lt;code&gt;Bar#initialize&lt;/code&gt; does
not call &lt;code&gt;super&lt;/code&gt; (nor have we implemented support for &lt;code&gt;super&lt;/code&gt; yet...). We need to patch &lt;code&gt;#puts&lt;/code&gt; to
handle our &quot;fake&quot; nils (that are still actual null values), which once again demonstrates that I need to make a decision on exactly what to do about this (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/10d7c6e&quot;&gt;10d7c6e&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;49&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt;
           &lt;span class=&quot;sx&quot;&gt;%s(assign raw (index str (callm i __get_raw)))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;sx&quot;&gt;%s(if raw (puts raw))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;sx&quot;&gt;%s(if raw (puts raw))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Adding Class#name to improve #inspect and &quot;send&quot; debug output&lt;/h2&gt;

&lt;p&gt;Since parts of this made it into the previous commits. &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e977bfc&quot;&gt;e977bfc&lt;/a&gt; adds test cases, and this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Class&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
     
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;name&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(__get_string @name)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;As mentioned earlier, we store the name &quot;raw&quot; to avoid bootstrap issues with &lt;code&gt;String&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another insidious little bug reared its head when dealing with the debugging output.
The method name needs to be the &lt;em&gt;second&lt;/em&gt; argument, since the &lt;em&gt;first&lt;/em&gt; argument is our &quot;hidden&quot;
place to store any block that gets passed to a method:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;522&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;522&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;
             &lt;span class=&quot;c1&quot;&gt;# Argh. Ok, then. Lets do send&lt;/span&gt;
             &lt;span class=&quot;n&quot;&gt;off&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@vtableoffsets&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_offset&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__send__&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
             &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;insert&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;n&quot;&gt;warning&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;WARNING: No vtable offset for '&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;method&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' (with args: &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;) -- you're likely to get a method_missing&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
             &lt;span class=&quot;c1&quot;&gt;#error(err_msg, scope, [:callm, ob, method, args])&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;With that out of the way, our failure to handle &quot;send&quot; can now easily be made to produce more useful output for things like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;As of &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7fc23ae840&quot;&gt;7fc23ae840&lt;/a&gt; you get something like this, correctly identifying the class name and method:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;WARNING: __send__ bypassing vtable (name not statically known at compile time) not yet implemented.
WARNING:    Method: 'bar'
WARNING:    symbol address = 0x8a36750
WARNING:    self = 0x8a36740
WARNING:    class 'Foo'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And a first pass on a default &lt;code&gt;#inspect&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8c74cd6&quot;&gt;8c74cd6&lt;/a&gt;. Clearly adding cleaner support for string
formatting also needs to go on the big list of outstanding items:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  def inspect
    %s(assign buf (malloc 20))
    %s(snprintf buf 20 &quot;%p&quot; self)
    %s(assign buf (__get_string buf))
    &quot;#&quot;
  end
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Chasing rabbits...&lt;/h2&gt;

&lt;p&gt;Like &lt;code&gt;ScannerString&lt;/code&gt;, we'll lift &lt;code&gt;Position&lt;/code&gt; out of &lt;code&gt;Scanner&lt;/code&gt;. We also avoid using &lt;code&gt;Struct&lt;/code&gt;, and so get to write a few lines extra.&lt;/p&gt;

&lt;p&gt;Thanks to the changes above, we now get semi-useful debugging output, and get the dubious pleasure
of chasing down missing piece after piece. With my &quot;scanner test in progress&quot; it warned of a missing
&lt;code&gt;String#empty?&lt;/code&gt; used in &lt;code&gt;Scanner#fill&lt;/code&gt;. I added &lt;code&gt;String#empty&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/334902c&quot;&gt;334902c&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up, I get a method missing for &lt;code&gt;==&lt;/code&gt;. On adding the class name to the method_missing output,
I get &lt;code&gt;Class#==&lt;/code&gt;, which makes no sense. But &lt;code&gt;String#length&lt;/code&gt; is empty, so this represents garbage
where we don't properly clear the return value for an empty method. I added a first pass at
&lt;code&gt;String#length&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/c3eac1f&quot;&gt;c3eac1f&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next up we're warned about &lt;code&gt;Fixnum#getc&lt;/code&gt;?!? Turns out we call &lt;code&gt;@io.getc&lt;/code&gt; in &lt;code&gt;Scanner#get&lt;/code&gt;, and we
stubbed out &lt;code&gt;STDIN&lt;/code&gt; as &lt;code&gt;0&lt;/code&gt; a while back... Changing it to &lt;code&gt;IO.new&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/66e976f&quot;&gt;66e976f&lt;/a&gt;) suddenly gets us
somewhere: My test code waits for input!&lt;/p&gt;

&lt;p&gt;&lt;code&gt;echo Foo | /tmp/scanner4&lt;/code&gt; gave me a &quot;send warning&quot; for &lt;code&gt;Fixnum#chr&lt;/code&gt; which I added in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/186986f&quot;&gt;186986f&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Repeating this gave me method missing for &lt;code&gt;String#[]&lt;/code&gt;. And here we'll spend a little bit more time,
as there are (minor) complications ahead.&lt;/p&gt;

&lt;h2&gt;String#[] and %s(bindex)&lt;/h2&gt;

&lt;p&gt;First lets look at a not particularly inspired first version of &lt;code&gt;String#[]&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7bc84e6&quot;&gt;7bc84e6&lt;/a&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt;
         &lt;span class=&quot;sx&quot;&gt;%s(assign @buffer 0)&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;[]&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;length&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign index (callm index __get_raw))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(assign c (bindex @buffer index))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(__get_fixnum c)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;First of all, we &lt;em&gt;need&lt;/em&gt; bounds checking. &lt;code&gt;String#length&lt;/code&gt; currently counts, which is
obviously stupid, but we'll sort that out later. It's really only the last 3 lines
we care about here. How do we get a single byte out of our strings? Well, so far
we can't easily do that - we haven't exposed any way of addressing single bytes.&lt;/p&gt;

&lt;p&gt;Above that's fixed by introducing &lt;code&gt;bindex&lt;/code&gt; as a byte-oriented alternative to our
32-bit (or in theory pointer-sized - if/when we add a 64 bit target, it needs to
be 64-bit) &lt;code&gt;index&lt;/code&gt; primitive.&lt;/p&gt;

&lt;p&gt;All the code does is obtain the raw index value, use it to obtain the raw byte value,
and then obtain a &lt;code&gt;Fixnum&lt;/code&gt; (note, we're still following Ruby 1.8 behaviour here -
1.9+ returns a &lt;code&gt;String&lt;/code&gt; -, which we probably should stop with, given that the compiler
itself is now updated to support 1.9; but devil you know and all that).&lt;/p&gt;

&lt;p&gt;Apart from adding it to the &lt;code&gt;@@keywords&lt;/code&gt; set in &lt;code&gt;compiler.rb&lt;/code&gt;, we add this, which
is a direct parallel to &lt;code&gt;compile_index&lt;/code&gt; apart from not scaling the value, and
the type we return. If we need more scales we might want to create a more generic
version (also in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/7bc84e6&quot;&gt;7bc84e6&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Compiles an 8-bit array indexing-expression.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Takes the current scope, the array as well as the index number to access.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_bindex&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;source&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:indirect8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This again requires some changes to &lt;code&gt;emitter.rb&lt;/code&gt; to add support for loading &lt;code&gt;:indirect8&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emitter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;emitter&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;234&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;234&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Emitter&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_address&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:indirect&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:indirect8&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_indirect8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:arg&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;load_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;result_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;when&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lvar&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;325&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;327&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Emitter&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(%&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;load_indirect8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;movzbl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;to_operand_value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:stripdollar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: gcc includes this second movzbl; why is it needed?&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;movzbl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:al&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;In which we unwillingly revisit register allocation&lt;/h2&gt;

&lt;p&gt;This leads us further down the rabbit hole: A method missing for &lt;code&gt;String#position&lt;/code&gt;....
Which should be &lt;code&gt;Scanner#position&lt;/code&gt;, accessed via &lt;code&gt;self.position&lt;/code&gt; in &lt;code&gt;Scanner#get&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I wish I'd taken better notes of how I tracked down this bug, but it involved lots of
printf type debugging making use of our now available &lt;code&gt;Class#name&lt;/code&gt; etc., as well as
pouring over the asm output. The problem is actually triggered in &lt;code&gt;Scanner#fill&lt;/code&gt;, which
in my test version looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;fill&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getc&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;chr&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@buf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Looks innocent, because it is. However, the asm output is not so innocent and reflects how
tricky getting register allocation right is. The below fragment reflects just
&lt;code&gt;@buf = c ? c.to_s : &quot;&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
       # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Allocated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;reg&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;ecx&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;c&lt;/span&gt;
        # [:&lt;span class=&quot;operator&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;ecx&lt;/span&gt;]
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;testl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;je&lt;/span&gt;  &lt;span class=&quot;label&quot;&gt;.L189&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Above we've loaded &lt;code&gt;c&lt;/code&gt; and we're jumping to &lt;code&gt;.L189&lt;/code&gt; if false.&lt;/p&gt;

&lt;p&gt;Now we execute &lt;code&gt;c.to_s&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;operator&quot;&gt;callm&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;c.&lt;/span&gt;:&lt;span class=&quot;label&quot;&gt;to&lt;/span&gt;_&lt;span class=&quot;label&quot;&gt;s&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Already&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;cached&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;ecx&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;c&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;popl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esi&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esi&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;call&lt;/span&gt;    *&lt;span class=&quot;number&quot;&gt;384&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Evicting&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;c.to&lt;/span&gt;_&lt;span class=&quot;label&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;END&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;jmp&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;.L190&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;At the end, note that we're marking &lt;code&gt;self&lt;/code&gt; as evicted from &lt;code&gt;%esi&lt;/code&gt; where we put it.&lt;/p&gt;

&lt;p&gt;Now for the &quot;else&quot; part, that just returns an empty string:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;L189&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebx&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;L0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$__get_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;*%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RA: Allocated reg 'esi' for self&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# [:arg, 0, :esi]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Hang on? At the end, this reloads &lt;code&gt;self&lt;/code&gt; into &lt;code&gt;%esi&lt;/code&gt;, which in itself isn't a problem.
The problem is that since the very next label, &lt;code&gt;.L190&lt;/code&gt;, reflects a merge of two
control flows, even though &lt;code&gt;self&lt;/code&gt; was just reloaded, unless we know that &lt;code&gt;self&lt;/code&gt; will
be present in &lt;code&gt;%esi&lt;/code&gt; when leaving the &quot;if&quot; arm above too, the code below is broken:&lt;/p&gt;

&lt;p&gt;.L190:
    movl    %eax, %ecx
    # RA: Already cached 'esi' for self
    movl    %ecx, 8(%esi)&lt;/p&gt;

&lt;p&gt;... because it assumes &lt;code&gt;self&lt;/code&gt; is cached. And in fact, it is totally broken: &lt;code&gt;%esi&lt;/code&gt;
will reflect the class of &lt;code&gt;c&lt;/code&gt;, because of the &lt;code&gt;c.to_s&lt;/code&gt; call that is the last part
of the ternary-if arm above. There are several ways of fixing this, one of them
being to try to prove which registers are safe across both control flows. The other,
the brute-force approach, is to assume all bets are off and start afresh.&lt;/p&gt;

&lt;p&gt;The change is trivial, so you can see it in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/549e091&quot;&gt;549e091&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Method 'comma' ?!?&lt;/h2&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/tmp/s&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;canner4&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Got&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;70&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PEEK&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bypassing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;statically&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;known&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implemented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Method&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'comma'&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;symbol&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;address&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8580510&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x85802e0&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'Scanner'&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Method&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;missing: &lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Class&lt;/span&gt;&lt;span class=&quot;c1&quot;&gt;#==&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We don't have a method comma. So let's break out the debug output with &lt;code&gt;ruby compiler.rb --norequire --parsetree&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;defm&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__env__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__tmp_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comma&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@lineno&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The relevant part corresponds to:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@lineno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;So let's add a test case to &lt;code&gt;parser.feature&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Position.new(@filename,@lineno,@col)&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:Position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:&quot;@filename&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;@lineno&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:&quot;@col&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;       &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The problem here is in &lt;code&gt;treeoutput.rb&lt;/code&gt;, which badly needs more comments... The code
attempts to simplify the parse tree created by the operator precedence parser, in
order to make it easier to work with later.&lt;/p&gt;

&lt;p&gt;The relevant part is this, which triggers on method calls etc.. I've included the
one line fix as a diff. It's in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/13368e0&quot;&gt;13368e0&lt;/a&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;la&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;leftv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;o&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sym&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ra&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:flatten&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;][&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:block&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;comma&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ra&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:comma&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comma&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;       &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;comma&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;flatten&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rightv&lt;/span&gt;          
            &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comma&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;block&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@vstack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;leftv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@vstack&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;leftv&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The hint to the location comes from seeing the &quot;comma&quot; reference. If we add a &lt;code&gt;--dont-rewrite&lt;/code&gt;
flag and re-run &lt;code&gt;ruby compiler.rb&lt;/code&gt; as above, we get this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
              &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Position&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comma&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;comma&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@lineno&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;So the rewrite fails to rewrite the last part. The bug probably stems from forgetting that
&lt;code&gt;rightv&lt;/code&gt; in the above case refers to the entire argument list.&lt;/p&gt;

&lt;h2&gt;Delayed reaction&lt;/h2&gt;

&lt;p&gt;The next problem up is a method missing for &lt;code&gt;Class#==&lt;/code&gt;, which occurs in &lt;code&gt;Scanner#get&lt;/code&gt; where
I marked with &quot;(1)&quot;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fill&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;position&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;# (2)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@buf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;slice!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;# (1)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ch&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@lineno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@lineno&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;So at &lt;code&gt;(1)&lt;/code&gt;, ch is of object &lt;code&gt;Class&lt;/code&gt;. Since we get &lt;code&gt;ch&lt;/code&gt; from &lt;code&gt;@buf.slice!(-1,1)&lt;/code&gt; above, that's
where we need to look. The immediately obviously reason is that &lt;code&gt;String#slice!&lt;/code&gt; was not implemented
at all. It is in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/5133315&quot;&gt;5133315&lt;/a&gt; which I'm not in the mood to walk through (but do feel free to ask in
the comments if anything is unclear) - it's virtually guaranteed to be possible to clean up. The only
thing I want to mention is &lt;code&gt;__copy_raw&lt;/code&gt;, which is an alternative to &lt;code&gt;__set_raw&lt;/code&gt; that will copy the
raw buffer instead of just setting the pointer:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__copy_raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(assign len (callm len __get_raw))&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(assign @buffer (malloc len))&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(memmove @buffer str len)&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In the above commit I've also included &lt;code&gt;String#==&lt;/code&gt; as that is the &quot;next one out&quot; and quite obviously
so from the earlier error. The one thing to worth noting about that, is that &quot;!&quot; is not implemented,
and that I also added an &lt;code&gt;Object#true&lt;/code&gt; as a workaround. A shameful hack.&lt;/p&gt;

&lt;p&gt;Next we need &lt;code&gt;Object#nil?&lt;/code&gt;, because &quot;!&quot; does not work, and so a &quot;!&quot; occurrence in &lt;code&gt;Scanner#get&lt;/code&gt;
was changed to &lt;code&gt;#nil?&lt;/code&gt; for the test code.&lt;/p&gt;

&lt;h2&gt;Fixnum#position !?&lt;/h2&gt;

&lt;p&gt;Since we've already run into problems with register allocation, I'm not going to go into a lot of
detail about the debugging here. Suffice to say that given that we're not actually calling &quot;#position&quot;
on what should be a &lt;code&gt;Fixnum&lt;/code&gt;, it was time to break out the assembly source, and look at what was
actually being called. It was quickly clear that the wrong value was in the register.&lt;/p&gt;

&lt;p&gt;I decided it was time to add some rspec tests for &lt;code&gt;regalloc.rb&lt;/code&gt;, and you can find the first set in
&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/9bfee76&quot;&gt;9bfee76&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That didn't reveal anything, and I had to start digging into &lt;code&gt;#with_register&lt;/code&gt;. The test case that
reproduces the problem is in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8dcd18b&quot;&gt;8dcd18b&lt;/a&gt; together with the one line fix. The problem turned out
to be that &lt;code&gt;#with_register&lt;/code&gt; calls &lt;code&gt;evict&lt;/code&gt; on a register found in the cache, and then hands the
register out, without taking into account that &lt;code&gt;evict&lt;/code&gt; put the register back on the free list.&lt;/p&gt;

&lt;h2&gt;Return&lt;/h2&gt;

&lt;p&gt;Next is another case of the wrong value being returned. Going over assembly output again, I could
find no obvious register allocation issue. Next up was peppering some &lt;code&gt;puts some_object.class.name&lt;/code&gt;
around to see where the objects got confused, and this let to &lt;code&gt;compile_return&lt;/code&gt;. This is likely
indirectly a regression caused by the register allocation: As it turns out, previously, we've not
used the return statement other than in cases where it was not strictly necessary, as the last
computation left the result in &lt;code&gt;%eax&lt;/code&gt;. But this is substantially less likely after introducing
the register allocation.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#compile_return&lt;/code&gt; simply did not ensure the result of the evaluation of its argument would be
saved to `%eax:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;leave&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;ret&lt;/span&gt;
         &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And there we are...&lt;/p&gt;

&lt;h2&gt;Some notes on scanner4.rb&lt;/h2&gt;

&lt;p&gt;I'll just briefly mention some remaining problems.&lt;/p&gt;

&lt;p&gt;First of all, I found a bug in string interpolation, that I'll likely fix separate from the following articles, unless
it proves particularly interesting:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# Works:&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#    puts self.lineno&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#    puts self.filename&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# FIXME: Seg faults&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;#    &quot;line #{self.lineno}, col #{self.col} in #{self.filename}&quot;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;# FIXME: Including self.lineno or self.col seg faults:&lt;/span&gt;
        &lt;span class=&quot;s2&quot;&gt;&quot;line &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@lineno&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, col &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; in &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Secondly there's this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;c1&quot;&gt;# FIXME: += translates to &quot;incr&quot; primitive, which is a low level instrucion&lt;/span&gt;
     &lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@col&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;As above, I might fix that separately. For now I considered the workaround the most expedient way of getting further.&lt;/p&gt;

&lt;p&gt;Lastly there's this horrific piece:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# FIXME: ScannerString is broken -- need to handle String.new with an argument
#  - this again depends on handling default arguments

    s = ScannerString.new
    r = ch.__get_raw
    s.__set_raw(r)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This obviously needs to be fixed. The issue is that a proper fix it requires handling default arguments, as well as &lt;code&gt;super&lt;/code&gt; so that &lt;code&gt;ScannerString&lt;/code&gt; as a subclass of &lt;code&gt;String&lt;/code&gt; can pass on the string argument rather than set it after the fact (I could have hidden the &lt;code&gt;#__get_raw&lt;/code&gt; and &lt;code&gt;#__set_raw&lt;/code&gt; bits in &lt;code&gt;ScannerString&lt;/code&gt;, but that would just have obscured the problem)&lt;/p&gt;

&lt;h2&gt;Next&lt;/h2&gt;

&lt;p&gt;Next we'll deal with the issue above, of default arguments and &lt;code&gt;super&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then in the following part, we'll be looking at the next step towards compiling a test program that uses the compiler code to parse s-expressions, which will
be to get &lt;code&gt;Scanner#expect&lt;/code&gt; to work.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <pubDate>Fri, 27 Jun 2014 03:05:00 +0000</pubDate>
      <dc:date>2014-06-27T03:05:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 35</title>
      <link>http://hokstad.com/compiler/35-towards-self-hosting</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Towards Self Hosting&lt;/h2&gt;

&lt;p&gt;As mentioned &lt;a href=&quot;/compiler/34-self-in-a-register&quot;&gt;last time&lt;/a&gt;, this time around,
I've first landed a number of changes that will make the parser able to parse the
entire compiler (whether or not it parses it &lt;em&gt;correctly&lt;/em&gt; or not remains to be seen,
and is outside the scope).&lt;/p&gt;

&lt;p&gt;You can find these merged in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/37d6a0510&quot;&gt;37d6a0510&lt;/a&gt; and &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/44914839a72&quot;&gt;44914839a72&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Secondly, we'll start looking at small parts of the compiler to break into pieces
that are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Amenable to separate testing&lt;/li&gt;
&lt;li&gt;Simple enough to try to compile&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The goal is to lay the groundwork for refactoring what we now have into smaller
units that at the same time both allow us to unit test the module &lt;em&gt;and&lt;/em&gt; use it as
a test case for the compiler at the same time. Each module we can compile will then
both give increased confidence in the generated code &lt;em&gt;and&lt;/em&gt; bring us one step closer
to the state where the compiler can fully compile itself.&lt;/p&gt;

&lt;p&gt;A good set of candidates to start with appears to be the basic &lt;code&gt;Scanner&lt;/code&gt; class,
followed by the code to parse and print our &quot;s-expression syntax&quot;. Will it prove
more challenging than expected? We'll see...&lt;/p&gt;

&lt;h2&gt;Compiling Scanner&lt;/h2&gt;

&lt;p&gt;The remarkable thing is that &quot;out of the box&quot; &lt;code&gt;./compile scanner.rb&lt;/code&gt; actually
yields a binary, though it will not-so-remarkably run into missing &quot;stuff&quot; on trying to run it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ /tmp/scanner
attr_reader col
define_method col
Method missing: __send__
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Note that this &lt;em&gt;also&lt;/em&gt; means that e.g. it quietly accepts that it has no
definition for &lt;code&gt;Struct&lt;/code&gt;. However that is actually in line with Ruby
semantics, and one of the things that makes efficiency such a problem:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ruby scanner.rb&lt;/code&gt; runs all the way through (with no output), as it is
legal to reference an un-defined variable - it is first if we try to
&lt;em&gt;access&lt;/em&gt; it we are meant to get an error.&lt;/p&gt;

&lt;p&gt;In reality, for a compiler, we'll likely want to at least warn about
the most obvious of these at least (I'm sure I can fill several articles
on the topic of adding warnings for &quot;legal but stupid&quot; behaviour in
semi-sane ways, but lets wait until we can actually compile a reasonably
sized program first).&lt;/p&gt;

&lt;h3&gt;The challenges&lt;/h3&gt;

&lt;p&gt;In its present form, &lt;code&gt;Scanner&lt;/code&gt; actually presents some challenges off
the bat just from a cursory look:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It defines an inner class&lt;/li&gt;
&lt;li&gt;It relies on &lt;code&gt;Struct&lt;/code&gt; which we haven't done anything to implement (and
then re-opens the new class, which we don't yet support.&lt;/li&gt;
&lt;li&gt;It relies on &lt;code&gt;attr_accessor&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;It uses blocks&lt;/li&gt;
&lt;li&gt;It uses #respond_to?&lt;/li&gt;
&lt;li&gt;It references &lt;code&gt;Tokens::Keyword&lt;/code&gt;. Looking up &lt;code&gt;Tokens::Keyword&lt;/code&gt; will likely fail&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is why self hosting is such a useful step - you're instantly faced with the
practicalities of a real program written in the language. And while this program is
in our control, making too drastic changes to it will defeat the purpose, so we have
an incentive to fix things properly whenever reasonable.&lt;/p&gt;

&lt;h3&gt;Some solutions&lt;/h3&gt;

&lt;p&gt;We now have to consider whether to add support for these, whether full or temporary
hacks, or change &lt;code&gt;Scanner&lt;/code&gt; accordingly.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;#respond_to?&lt;/code&gt;: Doing this properly involves a &lt;code&gt;Hash&lt;/code&gt; of the methods of a class.
We'll make a note the method hash is needed, and defer that to a future part.
Instead we'll hack up a default &lt;code&gt;#respond_to?&lt;/code&gt; which is rater anaemic, and
override it for &lt;code&gt;ScannerString&lt;/code&gt;, which is the point here anyway.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;We'll ignore the inner classes, and move ScannerString and Position out of
Scanner.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Struct&lt;/code&gt;: We'll change the code here, and define a &quot;proper&quot; &lt;code&gt;Position&lt;/code&gt; class
and defer &lt;code&gt;Struct&lt;/code&gt; until later.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;attr_accessor&lt;/code&gt;: We've had our painful trip down &lt;em&gt;this&lt;/em&gt; road before. I'm not inclined
to revisit it anytime soon. We'll do this the hacky way, and special case &lt;code&gt;attr_accessor&lt;/code&gt; /
&lt;code&gt;attr_reader&lt;/code&gt; / &lt;code&gt;attr_writer&lt;/code&gt; to custom generate methods for now at least (it may be the
best long term solution, though they were the &quot;test case&quot; for &lt;code&gt;define_method&lt;/code&gt; previously)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Blocks could / should work in &lt;em&gt;theory&lt;/em&gt;. Lets see what is broken and fix it.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;Tokens::Keyword&lt;/code&gt;: Lets refactor this part. The code calling &lt;code&gt;Tokens::Keyword&lt;/code&gt; does not
belong in the &lt;code&gt;Scanner&lt;/code&gt;. Lets move it to &lt;code&gt;ParserBase&lt;/code&gt;, and thus defer this issue.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;#is_a?&lt;/code&gt;: &lt;code&gt;Scanner#initialize&lt;/code&gt; uses '#is_a?' to see if it has been given a &lt;code&gt;File&lt;/code&gt; or a stream.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;File.file?&lt;/code&gt;, &lt;code&gt;File.expand_path&lt;/code&gt; and &lt;code&gt;#path&lt;/code&gt; are used if we're given a &lt;code&gt;File&lt;/code&gt; object, to extract and expand the path name.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;But first of all, lets start chopping &lt;code&gt;Scanner&lt;/code&gt; into pieces and creating test cases
to see what works and doesn't, and then gradually flesh out a more and more complete
equivalent.&lt;/p&gt;

&lt;h3&gt;The first few tests&lt;/h3&gt;

&lt;h4&gt;STDIN and STDOUT&lt;/h4&gt;

&lt;p&gt;We will need to be able to read from somewhere for the &lt;code&gt;Scanner&lt;/code&gt; class to work, so lets
first add a basic test of &lt;code&gt;STDIN&lt;/code&gt; and &lt;code&gt;STDOUT&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;no&quot;&gt;STDOUT&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello world from STDOUT&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}}}&lt;/span&gt;   
    
    &lt;span class=&quot;no&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;instantly&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fails&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;we&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;haven&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'t even defined STDOUT. We'&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ll&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;remedy&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;adding&lt;/span&gt;
    
        &lt;span class=&quot;no&quot;&gt;STDOUT&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;IO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;to &lt;code&gt;lib/core/core.rb&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/d24d56b&quot;&gt;d24d56b&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Next we add a test of STDIN:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;getc&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;and modify our step definition to echo &quot;test&quot; into the compiled binaries. This will also fail
because STDIN is missing. We make the same change as for STDOUT, but in this case it is not
enough:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;WARNING: __send__ bypassing vtable not yet implemented.
WARNING:    Called with 0x8766bf8
WARNING:    self = 0x8766b78
WARNING:    (string: 'getc')
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This one comes when there is no allocated vtable slot. The intent is for the class structures
to use vtable slots like in C++ for example for most methods. The heuristics used to allocate
vtable slots currently considers only methods we have seen &lt;em&gt;defined&lt;/em&gt;, not methods that have
been otherwise mentioned. In this case &lt;code&gt;#getc&lt;/code&gt; has not been defined anywhere yet, and so
the compiler should have done a lookup in a hash table for this class, and then ended up
falling back on a generic &lt;code&gt;#method_missing&lt;/code&gt;, but the hash lookup is not yet implemented.&lt;/p&gt;

&lt;p&gt;Anyway, lets put in place a &lt;code&gt;#getc&lt;/code&gt; in &lt;code&gt;lib/core/io.rb&lt;/code&gt;. This is harder than expected, as
our s-expression language does not expose a way to get addresses to stack variables easily.
So here's a first, horribly inefficient, stab (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/54a0c13&quot;&gt;54a0c13&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;c1&quot;&gt;# FIXME: This code is specific to a 32 bit little endian&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# arch, and is also horribly inefficient because we don't&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# have an easy way of getting the address of a stack allocated&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# variable.&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(do
             (assign tmp (malloc 4))
             (assign (index tmp 0) 0)
             (read 0 tmp 1)
             (assign c (__get_fixnum (index tmp 0)))
             (free tmp)
             )&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Of course we can do a lot better by adding, say, an &quot;(addr var)&quot; construct. This is
still horribly bad, though - no error checking from &lt;code&gt;read&lt;/code&gt;; and it just reads from
&lt;code&gt;STDIN&lt;/code&gt; regardless of desired filedescriptor for this &lt;code&gt;IO&lt;/code&gt; object, and it does no
buffering, and other nastiness. Plenty to deal with later...&lt;/p&gt;

&lt;h4&gt;The constructor&lt;/h4&gt;

&lt;p&gt;Our first test case from the actual Scanner class will be the only tricky part in &lt;code&gt;#initialize&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Scanner&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# set filename if io is an actual file (instead of STDIN)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# otherwhise, indicate it comes from a stream&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;stream&amp;gt;&quot;&lt;/span&gt;
    
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Scanner&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;STDIN&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;However this will fail:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Object#is_a? not implemented
Method missing: file?
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Looking more closely into this, we'll find a few things: First I thought I'd not yet implemented
the ternary conditional, but the actual problem is that it fails to parse the ternary correctly
in the face of the logical and ('&amp;amp;&amp;amp;'). You can see this if you run the compiler like this: &lt;code&gt;ruby compiler.rb --parsetree -norequire features/inputs/scanner1.rb&lt;/code&gt;. This is likely &quot;just&quot; a priority issue.&lt;/p&gt;

&lt;p&gt;But let's untangle this into two tests - one with the ternary if, and one without.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;file?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;File&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;expand_path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;path&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@filename&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&amp;lt;stream&amp;gt;&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Changing the ternary to a full if will still prove interesting. Let us quickly hack in
a &lt;code&gt;#is_a?&lt;/code&gt; just for &lt;code&gt;File&lt;/code&gt;. First we need to add one to &lt;code&gt;lib/core/object.rb&lt;/code&gt; (&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/882c71b&quot;&gt;882c71b&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# We're pessimists&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Now for the next surprise: We don't have false, do we? We've defined false/true in &lt;code&gt;lib/core/core.rb&lt;/code&gt;, but there they are ordinary local variables, only accessible in the main scope. We really ought to give them special treatment as fake global variables referring to global instances of &lt;code&gt;FalseClass&lt;/code&gt; and &lt;code&gt;TrueClass&lt;/code&gt;, but that opens another can of worms (we can no longer assume non-null means true and null means false, which will change comparisons.&lt;/p&gt;

&lt;p&gt;For the time being we sidestep this by defining &lt;code&gt;false in&lt;/code&gt;Object` as a method (!) (I added that too in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/882c71b&quot;&gt;882c71b&lt;/a&gt;) :&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;false&lt;/span&gt;
         &lt;span class=&quot;sx&quot;&gt;%s(sexp 0)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This gives us another surprise when trying to compile &lt;code&gt;features/inputs/scanner2.rb&lt;/code&gt; (&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/04b6060&quot;&gt;04b6060&lt;/a&gt;) ; the one without the ternary if:&lt;/p&gt;

&lt;p&gt;We still get &quot;Method missing file?&quot;, which means the second part of the supposedly short-circuiting '&amp;amp;&amp;amp;' expression gets executed, but we're not passing a &lt;code&gt;File&lt;/code&gt; object in.&lt;/p&gt;

&lt;p&gt;This is yet another of our earlier convenient hacks that now needs to be sorted out: &lt;code&gt;&amp;amp;amp;&amp;amp;amp;&lt;/code&gt; gets turned into &lt;code&gt;and&lt;/code&gt;, which in turn gets interpreted as a &lt;em&gt;method call&lt;/em&gt; because the compiler does not have a builtin &lt;code&gt;and&lt;/code&gt; construct. As a result, it is evaluated after its arguments. Or rather, it would have been, had not the second argument been a sub-expression which itself fails.&lt;/p&gt;

&lt;p&gt;As a lesson in why proper testing is essential, let us use this as an excuse to skip &lt;code&gt;File.file?&lt;/code&gt; and &lt;code&gt;File.expand_path&lt;/code&gt; and &lt;code&gt;File#path&lt;/code&gt; this time around: Instead let use make the compiler handle &lt;code&gt;&amp;amp;amp;&amp;amp;amp;&lt;/code&gt; properly, so that we never get to them. Well, as long as we're only ever trying to compile from &lt;code&gt;STDIN&lt;/code&gt; anyway. It's a start.&lt;/p&gt;

&lt;h4&gt;Fixing the short circuit operator.&lt;/h4&gt;

&lt;p&gt;The changes to handle it are absolutely minor: We need to add ':and' to the list of keywords in
&lt;code&gt;compiler.rb&lt;/code&gt;, and define &lt;code&gt;compile_and&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/75d1ecd62d&quot;&gt;75d1ecd62d&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;c1&quot;&gt;# Shortcircuit 'left &amp;amp;&amp;amp; right' is equivalent to 'if left; right; end'&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;compile_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But the test case also reveals another bug: When adding the caching of 'self', I failed to account
for the special handle of 'self' in the outermost scope (it's treated as a global variable). Maybe
treating the global scope any differently is the mistake, and we should just put that too on the
stack, but for now the fix is trivial: Just add a check for &lt;code&gt;[:global,:self]&lt;/code&gt; in &lt;code&gt;get_arg&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lvar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:arg&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lvar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:global&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Doing a &quot;./compile features/inputes/shortcircuit.rb&quot; (or running the rspec tests) now yields a
/tmp/shortcircuit that actually short-circuits.&lt;/p&gt;

&lt;p&gt;And &lt;code&gt;features/inputs/scanner2.rb&lt;/code&gt; now successfully sidesteaps the methods on &lt;code&gt;File&lt;/code&gt; we're being
too lazy to implement. Though &lt;code&gt;features/inputs/scanner1.rb&lt;/code&gt; that uses the ternary conditional
still crashes, so there's that.&lt;/p&gt;

&lt;p&gt;This is where we'll leave it for now.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;This part probably seems all over the place, but it's part of the fun once you get to a stage
where it becomes viable to start looking at bootstrapping the compiler in itself.&lt;/p&gt;

&lt;p&gt;I'll make the next few parts shorter than some of the 3000+ word monsters I've put out in the past,
to also try to focus them a bit more, but next time will focus on getting &lt;code&gt;Scanner#get&lt;/code&gt; and &lt;code&gt;Scanner#unget&lt;/code&gt; to work, and then work our way through &lt;code&gt;Scanner#expect&lt;/code&gt; and &lt;code&gt;Scanner#ws&lt;/code&gt; too. If you look
at our intended milestone of getting the s-expression parser to compile, it might look like that
brings us almost there.&lt;/p&gt;

&lt;p&gt;Not so - look forward to complication after complication being revealed as we stumble into class
after class, method after method, that we need to implement at least partially before we get there.
And possibly some more simplifying compiler changes to sidestep some of them.&lt;/p&gt;

&lt;p&gt;But incidentally, each one of them will make the next parts of the compiler easier to get past too.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>operators</category>
      <pubDate>Fri, 16 May 2014 05:00:00 +0000</pubDate>
      <dc:date>2014-05-16T05:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 34</title>
      <link>http://hokstad.com/compiler/34-self-in-a-register</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Putting Self In A Register&lt;/h2&gt;

&lt;p&gt;Where we left off, we had a simple but tolerable register allocator. But as it happens, for now
at least the code will not often get all that huge benefits from it, for the simple reason that a
huge amount of a typical Ruby application consists of method calls, and most of these method calls
causes us to have to evict most of the registers.&lt;/p&gt;

&lt;p&gt;However, there is one obvious candidate for the register treatment that we have alreay touched on:&lt;/p&gt;

&lt;p&gt;self.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;self&lt;/code&gt; is even more ubiquitous in Ruby programs than the source lets on: In addition
to every method call, every access to an instance variable is conceptually either
&lt;code&gt;&amp;lt;self offset&amp;gt;&lt;/code&gt; or  &lt;code&gt;&amp;lt;self.some_hidden_hash_table var&amp;gt;&lt;/code&gt;. Every class
variable requires &lt;code&gt;self.class&lt;/code&gt;, and thus &lt;code&gt;self&lt;/code&gt;. And so on.&lt;/p&gt;

&lt;p&gt;And when calling a method on another object, &lt;code&gt;self&lt;/code&gt; just temporarily changes - usually the &quot;new self&quot;
will be used a number of times before we return.&lt;/p&gt;

&lt;p&gt;So then, this is why I &quot;reserved&quot; a register for caching &lt;code&gt;self&lt;/code&gt; - we'll use &lt;code&gt;%esi&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I originally intended to include it in the register allocation part, but when that ballooned to 6k
words (including source, to be fair), I decided enough was enough.&lt;/p&gt;

&lt;p&gt;In comparison, this part will be pleasantly short and simple.&lt;/p&gt;

&lt;h2&gt;Changing the calling convention&lt;/h2&gt;

&lt;p&gt;More than just caching &lt;code&gt;self&lt;/code&gt;, we will change the calling convention somewhat:&lt;/p&gt;

&lt;p&gt;For now, while we still retain self on the stack (I'm not sure whether I'll keep it that way,
but I'd rather avoid messing with it right now), we also put it in &lt;code&gt;%esi&lt;/code&gt; before we call the
method.&lt;/p&gt;

&lt;p&gt;The reasons for doing so are fairly simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;It means we can assume &lt;code&gt;self == %esi&lt;/code&gt; throughout a method, &lt;em&gt;except&lt;/em&gt; immediately surrounding
a method call on another object.&lt;/li&gt;
&lt;li&gt;We have been loading the object value into a register in order to use an indirect load to
get &lt;code&gt;self.class&lt;/code&gt; anyway, so we might as well use that load to load &lt;code&gt;self&lt;/code&gt; straight into
&lt;code&gt;%esi&lt;/code&gt; and leave it there for the duration.&lt;/li&gt;
&lt;li&gt;Since &lt;code&gt;%esi&lt;/code&gt; is callee saved, we can trust that it won't suddenly change on us in a
method call or function call to external code - when the code returns, &lt;code&gt;%esi&lt;/code&gt; should still
refer to the object we just called a method on&lt;/li&gt;
&lt;li&gt;It makes the code pleasantly simple...&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;Since &lt;code&gt;%esi&lt;/code&gt; is callee saved, it means that we should be able to defer reloading &lt;code&gt;self&lt;/code&gt; into
it after a call until/unless we know it is needed. This will save some reloads, and may also
allow it to be reused on occasion when we call multiple methods on the same object in succession.
I'll leave that optimization for later, though.&lt;/p&gt;

&lt;p&gt;There are a few parts to this change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure &lt;code&gt;%esi&lt;/code&gt; is reloaded on method exit; we'll do this in &lt;code&gt;#output_functions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Changing &lt;code&gt;#compile_callm&lt;/code&gt; to load the &quot;new self&quot; for the called method as needed, and reload &lt;code&gt;self&lt;/code&gt; if needed&lt;/li&gt;
&lt;li&gt;adding a few helpers to &lt;code&gt;Compiler&lt;/code&gt; and &lt;code&gt;Emitter&lt;/code&gt; as part of refactoring that code&lt;/li&gt;
&lt;li&gt;a minor change to the new register allocator in order to recognize &lt;code&gt;%esi&lt;/code&gt;'s special status.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;We'll go through them &quot;from the top&quot; (of the call flow) anyway. You can find all the code
for this part in this single commit: &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/4b190694bc&quot;&gt;4b190694bc&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;output_functions&lt;/h3&gt;

&lt;p&gt;The only change here is that we want to make sure that &lt;code&gt;%esi&lt;/code&gt; is returned to its original state.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Reloading self if evicted:&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;c1&quot;&gt;# Ensure %esi is intact on exit, if needed:&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;reload_self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fscope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note that this is slightly broken: In the case of &lt;code&gt;defun&lt;/code&gt; nodes, it will load the global &lt;code&gt;self&lt;/code&gt;,
but for these nodes, &lt;code&gt;%esi&lt;/code&gt; will actually originally contain the calling &lt;code&gt;self&lt;/code&gt;. We'll sort
that out later - for now theres a little workaround at the end of &lt;code&gt;#compile_defun&lt;/code&gt;. This
triggers unnecessary &lt;code&gt;self&lt;/code&gt; reloads, but it works:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_regs_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;reload_self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;compile_callm&lt;/h2&gt;

&lt;p&gt;The change to &lt;code&gt;compile_callm&lt;/code&gt; is pleasantly small. It only involves the block that's called
back from &lt;code&gt;#compile_callm_args&lt;/code&gt; to handle the actual call, and should be reasonably
self-explanatory (but I'll explain it anyway):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;n&quot;&gt;compile_callm_args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here, if we're calling a method on an object named anything other than &lt;code&gt;self&lt;/code&gt;, we load
the address of the object from the top of the stack, where it has been stuffed as part
of preparing the arguments anyway. Do note that this is in many cases going to be wasteful:
If the method only has static arguments (or no arguments), we can safely load it into &lt;code&gt;%esi&lt;/code&gt;
first, and &lt;em&gt;then&lt;/em&gt; put it onto the stack from &lt;code&gt;%esi&lt;/code&gt;, potentially (unless the object is
already in a register) saving a memory load. That's one of many low hanging fruits for
optimization later on.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;load_indirect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:esi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;If, on the other hand, we called a method on &lt;code&gt;self&lt;/code&gt;, we &quot;reload&quot; &lt;code&gt;self&lt;/code&gt; if needed.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Reload self?&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;reload_self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;#reload_self&lt;/code&gt; is just a tiny helper that calls &lt;code&gt;#get_arg(scope,:self)&lt;/code&gt; for now,
and relies on the register allocation in &lt;code&gt;#get_arg&lt;/code&gt; to reload &lt;code&gt;%esi&lt;/code&gt; with &lt;code&gt;self&lt;/code&gt;
if it has been evicted.&lt;/p&gt;

&lt;p&gt;And here's our cleaned up code to load self.class, and call the right vtable offset.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
            &lt;span class=&quot;n&quot;&gt;load_class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Load self.class into %eax&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Finally, if the object wasn't &lt;code&gt;self&lt;/code&gt;, we ensure &lt;code&gt;self&lt;/code&gt; is evicted from &lt;code&gt;%esi&lt;/code&gt; so that
it will be reloaded later if needed.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Evicting self&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_regs_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The only other change in &lt;code&gt;Compiler&lt;/code&gt; is to evict &lt;code&gt;self&lt;/code&gt; when starting a new scope for
classes - see the start of &lt;code&gt;#compile_class&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;Emitter&lt;/h3&gt;

&lt;p&gt;For the emitter, I've added more debug output as comments to the code - I'll ignore
those changes, you can find them in the commit.&lt;/p&gt;

&lt;p&gt;Other than that, I've made the following changes.&lt;/p&gt;

&lt;p&gt;First, a new &lt;code&gt;#callm&lt;/code&gt; method that moves the offset calculations etc. out of &lt;code&gt;Compiler&lt;/code&gt;,
where it didn't belong:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;c1&quot;&gt;# Call an entry in a vtable, by default held in %eax&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_caller_saved&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;*&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;off&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Emitter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;(%&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Other than that, I've just added a single line to &lt;code&gt;Emitter#func&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cache_reg!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This ensures that the compiler treats &lt;code&gt;%esi&lt;/code&gt; as already holding &lt;code&gt;self&lt;/code&gt; when entering
a method.&lt;/p&gt;

&lt;h3&gt;RegisterAllocator&lt;/h3&gt;

&lt;p&gt;To the register allocator there are a few more changes.&lt;/p&gt;

&lt;p&gt;First I've added the name of the cached variable to the cache. I've also added an
instance variable holding the register set aside for &lt;code&gt;self&lt;/code&gt;, and started refactoring
to handle the caller saved variables separately. See &lt;code&gt;#evict_by_cache&lt;/code&gt; and &lt;code&gt;#evict_vars&lt;/code&gt;
for that change.&lt;/p&gt;

&lt;p&gt;The main changes, though, are to give &lt;code&gt;self&lt;/code&gt; special treatment as a variable with its own
special register that won't otherwise be handed out.&lt;/p&gt;

&lt;p&gt;This is mainly handled here in &lt;code&gt;#cache_reg!&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;174&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;13&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;191&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;18&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RegisterAllocator&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# available, the emitter will use its scratch register (e.g. %eax)&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# instead&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cache_reg!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;member?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:self&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@selfreg&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;member?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;self in action&lt;/h3&gt;

&lt;p&gt;Let us finally take a look at what some of our now slightly less horrible code looks like.&lt;/p&gt;

&lt;p&gt;This is one of our test cases, found in &lt;code&gt;features/inputs/method2.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;foo&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And here is the asm output for &lt;code&gt;Foo#bar&lt;/code&gt;. You can see the copious comments
that the register allocation emits, but I've added some extra commentary
inline anyway:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
    __&lt;span class=&quot;label&quot;&gt;method_Foo_bar:&lt;/span&gt;
        &lt;span class=&quot;directive&quot;&gt;.stabn&lt;/span&gt;  &lt;span class=&quot;number&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LM463&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LFBB126&lt;/span&gt;
    &lt;span class=&quot;label&quot;&gt;.LM463:&lt;/span&gt;
    &lt;span class=&quot;label&quot;&gt;.LFBB126:&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;At this point &lt;code&gt;%esi&lt;/code&gt; holds &lt;code&gt;self&lt;/code&gt;, but as a &quot;backup&quot; &lt;code&gt;[:arg,0]&lt;/code&gt;
in the compiler, which is mapped at &lt;code&gt;8(%ebp)&lt;/code&gt;, also holds &lt;code&gt;%esi&lt;/code&gt;.
Though in this case, we luckily won't need it, as you can see
&lt;code&gt;self&lt;/code&gt; remains in &lt;code&gt;%esi&lt;/code&gt; throughout:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;callm&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;self.&lt;/span&gt;:&lt;span class=&quot;label&quot;&gt;puts&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;At this point, the compiler is trying to push &lt;code&gt;self&lt;/code&gt; onto the
stack, and when it checks the register cache, it tells us self
is already in &lt;code&gt;%esi&lt;/code&gt;, courtesy of explicitly marking it as
cached in &lt;code&gt;Emitter#func&lt;/code&gt;. it then proceeds to fill in the arguments:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Already&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;cached&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;esi&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%esi&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Allocated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;reg&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;ecx&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;arg&lt;/span&gt;
        # [:&lt;span class=&quot;operator&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;ecx&lt;/span&gt;]
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;popl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here it is checking if it needs to reload &lt;code&gt;self&lt;/code&gt; into the register.
If the arguments had contained expressions that included calls to
methods of other objects, that might have been necessary. But not
this time. So it loads &lt;code&gt;self.class&lt;/code&gt; via an indirect load from &lt;code&gt;(%esi)&lt;/code&gt;
(as a reminder, if &lt;code&gt;esi&lt;/code&gt; and &lt;code&gt;eax&lt;/code&gt; was C variables, &lt;code&gt;movl (%esi), %eax)&lt;/code&gt;
is equivalent to &lt;code&gt;eax = esi[0]&lt;/code&gt; or &lt;code&gt;eax = *esi&lt;/code&gt;). Then it does
the method call, via the vtable - the address of &lt;code&gt;#puts&lt;/code&gt; have happened
to get allocated to slot 36.&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;operator&quot;&gt;Reload&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;?
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Already&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;cached&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;esi&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esi&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;call&lt;/span&gt;    *&lt;span class=&quot;number&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self.puts&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;END&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Finally, we need to check if there's a chance &lt;code&gt;%esi&lt;/code&gt; has been evicted
but not reloaded yet, so we can ensure &lt;code&gt;%esi&lt;/code&gt; has the right value when
we return back up to the calling method. In this case, &lt;code&gt;%esi&lt;/code&gt; already
holds the right thing:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;operator&quot;&gt;Reloading&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;evicted&lt;/span&gt;:
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Already&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;cached&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;esi&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;leave&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;ret&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Let's take a look at another example too, namely the start of &lt;code&gt;Object#puts&lt;/code&gt;
(note that &lt;code&gt;Object&lt;/code&gt; is not the right place for &lt;code&gt;#puts&lt;/code&gt; - it is there temporarily
because we don't support modules yet):&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
    __&lt;span class=&quot;label&quot;&gt;method_Object_puts:&lt;/span&gt;
        &lt;span class=&quot;directive&quot;&gt;.stabn&lt;/span&gt;  &lt;span class=&quot;number&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LM347&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LFBB65&lt;/span&gt;
    &lt;span class=&quot;label&quot;&gt;.LM347:&lt;/span&gt;
    &lt;span class=&quot;label&quot;&gt;.LFBB65:&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        &lt;span class=&quot;directive&quot;&gt;.stabn&lt;/span&gt;  &lt;span class=&quot;number&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;37&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LM348&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LFBB65&lt;/span&gt;
    &lt;span class=&quot;label&quot;&gt;.LM348:&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Allocated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;reg&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;edi&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;numargs&lt;/span&gt;
        # [:&lt;span class=&quot;operator&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-1&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;edi&lt;/span&gt;]
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edi&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%edi&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;__&lt;span class=&quot;label&quot;&gt;get&lt;/span&gt;_&lt;span class=&quot;label&quot;&gt;fixnum&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;call&lt;/span&gt;    *&lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here we see what currently happens when we call a function defined with &lt;code&gt;%s(defun ...)&lt;/code&gt;.
Because I've been too lazy to ensure it doesn't load the &quot;wrong&quot; &lt;code&gt;self&lt;/code&gt; before exit,
I added the workaround to forcibly reload &lt;code&gt;self&lt;/code&gt; after the call, and that is what is
happening here. It's wasteful, so I'll address this soon:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Evicted&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Allocated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;reg&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;esi&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        # [:&lt;span class=&quot;operator&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;esi&lt;/span&gt;]
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here comes a call to &lt;code&gt;#==&lt;/code&gt;, which gets a double whammy, as the other argument is a
literal &lt;code&gt;2&lt;/code&gt;, and so triggers a call to &lt;code&gt;__get_fixnum&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-20&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;directive&quot;&gt;.stabn&lt;/span&gt;  &lt;span class=&quot;number&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;39&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LM349&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.LFBB65&lt;/span&gt;
    &lt;span class=&quot;label&quot;&gt;.LM349:&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;callm&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;na.&lt;/span&gt;:==
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Allocated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;reg&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;ecx&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;na&lt;/span&gt;
        # [:&lt;span class=&quot;operator&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;ecx&lt;/span&gt;]
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-20&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;__&lt;span class=&quot;label&quot;&gt;get&lt;/span&gt;_&lt;span class=&quot;label&quot;&gt;fixnum&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;call&lt;/span&gt;    *&lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Evicted&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Allocated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;reg&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;esi&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;self&lt;/span&gt;
        # [:&lt;span class=&quot;operator&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;esi&lt;/span&gt;]
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esi&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This code is still far from optimal. Ignoring all the &lt;em&gt;other&lt;/em&gt; problems, in terms of
the &lt;code&gt;self&lt;/code&gt; caching, we evict &lt;code&gt;self&lt;/code&gt; on return from a &lt;code&gt;call&lt;/code&gt; node just because
the current code doesn't maintain the calling convention properly. But after
the previous part, I want to keep this short and focused, so lets leave it
here for now.&lt;/p&gt;

&lt;h2&gt;Next time&lt;/h2&gt;

&lt;p&gt;... we will revisit an old goal: Self-hosting.&lt;/p&gt;

&lt;p&gt;First I'll land a number of changes that will make the parser able to parse the
entire compiler (whether or not it parses it &lt;em&gt;correctly&lt;/em&gt; or not remains to be seen,
and is outside the scope).&lt;/p&gt;

&lt;p&gt;Secondly, we'll start looking at small parts of the compiler to break into pieces
that are:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Amenable to separate testing&lt;/li&gt;
&lt;li&gt;Simple enough to try to compile&lt;/li&gt;
&lt;/ol&gt;


&lt;p&gt;The goal is to lay the ground work for refactoring what we now have into smaller
units that at the same time both allow us to unit test the module &lt;em&gt;and&lt;/em&gt; use it as
a test case for the compiler at the same time. Each module we can compile will then
both give increased confidence in the generated code &lt;em&gt;and&lt;/em&gt; bring us one step closer
to the state where the compiler can fully compile itself.
&amp;lt;/self.some_hidden_hash_table&gt;&lt;/self&gt;&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <pubDate>Wed, 16 Apr 2014 01:45:00 +0000</pubDate>
      <dc:date>2014-04-16T01:45:00+00:00</dc:date>
    </item>
    <item>
      <title>The Oberon-07 language report is 17 pages</title>
      <link>http://hokstad.com/oberon</link>
      <description>&lt;p&gt;&lt;a href=&quot;http://wirth-symposium.ethz.ch/&quot;&gt;Niklaus Wirth turned 80 this year&lt;/a&gt;, and when stumbling on this
link &lt;a href=&quot;https://news.ycombinator.com/item?id=7578724&quot;&gt;on HackerNews&lt;/a&gt;, I was reminded that I have had
some notes sitting around in my drafts for a long time.&lt;/p&gt;

&lt;h2&gt;The Oberon-07 language report&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;http://www.inf.ethz.ch/personal/wirth/Oberon/Oberon07.Report.pdf&quot;&gt;You can find the PDF here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It starts with an Albert Einstein quote:&lt;/p&gt;

&lt;p&gt;&amp;gt; Make it as simple as possible, but not simpler.&lt;/p&gt;

&lt;h2&gt;How Wirth influenced me&lt;/h2&gt;

&lt;p&gt;Wirth was one of my earliest computer science influences. Ever since we got a copy of &lt;a href=&quot;http://en.wikipedia.org/wiki/Turbo_Pascal&quot;&gt;Turbo Pascal&lt;/a&gt;,
3.3 I think, which my dad got hold of for his new PC - probably in 1987 or so -, I have been fascinated by Wirth.
I don't remember &lt;em&gt;why&lt;/em&gt; my dad got Turbo Pascal. While he did some programming, and made a living of it for
many years, his focus was dBase. He may have considered using it, or it may have been because he thought
I'd like it.&lt;/p&gt;

&lt;p&gt;You can see &lt;a href=&quot;http://bitsavers.informatik.uni-stuttgart.de/pdf/borland/turbo_pascal/TURBO_Pascal_Reference_Manual_CPM_Version_3_Dec88.pdf&quot;&gt;why I was fascinated by checking out the TP 3.0 manual (PDF)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What fascinated me was the BNF for Pascal: The entire language syntax was defined in about 5 pages of BNF.
As if that was not enough, I soon learned that Niklaus Wirth published on of the first &lt;a href=&quot;http://en.wikipedia.org/wiki/Extended_Backus%E2%80%93Naur_Form&quot;&gt;Extended Backus-Naur
Form&lt;/a&gt; descriptions (there are now many
variations).&lt;/p&gt;

&lt;p&gt;Soon I was trying to figure out how to write compilers. My earliest experiments were with Turbo Pascal,
which required more knowledge of PC internals than I had. I moved back to my C64, and wrote some small
initial attempts of demo-oriented micro-languages (e.g. one had a &quot;raster&quot; command that'd generate code
for simple interrupt driven raster effects... rather specialised). Later I moved on to the Amiga, and
&lt;a href=&quot;http://blog.home.hokstad.com/operator-precedence-parser&quot;&gt;used eventually ended up using Pascal again for one of my most serious compiler efforts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But Wirth influenced me in deeper ways too, and the Oberon-07 language report in many ways exemplifies
what I love about his languages.&lt;/p&gt;

&lt;p&gt;For a while I wanted to study at ETH because of him, but while I didn't go ahead with that, for years
I've kept track of their computer science research groups. One fun thing is that one of the speakers
at the symposium for his 80th birthday was Professor Michael Franz at UC Irvine, one of Wirths Ph.D.
students, whose doctoral dissertation from 1994 is one of my all time favourite papers, describing
&lt;a href=&quot;/semantic-dictionary-encoding&quot;&gt;Semantic Dictionary Encoding&lt;/a&gt;, an alternative to &quot;normal&quot; CPU independent
bytecode. (One of Michael Franz students again, Andreas Gal, is familiar to a lot of people who follow
Javascript interpreter work, from his work on Trace Trees)&lt;/p&gt;

&lt;p&gt;I'm deeply indebted to Wirth for setting the trajectory of the way I think about programming languages
This may seem odd given how much I &lt;a href=&quot;/compiler&quot;&gt;write about Ruby&lt;/a&gt;, a language which in many ways is
the anti-thesis of Wirthian languages. But while I love programming &lt;em&gt;in&lt;/em&gt; Ruby, one of my motivations
for wanting to write a Ruby compiler was in fact trying to make sense of the language, and &quot;untangling&quot;
it and trying to understand if there are ways of simplifying it while retaining it's flexibility, much
in the spirit of how Wirth's language career was one long journey of reduction of complexity. And
this stands as one of his most important legacies:&lt;/p&gt;

&lt;h2&gt;The simplicity of Oberon should stand as a beacon&lt;/h2&gt;

&lt;p&gt;The syntax of the entire Oberon-07 language takes up page 16 and half of page 17 of the report.&lt;/p&gt;

&lt;p&gt;This is not news, but I like to revisit various parts of &lt;a href=&quot;http://en.wikipedia.org/wiki/Niklaus_Wirth&quot;&gt;Niklaus Wirth&lt;/a&gt;'s
legacy every now and again for the simple reason that his compilers and his languages are exceptional for their
simplicity.&lt;/p&gt;

&lt;p&gt;Wirth himself has said he was vary about adding features to his language specifications that he did not have
a clear idea of how to implement or how they would work. His group did plenty of research on augmentations
to his languages, informing the &lt;em&gt;next&lt;/em&gt; generation, but each specification is based on careful selection of
&lt;em&gt;proven&lt;/em&gt; features and lessons learned from the previous languages.&lt;/p&gt;

&lt;p&gt;Oberon follows from Modula, follows from Pascal, follows from Algol-W, follows from Euler, following from Wirths
work on the Algol-60 committee, presenting an unbroken chain of careful &lt;em&gt;engineering&lt;/em&gt; stretching from the 60's until
Wirths latest revisions to the Oberon-07 report quite recently (this year).&lt;/p&gt;

&lt;p&gt;These languages are under-appreciated, which is particularly sad given the enormous success of products like
Turbo Pascal and later Delphi that shaped a huge number of programmers.&lt;/p&gt;

&lt;p&gt;It is also particularly silly since these languages are so small and simple to learn. It is 17 pages. And it
is not 17 pages of mathematical notation or hugely complicated ideas. It is 15 pages of mostly prose and a few
tables, and 1.5 pages of the syntax re-stated formally in BNF.&lt;/p&gt;

&lt;p&gt;It is &lt;em&gt;simple&lt;/em&gt; prose. Consider section 2. Syntax:&lt;/p&gt;

&lt;p&gt;&amp;gt; A language is an infinite set of sentences, namely the sentences well formed according to its
&amp;gt; syntax. In Oberon, these sentences are called compilation units. Each unit is a finite sequence of
&amp;gt; symbols from a finite vocabulary. The vocabulary of Oberon consists of identifiers, numbers,
&amp;gt; strings, operators, delimiters, and comments. They are called lexical symbols and are composed of
&amp;gt; sequences of characters. (Note the distinction between symbols and characters.)
&amp;gt;
&amp;gt; To describe the syntax, an extended Backus-Naur Formalism called EBNF is used. Brackets [ and ]
&amp;gt; denote optionality of the enclosed sentential form, and braces { and } denote its repetition (possibly
&amp;gt; 0 times). Syntactic entities (non-terminal symbols) are denoted by English words expressing their
&amp;gt; intuitive meaning. Symbols of the language vocabulary (terminal symbols) are denoted by strings
&amp;gt; enclosed in quote marks or by words in capital letters.&lt;/p&gt;

&lt;p&gt;That's it. The BNF rules for the various parts of the language are then presented in each relevant
section, as well as restated in the final two pages in one go.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Updated: Fixed the article link; corrected to take into account Paul McJones comments on chronology
of Euler and Algol-W&lt;/strong&gt;&lt;/p&gt;
</description>
      <category>programming</category>
      <category>compilers</category>
      <pubDate>Sun, 13 Apr 2014 02:00:00 +0000</pubDate>
      <dc:date>2014-04-13T02:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 33</title>
      <link>http://hokstad.com/compiler/33-register-allocation</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;p&gt;It took me two months to push this out, but I promise it doesn't mean I'm about
to stop publishing these again anytime soon. I intend to shorten my &quot;lead time&quot;
further again, so I'm hoping to publish the next one in 2-3 weeks time.&lt;/p&gt;

&lt;h2&gt;Register Allocation&lt;/h2&gt;

&lt;p&gt;We saw in some of the recent parts that the code is getting more and more prone to
problems due to attempts at reusing registers.&lt;/p&gt;

&lt;p&gt;Register allocation is the proper solution to this. That is, to introduce a mechanism
for determining what code gets to use which registers when, and that handles the situation
where too few registers are available properly (by &quot;spilling&quot; registers onto the stack)&lt;/p&gt;

&lt;p&gt;Let me first make it clear that the &lt;em&gt;really&lt;/em&gt; naive alternative to this is to avoid
register allocation entirely, and to declare a few registers to be &quot;scratch&quot; registers
that can only be safely used within code where no code generation is delegated further
down.&lt;/p&gt;

&lt;p&gt;This is possible to do by pushing all intermediate results onto the stack, and popping
them off only briefly to carry out necessary operations and push them back onto the
stack again (optionally with simple optimizations to operate directly on the top
of the stack for single operand operations or when possible with the last of multiple
operand instructions).&lt;/p&gt;

&lt;p&gt;Basically, this means you're &quot;emulating&quot; a &lt;a href=&quot;http://en.wikipedia.org/wiki/Stack_machine&quot;&gt;stack machine&lt;/a&gt;
with registers.&lt;/p&gt;

&lt;p&gt;This is an approach taken by many simple compilers for unoptimized code, deferring
the problem of register allocation to optimization passes.&lt;/p&gt;

&lt;p&gt;In reality we're very close to that, and in some respects I wish I'd kept &lt;em&gt;purely&lt;/em&gt; to
that approach, not least because it took me two months to get time to wrap up this
part properly. But on the other hand, doing very basic register allocation is not &lt;em&gt;that&lt;/em&gt;
hard, and since we've started down that path we might as well go a bit further.&lt;/p&gt;

&lt;p&gt;Only a bit mind you.&lt;/p&gt;

&lt;p&gt;We will in fact in this part refactor some code to need register allocation &lt;em&gt;less&lt;/em&gt;,
to the point where we can get away with only minor adjustments to the original really
primitive allocator.&lt;/p&gt;

&lt;p&gt;Optimal register allocation is hard, and tends to require  analysis that will require
or at least strongly favor a solution with a low level intermediate representation that
allows more in-depth analysis of register usage.&lt;/p&gt;

&lt;p&gt;A first step is generally to analyse &quot;liveness&quot; of each variable, including temporary
variables introduced by the compiler. Then the problem basically boils down to finding
a way to map as many variable references as possible to registers so that you don't
exceed the available number of registers for your architecture at any one point.&lt;/p&gt;

&lt;p&gt;The &quot;at any one point&quot; part adds complexity, since reuse of registers is central to
minimizing the number of memory accesses, which is the main goal of register allocation:&lt;/p&gt;

&lt;p&gt;For most systems, memory accesses are substantially slower than register access
(though this is less of an issue in these days of multi-level processor caches than
in the old days where every memory access when to external memory; when you fail to hit
cache, though, you are far more brutally penalized on modern CPUs as the gap between
CPU performance and memory latency has widened)&lt;/p&gt;

&lt;p&gt;If you have n registers, and no more than n variables are &quot;live&quot; at once, then you
have it easy if you are able to determine wich variables are &quot;live&quot;.&lt;/p&gt;

&lt;p&gt;The fun begins when (and on an architecture like i386, this is likely to be pretty
much all the time) the code block you are allocating registers for is referencing
more stuff than you have registers for.&lt;/p&gt;

&lt;p&gt;This either means &quot;spilling&quot; the contents of a register to memory in the middle of
a function in order to load another variable, or keeping some variables you'd like
to have in a register in memory instead, other than when operating on it.&lt;/p&gt;

&lt;p&gt;That's where the challenge arises.&lt;/p&gt;

&lt;p&gt;(though Ruby reduces this problem through other inefficiences: Almost everything
is accessed via methods, which reduces the number of variables that are easy
to put into registers; we may hope to improve on that later, but for now it reduces
the immediate benefit of register allocation)&lt;/p&gt;

&lt;p&gt;Another typical approach is &lt;a href=&quot;http://en.wikipedia.org/wiki/Graph_coloring&quot;&gt;graph coloring&lt;/a&gt;,
which I'm not going to go into at all, as it's slow and complicated. A more recent
approach is &lt;a href=&quot;http://en.wikipedia.org/wiki/Register_allocation&quot;&gt;Linear Scan allocators, covered on the Wikipedia page for register allocation&lt;/a&gt;,
which is popular for JIT's etc because it is in general a lot faster (and simpler)
at the cost of some performance in the generated code.&lt;/p&gt;

&lt;p&gt;In any case, down the rabbit hole you go...&lt;/p&gt;

&lt;p&gt;I have no desire to deal with that anytime soon, and &lt;em&gt;especially not&lt;/em&gt; on an
architecture like i386 where the number of registers is so small. On, say, x86-64,
or M68k it'd be a different matter, as you have vastly better chances of being
able to keep a substantial proportion of intermediate results in registers and
largely avoid spilling the results to the stack, and so  you're a real sucker if
you don't take maximal advantage of the registers (however, as mentioned above,
without other work, we'd have problems taking full advantage).&lt;/p&gt;

&lt;p&gt;(translation: I'll have to deal with this &lt;em&gt;some day&lt;/em&gt;, but not now)&lt;/p&gt;

&lt;p&gt;What we will do for now is to mostly rely on keeping stuff in memory (including on
the stack), except for short term loading stuff into &lt;code&gt;%eax&lt;/code&gt; when operating on it.
As needed we'll also use &lt;code&gt;%edx&lt;/code&gt; (see below). Beyond that, we will just guess wildly
at some heuristics...&lt;/p&gt;

&lt;p&gt;Apart from the guessing wildly at some heuristics part, this is roughly what we've
done so far anyway...&lt;/p&gt;

&lt;p&gt;But so far we've done the register allocation extremely ad-hoc, so it is worth first
establishing our actual conventions. We start with the C calling convention, since
we're trying to allow our code to call C code directly:&lt;/p&gt;

&lt;h3&gt;C calling convention on i386&lt;/h3&gt;

&lt;p&gt;We roughly follow &lt;a href=&quot;http://en.wikipedia.org/wiki/X86_calling_conventions#cdecl&quot;&gt;the cdecl calling convention for i386&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That is, we will aim for &lt;code&gt;%eax&lt;/code&gt;, &lt;code&gt;%ecx&lt;/code&gt; and &lt;code&gt;%edx&lt;/code&gt; to be caller saved. That is,
if we rely on them to maintain their values, we will push them onto the stack
before calling another method.&lt;/p&gt;

&lt;p&gt;In practice we will treat &lt;code&gt;%eax&lt;/code&gt; as a scratch register that is only used for short
windows, and so we will rarely if ever want to bother to save it, especially as it
is also generally used as the return value anyway.&lt;/p&gt;

&lt;p&gt;Everything else is to be callee saved (but see caveat below); that is, if they are
used in the &lt;em&gt;called&lt;/em&gt; method, they will be saved there, and needs to be back to
their original value by the time the method returns.&lt;/p&gt;

&lt;p&gt;And we store arguments on the stack.&lt;/p&gt;

&lt;p&gt;Next we add on some extensions:&lt;/p&gt;

&lt;h3&gt;Additions for splats and arity&lt;/h3&gt;

&lt;p&gt;Specifically we store the number of arguments in &lt;code&gt;%ebx&lt;/code&gt; as methods needs to be
able to determine the precise number of arguments whether due to &quot;splats&quot;
or to throw appropriate exceptions to enforce arity (ensure that the number
of arguments matches the declared number of arguments for the method; we
don't do this yet).&lt;/p&gt;

&lt;p&gt;Note that this breaks the &quot;cdecl&quot; calling convention. However this is only a
problem if C code (or other code conforming to the &lt;code&gt;cdecl&lt;/code&gt; calling convention)
calls into our code.&lt;/p&gt;

&lt;p&gt;For now we're not sticking our head into that worms nest (though you need to
be aware of this if you want to experiment with the code and use C-functions
like &lt;code&gt;qsort&lt;/code&gt; which uses callbacks), so it's a non-issue (if/when we do, we'll
either need to consider preserving &lt;code&gt;%ebx&lt;/code&gt;, or more likely we'll need to
bridge calls, as the method will likely require &lt;code&gt;%ebx&lt;/code&gt; to hold the number of
arguments for more than just the splats to work (e.g. Ruby methods are expected
to throw &lt;code&gt;ArgumentError&lt;/code&gt; if called with the wrong number of arguments, which
will eventually force us to add additional checks at the start of each method).&lt;/p&gt;

&lt;p&gt;As a result, &lt;code&gt;%ebx&lt;/code&gt; is in practice free other than on entering a function, as
we save it to the local stack frame. I'm of two minds whether to keep passing
the number of arguments this way, as the code has gotten to the point where we
end up temporarily pushing it on the stack anyway on call, and pushing it on
the stack again afterwards. The only real current benefit of using a register
for it is that we can directly call C functions that are totally unaware of
how we pass the number of arguments.&lt;/p&gt;

&lt;p&gt;These C functions don't know about the &quot;fake&quot; &lt;code&gt;numargs&lt;/code&gt; &quot;variable&quot; anyway,
and so we could as an alternative introduce a way of indicating we want C
calling convention that would just leave out numargs entirely. It'd be
slightly more hassle to use, but it'd only ever be used for low level &lt;code&gt;%s()&lt;/code&gt;
code anyway.&lt;/p&gt;

&lt;p&gt;We're not going to change this right now, regardless.&lt;/p&gt;

&lt;h3&gt;What's left?&lt;/h3&gt;

&lt;p&gt;Well, on i386 we have &lt;code&gt;%ecx&lt;/code&gt;,&lt;code&gt;%edx&lt;/code&gt;,&lt;code&gt;%esi&lt;/code&gt;, &lt;code&gt;%edi&lt;/code&gt;. The &quot;problem&quot; is that all
of them have special purposes in some cases. We've run into one of them: &lt;code&gt;%edx&lt;/code&gt;
is used to hold the high 32 bits of the dividend for &lt;code&gt;idivl&lt;/code&gt;, and the remainder
of the result, and needs special treatment as a result. There's also a number
of floating point registers.&lt;/p&gt;

&lt;p&gt;We also have &lt;code&gt;%ebp&lt;/code&gt; which we use for the frame pointer to access local variables
and method arguments via, and &lt;code&gt;%esp&lt;/code&gt;, the stack pointer.&lt;/p&gt;

&lt;p&gt;As discussed above, we could in theory use &lt;code&gt;%ebx&lt;/code&gt;, with the caveat that while the
splat handling is as is is, it'll get clobbered often, so for now I've kept it out.&lt;/p&gt;

&lt;p&gt;(There are many other register &lt;em&gt;names&lt;/em&gt; on i386, but many of them alias 16- and 8-bit
portions of the 32-bit registers referred to above; as someone who grew up with M68k
asm, where this kind of thing did not occur, in general I'll pretend I never heard
about that wart)&lt;/p&gt;

&lt;h2&gt;What to use the free registers for?&lt;/h2&gt;

&lt;p&gt;As I said, we'll guess wildly.&lt;/p&gt;

&lt;p&gt;As a first approximation, we'll make &lt;code&gt;%esi&lt;/code&gt; hold &lt;code&gt;self&lt;/code&gt; from the first
reference to self in each method. We'll cover the implementation of that in
the next part, so for now we will ignore &lt;code&gt;%esi&lt;/code&gt;. This is because method calls
and instance variable access both require &lt;code&gt;self&lt;/code&gt;, and so we can assume it
will be quite frequent, and as I will show next time, this pans out quite
nicely.&lt;/p&gt;

&lt;p&gt;I toyed with the idea of making &lt;code&gt;%edi&lt;/code&gt; hold &lt;code&gt;self.class&lt;/code&gt;, based on the
same assumption, but this has two problems: It reduces the set of registers
available to us further, &lt;em&gt;and&lt;/em&gt; it complicates handling of eigenclasses:&lt;/p&gt;

&lt;p&gt;The &quot;internal&quot; inheritance chain for Ruby objects can actually change at
nearly any time, if someone decides to extend the object with methods
tied to the objects meta class / eigenclass. If we cache &lt;code&gt;self.class&lt;/code&gt;
that limits us in how to handle that further down the line. So for now
I won't do anything about that.&lt;/p&gt;

&lt;p&gt;This leaves us with &lt;code&gt;%ecx&lt;/code&gt;, &lt;code&gt;%edx&lt;/code&gt; and &lt;code&gt;%edi&lt;/code&gt; free for allocation so far. We
further allow &quot;forced&quot; allcation of specific registers in order to handle
cases like &lt;code&gt;idivl&lt;/code&gt; metioned earlier.&lt;/p&gt;

&lt;p&gt;At the same time we'll make some small changes
that has the effect of minimizing the amount of time temporary values are
kept in registers that has the effect of ensuring we never need many of them.&lt;/p&gt;

&lt;p&gt;Then we'll add a &quot;quick and dirty scan&quot; step that will simply create a
set of candidate variables as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We only consider local variables or arguments. Considering instance variables
etc. adds all sorts of problems that will come back and bite us when we add
thread support. I'd rather think about those issues at a later time.&lt;/li&gt;
&lt;li&gt;We only consider variables that are not &quot;captured&quot; by a closure, for much the
same reason: We lose control over what/who/when effects of assignments etc.
might be seen. This can be much improved - e.g. allocating a register for
such variables, but &quot;spilling&quot; them when the closure is created, and allocating
them again inside the body of the closure should in general be fine, but
it's easy to mess it up, so one thing at a time.&lt;/li&gt;
&lt;li&gt;We count the number of times the variable is referenced, and sort by that.
When we run out of registers, we prefer to evict / free up the registers
used to cache the least frequently used (in that method) variables. This is
sub-optimal, as we don't make any attempts at figuring out &lt;em&gt;where&lt;/em&gt; in a
method the variable is used. We'll get back to that (much) later.&lt;/li&gt;
&lt;li&gt;In any case ignore anything that's only referenced once (as we'll rather
just load that into a scratch register)&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Note that at this point we &lt;em&gt;could&lt;/em&gt; go the next step and store information about
liveness ranges, and use that to allow register usage to overlap, but one step
at a time. The main thing is to get the overall mechanism in place.&lt;/p&gt;

&lt;h3&gt;What will we do with this information?&lt;/h3&gt;

&lt;p&gt;As little as possible. On accesing any local variables or arguments, we
check if they're in a register first, if not we try to load it into a free
register if there is one, and if not we fall back on the current behaviour of
using &lt;code&gt;%eax&lt;/code&gt; (and reloading / saving the variable on each access).&lt;/p&gt;

&lt;p&gt;This totally sidesteps the need for liveness analysis, but also means
we don't get the full benefit, and it's easy to create pathological cases
where it performs really badly (e.g. lots of variables accessed few times, used
one after the other, and then once you've referenced enough variables, reference
them all again, right after they've been evicted from the registers; repeat - in
this way you can construct cases where you get no benefit from the register
allocation at all, while if you'd kept a subset of the variables in the registers
throughout the code block, you would). But this is still no worse than the code
we currently generate.&lt;/p&gt;

&lt;h2&gt;Abstracting the registers out of Compiler&lt;/h2&gt;

&lt;p&gt;A number of methods surrently refer to registers through symbols or even strings
that directly reference them. A first step is to try to abstract away more of
this so that we as much as possible request registers from the &lt;code&gt;Emitter&lt;/code&gt; so that
the registers can be replaced later if possible/necessary.&lt;/p&gt;

&lt;p&gt;As a bonus, this will set us on the right path to make the compiler easier to
retarget to other architectures.&lt;/p&gt;

&lt;p&gt;This first changeset adds methods for the stack pointer, for using &lt;code&gt;%ebx&lt;/code&gt; as
scratch register, and a couple of other helpers, as well as start cleaning up
the &lt;code&gt;Compiler&lt;/code&gt; class to not explicitly mention registers by name so
many places. You can see it in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/92aa83f&quot;&gt;92aa83f&lt;/a&gt; - I won't cover that commit in
more detail.&lt;/p&gt;

&lt;h2&gt;Breaking our current primitive allocator&lt;/h2&gt;

&lt;p&gt;We already have &lt;code&gt;with_register&lt;/code&gt; that sort-of tried to do a little bit of very
basic register allocation. But &lt;code&gt;with_register&lt;/code&gt; comes with substantial
caveats: It knows nothing about what to do if it runs out of registers to
allocate. So lets try to provoke it to fail, so we have something to fix to
start with:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%d = 2\n&quot; (div (div (div 16 2) 2) 2))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;I picked &lt;code&gt;div&lt;/code&gt; as our recent rewrite away from &lt;code&gt;runtime.c&lt;/code&gt; left us with code
in &lt;code&gt;compile_div&lt;/code&gt; that does dual nested &lt;code&gt;with_register&lt;/code&gt; calls already, so it's
well suited to ensure we run out of registers in our current regime.&lt;/p&gt;

&lt;p&gt;You should get something like this if you try to compile it:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./emitter.rb:364:in `with_register': Register allocation FAILED (RuntimeError)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The problem is simply that we've only set aside &lt;code&gt;%edx&lt;/code&gt; and &lt;code&gt;%ecx&lt;/code&gt;, and
furthermore we're not doing anything to allow spilling the values to the
stack, or even to make them available again when caling into another
function.&lt;/p&gt;

&lt;p&gt;Triggering this in actual Ruby code is harder, as almost everything quickly
devolves into method calls that effectively &quot;reset&quot; the register allocations
by virtue of the calling conventions requirements for who saves which registers.&lt;/p&gt;

&lt;p&gt;But lets sort this out first of all anyway.&lt;/p&gt;

&lt;p&gt;First, since this revealed the danger of the nested &lt;code&gt;with_register&lt;/code&gt; calls,
which will remain inefficient at best, lets address the simpler case of
&lt;code&gt;compile_2&lt;/code&gt; which we've used for dual-operand arithmetic and comparisons:&lt;/p&gt;

&lt;p&gt;(You'll find these changes and the div test case in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/0fdfb34&quot;&gt;0fdfb34&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Just a tiny change here: We've lifted the &lt;code&gt;compile_eval_arg(scope,left)&lt;/code&gt; call out. Frankly
we should probably remove the need fully, and just use the stack. I'll consider that
later. In the meantime this reduces register usage substantially in cases where the left-hand
expression tree is deep.&lt;/p&gt;

&lt;p&gt;The bigger change is &lt;code&gt;compile_div&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dividend&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;divisor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;divisor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
            &lt;span class=&quot;c1&quot;&gt;# We need the dividend in %eax *and* sign extended into %edx, so&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# it doesn't matter which one of them we pop it into:&lt;/span&gt;
                    
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dividend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sarl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dividend&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;idivl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;divisor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is pretty much a rewrite - the old version was horribly messy and brittle, because
it tried to work around not being able to tell &lt;code&gt;with_register&lt;/code&gt; exactly what it wanted.&lt;/p&gt;

&lt;p&gt;So to simplify, lets make &lt;code&gt;with_register&lt;/code&gt; handle that.&lt;/p&gt;

&lt;p&gt;And at the same time we lift the argument evaluation out of the actual division, which
massively simplifies things:&lt;/p&gt;

&lt;p&gt;First we evaluate the left, and &lt;em&gt;push&lt;/em&gt; the result onto the stack. Then we evaluate the
right, and leave the result.&lt;/p&gt;

&lt;p&gt;Then we forcibly allocate &lt;code&gt;%edx&lt;/code&gt; since we know &lt;code&gt;idivl&lt;/code&gt; needs it for both arguments and return
value. Then we allocate a register for the divisor (right hand).&lt;/p&gt;

&lt;p&gt;We then get the dividend (left hand) off the stack, into &lt;code&gt;%eax&lt;/code&gt;, move it into the allocated
register, which will be &lt;code&gt;%edx&lt;/code&gt;. We then shift right to only leave the sign bit (see last time
we dicussed the divisions for more on this).&lt;/p&gt;

&lt;p&gt;Finally we do the division.&lt;/p&gt;

&lt;p&gt;You may note that this is going to be wasteful in cases where the left hand expression is
a static value etc. that we could just load directly into the right register. Adding some
code to detect that will save some stack manipulation. But that's not a priority now.&lt;/p&gt;

&lt;p&gt;The corresponding change to &lt;code&gt;emitter.rb&lt;/code&gt; to expand &lt;code&gt;with_register&lt;/code&gt; looks like this for now:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;required_reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# FIXME: This is a hack - for now we just hand out :edx or :ecx&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# and we don't handle spills.&lt;/span&gt;
     
         &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;required_reg&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;required_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In other words, this will still blow up spectacularly if we need more registers.&lt;/p&gt;

&lt;p&gt;Note that that the changes we've done means the register allocation now only surrounds a
handful of instructions doing calculation, and no further calls.&lt;/p&gt;

&lt;p&gt;Luckily this means that in reality we shouldn't &lt;em&gt;need&lt;/em&gt; more. We'd like more, but
most of our register usage will only be for &lt;em&gt;caching&lt;/em&gt; variables we've allocated
space in memory for.&lt;/p&gt;

&lt;p&gt;As such, we know the worst case for the register allocation is that we need to
juggle &lt;code&gt;%edx&lt;/code&gt; around, as that's the only register we specifically need (so far) for
&lt;code&gt;idivl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;As &quot;stage 1&quot; this gets our previous example to compile and run.&lt;/p&gt;

&lt;p&gt;For now we'll move on to the meatier part of register allocation: Moving variables
into registers.&lt;/p&gt;

&lt;h2&gt;Identifying variables for our registers&lt;/h2&gt;

&lt;p&gt;You're not going to like this part. It is hairy and ugly, and involves changing
&lt;code&gt;#rewrite_let_env&lt;/code&gt; and &lt;code&gt;find_vars&lt;/code&gt; in &lt;code&gt;transform.rb&lt;/code&gt;, which are not exactly the prettiest
part of the compiler to begin with.&lt;/p&gt;

&lt;p&gt;The relevant part of &lt;code&gt;rewrite_let_env&lt;/code&gt; is the simplest:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;c1&quot;&gt;# We use this to assign registers &lt;/span&gt;
    
     &lt;span class=&quot;n&quot;&gt;freq&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
     
     &lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;env&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;find_vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;freq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We set aside a &lt;code&gt;Hash&lt;/code&gt; with 0 as the default value, to keep count of the variable references
we see.&lt;/p&gt;

&lt;p&gt;Then we assign the frequency data to a new &lt;code&gt;extra&lt;/code&gt; field of the AST nodes:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extra&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:varfreq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;freq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sort_by&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;k&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;collect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;&lt;code&gt;extra&lt;/code&gt; is simply adding this to &lt;code&gt;AST::Expr&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/afdcd99&quot;&gt;afdcd99&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;extra&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@extra&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Back to &lt;code&gt;transform.rb&lt;/code&gt;, the changes to &lt;code&gt;find_vars&lt;/code&gt; are more extensive, but most of
them are about threading &lt;code&gt;freq&lt;/code&gt; through the recursive calls, and some refactoring
(especially breaking out &lt;code&gt;#is_special_name&lt;/code&gt;.  The meat of it is this little change:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;k&quot;&gt;elsif&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;sc&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in_scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scopes&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;freq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is_special_name?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Specifically, when we get to a &quot;leaf&quot;, if it is not a &quot;special&quot; name as defined in the
new utility method, we count it as a variable reference to take into account for the
later allocation. You can find the full changes to &lt;code&gt;transform.rb&lt;/code&gt; here: &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/3f2ab88&quot;&gt;3f2ab88&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;An overview of the register allocator&lt;/h2&gt;

&lt;p&gt;I've split out the &quot;backend&quot; of the new register allocation code in &lt;code&gt;regalloc.rb&lt;/code&gt; in
&lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/608adc1&quot;&gt;608adc1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It could probably do with some refactoring already, but that will have to wait.&lt;/p&gt;

&lt;p&gt;Most of the explanations here can be found in the source as well.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;RegisterAllocator&lt;/code&gt; class contains the &lt;code&gt;Cache&lt;/code&gt; class which is used to hold
information about the current state of a register that is currently used to hold
a variable.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Cache&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# The register this cache entry is for&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:reg&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# The block to call to spill this register if the register is dirty (nil if the register is not dirty)&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:spill&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# True if this cache item can not be evicted because the register is in use.&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:locked&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# Spill the (presumed dirty) value in the register in question,&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# and assume that the register is no longer dirty. @spill is presumed&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# to contain a block / Proc / object responding to #call that will&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# handle the spill.&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;spill!&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@spill&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@spill&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@spill&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;RegisterAllocator&lt;/code&gt; class itself is initialized like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# This is the list of registers that are available to be allocated&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@registers&lt;/span&gt;      &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# Initially, all registers start out as free.&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;dup&lt;/span&gt;
    
        &lt;span class=&quot;vi&quot;&gt;@cached&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@by_reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Cache information, by register&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;                                

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;@cached&lt;/code&gt; and &lt;code&gt;@by_reg&lt;/code&gt; hashes contains the &lt;code&gt;Cache&lt;/code&gt; objects referenced
by variable name and register respectively. &lt;code&gt;@order&lt;/code&gt; gets assigned an array
of variables in descending order of priority. As previously discussed, this
in effect means by descending order of number of times the variable is referenced
at this point.&lt;/p&gt;

&lt;p&gt;Additionally, &lt;code&gt;#with_register&lt;/code&gt; initializes two more instance variables as needed:
&lt;code&gt;@allocated_registers&lt;/code&gt; and &lt;code&gt;@allocators&lt;/code&gt;, which holds information on which registers
have been allocated for temporary use, and debug information about the code that
called &lt;code&gt;#with_register&lt;/code&gt; respectively.&lt;/p&gt;

&lt;p&gt;I won't go through every little method - you can look at the commit (and feel
free to ask questions if anything is not clear), but we'll take a look at
&lt;code&gt;#cache_reg!&lt;/code&gt; which is used to cache a register, as well as &lt;code&gt;evict&lt;/code&gt; which is
used to remove a variable from the registers (that is, remove the association
in the compiler, we do not generate code to actually clear the register), and
&lt;code&gt;#with_register&lt;/code&gt;, which is used to allocate temporary registers.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;#cache_reg!&lt;/code&gt; will only allocate registers for variables that have been &quot;registered&quot;
with the register allocator. First we try to obtain a register from the list
of free/unallocated/uncached registers:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cache_reg!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;member?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;debug_is_register?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;If a register is found, we create a new &lt;code&gt;Cache&lt;/code&gt; object, referencing the register.
If not, we (for now) output a warning. If a register is found, it is returned,
otherwise, we return &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@cached&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@by_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;NO FREE REGISTER (consider evicting if more important var?)&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We'll look at how this is used later.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;evict&lt;/code&gt; has the opposite role: When we need to ensure that a variable is retrieved
from memory next time, we pass it.&lt;/p&gt;

&lt;p&gt;We iterate over the variables passed, and try to delete them from the cache. If they
were in fact there, we call the spill handler if one was set. The spill handler is
any object (such as a Proc or lambda) that responds to &lt;code&gt;#call&lt;/code&gt;, and it is its responsibility
to store the contents of the register back to memory before it is freed.&lt;/p&gt;

&lt;p&gt;This is only assigned if the in-register version of the variable is intentionally
modified.&lt;/p&gt;

&lt;p&gt;We then add the register back in the list of free regsiters.&lt;/p&gt;

&lt;p&gt;For convenience, I've added an &lt;code&gt;#evict_all&lt;/code&gt; method that evicts all currently cached
variables.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;evict&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;collect&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@cached&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reg&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;debug_is_register?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;spill!&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@by_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;v&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;compact&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;evict_all&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;evict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@cached&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;keys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The longest method in the register allocator for now is &lt;code&gt;#with_register&lt;/code&gt;.
This has been lifted from &lt;code&gt;Emitter&lt;/code&gt; and adapted, and in fact we've covered
changes to that one above, but I'll go through it from scratch.&lt;/p&gt;

&lt;p&gt;First we check if the client has requested a &lt;code&gt;specific&lt;/code&gt; register. If so,
we try to retrieve this register. If not, we get the first one available.
This is the change we did above to the &lt;code&gt;Emitter&lt;/code&gt; version.&lt;/p&gt;

&lt;p&gt;If none was immediately vailable, we go through the variables cached from
least frequently used (in this method), to most, and evict the first one
that is not &quot;locked&quot; in place.&lt;/p&gt;

&lt;p&gt;(Note, there's a potential problem here: The client code does need to
be able to handle the case where the preferred register is already taken,
as we currently don't go on to evict the variable specifically allocated
to that register, but I punted on that when changing the version previously
in &lt;code&gt;Emitter&lt;/code&gt; - we probably should fix that, but now now)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;c1&quot;&gt;# Allocate a temporary register. If specified, we try to allocate&lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# a specific register.&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;required_reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;required_reg&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;required_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# If no register was immediately free, but one or more&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# registers is in use as cache, see if we can evict one of&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# them.&lt;/span&gt;
    
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@cached&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;empty?&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# Figure out which register to drop, based on order.&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# (least frequently used variable evicted first)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reverse&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@cached&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;locked&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reg&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;evict&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;v&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The next part is simply debug output, primarily in case we actually
run out of registers, which means we're trying to use more temporary registers
at one time than the allocator has registers available total (3 currently).
It should not happen if we are careful about what we allocate temporary registers
for:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;debug_is_register?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# This really should not happen, unless we are&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# very careless about #with_register blocks.&lt;/span&gt;
    
          &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;===&quot;&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@cached&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;--&quot;&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
          &lt;span class=&quot;no&quot;&gt;STDERR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@allocators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Register allocation FAILED&quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And some more debug support:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;c1&quot;&gt;# This is for debugging of the allocator - we store&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# a backtrace of where in the compiler the allocation&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# was attempted from in case we run out of registers&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# (which we shouldn't)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocators&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocators&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;caller&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Finally, we mark the register as allocated, yield to the
client code, and free the register again.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;c1&quot;&gt;# Mark the register as allocated, to prevent it from&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# being reused.&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# ... and clean up afterwards:&lt;/span&gt;
    
        &lt;span class=&quot;vi&quot;&gt;@allocators&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pop&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;debug_is_register?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Tieing the allocator into the Emitter and Compiler&lt;/h2&gt;

&lt;p&gt;The changes to &lt;code&gt;compiler.rb&lt;/code&gt; are fairly minor. We will go through the changes to
each of &lt;code&gt;get_arg&lt;/code&gt;, &lt;code&gt;output_functions&lt;/code&gt;, &lt;code&gt;compile_if&lt;/code&gt;, &lt;code&gt;compile_let&lt;/code&gt; and &lt;code&gt;compile_assign&lt;/code&gt;
from  &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e1049e3&quot;&gt;e1049e3&lt;/a&gt; separately, and intersperse that with how it ties in with the changes
to &lt;code&gt;Emitter&lt;/code&gt; in the same commit.&lt;/p&gt;

&lt;p&gt;Lets start with &lt;code&gt;#get_arg&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;86&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;86&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# If a Fixnum is given, it's an int -&amp;gt;   [:int, a]&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# If it's a Symbol, its a variable identifier and needs to be looked up within the given scope.&lt;/span&gt;
       &lt;span class=&quot;c1&quot;&gt;# Otherwise, we assume it's a string constant and treat it like one.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Fixnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Float&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# FIXME: uh. yes. This is a temporary hack&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;94&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;94&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Symbol&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
           &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intern&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?:&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# If this is a local variable or argument, we either&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# obtain the argument it is cached in, or we cache it&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# if possible. If we are calling #get_arg to get&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# a target to *save* a value to (assignment), we need&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# to mark it as dirty to ensure we save it back to memory&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# (spill it) if we need to evict the value from the&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# register to use it for something else.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lvar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:arg&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cache_reg!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;first&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The comment says almost all that needs to be said. The main thing
to notice here is the &quot;save&quot; argument, which we'll see used later by
&lt;code&gt;compile_assign&lt;/code&gt;. Let's take a look at &lt;code&gt;Emitter#cache_reg!&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First we see if this variable is currently cached in a register.&lt;/p&gt;

&lt;p&gt;If &lt;code&gt;save&lt;/code&gt; was passed, we mark this entry as dirty, so that if the
variable is later evicted from the register, we spill the value
back to memory. Regardless whether or not we got a register back,
we return, as we certainly don't want to &lt;em&gt;load&lt;/em&gt; the value into
memory just to overwrite it and then spill it later.&lt;/p&gt;

&lt;p&gt;(Note that we &lt;em&gt;could&lt;/em&gt; add code to request a register and fill it
with the modified value, and immediately mark it dirty; in some
cases this &lt;em&gt;might&lt;/em&gt; be worthwhile by potentially saving us a load
later on, but that's speculative enough that I'd want to do real
tests first)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;cache_reg!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;atype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cached_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;mark_dirty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;atype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Then we output some comments for debugging purposes and to make
it easier for us to examine the results of the allocation later
on (we might strip this out later), and if the register was not
already in the cache, we try to request a register to cache it
in, and if we get one we load it:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;RA: Already cached '&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' for &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cache_reg!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;RA: Allocated reg '&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;' for &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;inspect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;load&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;atype&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;aparam&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Let us also take a quick look at &lt;code&gt;Emitter#mark_dirty&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;The most important part here is the lambda that is used installed
to handle spills. It simply outputs another debug comment, and
saves the register back where it came from:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;mark_dirty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cached_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;var&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Marked &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; dirty (&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;mark_dirty&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;lambda&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Saving &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; to &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                                &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                              &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;As for &lt;code&gt;Compiler#output_functions&lt;/code&gt;, the only big change there is that it
now passes the variable frequency information:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;n&quot;&gt;varfreq&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;respond_to?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:extra&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;body&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;extra&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varfreq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[]&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rest?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;varfreq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;So lets see what &lt;code&gt;Emitter#func&lt;/code&gt; does with it. It ensures all registers are
evicted before we generate code for a new function, as the function obviously
can't control where it is called from. We then install the new frequency information
in the register allocator. And on the way out again, we evict the registers again,
for good measure. Actually the latter one is &lt;em&gt;necessary&lt;/em&gt; in case any of the registers needs
to be spilled. The former one is a precaution - the registers ought to have been evicted
before we get there.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save_numargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;func&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save_numargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varfreq&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.stabs  &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;:F(0,0)&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;,36,0,0,&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;export&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;?.&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;479&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;518&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;17&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Emitter&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;lineno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;position&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;position&lt;/span&gt;
                            &lt;span class=&quot;vi&quot;&gt;@out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.LFBB&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@curfunc&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_all&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;order&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varfreq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save_numargs&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;leave&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_all&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
                              &lt;span class=&quot;n&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;.size&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;.-&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@scopenum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@scopenum&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;494&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;538&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Emitter&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The change to &lt;code&gt;Compiler#compile_if&lt;/code&gt; is simple: We simply need to explicitly pass
the register to test, rather than rely on it always being &lt;code&gt;%eax&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;if_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;cond&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;l_end_if_arm&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp_on_false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;res&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;if_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jmp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_end_if_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l_end_if_arm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;else_arm&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In &lt;code&gt;compile_let&lt;/code&gt; the only change is that we want to ensure we evict all registers
that the &lt;code&gt;%s(let ...)&lt;/code&gt; node aliases, as otherwise we will be using values from the
wrong variable:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_regs_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vars&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ls&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;evict_regs_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;varlist&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In &lt;code&gt;compile_assign&lt;/code&gt;, our only concern is passing a truthy value for &quot;save&quot;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;get_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:save&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h2&gt;Optimizing temporary register usage for already cached values&lt;/h2&gt;

&lt;p&gt;We'll do one tiny little additional change, and then we'll look at the resulting code.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/e74d92d&quot;&gt;e74d92d&lt;/a&gt; we introduce &lt;code&gt;Emitter#with_register_for&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_register_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maybe_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@allocator&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lock_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;maybe_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Locked register &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reg&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Unlocked register &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;c&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;locked&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;maybe_reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The purpose of this is as a small optimization in cases where we need a temporary
register to hold a variable, but already have the variable in a register. We
need to ensure it doesn't get evicted, same as if we allocate a temporary register.&lt;/p&gt;

&lt;p&gt;And here's the only place we use it so far:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#      @e.emit(:movl, src, reg)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}}}&lt;/span&gt;    
       
    &lt;span class=&quot;no&quot;&gt;If&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;variable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;already&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;can&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;us&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    
    
    &lt;span class=&quot;c1&quot;&gt;## A quick look at the resulting code ##&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;us&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;example&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;code&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;earlier&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;It&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;give&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;something&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;like&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;this:
    
    &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;asm&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;__method_Object_foo:
        &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stabn&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LM336&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LFBB61&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LM336&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LFBB61&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stabn&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LM337&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LFBB61&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LM337&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RA: Allocated reg 'edx' for a&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# [:lvar, 0, :edx]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edx&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Locked register edx&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# RA: Allocated reg 'ecx' for b&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# [:lvar, 1, :ecx]&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ecx&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Here we see the first uses, and as you can see from the &quot;Locked&quot; comment above,
this also made use of the optimization where we'd previously have allocated
another register and moved or reloaded the variable:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Unlocked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And here we're assigning the result of &lt;code&gt;(add a b)&lt;/code&gt; back to &lt;code&gt;a&lt;/code&gt;, which
currently lives in &lt;code&gt;%edx&lt;/code&gt;. As a result it is marked &quot;dirty&quot;: It needs
to be written back to memory when evicted.&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;operator&quot;&gt;Marked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;dirty&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Already&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;cached&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;a&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Locked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Allocated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;reg&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;edi&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;c&lt;/span&gt;
        # [:&lt;span class=&quot;operator&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;edi&lt;/span&gt;]
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-16&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edi&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And we use &lt;code&gt;a&lt;/code&gt; again, from &lt;code&gt;%edx&lt;/code&gt; and start reaping the
rewards:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%edi&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Unlocked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Marked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;dirty&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Of course, note above, that we could save much more with smarter
handling of these registers - in these examples we could have done
&lt;code&gt;addl %edi, %edx&lt;/code&gt; directly, and saved two further &lt;code&gt;movl&lt;/code&gt;'s - we have
tons of further optimizations to do.&lt;/p&gt;

&lt;p&gt;And here are some more examples where we reuse &lt;code&gt;a&lt;/code&gt;&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Already&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;cached&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;a&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Locked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;imull&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Unlocked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;register&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;Marked&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;dirty&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;.L83&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        # &lt;span class=&quot;label&quot;&gt;RA:&lt;/span&gt; &lt;span class=&quot;operator&quot;&gt;Already&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;cached&lt;/span&gt; '&lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt;' &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;a&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And here we finally spill &lt;code&gt;a&lt;/code&gt; back to memory from &lt;code&gt;%edx&lt;/code&gt;, right before
we call &lt;code&gt;printf&lt;/code&gt;, as &lt;code&gt;%edx&lt;/code&gt; can be overwritten:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;operator&quot;&gt;Saving&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;edx&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;lvar&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;call&lt;/span&gt;    *&lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(Incidentally, this is where liveness analysis makes a big difference:
after the &lt;em&gt;last&lt;/em&gt; use of &lt;code&gt;a&lt;/code&gt;, it'll still get spilled, but that's of course
pointless since this is a local variable)&lt;/p&gt;

&lt;h2&gt;Final words&lt;/h2&gt;

&lt;p&gt;I'd like to reiterate that this is a trivial and primitive allocator. It misses
tons of opportunities, and may do stupid things, like load stuff, use it once,
have to evict it, load it again, use it once, have to evict it, and so on.&lt;/p&gt;

&lt;p&gt;The important thing, though, is to get some basic infrastructure in place that
we can expand on. We can now later add more advanced logic to determine which
variables to cache when with much less effort.&lt;/p&gt;

&lt;p&gt;Next time, we'll look at another side of this: Caching &lt;code&gt;self&lt;/code&gt; in &lt;code&gt;%esi&lt;/code&gt;, which
we'll handle quite differently (and in a much shorter part...)&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>operators</category>
      <pubDate>Sun, 06 Apr 2014 03:00:00 +0000</pubDate>
      <dc:date>2014-04-06T03:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 32</title>
      <link>http://hokstad.com/compiler/32-testing-code-generation</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;Testing And Debugging Code Generation&lt;/h2&gt;

&lt;p&gt;Unit testing code generation poses some particular challenges because so many things can go wrong,
and they can go wrong in all kinds of horrible ways that makes them extremely nasty to track down,&lt;/p&gt;

&lt;p&gt;If you've paid attention, you have seen some code generation tests (in &lt;code&gt;compiler.feature&lt;/code&gt;) that
will catch cases where the code blatantly crashes or returns completely wrong results. These can
be really nasty to figure out.&lt;/p&gt;

&lt;p&gt;But there are many far more insidious types of bugs that can lie latent and that often doesn't
get triggered for small test programs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Randomly overwriting wrong parts of memory - programs can often keep running for a long time
with such bugs, until suddenly something gets corrupted.&lt;/li&gt;
&lt;li&gt;Updating the stack incorrectly can lead to everything from calculations resulting in wrong
results, but often not the one you're testing for, to crashes that often leave you without
a stacktrace to hint at where you failed, or pointing at the wrong spot.&lt;/li&gt;
&lt;li&gt;Wrong values in registers might not be noticed until combined with another piece of code that
suddenly rely on those registers.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;And so on.&lt;/p&gt;

&lt;p&gt;So let us make the code generation testing more robust, and use these new facilities to see both
if we can catch some bugs, and make it easier to track down the causes. Hopefully we can clean
the board and fix some of these issues too.&lt;/p&gt;

&lt;p&gt;We will add a number of simple facilities to do more comprehensive testing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We have the option &lt;code&gt;--trace&lt;/code&gt; to make the compiler generate debug statements that trace entry and
exit from methods, but that one is currently broken. Lets fix it.&lt;/li&gt;
&lt;li&gt;The option &lt;code&gt;--stackfence&lt;/code&gt; that will make the compiler generate code to push magic values
onto the stack at every call site, and code
to check for the magic value on return and output an error if it is not present.&lt;/li&gt;
&lt;li&gt;%s(saveregs) will return an array of the current value of registers, so that we may
compare them against expected values or output them.&lt;/li&gt;
&lt;li&gt;The option &lt;code&gt;--memfence&lt;/code&gt; that is like &lt;code&gt;--stackfence&lt;/code&gt; except it will manipulate memory allocations
by replacing calls to &lt;code&gt;malloc&lt;/code&gt; with a function that pads the allocated regions on either side
with &quot;magic&quot; values.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;This is by no means a comprehensive set of possible debugging help we can add, but combined it
creates a good foundation to let us catch a whole series of bugs with code generation that might
otherwise require a lot of manual inspection and writing very complicated tests.&lt;/p&gt;

&lt;p&gt;To see what we can get out of these, we will try to make the rest of the &lt;code&gt;compiler.feature&lt;/code&gt; tests
run, and generally clean things up.&lt;/p&gt;

&lt;p&gt;But first, lets make things harder for ourselves based on some notes I've taken about
failing tests:&lt;/p&gt;

&lt;h2&gt;Tests and more tests.&lt;/h2&gt;

&lt;p&gt;Here's one that fails spectacularly (added as &lt;code&gt;features/inputs/method.rb&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/34e92a2&quot;&gt;34e92a2&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;baz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And this one (&lt;code&gt;features/inputs/method2.rb&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/34e92a2&quot;&gt;34e92a2&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;foo&quot;&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But this one works (&lt;code&gt;features/inputs/method3.rb&lt;/code&gt; in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/34e92a2&quot;&gt;34e92a2&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baz&lt;/span&gt;
        &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;baz&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;bar&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;baz&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;.. hinting at a problem with single argument methods, perhaps?&lt;/p&gt;

&lt;p&gt;And this one hints at problems with the splat (&lt;code&gt;*somearg&lt;/code&gt;) handling:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Foo&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg2&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;foo: %d\n&quot; numargs)&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%p\n&quot; arg1)&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%p\n&quot; arg2)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;bar: %d\n&quot; numargs)&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%p\n&quot; (index splat 0))&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%p\n&quot; (index splat 1))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;foo&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;bar&quot;&lt;/span&gt;
    
    &lt;span class=&quot;c1&quot;&gt;# Should give same pairs of output 3 times&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This will get us started, combined with what is already there (try &lt;code&gt;rake
failing&lt;/code&gt; to see what's not completing)&lt;/p&gt;

&lt;h2&gt;Debugging in the face of crashes&lt;/h2&gt;

&lt;p&gt;For all of these we can get some limited help from gdb. A lot of help if
we have the patience of a monk.&lt;/p&gt;

&lt;p&gt;A run of &lt;code&gt;method2&lt;/code&gt; shows us some of the reasons for better test tools, but also
gives plenty of hints:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/tmp/me&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thod2&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;GNU&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;6.8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debian&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Copyright&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2008&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Free&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Software&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foundation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Inc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;License&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GPLv3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GNU&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GPL&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;later&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gnu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;licenses&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;software: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;you&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;are&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redistribute&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;There&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NO&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;WARRANTY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;permitted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;law&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;show copying&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;show warranty&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GDB&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configured&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;i486-linux-gnu&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Starting&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;program: &lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/tmp/me&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thod2&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bypassing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implemented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Called&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8ae0f68&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bypassing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implemented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Called&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8ae0f68&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bypassing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implemented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Called&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8ae0f68&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;received&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SIGSEGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Segmentation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;mh&quot;&gt;0x0804c768&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__method_Object_puts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/home/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vidarh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;experiments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In this case the real problem is not where the crash happens, but clearly earlier. The &lt;code&gt;&quot;foo&quot;&lt;/code&gt; gets printed, so the problem likely arises after that, but well before &lt;code&gt;__method_Object_puts&lt;/code&gt; even though that is where the crash happens, as we shouldn't be seeing the &lt;code&gt;__send__ bypassing vtable not yet implemented.&lt;/code&gt; warnings.&lt;/p&gt;

&lt;p&gt;(Note: If you see something different, that is perfectly normal - stack smashing bugs are notoriously
tricky in that the smallest little thing can make the crash occur somewhere entirely different.)&lt;/p&gt;

&lt;p&gt;So let's start off by fixing our&lt;code&gt;--trace&lt;/code&gt; option and see what that tells us (with the caveat that it
will change the code that is output, and so may change the character of the crash)&lt;/p&gt;

&lt;h2&gt;Trace&lt;/h2&gt;

&lt;p&gt;Our &lt;code&gt;--trace&lt;/code&gt; option will just be a start. There's an endless amount of stuff we &lt;em&gt;can&lt;/em&gt; trace. The
tricky tradeoff will be to get the right balance to prevent us from spewing far much information.
At some point we'll probably want to add more granular tracing functionality. For now, we'll
experiment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We'll add a relatively generic &lt;code&gt;trace&lt;/code&gt; method to the &lt;code&gt;Compiler&lt;/code&gt; class that will allow us to ouput
debug text to &lt;code&gt;stderr&lt;/code&gt; if &lt;code&gt;--trace&lt;/code&gt; was given to the compiler.&lt;/li&gt;
&lt;li&gt;We'll add trace output for expressions an for entering and exiting functions.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Here's a first stab (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b31e22ed8&quot;&gt;b31e22ed8&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@trace&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# A bit ugly, but prevents infinite recursion&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# if we accidentally calls anything &quot;traceworthy&quot;:&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@trace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; 
    
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;short&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;sio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;StringIO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;sio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pos&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;:&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;  &quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; &quot;&lt;/span&gt;
    
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;sio&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;print_sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,{&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:prune&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;})&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sio&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;string&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;([&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:stderr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;fputs&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@trace&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We allocate space for two slots on the stack, outputs the source position if provided,
and either a string or an AST fragment serialized as &lt;code&gt;%s()&lt;/code&gt; expressions.&lt;/p&gt;

&lt;p&gt;Notice the way we go about the call. We use &lt;code&gt;compile_eval_arg&lt;/code&gt; only to load the address
of the formatted string, and then push it onto the stack, then put the address of the
C library's &lt;code&gt;stderr&lt;/code&gt; on, and call &lt;code&gt;fputs&lt;/code&gt;, but without taking advantage of the compilers
built in function call support.&lt;/p&gt;

&lt;p&gt;My reason for this is simply to ensure the change of being affected by any weird bugs
in other parts of the code generation - I want the generated trace code to be as simple
and straight-forward and isolated as possible.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/42c8dae&quot;&gt;42c8dae&lt;/a&gt; I added support for the &lt;code&gt;:prune&lt;/code&gt; option above, to make the trace output
simpler.&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/cc98262c4&quot;&gt;cc98262c4&lt;/a&gt; you can see the added calls to the &lt;code&gt;trace&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;On its own, this does not appear to really help all that much in tracking down the
issues raised by the various failing tests.&lt;/p&gt;

&lt;p&gt;But here's some example output from compiling &lt;code&gt;features/input/method2.rb&lt;/code&gt; with &lt;code&gt;--trace&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;38&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rest&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;
       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ob&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:initialize&lt;/span&gt;
    
    &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__env__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__tmp_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@buffer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;__env__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__tmp_proc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@buffer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@buffer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@buffer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@buffer&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
       &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;initialize&lt;/span&gt;
    
       &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__set_raw&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
       &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:s&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:__set_raw&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Segmentation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fault&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Clearly it can use some more love. But it does make it easier to follow what is actually
leading up to the crash, and that might prove useful in finding the exact cause later on.&lt;/p&gt;

&lt;h2&gt;Adding --stackfence&lt;/h2&gt;

&lt;p&gt;Stack fencing is conceptually very simple: Before the start of the allocated region
for a function call, push one or more items of data, at least one of which ought to be
a &quot;magic&quot; value. This can either be a static randomly picked value that is reasonable
unlikely to occur by accident (in other words, avoid low integer values), or it can be
a value that is randomly chosen for each occurrence. We'll do the latter.&lt;/p&gt;

&lt;p&gt;On return, after popping the arguments off the stack, we then want to compare the top
of the stack against the magic value, before returning the stack to its original state.
If the stack state is invalid, on the other hand, we'll want to output some trace data.&lt;/p&gt;

&lt;p&gt;We add the &lt;code&gt;stackfence&lt;/code&gt; method in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/dde1814&quot;&gt;dde1814&lt;/a&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;stackfence&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;vi&quot;&gt;@stackfence&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# Note: We don't care if this value is all that random.&lt;/span&gt;
        
        &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;rand&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;floor&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;$&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(%esp)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;l&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;get_local&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jz&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;trace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ERROR: Stack fence violation. Expected 0x&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;local&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/c806999&quot;&gt;c806999&lt;/a&gt; we simply then wrap &lt;code&gt;stackfence do ... end&lt;/code&gt; around calls we want to fence.&lt;/p&gt;

&lt;p&gt;Somewhat disappointingly, &lt;code&gt;--stackfence&lt;/code&gt; doesn't actually help us with the current set of failing
tests. At least not directly. But note that due to the nature of many stack trashing bugs,
pushing a random value like this onto the stack will often cause crashes earlier (on next
function return after the stack trashing), before the fence test is allowed to happen. We
can still benefit from that by starting the program under gdb, and requesting a backtrace
when the crash happens.&lt;/p&gt;

&lt;h2&gt;Adding %(saveregs)&lt;/h2&gt;

&lt;p&gt;So we move on to &lt;code&gt;%(saveregs)&lt;/code&gt;. We will continue to ignore portability for now (and let you
have the fun on watching me clean up that mess a while down the line, as I have a planned
part dealing with re-targeting the compiler to another CPU architecture) and just have
&lt;code&gt;saveregs&lt;/code&gt; dump the registers to a freshly allocated bit of memory with no indication of
what they are.&lt;/p&gt;

&lt;p&gt;Saveregs can be found in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b86ee7c&quot;&gt;b86ee7c&lt;/a&gt;. I do not know if x86 has an instruction to bulk save
registers (e.g. the M68k has &quot;MOVEM&quot; which can take a list of registers to copy), nor do
I care. As usual the point is not to be efficient, but to get results easily, and quickly.&lt;/p&gt;

&lt;p&gt;Note that we &lt;em&gt;don't&lt;/em&gt; take care to ensure the registers are unchanged at the end of this.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
    
      &lt;span class=&quot;c1&quot;&gt;# Debug instruction, to save registers &lt;/span&gt;
      &lt;span class=&quot;c1&quot;&gt;# &lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_saveregs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# First we push the registers on the stack, to ensure they won't get messed up&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# when we allocate memory.&lt;/span&gt;
    
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esi&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# Allocate memory&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;malloc&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;c1&quot;&gt;# We're naughty and assume we get memory:&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;4(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;8(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;12(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;16(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;20(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;24(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;28(%eax)&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Now that we have &lt;code&gt;%s(saveregs)&lt;/code&gt; we can do this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(defun printregs (regs) (do
      (printf &quot;eax: %08x, ebx: %08x, ecx: %08x, edx: %08x, esi: %08x, edi: %08x, ebp: %08x, esp: %08x\n&quot;
       (index regs 0)
       (index regs 1)
       (index regs 2)
       (index regs 3)
       (index regs 4)
       (index regs 5)
       (index regs 6)
       (index regs 7))
    ))&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;%s(assign regs (saveregs))&lt;/span&gt;
      &lt;span class=&quot;sx&quot;&gt;%s(printregs regs)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;sx&quot;&gt;%s(assign regs (saveregs))&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(printregs regs)&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(assign regs (saveregs))&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(printregs regs)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This will dump registers 3 times - once before calling foo, one inside, and one after.&lt;/p&gt;

&lt;p&gt;It may be tempting to define a function to save and dump the registers in one go, like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;%s(defun dumpregs () (printregs (saveregs)))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Or even just do &lt;code&gt;%s(printregs (saveregs))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;But this won't work well. The registers will then be saved after we start preparing the stack and
registers for the call to &lt;code&gt;printregs&lt;/code&gt;, and so the values will not be the same as what we're looking for.&lt;/p&gt;

&lt;p&gt;In the hypothetical &lt;code&gt;dumpregs&lt;/code&gt; example, it's worse: We've pushed an entirely unrelated stack frame
and modified registers just in order to call &lt;code&gt;dumpregs&lt;/code&gt;, and then another frame to prepare to call
&lt;code&gt;printregs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Lets take a quick look at the output:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;ss&quot;&gt;eax: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d47d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebx: &lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00000003&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ecx: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfb354c8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edx: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0823&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b184&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;080524&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;08048510&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfb354d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfb354d4&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;eax: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d47d&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebx: &lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00000001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ecx: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0823&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;af98&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edx: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b76ec0f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;080524&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;08048510&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfb354c4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfb354b0&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;eax: &lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00000077&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebx: &lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;0000000&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ecx: &lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edx: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b76ec0f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;080524&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;08048510&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfb354d8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfb354d4&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;There's not that much we will learn from this example. Many of these registers gets trashed regularly.
&lt;code&gt;ebp&lt;/code&gt; and &lt;code&gt;esp&lt;/code&gt; however, won't. In this case we do see that &lt;code&gt;ebp&lt;/code&gt; and &lt;code&gt;esp&lt;/code&gt; both are unchanged when &quot;outside&quot; &lt;code&gt;foo&lt;/code&gt;.
That's good - it means the call to &lt;code&gt;foo&lt;/code&gt; at the very least returns the stack and local variable frames to what they
should be (we index local variables and arguments relative to &lt;code&gt;ebp&lt;/code&gt;, remember, as &lt;code&gt;esp&lt;/code&gt; frequently changes inside a function).&lt;/p&gt;

&lt;p&gt;But lets augment the output. This prints out 32 bytes at (%esp), 4(%esp) etc. and (%ebp), 4(%ebp) etc., giving us
a quick way of looking at the arguments and return address of the current function (via &lt;code&gt;ebp&lt;/code&gt;) and current state of
the stack respectively (via &lt;code&gt;esp&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;I first added &lt;code&gt;printregs&lt;/code&gt; to &lt;code&gt;lib/core/core.rb&lt;/code&gt; as a utility (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/066b8e6&quot;&gt;066b8e6&lt;/a&gt;), and then augmented it as follows in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/20b4abc&quot;&gt;20b4abc&lt;/a&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;78&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;78&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;27&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: Should be an object of FalseClass&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regs&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regs&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regs&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regs&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;(ebp): %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;regs&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;(esp): %08x, %08x, %08x, %08x, %08x, %08x, %08x, %08x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;   &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sp&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
     &lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h4&gt;In practice - take 1&lt;/h4&gt;

&lt;p&gt;Let's try to make use of this to track down our regressions. Lets start with
features/inputs/method2.rb&lt;/p&gt;

&lt;p&gt;First, let's rewrite &lt;code&gt;bar&lt;/code&gt; like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(assign r (saveregs))&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(printregs r)&lt;/span&gt;
          &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;I get a bunch of nonsense, and then the register/stack output:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bypassing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implemented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Called&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8665f68&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bypassing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implemented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Called&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8665f68&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bypassing&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;yet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;implemented&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;no&quot;&gt;Called&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;WARNING&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x8665f68&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;eax: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e234&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebx: &lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00000004&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ecx: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0866&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ce28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edx: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b76f70f0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;080503&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;080484&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfc51aa8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bfc51a94&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bfc51ac8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a917&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0866&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bfc51ae0&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a902&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;08665&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f68&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0866&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d6a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0866&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d6c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bfc51ac8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a917&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0866&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d600&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Segmentation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fault&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;How do we interpret this? Well. The first curious thing is &lt;code&gt;ebx&lt;/code&gt;. Why does it contain &quot;4&quot;? We use &lt;code&gt;ebx&lt;/code&gt; to contain the
number of arguments passed, and while we need to account for &lt;code&gt;self&lt;/code&gt; and an optional block argument, that does not add
up to 4 together with &lt;code&gt;arg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Also note the &lt;code&gt;(ebp)&lt;/code&gt; line, which shows what was on the stack right after the start of the method. The top entry is the
old value of &lt;code&gt;%ebp&lt;/code&gt;. The next one is the return address. Then comes?&lt;/p&gt;

&lt;p&gt;We should expect the arguments. But there's just one non-null value, and
we expect more. This one does look quite nasty. Nasty enough to look
at the asm output again for a change (it is ugly, and in dire need
of some love - we'll definitively set aside a part for that soon).&lt;/p&gt;

&lt;p&gt;I've added comments to this to explain rather than break up the code segment:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;stabn&lt;/span&gt;  &lt;span class=&quot;mi&quot;&gt;68&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;24&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LM229&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;LM229&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# callm :f.:bar&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebx&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# This is the offending number of arguments&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebx&lt;/span&gt;        &lt;span class=&quot;c1&quot;&gt;# It's being pushed, so that in absence of proper&lt;/span&gt;
                            &lt;span class=&quot;c1&quot;&gt;# proper register allocation, we're pre-emptively&lt;/span&gt;
                            &lt;span class=&quot;c1&quot;&gt;# making sure it's not trashed. See (1) below&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;     
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# &quot;f&quot; will be &quot;self&quot; inside the method call&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;   &lt;span class=&quot;c1&quot;&gt;# We don't have a block to pass&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# callm :self.:sexp   # Uhm. WTF?!? (2)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;     &lt;span class=&quot;c1&quot;&gt;# Somehow the compiler got the idea we're trying to call &lt;/span&gt;
                              &lt;span class=&quot;c1&quot;&gt;# &quot;sexp&quot; as a method on self.&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebx&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# ... and that it has arguments&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(1) the reason we don't delay loading &lt;code&gt;%ebx&lt;/code&gt; until right before the call
is that in the case of &quot;splat&quot; handling (&lt;code&gt;*somevar&lt;/code&gt;), the value is dynamically
created. We should optimize this for the normal case of no splat, but as always
performance is low priority.&lt;/p&gt;

&lt;p&gt;(2) This points to a weaknes in the &lt;code&gt;%s()&lt;/code&gt; syntax: If we add a set of parentheses
too many, we'll try to call the return value of an expression. If we have one
too little, we'll treat something as an explicit value instead of calling it
to obtain a value. Lets take a look at the parse tree.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;f&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sexp&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__get_string&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;L1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;... and this appears to be the likely culprit - a missing set of parentheses surrounding
the &lt;code&gt;sexp&lt;/code&gt; node.&lt;/p&gt;

&lt;p&gt;This is curious. If you look at &lt;code&gt;rewrite_strconst&lt;/code&gt;, we explicitly have a line with a
&quot;FIXME&quot; in front talking about working around a parser inconsistency. But look  a few
lines up. &lt;code&gt;is_call&lt;/code&gt; determines if this change is applied, and &lt;code&gt;is_call&lt;/code&gt; doesn't trigger
for method calls, just low level function calls. So we do this (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/245c016&quot;&gt;245c016&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rewrite_strconst&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;depth_first&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:skip&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;is_call&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;is_call&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
             &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
               &lt;span class=&quot;n&quot;&gt;lab&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@string_constants&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And method2 now works:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;eax: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e0e6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebx: &lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;00000003&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ecx: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0805059&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;f&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edx: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;095&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c3e28&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;08050280&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;edi: &lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;080484&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;ebp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bf7ff3f8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;esp: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;bf7ff3e4&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bf7ff418&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a857&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;095&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c4600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;095&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c4690&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a6d6&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bf7ff430&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;):&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;095&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c4690&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00000001&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;095&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c46a0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a842&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bf7ff418&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0804&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a857&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;095&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c4600&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;bar&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;How does this frame look? Much better. &lt;code&gt;ebx&lt;/code&gt; is 3, which is (self, the optional empty block argument, and &lt;code&gt;arg&lt;/code&gt;).
I we look at the &lt;code&gt;(ebp)&lt;/code&gt; line, we see the old &lt;code&gt;%ebp&lt;/code&gt;, the return address, and then arguments: &lt;code&gt;self&lt;/code&gt;, 0 for the
block argument, and another address which presumably (since the code worked) is the string object for &quot;bar&quot;.&lt;/p&gt;

&lt;p&gt;(I don't like &quot;presumably&quot; - we can do better by expanding the &lt;code&gt;printargs&lt;/code&gt; function to recognize types and
dump more extensive data; for now I'll leave that as an exercise to the reader...)&lt;/p&gt;

&lt;h4&gt;In practice - features/inputs/method.rb&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;method.rb&lt;/code&gt; segmentation faults for me, and so I tried it under gdb:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/tmp/me&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thod&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;GNU&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;6.8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debian&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Copyright&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2008&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Free&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Software&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foundation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Inc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;License&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GPLv3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GNU&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GPL&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;later&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gnu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;licenses&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;software: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;you&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;are&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redistribute&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;There&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NO&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;WARRANTY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;permitted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;law&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;show copying&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;show warranty&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GDB&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configured&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;i486-linux-gnu&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Starting&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;program: &lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/tmp/me&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thod&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;received&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SIGSEGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Segmentation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;mh&quot;&gt;0x0804c90c&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;__method_Object_puts&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/home/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;vidarh&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;experiments&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;writing&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;
    &lt;span class=&quot;mi&quot;&gt;46&lt;/span&gt;          &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bt&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#0  0x0804c90c in __method_Object_puts () at /home/vidarh/src/compiler-experiments/writing-a-compiler-in-ruby/lib/core/object.rb:46&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#1  0x0804d98d in __method_Foo_initialize () at /home/vidarh/src/compiler-experiments/writing-a-compiler-in-ruby/features/inputs/method.rb:6&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#2  0x0804e4cc in __method_Class_new () at /home/vidarh/src/compiler-experiments/writing-a-compiler-in-ruby/lib/core/class.rb:38&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#3  0x0804a79c in main () at method.rb:12&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;When instrumented with saverags/printregs in &lt;code&gt;Foo#initialize&lt;/code&gt;, I get &lt;code&gt;5&lt;/code&gt; in ebx... Yikes. &lt;code&gt;--parsetree&lt;/code&gt; doesn't reveal any obvious
problems to me. So another look at assembler output. Oddly enough, that looks fairly sane. But here's the thing: we of course
don't call initialize directly - it's called by &lt;code&gt;Class#new&lt;/code&gt;.  So the next step is to instrument that too with saveregs.&lt;/p&gt;

&lt;p&gt;Unfortunately my tries with that blows up badly. Really badly. Clearly we're close. And it's yet again the assembler output we'll want to look at, I suspect. This time of &lt;code&gt;Class#new&lt;/code&gt;, specifically the
part where &lt;code&gt;Class#new&lt;/code&gt; calls &lt;code&gt;ob.initialize(*rest)&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I've annotated it inline:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        # &lt;span class=&quot;operator&quot;&gt;callm&lt;/span&gt; :&lt;span class=&quot;label&quot;&gt;ob.&lt;/span&gt;:&lt;span class=&quot;label&quot;&gt;initialize&lt;/span&gt;
        # &lt;span class=&quot;operator&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;generated&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;handle&lt;/span&gt;_&lt;span class=&quot;label&quot;&gt;splat&lt;/span&gt;:
        # *&lt;span class=&quot;operator&quot;&gt;rest&lt;/span&gt;
        
        # &lt;span class=&quot;operator&quot;&gt;UhOh&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;   # &lt;span class=&quot;label&quot;&gt;We&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;arguments&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;sall&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;         # &lt;span class=&quot;label&quot;&gt;Multiply&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;size&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;       # &lt;span class=&quot;label&quot;&gt;Allocate&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;enough&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;space&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;onto&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;stack&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;again&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;       # &lt;span class=&quot;label&quot;&gt;Make&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;bytes&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;leal&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;   # &lt;span class=&quot;label&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;where&lt;/span&gt; &lt;span class=&quot;quoted&quot;&gt;&quot;rest&quot;&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;located&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;stack&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;       # &lt;span class=&quot;label&quot;&gt;We&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;add&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;our&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;bytes&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;effectively&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;getting&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;last&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;adress&lt;/span&gt; + &lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;       # &lt;span class=&quot;label&quot;&gt;Make&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;stack&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;pointer&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;we&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;can&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;iterate&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;over&lt;/span&gt;
    &lt;span class=&quot;label&quot;&gt;.L144:&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;     # &lt;span class=&quot;label&quot;&gt;Copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;rest...&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;     # &lt;span class=&quot;label&quot;&gt;..to&lt;/span&gt; &lt;span class=&quot;quoted&quot;&gt;&quot;new rest&quot;&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;         # &lt;span class=&quot;label&quot;&gt;Bump&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;source&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;address&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;         # &lt;span class=&quot;label&quot;&gt;Bump&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;destination&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;address&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;cmpl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;       # &lt;span class=&quot;label&quot;&gt;At&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;end&lt;/span&gt;?
        &lt;span class=&quot;operator&quot;&gt;jne&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;.L144&lt;/span&gt;                # &lt;span class=&quot;label&quot;&gt;If&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;not&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;jump&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;back&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;.L144&lt;/span&gt;
        
        # &lt;span class=&quot;operator&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;hairy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;way&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;getting&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;arguments&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;back&lt;/span&gt;:
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt; 
        &lt;span class=&quot;operator&quot;&gt;sarl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;
        
        # *&lt;span class=&quot;operator&quot;&gt;rest&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;end&lt;/span&gt;
    
        # &lt;span class=&quot;operator&quot;&gt;UhOh&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;        # &lt;span class=&quot;label&quot;&gt;We&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;allocate&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;32&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;bytes&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;hex&lt;/span&gt; &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;on&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;stack&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;         # &lt;span class=&quot;label&quot;&gt;Number&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;arguments&lt;/span&gt;  &lt;span class=&quot;label&quot;&gt;before&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; *&lt;span class=&quot;label&quot;&gt;rest&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;       # &lt;span class=&quot;label&quot;&gt;Add&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;number&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;arguments&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;from&lt;/span&gt; *&lt;span class=&quot;label&quot;&gt;rest&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;             # &lt;span class=&quot;label&quot;&gt;Save&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;later&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-16&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;  # &lt;span class=&quot;label&quot;&gt;Copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;    # &lt;span class=&quot;label&quot;&gt;Save&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;stack&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;above&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;we&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;pushed&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;      # &lt;span class=&quot;label&quot;&gt;Save&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;optional&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;block&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;argument&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;popl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt;             # &lt;span class=&quot;label&quot;&gt;Remove&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebx&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;label&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;now&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;at&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;))&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;     # &lt;span class=&quot;label&quot;&gt;Copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;ob&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;     # &lt;span class=&quot;label&quot;&gt;Copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;pointer&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;40&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ecx&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;   # &lt;span class=&quot;label&quot;&gt;Copy&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;vtable&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;entry&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;for&lt;/span&gt; #&lt;span class=&quot;label&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;into&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;call&lt;/span&gt;    *&lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;            # &lt;span class=&quot;label&quot;&gt;call&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;ob.initialize&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;20&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;        # &lt;span class=&quot;label&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;stack&lt;/span&gt;
        
        # &lt;span class=&quot;operator&quot;&gt;UhOh&lt;/span&gt; &lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-4&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;   # &lt;span class=&quot;label&quot;&gt;get&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;numargs&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;sall&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;         # &lt;span class=&quot;label&quot;&gt;Multiply&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;4&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;       # &lt;span class=&quot;label&quot;&gt;Free&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;splat&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;arguments.&lt;/span&gt;
        
        # &lt;span class=&quot;operator&quot;&gt;callm&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;ob.initialize&lt;/span&gt; &lt;span class=&quot;label&quot;&gt;END&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Going through it like this suddenly makes it clearer... Or maybe not?&lt;/p&gt;

&lt;p&gt;See (1) above. Note that at this point we've spent a lot of time putting the splat
arguments onto the stack. Then we go ahead and subtract 32 bytes from &lt;code&gt;%esp&lt;/code&gt; even
though we're only using &lt;em&gt;8&lt;/em&gt; for the two arguments. Yikes.&lt;/p&gt;

&lt;p&gt;Let's look at &lt;code&gt;Emitter#with_stack&lt;/code&gt; which is responsible for this stack allocation:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numargs&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# We normally aim to make the stack frame aligned to 16&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# bytes. This however fails in the presence of the splat operator&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# If a splat is present, we instead allocate exact space, and use&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# %ebx to adjust %esp back again afterwards&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;adj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        
        &lt;span class=&quot;c1&quot;&gt;# If we're messing with the stack, any registers marked for saving will be&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# saved to avoid having to mess with the stack offsets later&lt;/span&gt;
            
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@save_register&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@save_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@save_register&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@out&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;r&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numargs&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;adj&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The comment looks promising. Except we've forgotten to take care of this.&lt;/p&gt;

&lt;p&gt;Thankfully this is easily fixed (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/b32ba75&quot;&gt;b32ba75&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;adj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;numargs&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;adj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;n&quot;&gt;adj&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;0.5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mf&quot;&gt;4.0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)).&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;round&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;PTR_SIZE&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;But that doesn't fix the odd value in &lt;code&gt;%ebx&lt;/code&gt;. Until we look at (2) above (near the top).
&lt;code&gt;numargs&lt;/code&gt; gives us the number of arguments &lt;em&gt;total&lt;/em&gt;. But we're only copying &lt;code&gt;rest&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Later, we actually want the number of elements in &lt;code&gt;rest&lt;/code&gt; and that's an entirely different
thing.&lt;/p&gt;

&lt;p&gt;We can fix that by accounting for the number of fixed arguments (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/bcb7668&quot;&gt;bcb7668&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;457&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;457&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
         &lt;span class=&quot;c1&quot;&gt;# (needs proper register allocation)&lt;/span&gt;
                          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;comment&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;*&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;last&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; 
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;472&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;473&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;jne&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;l&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sarl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note that this is still one huge hack, in that we're only handling splat properly
in a very small subset of cases where it can be used.&lt;/p&gt;

&lt;p&gt;That leaves us with (3): We overwrite the return value from &lt;code&gt;#initialize&lt;/code&gt;. Of course
in this specific case that doesn't matter, as &lt;code&gt;Class.new&lt;/code&gt; will ignore that return
value. But it's serious in other situations, so lets concoct up a test case.&lt;/p&gt;

&lt;p&gt;This is &lt;code&gt;features/inputs/splatreturn.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;s2&quot;&gt;&quot;Hey!&quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;splat&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
      &lt;span class=&quot;n&quot;&gt;foo&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We expect it to return &quot;Hey!&quot;, but it crashes because of the bug we've already found.&lt;/p&gt;

&lt;p&gt;We fix it with yet another messy change to the splat handling:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# We assume :ebx has been trashed at this point anyway&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The issue is that we need to safeguard &lt;code&gt;:eax&lt;/code&gt; and we don't want to use &lt;code&gt;with_register&lt;/code&gt;
as that might in the future spill registers to the stack. So we push &lt;code&gt;eax&lt;/code&gt; onto the
stack, and then we want to adjust the stack... But then &lt;code&gt;%eax&lt;/code&gt; will be somewhere we
don't want it. So we use &lt;code&gt;%ebx&lt;/code&gt; which at this point has likely been trashed (we'll
reinitialize it from the stack if needed anyway).&lt;/p&gt;

&lt;p&gt;But... We're not home free yet. We've changed &lt;code&gt;handle_splat&lt;/code&gt; to subtract the size
of the pre-existing address list. So we need to apply that here too.&lt;/p&gt;

&lt;p&gt;Here's finally a great test case for &lt;code&gt;--stackfence&lt;/code&gt;. With that option, this test program
gives me:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tmp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;splatreturn&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;snip&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
       &lt;span class=&quot;no&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Stack&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fence&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;violation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Expected&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x29fd8512&lt;/span&gt;
       &lt;span class=&quot;no&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Stack&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fence&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;violation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Expected&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x29fd8512&lt;/span&gt;
       &lt;span class=&quot;no&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Stack&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fence&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;violation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Expected&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x29fd8512&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Hey&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;
       &lt;span class=&quot;no&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Stack&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fence&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;violation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Expected&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x29fd8512&lt;/span&gt;
       &lt;span class=&quot;no&quot;&gt;ERROR&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Stack&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fence&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;violation&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Expected&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x29fd8512&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;So lets adjust the stack adjustment again. Notice the &lt;code&gt;@e.subl(args.size,reg)&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/8802ce5&quot;&gt;8802ce5&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
         &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:numargs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
           &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sall&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;c1&quot;&gt;# We assume :ebx has been trashed at this point anyway&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;      &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Final words, and next time&lt;/h3&gt;

&lt;p&gt;Debugging code generation is hairy. Unlike ordinary debugging you not only deal with broken higher
level logic, but all bets are off with respect to what the code actually does. I hope this part
has given some ideas about approaches and tools. But it's just a start, and frankly this part has
taken me a lot longer to write than I expected, as I tried to ensure I accurately reflected the
process of tracking down these bugs and ran into stumbling block after stumbling block.&lt;/p&gt;

&lt;p&gt;Ultimately, it is down to tracking values from register to register, and memory location to
memory location in some cases.&lt;/p&gt;

&lt;p&gt;Anyway. Next time we're moving on to register allocation. There's a lot of hairy code here by
now that makes assumptions about register usage that may or may not work only due to luck.&lt;/p&gt;

&lt;p&gt;So first order of business is to walk through our calling conventions and document the register
usage. Secondly, to create a more sound foundation for using registers, and leaving choice
of registers to the code generation backend (and hopefully reducing the dependencies on x86
in the process, though we still have x86 code littered all over the place).&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>operators</category>
      <pubDate>Sat, 08 Feb 2014 02:00:00 +0000</pubDate>
      <dc:date>2014-02-08T02:00:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 31</title>
      <link>http://hokstad.com/compiler/31-stringing-things-together</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;p&gt;I promised to get a second part out in December somewhere, and it seems like I only
barely made it. I'm still hoping to push two out in January, but that's contingent on
actually getting time to finish the next one too. But there'll be at least one in January,
sometimes towards the middle of the month. Anyway...&lt;/p&gt;

&lt;h2&gt;Stringing things together&lt;/h2&gt;

&lt;p&gt;With the new, though basic, &lt;code&gt;Fixnum&lt;/code&gt; support, it makes sense to want to print the numbers
without having to resort to &lt;code&gt;%s()&lt;/code&gt;. Let us add some basic output and conversion functionality.&lt;/p&gt;

&lt;p&gt;First lets make &lt;code&gt;compiler.feature&lt;/code&gt; actually run again. This turned out to be an embarrassing
case of me forgetting to check in two files. With &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/66d56ef&quot;&gt;66d56ef&lt;/a&gt; you can run these tests again.&lt;/p&gt;

&lt;p&gt;Even more embarrassingly that reveals a few regressions - a motivation for the next part,
where we will discuss testing og code generation in more detail, since that's definitively a
current weak spot.&lt;/p&gt;

&lt;p&gt;We will see soon to what extent these regressions affect what comes next, though.&lt;/p&gt;

&lt;p&gt;For now we will only support &lt;code&gt;Kernel#puts&lt;/code&gt; and &lt;code&gt;Kernel#print&lt;/code&gt;, and only the simplest of use
cases, though we will actually put them in &lt;code&gt;Object&lt;/code&gt;, again due to lack of &lt;code&gt;include&lt;/code&gt; support.&lt;/p&gt;

&lt;p&gt;We will assume that the output field separator (&lt;code&gt;$,&lt;/code&gt;) is always a linefeed, and we will not
do anything to explicitly support array arguments.&lt;/p&gt;

&lt;p&gt;We add this test case to &lt;code&gt;compiler.feature&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Should be one line down due to linefeed above&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello &quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;World&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;is&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;This&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;is&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;test&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We hope to see at least part of this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ruby features/inputs/06print.rb

Should be one line down due to linefeed above
Hello 42
World
Thisis1test
This
is
test
2
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Instead we get a segmentation fault. There's a number of issues here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There are missing methods&lt;/li&gt;
&lt;li&gt;The primitive method_missing &quot;handler&quot; that we added some time ago has broken.&lt;/li&gt;
&lt;li&gt;As you will see, even when we stub out the methods, there are regression with argument passing.&lt;/li&gt;
&lt;/ul&gt;


&lt;h3&gt;Stubbing out the basics&lt;/h3&gt;

&lt;p&gt;To begin with, we put a stub &lt;code&gt;Fixnum#to_s&lt;/code&gt; with an error, and a &lt;code&gt;String#to_s&lt;/code&gt; which simply returns
&lt;code&gt;self&lt;/code&gt; in place, as well as &lt;code&gt;#puts&lt;/code&gt; and &lt;code&gt;#print&lt;/code&gt; versions in &lt;code&gt;Object&lt;/code&gt; (rather than &lt;code&gt;Kernel&lt;/code&gt;, as
noted above):&lt;/p&gt;

&lt;p&gt;See &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/6af2c31&quot;&gt;6af2c31&lt;/a&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(puts (callm str __get_raw))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if raw
    +         (puts raw)
    +         (puts &quot;&quot;)
    +         )&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if raw
    +         (printf &quot;%s&quot; raw)
    +         )&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;These are woefully incomplete, but at least in theory they ought to not faily completely....&lt;/p&gt;

&lt;p&gt;However, let us take a look what happens if we run the compiler with &lt;code&gt;--parsetree&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parsetree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;norequire&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;06&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;file: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;06&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(do
      puts
      (call puts (
          (sexp (call __get_string .L0))))
      (call print (
          (sexp (call __get_string .L1))))
      (call puts ())
      (call print (
          (sexp (call __get_string .L2))))
      (call print (
          (sexp (call __get_string .L3)) (sexp (call __get_string .L4)) (sexp (call __get_fixnum 1))
          (sexp (call __get_string .L5))))
      (call puts (
          (sexp (call __get_string .L3)) (sexp (call __get_string .L4)) (sexp (call __get_string .L6))
          (sexp (call __get_fixnum 2))))
    )&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Some likely problems to begin with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &quot;naked&quot; &lt;code&gt;puts&lt;/code&gt; will likely break horribly as the methods specify a single argument, with
no default value, and we don't trap that in any way.&lt;/li&gt;
&lt;li&gt;Notice how the &lt;code&gt;puts 42&lt;/code&gt; line has resulted in an empty argument list (!)&lt;/li&gt;
&lt;li&gt;We obviously will fail on the parameter lists with multiple values as the methods don't
use splats at all. However we really need to actually test for that...&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Now, while the methods we added are obviously broken, &lt;em&gt;some&lt;/em&gt; stuff ought to get executed anyway
(subject to buffering, some of it ought to make it to output too), so lets deal with &lt;code&gt;puts 42&lt;/code&gt;
first, then add splats to the methods, try to get just &lt;code&gt;puts&lt;/code&gt; to work, and then see if we get
through any of the above at that point.&lt;/p&gt;

&lt;h3&gt;Tracking down the 'puts 42' regression&lt;/h3&gt;

&lt;p&gt;Passing &lt;code&gt;--notransform&lt;/code&gt; shows us the likely culprit is the rewrites in &lt;code&gt;transform.rb&lt;/code&gt;&quot;&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;  &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parsetree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;norequire&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;notransform&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;06&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;reading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;file: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;06&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;print&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(do
      puts
      (call puts Should be one line down due to linefeed above)
      (call print Hello )
      (call puts 42)
      (call print World\n)
      (call print (This is 1 test\n))
      (call puts (This is test 2))
    )&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We'll use that to add tests targetting specific the transforms as a whole, and then specifically
for &lt;code&gt;rewrite_fixnumconst&lt;/code&gt; since that seems like a reasonable place to start.&lt;/p&gt;

&lt;p&gt;But first, since running this code from gdb and doing a backtrace consistently shows crashes
related to our &lt;code&gt;__send__&lt;/code&gt; fallback or &lt;code&gt;method_missing&lt;/code&gt; - neither which &lt;em&gt;should&lt;/em&gt; get triggered
at this stage, lets change &lt;code&gt;__send__&lt;/code&gt; to make it more resilient to implementation
bugs for now (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1e23ae0&quot;&gt;1e23ae0&lt;/a&gt;) and give better debug output:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lib&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;core&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;19&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Object&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;__send__&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING: __send__ bypassing vtable not yet implemented. Called with %s\n&quot; (callm sym to_s))&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING: __send__ bypassing vtable not yet implemented.\n&quot;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING:    Called with %p\n&quot; sym)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;WARNING:    self = %p\n&quot; self)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(if sym (printf &quot;WARNING:    (string: '%s'\n&quot; (callm sym to_s)))
       end

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Next I've added a basic test case for 'puts 42' and the expected output only to &lt;code&gt;compiler.feature&lt;/code&gt;
in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/ae61dfd&quot;&gt;ae61dfd&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/5f792c4&quot;&gt;5f792c4&lt;/a&gt; I've added a simple test case for the transformations:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;puts 42&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__get_fixnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]]]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Running it gives us this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;ss&quot;&gt;expected: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:__get_fixnum&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]]]&lt;/span&gt;
               &lt;span class=&quot;ss&quot;&gt;got: &lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:call&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:puts&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;kp&quot;&gt;nil&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]]&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;using&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;RSpec&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Expectations&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;ExpectationNotMetError&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;step_definitions&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shunting_steps&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;32&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:in&lt;/span&gt; &lt;span class=&quot;sb&quot;&gt;`/^the parse tree should become (.*)$/'
          transform.feature:10:in `&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Then&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;should&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;become&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Looking carefully at &lt;code&gt;rewrite_fixnumconst&lt;/code&gt; and comparing to &lt;code&gt;rewrite_strconst&lt;/code&gt; reveals the
source: &quot;FIXME&quot; warning has been subtly broken to use the wrong index.&lt;/p&gt;

&lt;p&gt;The correct line reads (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/bfecf5d&quot;&gt;bfecf5d&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is_call&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Fixing this gets us the following output instead for the &lt;code&gt;compiler.feature&lt;/code&gt; &lt;code&gt;puts 42&lt;/code&gt; test:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;      expected: &quot;42\n&quot;
      got: &quot;Fixnum#to_s is not implemented\n&quot; (using ==)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;... which is reasonable, given that we haven't implemented it yet.&lt;/p&gt;

&lt;h3&gt;Implementing to_s for Fixnum&lt;/h3&gt;

&lt;p&gt;Handling this in pure Ruby should be possible with what we have available, though probably not
very efficiently. And again in pure laziness, let's defer to the C libs &lt;code&gt;snprintf&lt;/code&gt;. And leak
some memory in the process, but what's a little memory leak amongst friends who aren't freeing
anything at all until exit at the moment? ... (yeah, another fun subject we'll have to bite
the bullet on)&lt;/p&gt;

&lt;p&gt;This takes care of that (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a2f36be&quot;&gt;a2f36be&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;s2&quot;&gt;&quot;Fixnum#to_s is not implemented&quot;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(let (buf)
    +       (assign buf (malloc 16))
    +       (snprintf buf 16 &quot;%ld&quot; @value)
    +       (__get_string buf)
    +       )&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Our &lt;code&gt;puts 42&lt;/code&gt; test now works.&lt;/p&gt;

&lt;h3&gt;Handling variable arguments for puts an print&lt;/h3&gt;

&lt;p&gt;We now want to make &lt;code&gt;puts&lt;/code&gt; (with no arguments) and various other variations work. I'll go through
tracking down these regressions in some detail debugging code generation is frankly often one
of the most annoying and time consuming parts of writing a compiler. And just maybe it'll teach
me to write more tests...&lt;/p&gt;

&lt;p&gt;So lets start by adding one:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctrivial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;outputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctrivial&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;txt&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;A&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;with&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;no&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argument&lt;/span&gt;                     &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Where the input looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;   puts
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;and the output like this:&lt;/p&gt;

&lt;p&gt;... and it fails (I've run it directly rather than bothering to let Cucumber run it
yet):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;sr&quot;&gt;/tmp/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctrivial&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;GNU&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;6.8&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;debian&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Copyright&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2008&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Free&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Software&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Foundation&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Inc&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;License&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GPLv3&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GNU&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GPL&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;version&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;or&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;later&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;http&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:/&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gnu&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;org&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;licenses&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;software: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;you&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;are&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;change&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;redistribute&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;There&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;NO&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;WARRANTY&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;to&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;extent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;permitted&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;by&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;law&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;  &lt;span class=&quot;no&quot;&gt;Type&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;show copying&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;show warranty&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;details&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;This&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;GDB&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;was&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;configured&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;i486-linux-gnu&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;run&lt;/span&gt;
    &lt;span class=&quot;no&quot;&gt;Starting&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;program: &lt;/span&gt;&lt;span class=&quot;sr&quot;&gt;/tmp/&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;01&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctrivial&lt;/span&gt;
    
    &lt;span class=&quot;no&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;received&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;signal&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;SIGSEGV&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Segmentation&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;
    &lt;span class=&quot;mh&quot;&gt;0x00000000&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;sc&quot;&gt;??&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;bt&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#0  0x00000000 in ?? ()&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#1  0x0804c128 in __method_Object_puts () at /home/vidarh/src/compiler-experiments/writing-a-compiler-in-ruby/lib/core/object.rb:36&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;#2  0x0804a622 in main () at 01ctrivial.rb:1&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gdb&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;quit&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;That's &lt;code&gt;def puts str&lt;/code&gt;. First problem is that we're currently expecting an argument,
but we're not getting any. In reality the compiler should throw an &lt;code&gt;ArgumentError&lt;/code&gt; when
the method is declared like this and called with too few arguments. But we've not gotten
that far. Anyway, first step is to change this to &lt;code&gt;def puts *str&lt;/code&gt;. But we still need to
&lt;em&gt;handle&lt;/em&gt; the difference in argument numbers and it currently won't be very elegant, as we
don't convert &lt;code&gt;str&lt;/code&gt; to an actual Ruby array or anything, so we have to dip down to &lt;code&gt;%s(numargs)&lt;/code&gt; etc.&lt;/p&gt;

&lt;p&gt;We first try to add this to the start of &lt;code&gt;Object#puts&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(assign na (call __get_fixnum (numargs)))&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
           &lt;span class=&quot;sx&quot;&gt;%s(puts &quot;&quot;)&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We expect &lt;code&gt;na&lt;/code&gt; to be 2 because of &lt;code&gt;self&lt;/code&gt; + the optional &lt;code&gt;__closure__&lt;/code&gt; argument we pass
(but that is always present).&lt;/p&gt;

&lt;p&gt;This fixes &lt;code&gt;puts&lt;/code&gt; on its own, but breaks &lt;code&gt;puts 42&lt;/code&gt;. The reason is the splat operator -
we can't any longer refer directly to &lt;code&gt;str&lt;/code&gt; and expect to get an object - &lt;code&gt;str&lt;/code&gt; now
refers to an address to an array of objects.&lt;/p&gt;

&lt;p&gt;So we change the entire &lt;code&gt;puts&lt;/code&gt; to this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(assign na (__get_fixnum numargs))&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(puts &quot;&quot;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;sx&quot;&gt;%s(assign raw (index str 0))&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(if raw
             (puts raw)
             (puts &quot;&quot;)
             )&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Apart from being horribly ugly, this also doesn't handle multiple arguments,
but it's a step further.&lt;/p&gt;

&lt;p&gt;You find this and test in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/6918bf8&quot;&gt;6918bf8&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, lets try something more convoluted, like, say, &lt;code&gt;puts &quot;foo&quot;, &quot;bar&quot;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Uh-oh. Doesn't work. What more, if we add a debug printout like &lt;code&gt;%s(printf &quot;numargs=%d\n&quot; numargs)&lt;/code&gt; we get a nasty surprise: It returns 3. For me at least.&lt;/p&gt;

&lt;p&gt;Some probing in the assembler output shows us this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;c1&quot;&gt;# callm :self.:puts&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebx&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebx&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;L11&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$__get_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;*%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;subl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebx&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$.&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;L12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$__get_string&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;*%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edx&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edx&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;36&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;call&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;*%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;vg&quot;&gt;$20&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# callm self.puts END&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Spot the problem? We use &lt;code&gt;%ebx&lt;/code&gt; to hold the number of arguments we calculate, but with our
new &quot;proper&quot; support for strings, we now call &lt;code&gt;__get_string&lt;/code&gt; on the string argument, and
each one of them causes &lt;code&gt;%ebx&lt;/code&gt; to get clobbered. As, incidentally does &lt;code&gt;__get_string&lt;/code&gt;
itself, as we don't actually store this value anywhere. We have two choices: Load it
&quot;closer&quot; (That's generally a good idea anyway) or calculate it closer (for splat arguments).&lt;/p&gt;

&lt;p&gt;This again underlines that we need proper register allocation including ability to &quot;spill&quot;
registers to the stack. This is complicated in that if we push and pop values all over the
place, we need to be able to adjust all accesses to &lt;code&gt;%esp&lt;/code&gt; all over.&lt;/p&gt;

&lt;p&gt;For now we &quot;fake&quot; spilling of &lt;code&gt;%ebx&lt;/code&gt; by pushing &lt;code&gt;%ebx&lt;/code&gt; indiscriminately onto the
stack, and adjusting the generation of the arguments accordingly &quot;manualy&quot; so that when
we pop it off the stack again everything happens to work. We end up with changing the
central parts of &lt;code&gt;Compiler#compile_callm_args&lt;/code&gt; as follows (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/6901567&quot;&gt;6901567&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;splat&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
          &lt;span class=&quot;c1&quot;&gt;# we're for now going to assume that %ebx is likely&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# to get clobbered later, in the case of a splat,&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# so we store it here until it's time to call the method.&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
          &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ob&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;args&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;each_with_index&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;param&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_to_stack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;param&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
          &lt;span class=&quot;c1&quot;&gt;# This is where the actual call gets done&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# This differs depending on whether it's a normal&lt;/span&gt;
          &lt;span class=&quot;c1&quot;&gt;# method call or a closure call.&lt;/span&gt;
    
          &lt;span class=&quot;c1&quot;&gt;# But first we pull the number of arguments off the stack.&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ebx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The main change here is the &lt;code&gt;@e.pushl(:ebx)&lt;/code&gt; and &lt;code&gt;@e.popl(:ebx)&lt;/code&gt; lines. But
notice that we change the offsets for &lt;code&gt;self&lt;/code&gt; and method arguments accordingly.&lt;/p&gt;

&lt;p&gt;This finally allows us to handle &lt;code&gt;#puts&lt;/code&gt; and &lt;code&gt;#print&lt;/code&gt; reasonably close to can see the result of this in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/4511cea&quot;&gt;4511cea&lt;/a&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(assign na (__get_fixnum numargs))&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(puts &quot;&quot;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      
        &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(assign raw (index str (callm i __get_raw)))&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(if raw (puts raw))&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;print&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(assign na (__get_fixnum numargs))&lt;/span&gt;
    
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;nil&quot;)&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
        &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;na&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(assign raw (index str (callm i __get_raw)))&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;raw&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;__get_raw&lt;/span&gt;
          &lt;span class=&quot;sx&quot;&gt;%s(if raw (printf &quot;%s&quot; raw))&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;It's not pretty, and there's certainly a lot of room for improvement.
In particular &quot;proper&quot; access to the splat arguments would help tremendously,
so that's on the agendy for soon too, I think, after code generation testing
and some cleaner register allocation.&lt;/p&gt;

&lt;h3&gt;Some string interpolation&lt;/h3&gt;

&lt;p&gt;While we're at it, we might as well take a look at string interpolation
and see what kind of trouble we might run into.&lt;/p&gt;

&lt;p&gt;First we add a trivial test case (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/c7b4b540bb&quot;&gt;c7b4b540bb&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Hello World&quot;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;42&lt;/span&gt;
    
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;, &lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Unsurprisingly it doesn't work, so lets try compiling it with &lt;code&gt;--norequire --parsetree&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(do
      (assign a (sexp (call __get_string .L0)))
      (assign b (sexp (call __get_fixnum 42)))
      (call puts (
          (concat (sexp (call __get_string .L1)) a (sexp (call __get_string .L2)) b)))
    )&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This is clearly outdated - we'd expect &lt;code&gt;concat&lt;/code&gt; to be a method call on the string.&lt;/p&gt;

&lt;p&gt;Let us turn of transformations, to see what the parser actually created:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;$&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;parsetree&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;norequire&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;notransform&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interpolate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; 
    &lt;span class=&quot;n&quot;&gt;reading&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;from&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;file: &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;features&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;inputs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;interpolate&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(do
      (assign a &quot;Hello World&quot;)
      (assign b &quot;42&quot;)
      (call puts (
          (concat &quot;&quot; a &quot; , &quot; b)))
    )&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;A-ha. &lt;code&gt;concat&lt;/code&gt; nodes were how we implemented interpolation in the parser. So what we
need is to transform them to generate the equivalent of &lt;code&gt;&quot;&quot;.concat(a.to_s).concat(&quot; , &quot;).concat(b.to_s)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Here is how we do that (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/35d93b0&quot;&gt;35d93b0&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;create_concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pop&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;is_a?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;
        &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;create_concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;rewrite_concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;exp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;depth_first&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:concat&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;create_concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]))&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
          &lt;span class=&quot;ss&quot;&gt;:next&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We replace the existing &lt;code&gt;(concat a b c ...)&lt;/code&gt; with a series of method calls to create and convert
nodes to strings, and then call &lt;code&gt;String#concat&lt;/code&gt; to create the result.&lt;/p&gt;

&lt;p&gt;We for now implement &lt;code&gt;String#concat&lt;/code&gt; like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;concat&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(do
    +         (assign ro (callm other __get_raw))
    +         (assign osize (strlen ro))
    +         (assign bsize (strlen @buffer))
    +         (assign size (add bsize osize))
    +         (assign size (add size 1))
    +         (assign newb (malloc size))
    +         (strcpy newb @buffer)
    +         (strcat newb ro)
    +         (assign @buffer newb)
    +   )&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;nb&quot;&gt;self&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;  &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;While this is simple - it just allocates buffers and copies data into them - it isn't very elegant
code. So I might as well admit: Some of the simplicity is because of bugs that rears its head if
we make the expressions too advanced - likely due to memory protection issues.&lt;/p&gt;

&lt;p&gt;But we will take care of that in our part on testing code generation, next time. For now, this
works.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>operators</category>
      <pubDate>Tue, 31 Dec 2013 06:15:00 +0000</pubDate>
      <dc:date>2013-12-31T06:15:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 30</title>
      <link>http://hokstad.com/compiler/30-the-operators-4</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;The Operators - Part 4: Comparisons&lt;/h2&gt;

&lt;p&gt;Where we left off &lt;a href=&quot;/compiler/29-the-operators-3&quot;&gt;last time&lt;/a&gt;, we had everything but
comparison operators and &lt;code&gt;&amp;amp;amp;&amp;amp;amp;&lt;/code&gt;, &lt;code&gt;!&lt;/code&gt; sorted out. When I started replacing &lt;code&gt;runtime.c&lt;/code&gt;, I expected
to do it in one go, as I've mentioned, but as you have seen there was quite a bit to cover.&lt;/p&gt;

&lt;p&gt;This is it, though. &lt;code&gt;runtime.c&lt;/code&gt; will finally go, at any cost.&lt;/p&gt;

&lt;p&gt;I'll try to keep this short since we've covered most of the steps in the previous parts,
and only address differences affecting the remaining operators.&lt;/p&gt;

&lt;p&gt;(Note that I'll reduce my &quot;buffer&quot; which is currently about 5 months, as I've been able to
consistently write a part ever month since April; that means I'll aim to post the next
part in the next week or two, and will probably post two in January too)&lt;/p&gt;

&lt;h3&gt;Compiling comparisons&lt;/h3&gt;

&lt;p&gt;Let us dive right in and take a look at the first of the comparison operators first, as they
are all very similar:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;label&quot;&gt;ne:&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%esp&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;cmpl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;setne&lt;/span&gt;   &lt;span class=&quot;register&quot;&gt;%al&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movzbl&lt;/span&gt;  &lt;span class=&quot;register&quot;&gt;%al&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;popl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;ret&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This isn't too bad. After the normal setup, one operand is copied into &lt;code&gt;%eax&lt;/code&gt; and &lt;code&gt;cmpl&lt;/code&gt;
is used to compare the second one with &lt;code&gt;%eax&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Then &lt;code&gt;setne&lt;/code&gt; is used to set its operand to 1 if the condition flags set by &lt;code&gt;cmpl&lt;/code&gt; match the &lt;code&gt;ne&lt;/code&gt;
(not equal) condition, and there are equivalent variants for a long range of other conditions
that matches our comparison operators neatly. &lt;code&gt;%al&lt;/code&gt; is part of the ugliness of x86 - it is
a register descriptor that maps to the least significant byte of &lt;code&gt;%eax&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;movzbl&lt;/code&gt; is then used to clear the remaining bytes.&lt;/p&gt;

&lt;p&gt;All of the comparisons follow this patterns, with &lt;code&gt;le&lt;/code&gt;, &lt;code&gt;ge&lt;/code&gt;, &lt;code&gt;ne&lt;/code&gt; mapping one to one to
&lt;code&gt;set(something)&lt;/code&gt; opcodes, &lt;code&gt;lt&lt;/code&gt; mapping to &lt;code&gt;setl&lt;/code&gt;, &lt;code&gt;gt&lt;/code&gt; to &lt;code&gt;setg&lt;/code&gt; and &lt;code&gt;eq&lt;/code&gt; to &lt;code&gt;sete&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First lets write a simple test program:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(do
       (if (lt 2 5) (call puts (&quot;2 &amp;lt; 5&quot;)))
       (if (lt 1 2) (call puts (&quot;1 &amp;lt; 2&quot;)))
       (if (le 2 2) (call puts (&quot;2 &amp;lt;= 2&quot;)))
       (if (ge 2 2) (call puts (&quot;2 &amp;gt;= 2&quot;)))
       (if (gt 3 2) (call puts (&quot;3 &amp;gt; 2&quot;)))
       (if (eq 2 2) (call puts (&quot;2 == 2&quot;)))
       (if (ne 3 2) (call puts (&quot;3 != 2&quot;)))
    
       (puts &quot;false: (no output expected)&quot;)
    
       (if (lt 5 2) (call puts (&quot;5 &amp;lt; 2&quot;)))
       (if (lt 2 2) (call puts (&quot;2 &amp;lt; 2&quot;)))
       (if (le 3 2) (call puts (&quot;3 &amp;lt;= 2&quot;)))
       (if (ge 1 2) (call puts (&quot;1 &amp;gt;= 2&quot;)))
       (if (gt 2 2) (call puts (&quot;2 &amp;gt; 2&quot;)))
       (if (eq 4 2) (call puts (&quot;4 == 2&quot;)))
       (if (ne 2 2) (call puts (&quot;2 != 2&quot;)))
    
       (puts &quot;done&quot;)
    )&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The expected output is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ /tmp/testcmp 
2 &amp;amp;lt; 5
1 &amp;amp;lt; 2
2 &amp;amp;lt;= 2
2 &amp;amp;gt;= 2
3 &amp;amp;gt; 2
2 == 2
3 != 2
false: (no output expected)
done
&lt;/code&gt;&lt;/pre&gt;

&lt;dl&gt;
&lt;dt&gt;The actual compilation is easy. We make use of &lt;code&gt;#compile_2&lt;/code&gt; that we&lt;/dt&gt;
&lt;dt&gt;added in the previous part to compile both operands in turn and preserve&lt;/dt&gt;
&lt;dt&gt;the result, then compare it, and set and extend &lt;code&gt;%eax&lt;/code&gt; accordingly&lt;/dt&gt;
&lt;dd&gt;(in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/bba2c93&quot;&gt;bba2c93&lt;/a&gt;)&lt;/dd&gt;
&lt;/dl&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_comparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compile_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;cmpl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;emit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;set&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;op&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_sym&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:al&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movzbl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:al&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_eq&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compile_comparison&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;I've only given &lt;code&gt;#compile_eq&lt;/code&gt; as an example here, but the code is pretty
much identical for the rest - only substituting the &lt;code&gt;op&lt;/code&gt; argument according
to the &quot;set[op]&quot; variant we want to use.&lt;/p&gt;

&lt;p&gt;The rest is a trivial commit to strip these operators out of runtime.c, and
register them wth the &lt;code&gt;Compiler&lt;/code&gt; class, that you can see in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/ce6deb9&quot;&gt;ce6deb9&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;A first stab of Ruby level comparisons&lt;/h3&gt;

&lt;p&gt;Our first problem is that most of Ruby's comparisons are mixins in the &lt;code&gt;Comparable&lt;/code&gt; module.
We'll ignore that for now, and simply implement integer to integer comparisons directly in
&lt;code&gt;Fixnum&lt;/code&gt; and then generalize. We'll want specializations of the operators for integers anyway,
as we don't want to fall back on the &lt;code&gt;&amp;amp;lt;=&amp;amp;gt;&lt;/code&gt; operator for integer to integer comparisons.&lt;/p&gt;

&lt;p&gt;First a Ruby version of our tests from above:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 &amp;lt; 5&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1 &amp;lt; 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 &amp;lt;= 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 &amp;gt;= 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;3 &amp;gt; 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 == 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;3 != 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;false: (no output expected)&quot;&lt;/span&gt;
    
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;5 &amp;lt; 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 &amp;lt; 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;3 &amp;lt;= 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;1 &amp;gt;= 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 &amp;gt; 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;4 == 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;2 != 2&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    &lt;span class=&quot;nb&quot;&gt;puts&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;done&quot;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The we add the operators to &lt;code&gt;Fixnum&lt;/code&gt;. It's similar to what we did for &lt;code&gt;Fixnum.+&lt;/code&gt; etc, except
we can't turn it back into a &lt;code&gt;Fixnum&lt;/code&gt; object, since 0 would never get interpreted as false.
Since we don't have the proper &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; yet, we just do this (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a844694&quot;&gt;a844694&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(eq @value (callm other __get_raw))&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note that this will break hopelessly in a number of situations, such as if you try to
compare, say, a string with a Fixnum. In Ruby this should result in an &lt;code&gt;ArgumentError&lt;/code&gt;
exception, but here it'll cause a crash or nasty silent bugs. We'll quash those issues
later.&lt;/p&gt;

&lt;h3&gt;Not and and&lt;/h3&gt;

&lt;p&gt;The choice above to not treat &lt;code&gt;true&lt;/code&gt; and &lt;code&gt;false&lt;/code&gt; properly at the Ruby level leaves us in a
bit of a pickle. The input to these will often be the outcome of another comparison. If
the input is another expression the effect will potentially be entirely different than if
checking against variables set to &lt;code&gt;true&lt;/code&gt; or &lt;code&gt;false&lt;/code&gt; directly. Many results will be totally bogus.&lt;/p&gt;

&lt;p&gt;As a result I finally decided on writing this to punt entirely on &lt;code&gt;!&lt;/code&gt;. &lt;code&gt;&amp;amp;amp;&amp;amp;amp;&lt;/code&gt; is in a similar
situation, and furthermore it is easy to &quot;emulate&quot; with &lt;code&gt;if&lt;/code&gt;, and so we'll punt on that too.&lt;/p&gt;

&lt;p&gt;So we'll defer these until we can get a handle on &lt;code&gt;true&lt;/code&gt;, &lt;code&gt;false&lt;/code&gt; and &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We'll however still finally get rid of &lt;code&gt;runtime.c&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/28d246c&quot;&gt;28d246c&lt;/a&gt;). I won't cover the specifics -
look at the commit.&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>operators</category>
      <pubDate>Wed, 04 Dec 2013 01:30:00 +0000</pubDate>
      <dc:date>2013-12-04T01:30:00+00:00</dc:date>
    </item>
    <item>
      <title>Writing a (Ruby) compiler in Ruby bottom up - step 29</title>
      <link>http://hokstad.com/compiler/29-the-operators-3</link>
      <description>

&lt;p&gt;&lt;span style=&quot;color: red; &quot;&gt;This is &lt;a href=&quot;http://www.hokstad.com/compiler&quot;&gt;part of a series&lt;/a&gt;
I started in March 2008 - you may want to go back and look at older parts if you're
new to this series.&lt;/span&gt;&lt;/p&gt;


&lt;h2&gt;The Operators - Part 3: Operating on our newly minted Fixnums&lt;/h2&gt;

&lt;p&gt;Where we left off &lt;a href=&quot;/compiler/28-the-operators-2&quot;&gt;last time&lt;/a&gt;, we transform numbers into
&lt;code&gt;Fixnum&lt;/code&gt; objects, and turn &lt;code&gt;+&lt;/code&gt; and other operators into method calls. In theory at least
- we haven't actually &lt;em&gt;tested&lt;/em&gt; that functionality properly in practice.&lt;/p&gt;

&lt;h3&gt;Putting them to work&lt;/h3&gt;

&lt;p&gt;So lets start with the simplest possible test: Can we &lt;em&gt;call&lt;/em&gt; &lt;code&gt;Fixnum#+&lt;/code&gt; at all?&lt;/p&gt;

&lt;p&gt;Let's compile &lt;code&gt;5 + 3&lt;/code&gt;. Nope. Doesn't work. For starters, we need to add &lt;code&gt;require&lt;/code&gt;
statements for &lt;code&gt;Numeric&lt;/code&gt; and &lt;code&gt;Integer&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1c51f99&quot;&gt;1c51f99&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;But that's not enough. So lets try dipping down to our low level syntax, and
compile this decidedly non-Ruby test:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;test: %d\n&quot; (callm (call __get_fixnum 5) + ((call __get_fixnum 3))))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;The &lt;code&gt;(callm ...)&lt;/code&gt; is explicitly meant to do roughly what we should expect the
&lt;code&gt;5 + 3&lt;/code&gt; to get turned into.&lt;/p&gt;

&lt;p&gt;(You can compile this with &lt;code&gt;./compile [filename]&lt;/code&gt; in the working directory, and get
&lt;code&gt;/tmp/[filename]&lt;/code&gt; out if everything worked)&lt;/p&gt;

&lt;p&gt;To get it to return something other than junk, let's actually implement &lt;code&gt;Fixnum#+&lt;/code&gt;
still using &lt;code&gt;runtime.c&lt;/code&gt; to provide &lt;code&gt;add()&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/326ae54&quot;&gt;326ae54&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;
        &lt;span class=&quot;sx&quot;&gt;%s(call add (@value (callm other __get_raw)))&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;With that in place there's just one little wrinkle to get the example above to
compile: Our &lt;code&gt;%s()&lt;/code&gt; syntax can't handle operators. So for the sake of convenience,
let us fix that by allowing any valid method name (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a7d4c31&quot;&gt;a7d4c31&lt;/a&gt;) by modifying
&lt;code&gt;sexp.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;parse_exp&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;ws&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Quoted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse_sexp&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;expect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;Atom&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Int&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Quoted&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Methodname&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;parse_sexp&lt;/span&gt;
         &lt;span class=&quot;n&quot;&gt;ws&lt;/span&gt;
         &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;At this point you should be able to compile and run the test above, and get the
expected &lt;code&gt;test: 8&lt;/code&gt; output. So why is &lt;code&gt;5 + 3&lt;/code&gt; on its own segmentation faulting?&lt;/p&gt;

&lt;p&gt;Luckily we have a debugging tool in the &lt;code&gt;--norequire --parsetree&lt;/code&gt; options:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(do
      (callm (sexp (call __get_fixnum 5)) + (sexp (call __get_fixnum 3)))
    )&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And there we see an ugly pitfall of this syntax. Spotted it? The second argument to
&lt;code&gt;callm&lt;/code&gt; is a parameter list enclosed in parantheses, but here we pass it another
list/array that happens to be an expression. It does reveal rather weak error
handling and consistency checking for this syntax that we probably should do
something about, but for now let us focus on the operators.&lt;/p&gt;

&lt;p&gt;With a one line fix we get the output we need (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/1d9df53&quot;&gt;1d9df53&lt;/a&gt;:):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;transform&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;86&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;86&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;next&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:skip&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;
     
           &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;OPER_METHOD&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;member?&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;].&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;to_s&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;        &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]]&lt;/span&gt;
             &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
             &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:callm&lt;/span&gt;
           &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And now the parse output looks like this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(do
      (callm (sexp (call __get_fixnum 5)) + (
          (sexp (call __get_fixnum 3))))
    )&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}}}&lt;/span&gt;                                     
    
    &lt;span class=&quot;no&quot;&gt;Which&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;far&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;more&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reasonable&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;and&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;actually&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;doesn&lt;/span&gt;&lt;span class=&quot;err&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;t&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;segfault&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;So&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;us&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;it&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;returns&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;the&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;too:
    
    &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ruby&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    
    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%d\n&quot; a)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;... and that works. And that is wrong. Sigh. What we forgot above is that this
whole mess means we have to re-wrap integers into an object every time we get
one back. The example above should have been:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    
    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%d\n&quot; (callm a __get_raw))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And that still fails. Until we do this to &lt;code&gt;Fixnum#+&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/50fcf26&quot;&gt;50fcf26&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;other&lt;/span&gt;
       &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(call add (@value (callm other __get_raw)))&lt;/span&gt; 
       &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;sx&quot;&gt;%s(call __get_fixnum ((call add (@value (callm other __get_raw)))))&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And now our latest test should work.&lt;/p&gt;

&lt;p&gt;I made you look through this intensely frustrating sequence for a reason - it's
easy to present the more polished description of this process, but it's important
to keep an eye on just how many details are there to trip you up when generating
code and trying to debug things based on effects on generated code through several
layers like this. It is one of the hardest parts of writing a compiler.&lt;/p&gt;

&lt;p&gt;You may have noticed that despite a growing number of unit-tests for the parser
components, there's far fewer tests for the code generation, despite the fact
that it is far trickier to track down bugs there. One of the upcoming parts will
start addressing the difficulties of unit-testing the code generation.&lt;/p&gt;

&lt;p&gt;In the meantime, it is now &lt;em&gt;finally&lt;/em&gt; time to do what we came here for, and re-implement
&lt;code&gt;runtime.c&lt;/code&gt; as compiler intrinsics + Ruby.&lt;/p&gt;

&lt;h3&gt;What does  add/sub/etc. do anyway?&lt;/h3&gt;

&lt;p&gt;Time to break out our old friend gcc, and look at some asm output. To start with,
here's &lt;code&gt;add&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;globl&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;type&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@function&lt;/span&gt;
    &lt;span class=&quot;ss&quot;&gt;add:
        &lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pushl&lt;/span&gt;   &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;esp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edx&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;addl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;eax&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;popl&lt;/span&gt;    &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ebp&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ret&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;size&lt;/span&gt;   &lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;add&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Oh. That was simple. It &quot;just&quot; sets up the stack frame, moves the arguments into
&lt;code&gt;%edx&lt;/code&gt; and &lt;code&gt;%eax&lt;/code&gt; respectively, adds them, and frees the stack frame.&lt;/p&gt;

&lt;p&gt;We've put up with &lt;code&gt;runtime.c&lt;/code&gt; and do a function call on every
add for that? Of course, when we start trying to implement the Ruby semantics, an
extra function call doesn't look all that bad (we'll have a lot of fun trying to
optimize that out at some point in the future...), since there'll be a full blown
method call to begin with.&lt;/p&gt;

&lt;p&gt;Not all of them are &lt;em&gt;as&lt;/em&gt; simple (do &lt;code&gt;gcc -o runtime.s -S runtime.c&lt;/code&gt; and take a look
at &lt;code&gt;runtime.s&lt;/code&gt; yourself), but none of the few runtime functions we have are all that
much work. So let us get to it.&lt;/p&gt;

&lt;h3&gt;Adding 'add'&lt;/h3&gt;

&lt;p&gt;First we add a &lt;code&gt;:add&lt;/code&gt; keyword in the &lt;code&gt;Compiler&lt;/code&gt; class, and include a new file to
hold our arithmetic keywords so we don't keep messing up &lt;code&gt;compiler.rb&lt;/code&gt; (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/dc2bbd8&quot;&gt;dc2bbd8&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;diff&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;git&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;mo&quot;&gt;00&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;c857f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;mo&quot;&gt;05&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;abf4&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;100644&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;---&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+++&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compiler&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;rb&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;10&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'transform'&lt;/span&gt;
     &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'set'&lt;/span&gt;
     &lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'print_sexp'&lt;/span&gt;
     
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;require&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;'compile_arithmetic'&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
     &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
       &lt;span class=&quot;nb&quot;&gt;attr_reader&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:global_functions&lt;/span&gt;
       &lt;span class=&quot;nb&quot;&gt;attr_accessor&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:trace&lt;/span&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;21&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Compiler&lt;/span&gt;
                        &lt;span class=&quot;ss&quot;&gt;:do&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:class&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:defun&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:defm&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:if&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:lambda&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;ss&quot;&gt;:assign&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:while&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:let&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:case&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:ternif&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
                        &lt;span class=&quot;ss&quot;&gt;:hash&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:return&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:sexp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:module&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:rescue&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:incr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:block&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;                   &lt;span class=&quot;ss&quot;&gt;:required&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;                   &lt;span class=&quot;ss&quot;&gt;:required&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:add&lt;/span&gt;
                       &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We then add a simple implementation in &lt;code&gt;compile_arithmetic.rb&lt;/code&gt;:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Note that this is flawed in many ways: We don't do any simplification
even when both arguments are constants; we don't do anything to try to
avoid using two registers (if one of the arguments is an integer, we can
evaluate the other expression first, and just &lt;code&gt;addl&lt;/code&gt; the integer to this
result.&lt;/p&gt;

&lt;p&gt;We also for good measure comment out &lt;code&gt;add()&lt;/code&gt; from &lt;code&gt;runtime.c&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;As usual, we're being lazy and the above works, as you can show by compiling
this:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;test: %d\n&quot; (add 5 3))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Next up we need to make use of this in &lt;code&gt;Fixnum&lt;/code&gt;... And we'll find it doesn't
work. It turns out the above version is too naive - our &lt;code&gt;with_register&lt;/code&gt; is a
&quot;fake&quot; start to a register allocator - it only hands out &lt;code&gt;%edx&lt;/code&gt;. That's fine
for now. But what isn't fine is that it doesn't actually allocate it in any
way. You'll find it gets clobbered elsewhere.&lt;/p&gt;

&lt;p&gt;So we'll need to implement very basic register allocation. For now we'll just
add &lt;code&gt;%ecx&lt;/code&gt; to our set of registers to hand out, and actually keep track of them,
and raise an error if we run out (which we will sooner or later - at which
point we'll need to implement more sophisticated register allocation).&lt;/p&gt;

&lt;p&gt;We modify &lt;code&gt;emitter.rb&lt;/code&gt; like this (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/d84e905&quot;&gt;d84e905&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;83&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;6&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;83&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Emitter&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@out&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@basic_main&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;false&lt;/span&gt;
         &lt;span class=&quot;vi&quot;&gt;@section&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Are we in a stabs section?&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:ecx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
    
    &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;333&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;9&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;334&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt; &lt;span class=&quot;err&quot;&gt;@@&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Emitter&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
       &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: This is a hack - for now we just hand out :edx,&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# we don't actually do any allocation&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# FIXME: This is a hack - for now we just hand out :edx or :ecx&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;c1&quot;&gt;# and we don't handle spills.&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;Set&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;new&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;shift&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;raise&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;Register allocation FAILED&quot;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@allocated_registers&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;delete&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt;    &lt;span class=&quot;vi&quot;&gt;@free_registers&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;free&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Basically we've changed from just blindly handing out %edx for code that needs
a spare register, to handing out one of %edx or %ecx depending on which one
is already in use. But if we try to allocate more than two, we're screwed. The
reason I haven't added more registers is because I've not wanted to try to figure
out to what extent they're &quot;safe&quot;. E.g. we use &lt;code&gt;%eax&lt;/code&gt; as our default scratch
register all over the place.&lt;/p&gt;

&lt;p&gt;The normal way of handle running out of register is &quot;register spilling&quot;. That is,
we need to &quot;spill&quot; the registers into variables (this is reasonable if we've used
the registers to cache variables), or push them onto the stack. The latter adds
complexities in that it means we need to ensure we keep track of it when handling
offsets to the stack pointer.&lt;/p&gt;

&lt;p&gt;For now this will do.&lt;/p&gt;

&lt;p&gt;If you try to compile this, you should find it works:&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;
    
    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%d\n&quot; (callm a __get_raw))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;(This of course reveals that we now really should have some IO functions that can
handle other types - so that will be one of the things to handle in one of the
upcoming parts).&lt;/p&gt;

&lt;h3&gt;Subtracting 'sub' from the runtime.&lt;/h3&gt;

&lt;p&gt;So lets do the same thing for sub. I won't go over every detail as it's pretty
much identical to add. The meat is in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/0c6de44&quot;&gt;0c6de44&lt;/a&gt;. Let's test it.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
    &lt;span class=&quot;n&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;7&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;
    
    &lt;span class=&quot;sx&quot;&gt;%s(printf &quot;%d\n&quot; (callm a __get_raw))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;Compiling this gives &lt;code&gt;-5&lt;/code&gt;. What gives?&lt;/p&gt;

&lt;p&gt;Well, the evaluation order monster reared its head. We didn't spot this for &lt;code&gt;compile_add&lt;/code&gt;
since addition is commutative. So lets look at &lt;code&gt;compile_sub&lt;/code&gt; and figure out a fix we can
hopefully also apply to &lt;code&gt;compile_add&lt;/code&gt; (this might sound unnecessary, but consider that
expected evaluation order matters a great deal in a language with side effects, and few
languages have more potential side effects than one in which you can, if you please,
redefine even basic arithmetic operators, or modify classes as they are being defined...)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;We evaluate the left hand, then save it to a register, and we evaluate the right hand.
Then we subtract the left hand from the right, and that's obviously wrong...&lt;/p&gt;

&lt;p&gt;But if we switch the order, we leave the result in another register than our &quot;result&quot;
register &lt;code&gt;%eax&lt;/code&gt;, and end up having to move it. We can fix that by evaluating the right
side before the left, but that's the wrong evaluation order. We can try to save the
result from the left hand evaluation in &lt;code&gt;%eax&lt;/code&gt; and save the result of the right hand
in &lt;code&gt;%edx&lt;/code&gt;, which would solve the problem if it wasn't for the fact that we likely will
clobber &lt;code&gt;%eax&lt;/code&gt; when evaluating the left hand side.&lt;/p&gt;

&lt;p&gt;What we're seeing here is that choices made for simplicity early on are starting to
really affect the code-generation. Here are two possible alternatives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Not treat &lt;code&gt;%eax&lt;/code&gt; as a scratch register and allow allocating it. This is still
problematic as it &lt;em&gt;will&lt;/em&gt; get clobbered by a lot of calls we might want to make to
external code. It may still be the best choice in some cases.&lt;/li&gt;
&lt;li&gt;Allow returning results in something other than &lt;code&gt;%eax&lt;/code&gt;. This is a much more viable
choice for many situations. If we can return &lt;code&gt;reg&lt;/code&gt; from &lt;code&gt;compile_sub&lt;/code&gt;, we push the
problem up one level, and its quite possible that the next step up can make use of
&lt;code&gt;%edx&lt;/code&gt; directly. We may want to go further and not restrict it to variables, as that
would allow us to get rid of many instances of that awful &lt;code&gt;call *%eax&lt;/code&gt; thing that we
currently do for calls.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;It may be time to look into this in one of the forthcoming parts - as much as a focus of
this series has been about being &quot;lazy&quot; and deferring changes like these, we're now at a point
where not being able to do the above actually makes the code more convoluted.&lt;/p&gt;

&lt;p&gt;For this part, lets just bite the bullet and fix the order and do a &lt;code&gt;movl&lt;/code&gt; at the end for
&lt;code&gt;compile_sub&lt;/code&gt; (and this allows us to leave &lt;code&gt;#compile_add&lt;/code&gt; untouched, since the evaluation
order of the operands to the Ruby &lt;code&gt;+&lt;/code&gt; operator are left intact):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;This works, but is not very &lt;a href=&quot;http://en.wikipedia.org/wiki/Don't_repeat_yourself&quot;&gt;DRY&lt;/a&gt;, when
compared with &lt;code&gt;compile_add&lt;/code&gt;, so lets add a helper, since we'll keep relying on this same
pattern for the remaining bits and
pieces (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/a23f0d0&quot;&gt;a23f0d0&lt;/a&gt;):&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
     &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;yield&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_add&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compile_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;addl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_sub&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;compile_2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;subl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;  
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Div and mul&lt;/h3&gt;

&lt;p&gt;We'll mostly ignore &lt;code&gt;mul&lt;/code&gt;, since it's pretty much the same as &lt;code&gt;add&lt;/code&gt; except using the &lt;code&gt;imull&lt;/code&gt;
instruction. See &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/5036b94&quot;&gt;5036b94&lt;/a&gt; for the details.&lt;/p&gt;

&lt;p&gt;Div, however, looks curious, when we disassemble the code generated by gcc for &lt;code&gt;runtime.c&lt;/code&gt;.
With the normal prolog and epilog stripped out from the &lt;code&gt;div&lt;/code&gt; function:&lt;/p&gt;

&lt;pre class=&quot;asm codehilite&quot;&gt;&lt;code&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;number&quot;&gt;-8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;number&quot;&gt;-8&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;movl&lt;/span&gt;    &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%eax&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;sarl&lt;/span&gt;    &lt;span class=&quot;value&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;number&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;comma&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;register&quot;&gt;%edx&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;idivl&lt;/span&gt;   &lt;span class=&quot;number&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;register&quot;&gt;%ebp&lt;/span&gt;&lt;span class=&quot;paren&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;leave&lt;/span&gt;
        &lt;span class=&quot;operator&quot;&gt;ret&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;What is going on here? For starters, it doesn't look very optimized. &lt;code&gt;8(%ebp)&lt;/code&gt; and &lt;code&gt;12(%ebp)&lt;/code&gt; are
the operands passed in to the function. The moves back and worth between &lt;code&gt;%eax&lt;/code&gt;, &lt;code&gt;-8(%ebp)&lt;/code&gt; and
&lt;code&gt;%edx&lt;/code&gt; looks fairly wasteful.&lt;/p&gt;

&lt;p&gt;As it turns out, &lt;code&gt;idivl&lt;/code&gt; performs signed division of a double-word (64 bit on i386) combination of
&lt;code&gt;%edx&lt;/code&gt; and &lt;code&gt;%eax&lt;/code&gt; registers by a third register or a memory location. The &lt;code&gt;sarl&lt;/code&gt; instruction does
an Arithmethic Shift Right on a Long.&lt;/p&gt;

&lt;p&gt;For those who are still not up on assembler, consider an &quot;arithmetic shift&quot; effectively moving the
bits of the binary representation of the value one step in the specified direction. The prefix
&quot;arithmetic&quot; is usually used on assembler instructions to indicate that the shift copies in the
furthermost bit in the &quot;empty&quot; slots. So if you shift one bit right with an arithmetic shift right,
it is equivalent to dividing by two regardless whether or not the value is negative or positive,
as the left-most (furthermost for a shift right) bit is the sign bit.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;http://programmedlessons.org/AssemblyTutorial/Chapter-14/ass14_13.html&quot;&gt;Here is a page that illustrates it with a little graphic&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So what is happening here is that it is filling all of &lt;code&gt;%edx&lt;/code&gt; by the sign bit from &lt;code&gt;%eax&lt;/code&gt; in order
to handle negative values correctly.&lt;/p&gt;

&lt;p&gt;Lets take a stab at implementing that. I end up with this horrible monstrosity, which is another
reason to take another look at the code generation shortly (in &lt;a href=&quot;https://github.com/vidarh/writing-a-compiler-in-ruby/commit/95d642e&quot;&gt;95d642e&lt;/a&gt;)&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
      &lt;span class=&quot;k&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;compile_div&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# FIXME: We really want to be able to request&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# %edx specifically here, as we need it for idivl.&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Instead we work around that below if we for some&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# reason don't get %edx.&lt;/span&gt;
        &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
          &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;left&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;So far, so good. We've just evaluated the left hand, and moved the result out of the way.
Then we evaluate the right hand.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;save_result&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;compile_eval_arg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;scope&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;right&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;p&gt;And then the ugly stuff starts. Depending on what registers we got allocated, we spit out
variout variations up to and including temporarily pushing &lt;code&gt;%edx&lt;/code&gt; onto the stack, since we &lt;em&gt;need&lt;/em&gt;
to have &lt;code&gt;%edx&lt;/code&gt; free. This is a mess. One way to make it simpler would be to be able to request
two registers, of which one should be &lt;code&gt;%edx&lt;/code&gt; and the other doesn't matter. Then we could be
assured a cleaner way of setting this up. So another task for when we clean up the code generator
shortly.&lt;/p&gt;

&lt;pre class=&quot;ruby codehilite&quot;&gt;&lt;code&gt;
          &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;with_register&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;|&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;divby&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
              &lt;span class=&quot;n&quot;&gt;divby&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;r2&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
                &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kp&quot;&gt;true&lt;/span&gt;
                &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pushl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;reg&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
              &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;movl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:eax&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sarl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;31&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;idivl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;divby&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    
            &lt;span class=&quot;c1&quot;&gt;# NOTE: This clobber the remainder made available by idivl,&lt;/span&gt;
            &lt;span class=&quot;c1&quot;&gt;# which we'll likely want to be able to save in the future&lt;/span&gt;
            &lt;span class=&quot;vi&quot;&gt;@e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;popl&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:edx&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;save&lt;/span&gt;
          &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;ss&quot;&gt;:subexpr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;end&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;


&lt;h3&gt;Next time&lt;/h3&gt;

&lt;p&gt;It is finally time for the rest of the operators (for now), and wiping out &lt;code&gt;runtime.c&lt;/code&gt;!&lt;/p&gt;
</description>
      <category>compiler-in-Ruby-bottom-up</category>
      <category>compiler</category>
      <category>ruby</category>
      <category>operators</category>
      <pubDate>Mon, 04 Nov 2013 22:00:00 +0000</pubDate>
      <dc:date>2013-11-04T22:00:00+00:00</dc:date>
    </item>
    <dc:date>2013-11-04T22:00:00+00:00</dc:date>
  </channel>
</rss>