Jekyll2020-03-02T22:51:53+00:00http://machinamentum.github.io/feed.xmlmachinamentum’s word stuffJosh HuelsmanJiyu Update - March 20202020-03-02T00:00:00+00:002020-03-02T00:00:00+00:00http://machinamentum.github.io/Jiyu-Update-March-2020<p>February has been a bit of a slow month, but we’ve managed to add a few interesting features.</p>
<ul>
<li>Added support for default parameters:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="kd">func</span> <span class="nf">test</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="n">int32</span> <span class="o">=</span> <span class="mi">10</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="n">float</span> <span class="o">=</span> <span class="mi">1</span><span class="p">,</span> <span class="n">c</span> <span class="o">=</span> <span class="s">"hello"</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"a: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">a</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"b: %f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"c: %.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">// We don't currently error on the case that two or more functions</span>
<span class="c1">// cause an ambigous overload situation. Currently, the behavior</span>
<span class="c1">// is that the functions with fewer needed default params is prefered.</span>
<span class="c1">// This means you cannot call the above function via test(2, 3), or test(1), as</span>
<span class="c1">// the function below will be chosen instead since it requires less parameters</span>
<span class="c1">// to be filled in.</span>
<span class="kd">func</span> <span class="nf">test</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="n">int32</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="n">float</span> <span class="o">=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Dang</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">test</span><span class="p">();</span>
<span class="nf">test</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="nf">test</span><span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="s">"test"</span><span class="p">);</span>
<span class="c1">// Will print "Dang"</span>
<span class="nf">test</span><span class="p">(</span><span class="mi">3</span><span class="p">,</span> <span class="mi">5</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Added support for binary literals, starting with the prefix <code class="language-plaintext highlighter-rouge">0b</code> or <code class="language-plaintext highlighter-rouge">0B</code>.</li>
<li>Added support for switch-case control flow:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cp">#import "LibC";</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">enum</span> <span class="kt">Test</span> <span class="p">{</span>
<span class="kt">A</span><span class="p">;</span>
<span class="kt">B</span><span class="p">;</span>
<span class="kt">C</span><span class="p">;</span>
<span class="kt">D</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">i</span> <span class="o">=</span> <span class="kt">Test</span><span class="o">.</span><span class="kt">D</span><span class="p">;</span>
<span class="k">switch</span> <span class="n">i</span> <span class="p">{</span>
<span class="k">case</span> <span class="o">.</span><span class="kt">A</span><span class="p">:</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">".A</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">case</span> <span class="o">.</span><span class="kt">B</span><span class="p">:</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">".B</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">case</span> <span class="o">.</span><span class="kt">C</span><span class="p">,</span> <span class="o">.</span><span class="kt">D</span><span class="p">:</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">".C or .D</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">Y</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">x</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="c1">// Currently only integer and enum (integer derived) types are support.</span>
<span class="k">switch</span> <span class="n">x</span> <span class="p">{</span>
<span class="c1">// Currently only expressions that resolve to integer literals are supported.</span>
<span class="k">case</span> <span class="mi">1</span><span class="p">:</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"1</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="c1">// Multiple case conditions can be declared per case-block.</span>
<span class="k">case</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">:</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"2</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="k">case</span> <span class="kt">Y</span><span class="p">:</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Y</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Done</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Added support for overloading the array index operator <code class="language-plaintext highlighter-rouge">[]</code>, and the lvalue-assignment array index operator <code class="language-plaintext highlighter-rouge">[]=</code>:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">operator</span><span class="p">[]</span> <span class="o"><</span><span class="kt">T</span><span class="p">,</span> <span class="kt">R</span><span class="o">></span><span class="p">(</span><span class="nv">arr</span><span class="p">:</span> <span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">index</span><span class="p">:</span> <span class="kt">R</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">index</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">&&</span> <span class="nf">cast</span><span class="p">(</span><span class="n">int64</span><span class="p">)</span> <span class="n">index</span> <span class="o"><</span> <span class="n">arr</span><span class="o">.</span><span class="n">count</span><span class="p">,</span> <span class="s">"Array index out of range!"</span><span class="p">);</span>
<span class="k">return</span> <span class="n">arr</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="n">index</span><span class="p">];</span>
<span class="p">}</span>
<span class="k">operator</span><span class="p">[]</span><span class="o">=</span> <span class="o"><</span><span class="kt">T</span><span class="p">,</span> <span class="kt">R</span><span class="o">></span><span class="p">(</span><span class="nv">arr</span><span class="p">:</span> <span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">index</span><span class="p">:</span> <span class="kt">R</span><span class="p">,</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">T</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">index</span> <span class="o">>=</span> <span class="mi">0</span> <span class="o">&&</span> <span class="nf">cast</span><span class="p">(</span><span class="n">int64</span><span class="p">)</span> <span class="n">index</span> <span class="o"><</span> <span class="n">arr</span><span class="o">.</span><span class="n">count</span><span class="p">,</span> <span class="s">"Array index out of range!"</span><span class="p">);</span>
<span class="n">arr</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="n">index</span><span class="p">]</span> <span class="o">=</span> <span class="n">value</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Added support for template structs:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="kd">struct</span> <span class="kt">Poly</span><span class="o"><</span><span class="kt">T</span><span class="o">></span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">a</span><span class="p">:</span> <span class="kt">T</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">do_thing</span><span class="p">(</span><span class="nv">this</span><span class="p">:</span> <span class="o">*</span><span class="kt">Poly</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">T</span> <span class="o">==</span> <span class="n">int</span><span class="p">)</span> <span class="nf">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this</span><span class="o">.</span><span class="n">a</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="kt">T</span> <span class="o">==</span> <span class="n">float</span><span class="p">)</span> <span class="nf">printf</span><span class="p">(</span><span class="s">"%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this</span><span class="o">.</span><span class="n">a</span><span class="p">);</span>
<span class="c1">// Unfortunately, we cannot straight up do this because this is invalid when T == int or T == float</span>
<span class="c1">// if (T == string)printf("%.*s\n", this.a.length, this.a.data);</span>
<span class="c1">// But if we added another static-if construct like `when` in Odin then</span>
<span class="cm">/*
when (T == string) printf("%.*s\n", this.a.length, this.a.data);
*/</span>
<span class="c1">// would work. I do not want to make #if this generous as #if operates directly on</span>
<span class="c1">// the scope it is declared in, `when` on the other hand would work exactly like a</span>
<span class="c1">// a regular `if` except the body is only evaluated when the condition is a literal</span>
<span class="c1">// `true` (or folds to).</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">a</span><span class="p">:</span> <span class="kt">Poly</span><span class="o"><</span><span class="n">int</span><span class="o">></span><span class="p">;</span>
<span class="n">a</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="n">a</span><span class="o">.</span><span class="nf">do_thing</span><span class="p">();</span>
<span class="k">var</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">Poly</span><span class="o"><</span><span class="n">float</span><span class="o">></span><span class="p">;</span>
<span class="n">b</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="mf">1345.234</span><span class="p">;</span>
<span class="n">b</span><span class="o">.</span><span class="nf">do_thing</span><span class="p">();</span>
<span class="k">var</span> <span class="nv">c</span><span class="p">:</span> <span class="kt">Poly</span><span class="o"><</span><span class="n">string</span><span class="o">></span><span class="p">;</span>
<span class="n">c</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="s">"Hello, Pilot!"</span><span class="p">;</span>
<span class="n">c</span><span class="o">.</span><span class="nf">do_thing</span><span class="p">();</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">a</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">c</span><span class="o">.</span><span class="n">a</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="c1">// We currently do not have a way to parse TypeName<Typearg, Typearg2, etc></span>
<span class="c1">// in regular expressions, so currently one cannot use templates in first-class</span>
<span class="c1">// uses unless one uses a typealias (since the right hand side of a type alias is</span>
<span class="c1">// always a type instantiation).</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Added an intrinsic function for inserting a debugging breakpoint in code <code class="language-plaintext highlighter-rouge">__builtin_debugtrap()</code>.</li>
<li><a href="https://github.com/castano">castano</a> added support for filling function types in polymorphic parameters:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "Basic";</span>
<span class="cp">#import "LibC";</span>
<span class="kd">func</span> <span class="n">test</span><span class="o"><</span><span class="kt">T</span><span class="o">></span> <span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">comp</span><span class="p">:</span> <span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="n">int</span><span class="p">)</span> <span class="o">-></span> <span class="n">int</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">compare</span><span class="p">(</span><span class="n">a</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">compare</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="n">int</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="n">int</span><span class="p">)</span> <span class="o">-></span> <span class="n">int</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">a</span> <span class="o">-</span> <span class="n">b</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="n">bar</span><span class="o"><</span><span class="kt">T</span><span class="o">></span> <span class="p">(</span><span class="nv">foo</span><span class="p">:</span> <span class="p">()</span> <span class="o">-></span> <span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">foo</span><span class="p">();</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">zero</span> <span class="p">()</span> <span class="o">-></span> <span class="n">int</span> <span class="p">{</span>
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span> <span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">i</span> <span class="o">=</span> <span class="nf">bar</span><span class="p">(</span><span class="n">zero</span><span class="p">);</span>
<span class="k">var</span> <span class="nv">j</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">result</span> <span class="o">=</span> <span class="nf">test</span><span class="p">(</span><span class="n">i</span><span class="p">,</span> <span class="n">j</span><span class="p">,</span> <span class="n">compare</span><span class="p">);</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">result</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"result = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">result</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li><a href="https://github.com/castano">castano</a> added support for declaring float literals in scientific notation.</li>
<li>Added support for anonymous unions and anonymous structs:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="kd">struct</span> <span class="kt">Test</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">d</span><span class="p">:</span> <span class="n">float</span><span class="p">;</span>
<span class="n">union</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">a</span><span class="p">:</span> <span class="n">int</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">b</span><span class="p">:</span> <span class="n">int</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">c</span><span class="p">:</span> <span class="n">int</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">t</span><span class="p">:</span> <span class="kt">Test</span><span class="p">;</span>
<span class="n">t</span><span class="o">.</span><span class="n">a</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="n">t</span><span class="o">.</span><span class="n">c</span> <span class="o">=</span> <span class="mi">20</span><span class="p">;</span>
<span class="n">t</span><span class="o">.</span><span class="n">d</span> <span class="o">=</span> <span class="mf">15.5</span><span class="p">;</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"t.d: %f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">d</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"t.a: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">a</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"t.b: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">b</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"t.c: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">c</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Upgraded to LLVM 9. This change has been made primarily to pull in newer features from libclang inorder to properly detect and import anonymous unions/structs.</li>
</ul>
<p>Additional changes include various fixes.</p>
<h2 id="projects">Projects</h2>
<p>One of the main reasons I am building this language is to have fun programming in the language myself. In early February, I had decided to start a new project that could be built within a reasonably short amount of time, but still do something that is interesting and relatively nontrivial. I chose to build an Atari 2600 emulator since I have had previous experience building this type of emulator, and it fits within this criteria: the 6507/6502 has a relatively small instruction set and is well documented, the 2600 has a fairly small number of hardware interface registers, and thus has a small surface area to implement for each of the onboard chips, and the hardware’s behavior is fairly simple. That being said, the hardware does have a large number of minor quirks, but if you are not aimaing for 100% accuracy, then a mostly naive implementation of the hardware from the perspective of the Stella programmer’s manual is enough to get a good number of games working in a relatively small amount of time.</p>
<p>I am planning to do a separate write up on the project in the near future. The source code can be found <a href="https://github.com/machinamentum/HM2600">here</a>. I’ve uploaded a Windows binary <a href="https://github.com/machinamentum/HM2600/releases/tag/release_1">here</a>.</p>
<div class="embed-container">
<iframe src="https://www.youtube.com/embed/a1_7y4wQZMc" width="700" height="480" frameborder="0" allowfullscreen="">
</iframe>
</div>
<h2 id="conclusion">Conclusion</h2>
<p>I want to again thank the contributors for picking up this project and helping to improve it!</p>
<p>The code for the compiler can be found at: <a href="https://github.com/machinamentum/jiyu">jiyu</a>.
Pull requests, feature requests, and issue reports are all welcome.</p>Josh HuelsmanFebruary has been a bit of a slow month, but we’ve managed to add a few interesting features.Jiyu Update - February 20202020-02-01T00:00:00+00:002020-02-01T00:00:00+00:00http://machinamentum.github.io/Jyu-Update-February-2020<p>Progress has been a bit slow for the last few weeks because I’ve personally lost a large amount of time to playing Stardew Valley, but we’ve managed to still fit in a number of important features for this month’s update.</p>
<ul>
<li>There is now support for harnessing LLVM’s JIT engine in user code</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "Compiler";</span>
<span class="c1">// Since metaprograms are just fully JIT-ed LLVM modules,</span>
<span class="c1">// we have been internally using the JIT-er to lookup the "main" symbol</span>
<span class="c1">// in a program and call that... We no longer do that internally.</span>
<span class="c1">// There is a legacy function in Compiler to mimick the way this worked</span>
<span class="c1">// previously, but now we allow user code to fully leverage this functionality.</span>
<span class="kd">func</span> <span class="kd">@metaprogram</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">options</span><span class="p">:</span> <span class="kt">Build_Options</span><span class="p">;</span>
<span class="n">options</span><span class="o">.</span><span class="n">only_want_obj_file</span> <span class="o">=</span> <span class="kc">true</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">compiler</span> <span class="o">=</span> <span class="nf">create_compiler_instance</span><span class="p">(</span><span class="o">*</span><span class="n">options</span><span class="p">);</span>
<span class="k">if</span> <span class="nf">compiler_load_string</span><span class="p">(</span><span class="n">compiler</span><span class="p">,</span> <span class="kt">CODE_TO_COMPILE</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="k">if</span> <span class="nf">compiler_typecheck_program</span><span class="p">(</span><span class="n">compiler</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="k">if</span> <span class="nf">compiler_generate_llvm_module</span><span class="p">(</span><span class="n">compiler</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="c1">// New function to JIT the entire program.</span>
<span class="k">if</span> <span class="nf">compiler_jit_program</span><span class="p">(</span><span class="n">compiler</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="c1">// Once compiler_jit_program passes, we can now arbitrarily query symbols</span>
<span class="c1">// and call into them.</span>
<span class="k">var</span> <span class="nv">do_a_thing</span> <span class="o">=</span> <span class="nf">cast</span><span class="p">(()</span> <span class="o">-></span> <span class="n">void</span><span class="p">)</span> <span class="nf">compiler_jit_lookup_symbol</span><span class="p">(</span><span class="n">compiler</span><span class="p">,</span> <span class="s">"do_a_thing"</span><span class="p">);</span>
<span class="nf">do_a_thing</span><span class="p">();</span>
<span class="k">var</span> <span class="nv">do_a_thing2</span> <span class="o">=</span> <span class="nf">cast</span><span class="p">((</span><span class="nv">p</span><span class="p">:</span> <span class="n">string</span><span class="p">)</span> <span class="o">-></span> <span class="n">void</span><span class="p">)</span> <span class="nf">compiler_jit_lookup_symbol</span><span class="p">(</span><span class="n">compiler</span><span class="p">,</span> <span class="s">"do_a_thing2"</span><span class="p">);</span>
<span class="nf">do_a_thing2</span><span class="p">(</span><span class="s">"Howdy :)"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">CODE_TO_COMPILE</span> <span class="o">=</span>
<span class="s">"""
#import "</span><span class="kt">LibC</span><span class="s">";
// We are using the @export tag here for the sake of demonstration, otherwise
// we would need to lookup the proper jiyu-mangled names.
func @export("</span><span class="n">do_a_thing</span><span class="s">") do_a_thing() {
printf("</span><span class="kt">Hello</span><span class="p">,</span> <span class="kt">Sailor</span><span class="p">\</span><span class="n">n</span><span class="s">");
}
func @export("</span><span class="n">do_a_thing2</span><span class="s">") do_a_thing2(str: string) {
printf("</span><span class="kt">Hello</span><span class="p">,</span> <span class="kt">Pilot</span><span class="o">!</span> <span class="o">%.*</span><span class="n">s</span><span class="p">\</span><span class="n">n</span><span class="s">", str.length, str.data);
}
"""</span><span class="p">;</span>
</code></pre></div></div>
<p>Additionally, we now provide a library version of the compiler that is built alongside the compiler driver program. The API is exactly the same whether the user code is running as a metaprogram or as a compiled binary. This allows users to effectively implement custom driver frontends that support arbitrary operations that the official driver does not. This also allows compiled user code to JIT-compile Jiyu code at runtime, enabling games to embed Jiyu as a robust scripting system, or enabling IDEs to embed Jiyu in environments where running external executables and toolchains is not allowed.</p>
<ul>
<li>Support for operator overloading has been added. Currently, only <code class="language-plaintext highlighter-rouge">+</code>, <code class="language-plaintext highlighter-rouge">-</code>, <code class="language-plaintext highlighter-rouge">*</code>, and <code class="language-plaintext highlighter-rouge">/</code> can be overloaded, but support for more operators will be added in the future.</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="kd">struct</span> <span class="kt">Vector3</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">x</span><span class="p">:</span> <span class="n">float</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">y</span><span class="p">:</span> <span class="n">float</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">z</span><span class="p">:</span> <span class="n">float</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">make</span><span class="p">(</span><span class="nv">x</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">y</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">z</span><span class="p">:</span> <span class="n">float</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Vector3</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">v</span><span class="p">:</span> <span class="kt">Vector3</span><span class="p">;</span>
<span class="n">v</span><span class="o">.</span><span class="n">x</span> <span class="o">=</span> <span class="n">x</span><span class="p">;</span>
<span class="n">v</span><span class="o">.</span><span class="n">y</span> <span class="o">=</span> <span class="n">y</span><span class="p">;</span>
<span class="n">v</span><span class="o">.</span><span class="n">z</span> <span class="o">=</span> <span class="n">z</span><span class="p">;</span>
<span class="k">return</span> <span class="n">v</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">operator</span><span class="o">+</span><span class="p">(</span><span class="nv">b</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">str</span><span class="p">:</span> <span class="n">string</span><span class="p">)</span> <span class="o">-></span> <span class="n">float</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">b</span> <span class="o">+</span> <span class="nf">cast</span><span class="p">(</span><span class="n">float</span><span class="p">)</span> <span class="n">str</span><span class="o">.</span><span class="n">length</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">operator</span><span class="o">+</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="kt">Vector3</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">Vector3</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Vector3</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Vector3</span><span class="o">.</span><span class="nf">make</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">x</span><span class="o">+</span><span class="n">b</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="o">.</span><span class="n">y</span><span class="o">+</span><span class="n">b</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">a</span><span class="o">.</span><span class="n">z</span><span class="o">+</span><span class="n">b</span><span class="o">.</span><span class="n">z</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">operator</span><span class="o">-</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="kt">Vector3</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="kt">Vector3</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Vector3</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Vector3</span><span class="o">.</span><span class="nf">make</span><span class="p">(</span><span class="n">a</span><span class="o">.</span><span class="n">x</span><span class="o">-</span><span class="n">b</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">a</span><span class="o">.</span><span class="n">y</span><span class="o">-</span><span class="n">b</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">a</span><span class="o">.</span><span class="n">z</span><span class="o">-</span><span class="n">b</span><span class="o">.</span><span class="n">z</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">print_vector</span><span class="p">(</span><span class="nv">v</span><span class="p">:</span> <span class="kt">Vector3</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"vector3: %f, %f, %f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">v</span><span class="o">.</span><span class="n">x</span><span class="p">,</span> <span class="n">v</span><span class="o">.</span><span class="n">y</span><span class="p">,</span> <span class="n">v</span><span class="o">.</span><span class="n">z</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="kd">@metaprogram</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">a</span> <span class="o">=</span> <span class="kt">Vector3</span><span class="o">.</span><span class="nf">make</span><span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">,</span> <span class="mi">3</span><span class="p">);</span>
<span class="k">var</span> <span class="nv">b</span> <span class="o">=</span> <span class="kt">Vector3</span><span class="o">.</span><span class="nf">make</span><span class="p">(</span><span class="mi">4</span><span class="p">,</span> <span class="mi">5</span><span class="p">,</span> <span class="mi">6</span><span class="p">);</span>
<span class="k">var</span> <span class="nv">c</span> <span class="o">=</span> <span class="n">a</span> <span class="o">+</span> <span class="n">b</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">d</span> <span class="o">=</span> <span class="n">b</span> <span class="o">-</span> <span class="n">a</span><span class="p">;</span>
<span class="nf">print_vector</span><span class="p">(</span><span class="n">a</span><span class="p">);</span>
<span class="nf">print_vector</span><span class="p">(</span><span class="n">b</span><span class="p">);</span>
<span class="nf">print_vector</span><span class="p">(</span><span class="n">c</span><span class="p">);</span>
<span class="nf">print_vector</span><span class="p">(</span><span class="n">d</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"1.0 + </span><span class="se">\"</span><span class="s">Hello</span><span class="se">\"</span><span class="s">: %f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="mf">1.0</span> <span class="o">+</span> <span class="s">"Hello"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>
<p><a href="https://github.com/castano">castano</a> has implemented support for <code class="language-plaintext highlighter-rouge">typeof()</code> operator that resolves to the type of an input declaration.</p>
</li>
<li>
<p><a href="https://github.com/castano">castano</a> has implemented support for enums:</p>
</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="cp">#import "Basic";</span>
<span class="kd">enum</span> <span class="kt">Day</span> <span class="p">:</span> <span class="n">uint</span> <span class="p">{</span>
<span class="kt">Monday</span><span class="p">;</span>
<span class="kt">Tuesday</span> <span class="o">=</span> <span class="kt">Monday</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="kt">Wednesday</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="kt">Thursday</span><span class="p">;</span>
<span class="kt">Friday</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">+</span> <span class="kt">Thursday</span><span class="p">;</span>
<span class="kt">Saturday</span><span class="p">;</span>
<span class="kt">Sunday</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">enum</span> <span class="kt">WeekendDay</span> <span class="p">{</span>
<span class="kt">Saturday</span> <span class="o">=</span> <span class="nf">cast</span><span class="p">(</span><span class="kt">WeekendDay</span><span class="p">)</span><span class="kt">Day</span><span class="o">.</span><span class="kt">Saturday</span><span class="p">;</span> <span class="c1">// This should require a cast. Do not allow implicit cast from one enum to another.</span>
<span class="kt">Sunday</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">enum</span> <span class="kt">Bool</span> <span class="p">:</span> <span class="n">uint8</span> <span class="p">{</span> <span class="kt">False</span><span class="p">;</span> <span class="kt">True</span><span class="p">;</span> <span class="p">}</span>
<span class="kd">typealias</span> <span class="kt">DAY</span> <span class="o">=</span> <span class="kt">Day</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">another_day</span> <span class="p">:</span> <span class="kt">DAY</span> <span class="o">=</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Monday</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">monday</span> <span class="o">=</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Monday</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">tuesday</span> <span class="p">:</span> <span class="kt">Day</span> <span class="o">=</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Tuesday</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">sunday</span> <span class="p">:</span> <span class="kt">Day</span> <span class="o">=</span> <span class="nf">cast</span><span class="p">(</span><span class="kt">Day</span><span class="p">)</span><span class="kt">WeekendDay</span><span class="o">.</span><span class="kt">Sunday</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">my_day</span> <span class="p">:</span> <span class="kt">Day</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">test</span><span class="p">(</span><span class="nv">day</span> <span class="p">:</span> <span class="kt">Day</span><span class="p">)</span> <span class="o">-></span> <span class="n">int</span> <span class="p">{</span>
<span class="k">return</span> <span class="nf">cast</span><span class="p">(</span><span class="n">int</span><span class="p">)</span><span class="n">day</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="p">{</span>
<span class="k">var</span> <span class="nv">day</span> <span class="p">:</span> <span class="kt">Day</span><span class="p">;</span>
<span class="k">let</span> <span class="nv">Monday</span> <span class="o">=</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Monday</span><span class="p">;</span>
<span class="k">let</span> <span class="nv">Tuesday</span> <span class="o">=</span> <span class="kt">Monday</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="nf">assert</span><span class="p">(</span><span class="nf">typeof</span><span class="p">(</span><span class="kt">Monday</span><span class="p">)</span> <span class="o">==</span> <span class="kt">Day</span><span class="p">);</span>
<span class="k">let</span> <span class="nv">MONDAY</span> <span class="o">=</span> <span class="nf">cast</span><span class="p">(</span><span class="n">int</span><span class="p">)</span><span class="kt">Day</span><span class="o">.</span><span class="kt">Monday</span><span class="p">;</span> <span class="c1">// Type of MONDAY is int</span>
<span class="nf">assert</span><span class="p">(</span><span class="nf">typeof</span><span class="p">(</span><span class="kt">MONDAY</span><span class="p">)</span> <span class="o">==</span> <span class="n">int</span><span class="p">);</span>
<span class="p">}</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Monday = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Monday</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Tuesday = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Tuesday</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Wednesday = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Wednesday</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Thursday = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Thursday</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Friday = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Friday</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Saturday = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Saturday</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Sunday = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Day</span><span class="o">.</span><span class="kt">Sunday</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"test(Day.Monday) = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="nf">test</span><span class="p">(</span><span class="kt">Day</span><span class="o">.</span><span class="kt">Monday</span><span class="p">));</span>
<span class="c1">// Implicit calls from integer to enum:</span>
<span class="c1">// Currently these are only allowed when the expression is a mutable literal.</span>
<span class="p">{</span>
<span class="k">var</span> <span class="nv">day</span> <span class="p">:</span> <span class="kt">Day</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"test(0) = %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="nf">test</span><span class="p">(</span><span class="mi">0</span><span class="p">));</span>
<span class="p">}</span>
<span class="c1">//printf("Whatever = %d\n", Day.Whatever); // This should trigger an error.</span>
<span class="p">{</span>
<span class="k">var</span> <span class="nv">day</span> <span class="p">:</span> <span class="kt">Day</span> <span class="o">=</span> <span class="o">.</span><span class="kt">Monday</span><span class="p">;</span>
<span class="nf">test</span><span class="p">(</span><span class="o">.</span><span class="kt">Tuesday</span><span class="p">);</span>
<span class="k">if</span> <span class="n">day</span> <span class="o">==</span> <span class="o">.</span><span class="kt">Wednesday</span> <span class="p">{</span>
<span class="n">day</span> <span class="o">=</span> <span class="o">.</span><span class="kt">Sunday</span><span class="p">;</span>
<span class="p">}</span>
<span class="k">if</span> <span class="o">.</span><span class="kt">Wednesday</span> <span class="o">></span> <span class="n">day</span> <span class="p">{</span>
<span class="c1">// test(1 + .Tuesday); // This produces an error, as expected. </span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Additionally, support for enum bit-flags is also available:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="cp">#import "Basic";</span>
<span class="kd">enum</span> <span class="kd">@flags</span> <span class="kt">Entity_Flags</span> <span class="p">{</span>
<span class="kt">Invisible</span><span class="p">;</span>
<span class="kt">Solid</span><span class="p">;</span>
<span class="kt">Cast_Shadows</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span> <span class="p">()</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="kt">Entity_Flags</span><span class="o">.</span><span class="kt">Invisible</span> <span class="o">|</span> <span class="o">.</span><span class="kt">Solid</span> <span class="o">|</span> <span class="o">.</span><span class="kt">Cast_Shadows</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Tuples are now part of the language:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="kd">func</span> <span class="nf">test</span><span class="p">()</span> <span class="o">-></span> <span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="n">int</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="n">float</span><span class="p">)</span> <span class="p">{</span>
<span class="c1">// arguments in tuple-expressions are automatically inferred</span>
<span class="c1">// according to the fields of the tuple being assigned, returned, or passed to.</span>
<span class="nf">return</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">test3</span><span class="p">()</span> <span class="o">-></span> <span class="p">(</span><span class="nv">c</span><span class="p">:</span> <span class="n">int</span><span class="p">,</span> <span class="nv">d</span><span class="p">:</span> <span class="n">float</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">return</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="mi">2</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">test2</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="n">int</span><span class="p">,</span> <span class="nv">b</span><span class="p">:</span> <span class="n">float</span><span class="p">))</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"T2: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">a</span><span class="o">.</span><span class="n">a</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"T2: %f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">a</span><span class="o">.</span><span class="n">b</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">t</span> <span class="o">=</span> <span class="nf">test</span><span class="p">();</span>
<span class="k">var</span> <span class="nv">t3</span> <span class="o">=</span> <span class="nf">test3</span><span class="p">();</span>
<span class="c1">// t and t3 are the same type as far as the type system is concerned,</span>
<span class="c1">// their tuples will share the same type information in the RTTI system,</span>
<span class="c1">// and internally, they will have the same type table index,</span>
<span class="c1">// however, since the semantic analysis system assigns types in-place,</span>
<span class="c1">// t and t3 have distinct fields.</span>
<span class="c1">// t.c = t3.a; // this fails</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">a</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">b</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t3</span><span class="o">.</span><span class="n">c</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t3</span><span class="o">.</span><span class="n">d</span><span class="p">);</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">t3</span><span class="p">;</span>
<span class="n">t</span> <span class="o">=</span> <span class="p">(</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">a</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">t</span><span class="o">.</span><span class="n">b</span><span class="p">);</span>
<span class="nf">test2</span><span class="p">(</span><span class="n">t</span><span class="p">);</span>
<span class="nf">test2</span><span class="p">((</span><span class="mi">6</span><span class="p">,</span> <span class="mi">9</span><span class="p">));</span>
<span class="k">var</span> <span class="nv">n</span><span class="p">:</span> <span class="n">int</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">m</span><span class="p">:</span> <span class="n">float</span><span class="p">;</span>
<span class="c1">// In the event that a tuple-expression is on the left-hand-side</span>
<span class="c1">// of an assignment, the type of the tuple is directly determined by</span>
<span class="c1">// the types of its arguments, regardless of the type of the tuple</span>
<span class="c1">// on the right-hand-side.</span>
<span class="c1">// Each field of the tuple on the right-hand-side is unpacked into</span>
<span class="c1">// the individual arguments of the tuple-expression on the left-hand-</span>
<span class="c1">// side.</span>
<span class="p">(</span><span class="n">n</span><span class="p">,</span> <span class="n">m</span><span class="p">)</span> <span class="o">=</span> <span class="nf">test</span><span class="p">();</span>
<span class="c1">// Like other types of assignments, you cannot try to use a literal</span>
<span class="c1">// in a tuple expression on the left-hand-side of an assignment.</span>
<span class="c1">// (n, 1) = test(); // does not work.</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"n: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"m: %f</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">m</span><span class="p">);</span>
<span class="c1">// These do not work yet, but are planned to be available eventually.</span>
<span class="cm">/*
var (i, j) = test();
var (i: int, j: float) = test();
*/</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Additional changes include improved support for C interfaces on various platforms, improved support for trivial-constant-folding, and various fixes.</p>
<p>I want to again thank the contributors for picking up this project and helping to improve it!</p>
<p>The code for the compiler can be found at: <a href="https://github.com/machinamentum/jiyu">jiyu</a>.
Pull requests, feature requests, and issue reports are all welcome.</p>Josh HuelsmanProgress has been a bit slow for the last few weeks because I’ve personally lost a large amount of time to playing Stardew Valley, but we’ve managed to still fit in a number of important features for this month’s update.Jiyu Update - January 20202020-01-01T00:00:00+00:002020-01-01T00:00:00+00:00http://machinamentum.github.io/Jyu-Update-January-2020<p>Progress has been going pretty strong this past monthly-ish period.</p>
<ul>
<li>There is now a #clang_import directive. This allows importing declarations from C header files directly into Jiyu scopes. Example:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="cp">#clang_import "#include <stdio.h>";</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Hello, Moonman!</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The string following the directive can contain arbitrary C code. This works for a number of C declaration types, including structs, unions, enums, functions, and typedefs. Do note however, that only importing bindings for declarations is supported, there is no support for compiling C function bodies, and there are no plans for Jiyu to replace a C compiler. I have been using this for awhile on Windows, and have even gotten the <a href="https://twitter.com/machinamentum/status/1211501147808247808">nuklear imgui library working without needing to manually write bindings</a>, but this may not work well on Mac/Linux yet if you need to import system headers.</p>
<ul>
<li>There is now a mechanism to enable member-function-call syntax for arrays. I have documented this in this demo below:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "LibC";</span>
<span class="cp">#import "Array";</span>
<span class="c1">// Array module defines:</span>
<span class="c1">// __array_add<T>(arr: *[..] T, item: T)</span>
<span class="c1">// __array_reset<T>(arr: *[..] T)</span>
<span class="c1">// __array_reserve<T>(arr: *[..] T)</span>
<span class="c1">// __array_resize<T>(array: *[..] T, _amount: int)</span>
<span class="c1">// __array_pop<T>(array: *[..] T) -> T</span>
<span class="c1">// __array_contains<T>(array: *[..] T, item: T) -> bool</span>
<span class="c1">// __array_add_if_unique<T>(array: *[..] T, item: T) -> bool</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// When the compiler sees <array>.func(...), it will attempt to transform this sequence into</span>
<span class="c1">// __array_func(<array>, ...) or __array_func(*<array>, ...).</span>
<span class="k">var</span> <span class="nv">arr</span><span class="p">:</span> <span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="n">int64</span><span class="p">;</span>
<span class="n">arr</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="n">arr</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
<span class="n">arr</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
<span class="n">arr</span><span class="o">.</span><span class="nf">add_if_unique</span><span class="p">(</span><span class="mi">3</span><span class="p">);</span>
<span class="n">arr</span><span class="o">.</span><span class="nf">add_if_unique</span><span class="p">(</span><span class="mi">4</span><span class="p">);</span>
<span class="k">for</span> <span class="n">arr</span> <span class="nf">printf</span><span class="p">(</span><span class="s">"Value: %lld</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">it</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Popped value: %lld</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">arr</span><span class="o">.</span><span class="nf">pop</span><span class="p">());</span>
<span class="k">for</span> <span class="n">arr</span> <span class="nf">printf</span><span class="p">(</span><span class="s">"Remaining Value: %lld</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">it</span><span class="p">);</span>
<span class="n">arr</span><span class="o">.</span><span class="nf">reset</span><span class="p">();</span>
<span class="k">for</span> <span class="n">arr</span> <span class="nf">printf</span><span class="p">(</span><span class="s">"Remaining Value ????: %lld</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">it</span><span class="p">);</span> <span class="c1">// This should not output anything!</span>
<span class="nf">locally_scoped_functions</span><span class="p">();</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">locally_scoped_functions</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Since this special syntax turns into a scope-lookup,</span>
<span class="c1">// we can override the defaults defined in the Array module.</span>
<span class="kd">func</span> <span class="n">__array_add</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="nv">array</span><span class="p">:</span> <span class="o">*</span><span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">item</span><span class="p">:</span> <span class="kt">T</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Hello, Sailor!"</span><span class="p">);</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">arr</span><span class="p">:</span> <span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="n">int64</span><span class="p">;</span>
<span class="n">arr</span><span class="o">.</span><span class="nf">add</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="k">for</span> <span class="n">arr</span> <span class="nf">printf</span><span class="p">(</span><span class="s">"Remaining Value ????: %lld</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">it</span><span class="p">);</span> <span class="c1">// should not print anything!</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>There is now a <code class="language-plaintext highlighter-rouge">-emit-llvm</code> flag to dump generated LLVM IR to a file.</li>
<li>Unions are now available, simply use the <code class="language-plaintext highlighter-rouge">union</code> keyword in place of <code class="language-plaintext highlighter-rouge">struct</code>.</li>
<li><code class="language-plaintext highlighter-rouge">break</code> and <code class="language-plaintext highlighter-rouge">continue</code> now work for while-loops.</li>
<li><code class="language-plaintext highlighter-rouge">os()</code> now checks against LLVM’s support operating system types and the target triple of the compilation. See <a href="https://llvm.org/doxygen/Triple_8cpp_source.html#l00175">Triple::getOSTypeName</a> for a list of valid inputs. The input is case-insensitive.</li>
<li>Raspberry Pi 4 is now officially supported. <a href="https://twitter.com/machinamentum/status/1206056214028787712">Relevant tweet</a>.</li>
<li>Diagnostic-esque information is no longer printed to the terminal by default. There is now a <code class="language-plaintext highlighter-rouge">-v</code> flag to print out this information for debugging. There’s also a <code class="language-plaintext highlighter-rouge">verbose_diagnostics</code> Build_Option available to get this information out of a compilation through a metaprogram.</li>
<li>while-loop conditions now coerce-to-bool.</li>
<li>There are now built-in typealiases to reference the types for <string>.length and <array>.count fields. They are <code class="language-plaintext highlighter-rouge">__builtin_string_length_type</code> and <code class="language-plaintext highlighter-rouge">__builtin_array_count_type</code>.</li>
<li>Global variable structs are now properly default-initialized based on the default initializations of their fields.</li>
<li><a href="https://github.com/castano">castano</a> has added support for referencing let-constants declared within structs.</li>
<li><a href="https://github.com/castano">castano</a> has added a Sublime Text highlighting extension.</li>
<li><a href="https://github.com/castano">castano</a> has added support for multiline string literals similar to how they are implemented in Swift:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code>
<span class="cp">#import "Basic";</span>
<span class="cp">#import "LibC";</span>
<span class="k">let</span> <span class="nv">singleLineString</span> <span class="o">=</span> <span class="s">"These are the same."</span><span class="p">;</span>
<span class="k">let</span> <span class="nv">multilineString</span> <span class="o">=</span> <span class="s">"""
These are the same.
"""</span><span class="p">;</span>
<span class="k">let</span> <span class="nv">multilineString2</span> <span class="o">=</span> <span class="s">"""These are the same."""</span><span class="p">;</span>
<span class="k">let</span> <span class="nv">multilineString3</span> <span class="o">=</span> <span class="s">"""
These are the same.
"""</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="c1">// Multi-line string equivalency.</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">singleLineString</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">singleLineString</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">multilineString</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">multilineString</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">multilineString2</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">multilineString2</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">multilineString3</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">multilineString3</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">singleLineString</span> <span class="o">==</span> <span class="n">multilineString</span><span class="p">);</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">singleLineString</span> <span class="o">==</span> <span class="n">multilineString2</span><span class="p">);</span>
<span class="nf">assert</span><span class="p">(</span><span class="n">singleLineString</span> <span class="o">==</span> <span class="n">multilineString3</span><span class="p">);</span>
<span class="k">let</span> <span class="nv">indentation</span> <span class="o">=</span> <span class="s">"""
This text has indentation.
And that is fine.
"""</span><span class="p">;</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"%.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">indentation</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">indentation</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li>Support for passing and returning structs to/from C has been improved.</li>
<li>There are now <code class="language-plaintext highlighter-rouge">strideof()</code> and <code class="language-plaintext highlighter-rouge">alignof()</code> operators. These return the stride and alignment of any input type. Unlike C, the the size of a struct is the amount of space required to store the struct, the stride is the amount of space needed to store the struct with padding to its alignment.</li>
<li>There is now support for unary <code class="language-plaintext highlighter-rouge">!</code> and unary <code class="language-plaintext highlighter-rouge">~</code>.</li>
<li>There is now support for a rudimentary level of struct inheritance:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code> <span class="kd">func</span> <span class="nf">test_inheritance</span><span class="p">()</span> <span class="p">{</span>
<span class="kd">struct</span> <span class="kt">Node</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">i</span> <span class="o">=</span> <span class="mi">10</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">do_a_thing</span><span class="p">()</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Node do_a_thing()</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">do_a_thing2</span><span class="p">(</span><span class="nv">n</span><span class="p">:</span> <span class="o">*</span><span class="kt">Node</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Node.i: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">i</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">struct</span> <span class="kt">Node_Child</span> <span class="p">:</span> <span class="kt">Node</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">b</span> <span class="o">=</span> <span class="s">"test"</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">do_a_thing3</span><span class="p">(</span><span class="nv">n</span><span class="p">:</span> <span class="o">*</span><span class="kt">Node_Child</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Node_Child.i: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">i</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="s">"Node_Child.b: %.*s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">b</span><span class="o">.</span><span class="n">length</span><span class="p">,</span> <span class="n">n</span><span class="o">.</span><span class="n">b</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">child</span><span class="p">:</span> <span class="kt">Node_Child</span><span class="p">;</span>
<span class="n">child</span><span class="o">.</span><span class="nf">do_a_thing2</span><span class="p">();</span>
<span class="n">child</span><span class="o">.</span><span class="nf">do_a_thing3</span><span class="p">();</span>
<span class="kt">Node_Child</span><span class="o">.</span><span class="nf">do_a_thing</span><span class="p">();</span>
<span class="p">}</span>
</code></pre></div></div>
<p>I want to again thank the contributors for picking up this project and helping to improve it!</p>
<p>The code for the compiler can be found at: <a href="https://github.com/machinamentum/jiyu">jiyu</a>.
Pull requests, feature requests, and issue reports are all welcome.</p>Josh HuelsmanProgress has been going pretty strong this past monthly-ish period.Jiyu Update - November 20192019-11-29T00:00:00+00:002019-11-29T00:00:00+00:00http://machinamentum.github.io/Jiyu-Update-November-2019<p>It has been a awhile seen I’ve written one of these. I had taken some time off from working on the compiler to focus my free time on learning some traditional arts. That being said, there’s a number of changes to talk about so let’s get into it.</p>
<ul>
<li>There is now a psuedo-test-suite program located at <jiyu>/tests.jyu. This automatically compiles the test programs in <jiyu>/tests. This is a way to quickly verify that changes to the compiler don’t break some basic features.</li>
<li>String-literals can be implicitly cast to *uint8 and *int8. This is a convinience for passing string-literals to C functions.</li>
<li>Added compiler_run_metaprogram(). This function allows metaprograms to compile and run other programs at compile-time.</li>
<li>There’s now support for loading libraries that the user has specified with the <em>library</em> keyword into metaprograms. This is a seemless operation, so there is no extra work required of the user. This may not entirely work with user-installed libraries on Linux/Mac at the moment, but this will be improved over time.</li>
<li>The compiler now accepts the “-c” switch to end compilation at generating an object file.</li>
<li>The compiler now accepts the “-o” switch to specify the target file/executable name to output to.</li>
<li>The switch “-triple” is now “-target”.</li>
<li><a href="https://github.com/ahmadrosid">ahmadrosid</a> has added some missing functionality on Linux and the compiler should work on Linux now.</li>
<li>Control-flow statements <em>break</em> and <em>continue</em> are now available and working.</li>
<li>There is now a version of <em>for</em> that gives a pointer to array elements instead of a const-copy of the elements. The syntax is “for * <array_typed_expression> { … }”.</li>
<li><a href="https://github.com/castano/">castano</a> has added an open-half version of <em>for</em>, which excludes the value of the upper-bound expression of the <em>for</em> range. Example: “for 0 ..< 2 { … }”, would be equivalent of “for { int it = 0; it < 2; it += 1) { … }” in C.</li>
<li><em>if</em>-conditions now have coerce-to-bool. Integer, float, and pointer-types are now automatically compared to literal-0, string is automatically compared to empty-string.</li>
<li>There is now syntax for calling member-functions of structs with more ease:</li>
</ul>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">My_Struct</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">i</span><span class="p">:</span> <span class="n">int</span><span class="p">;</span>
<span class="c1">// You can overload between a reference and a pointer.</span>
<span class="kd">func</span> <span class="nf">do_something</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span> <span class="kt">My_Struct</span><span class="p">)</span> <span class="p">{</span> <span class="o">....</span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">do_something</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span> <span class="o">*</span><span class="kt">My_Struct</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">do_something2</span><span class="p">(</span><span class="nv">data</span><span class="p">:</span> <span class="o">*</span><span class="kt">My_Struct</span><span class="p">)</span> <span class="p">{</span> <span class="o">...</span> <span class="p">}</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">my_func</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">data</span><span class="p">:</span> <span class="kt">My_Struct</span><span class="p">;</span>
<span class="n">data</span><span class="o">.</span><span class="nf">do_something</span><span class="p">();</span> <span class="c1">// _data_ is implicitly passed to My_Struct.do_something(data: My_Struct);</span>
<span class="k">var</span> <span class="nv">data_ptr</span> <span class="o">=</span> <span class="o">*</span><span class="n">data</span><span class="p">;</span>
<span class="n">data_ptr</span><span class="o">.</span><span class="nf">do_something</span><span class="p">();</span> <span class="c1">// _data_ptr_ is implicitly passed to My_Struct.do_something(data: *My_Struct);</span>
<span class="n">data</span><span class="o">.</span><span class="nf">do_something2</span><span class="p">();</span> <span class="c1">// A pointer is taken of _data_ and passed to My_Struct.do_something2();</span>
<span class="c1">// You can still call these functions the traditional way, too</span>
<span class="kt">My_Struct</span><span class="o">.</span><span class="nf">do_something</span><span class="p">(</span><span class="n">data</span><span class="p">);</span>
<span class="kt">My_Struct</span><span class="o">.</span><span class="nf">do_something</span><span class="p">(</span><span class="o">*</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<ul>
<li><a href="https://github.com/castano/">castano</a> has added compiler_load_string(), exposing previously internal functionality to directly compile code from strings, in metaprograms.</li>
<li>Cross-compilation support has been improved. I have demonstrated <a href="https://twitter.com/machinamentum/status/1195569426105536512?s=20">running Jiyu code on an iOS device</a>, and <a href="https://twitter.com/machinamentum/status/1193671625771769856?s=20">running Jiyu code bare-metal under Qemu</a>.</li>
</ul>
<p>Additionally, there have been a number of fixes and changes to improve the compiler, by myself and others.</p>
<p>There’s currently work being done to import C-headers directly into Jiyu code without any external tools. I will write another post documenting that once it is working well.</p>
<p>I want to again thank the contributors for picking up this project and helping to improve it!</p>
<p>The code for the compiler can be found at: <a href="https://github.com/machinamentum/jiyu">jiyu</a>.
Pull requests, feature requests, and issue reports are all welcome.</p>Josh HuelsmanIt has been a awhile seen I’ve written one of these. I had taken some time off from working on the compiler to focus my free time on learning some traditional arts. That being said, there’s a number of changes to talk about so let’s get into it.Jiyu Update - August 20192019-08-18T00:00:00+00:002019-08-18T00:00:00+00:00http://machinamentum.github.io/Jiyu-Update-August-2019<p>It has been about a month since I <a href="/Jiyu-A-Programming-Language/">last wrote about my new programming-language project, Jiyu</a>, so I’m going to briefly talk about the changes that have happened since.</p>
<h2 id="libraries">Libraries</h2>
<p>Libraries and macOS frameworks can now be specified using the declarators <code class="language-plaintext highlighter-rouge">library</code> and <code class="language-plaintext highlighter-rouge">framework</code>, respectively.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#if os(Windows) {</span>
<span class="n">library</span> <span class="s">"msvcrt"</span><span class="p">;</span>
<span class="n">library</span> <span class="s">"opengl32"</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#if os(MacOSX) {</span>
<span class="n">library</span> <span class="s">"c"</span><span class="p">;</span>
<span class="n">framework</span> <span class="s">"OpenGL"</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>These inform the built-in linker command on what libraries to link, and will eventually inform the LLVM JIT on what libraries to load.</p>
<h2 id="modules">Modules</h2>
<p>The compiler now looks for module-libraries in the <code class="language-plaintext highlighter-rouge">jiyu/modules</code> folder. The folder is located by searching up the directory tree from the executable’s path for a folder named <code class="language-plaintext highlighter-rouge">jiyu</code>, then <code class="language-plaintext highlighter-rouge">modules</code> is appended to the path. This will likely change as the compiler matures, but it currently makes working with modules easy. There is a new <code class="language-plaintext highlighter-rouge">#import</code> directive to reference a module from the scope that the directive is declared in. Since modules are intended to be referenced from many parts of a program, they exist in a scope-bubble of their own and cannot see declarations in the program’s global scope. Due to this, modules must also import other modules that they depend on.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#import "Array";</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">array</span><span class="p">:</span> <span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="n">uint8</span><span class="p">;</span>
<span class="nf">array_add</span><span class="p">(</span><span class="o">*</span><span class="n">array</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="compiler">Compiler</h2>
<p>There is now a <code class="language-plaintext highlighter-rouge">Build_Options</code> struct for specifying compilation options. Currently, only the output executable name and target-triple can be specified. Consequently, <code class="language-plaintext highlighter-rouge">create_compiler_instance() -> *Compiler</code> now accepts a <code class="language-plaintext highlighter-rouge">*Builder_Options</code> parameter. Build options for a compiler instance can not be changed after <code class="language-plaintext highlighter-rouge">create_compiler_instance()</code> is called.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">Build_Options</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">executable_name</span><span class="p">:</span> <span class="n">string</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">target_triple</span><span class="p">:</span> <span class="n">string</span><span class="p">;</span>
<span class="p">}</span>
<span class="c1">// ...</span>
<span class="cp">#import "Compiler";</span>
<span class="kd">func</span> <span class="kd">@metaprogram</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">options</span><span class="p">:</span> <span class="kt">Build_Options</span><span class="p">;</span>
<span class="n">options</span><span class="o">.</span><span class="n">executable_name</span> <span class="o">=</span> <span class="s">"my_cool_program"</span><span class="p">;</span>
<span class="n">options</span><span class="o">.</span><span class="n">target_triple</span> <span class="o">=</span> <span class="s">"arm-none-elf-eabi"</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">compiler</span> <span class="o">=</span> <span class="nf">create_compiler_instance</span><span class="p">(</span><span class="o">*</span><span class="n">options</span><span class="p">);</span>
<span class="c1">// ...</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="llvm">LLVM</h2>
<ul>
<li>Jiyu programs can now be debugged in your favorite debugger!</li>
</ul>
<p><img src="/assets/2019-8-18-Jiyu-Update-August-2019_MSVC_debugging.PNG" alt="Jiyu Program in MSVC debugger" /></p>
<ul>
<li>Aggregate types are now passed via an invisible reference.</li>
<li>As mentioned previously, one can now specify a target triple to the compiler. LLVM will honor this, enabling cross-compilation.</li>
</ul>
<h2 id="conclusion">Conclusion</h2>
<p>With these few changes, the compiler and language should be a bit more practical to use. I plan to post updates on a monthly basis, granted there’s enough changes, or a big enough change, that’s worth talking about.</p>
<p>The code for the compiler can be found at: <a href="https://github.com/machinamentum/jiyu">jiyu</a>.
Pull requests, feature requests, and issue reports are all welcome.</p>Josh HuelsmanIt has been about a month since I last wrote about my new programming-language project, Jiyu, so I’m going to briefly talk about the changes that have happened since. LibrariesJiyu - A Programming Language2019-07-22T00:00:00+00:002019-07-22T00:00:00+00:00http://machinamentum.github.io/Jiyu-A-Programming-Language<p>Every so often, I am introduced to a new programming language or compiler project that, at the surface level, seems interesting, but leaves a lot, for me, to be desired. Several of these include relatively new, currently-used-in-production languages, such as Swift, where ideological constraints on the language design have made it difficult to write general purpose programs that exist outside the scope of the language’s primary, intended use. Additionally, I have some reservations about the language and compiler I work on professionally. I still yearn for something to meet my needs as a programmer. I still need to write programs that manually manage memory; I still need to write code that runs at CPU boot-time; I still need a lot of C++’s convenience.</p>
<p>Back in 2015, I had started a compiler project, called <a href="https://github.com/machinamentum/htn">htn</a>, with just the goal of being able to compile code, interact with C-code, and output to a handful of assembly-language targets, including 6502, 32-bit ARM, and 32-bit x86. I’ve since dropped the project due to other projects and my day-job at-the-time consuming much more of my free-time. I had been thinking about this project often over the years as I had enjoyed the work I was doing on it. Unfortunately, the code isn’t maintainable for me anymore, I have grown considerably as a programmer since and am unwilling to change substantial portions of the code just to get it to a point of maintainability. Doing so would require nearly starting over again; so I started over, again.</p>
<h2 id="jiyu">Jiyu</h2>
<p>This time around, I’ve built an LLVM-based compiler with an out-of-order compilation model not unlike any modern language created in the last 5 or so years. My initial goals are quite simple: implement an appealing syntax that reduces friction and enables ease of refactoring, have the ability to just drop the compiler and its dependencies into existing toolchains for cross-compiling, and be able to manipulate memory unencumbered. Fortunately for me, the former and latter-most issues have largely been solved by other projects in this space. I really, <em>really</em>, enjoy Swift’s syntax, but I despise its type system as the design of it makes writing code, that needs to read and write unmanaged memory, difficult. I also really like Jai’s type system; it is reminiscent of C’s, but with built-in array, and string, types, and less confusion. I’ve opted to adopt both these things, let’s look at some code:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="kd">@c_function</span> <span class="nf">printf</span><span class="p">(</span><span class="nv">fmt</span><span class="p">:</span> <span class="o">*</span><span class="n">uint8</span><span class="p">,</span> <span class="n">temporary_c_vararg</span><span class="p">)</span> <span class="o">-></span> <span class="n">int</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">b</span> <span class="o">=</span> <span class="nf">cool_function</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="err">“</span><span class="kt">Value</span> <span class="n">of</span> <span class="nv">b</span><span class="p">:</span> <span class="o">%</span><span class="n">f</span><span class="p">\</span><span class="n">n</span><span class="err">”</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">cool_function</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="n">float</span><span class="p">)</span> <span class="o">-></span> <span class="n">float</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">a</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Most of the syntax here should be familiar to anyone who’s done even a light amount of Swift programming, with a few notable exceptions. The tag, <code class="language-plaintext highlighter-rouge">@c_function</code>, informs the compiler that we’re declaring a function that is external C-code, and to take care in calling this function correctly. <code class="language-plaintext highlighter-rouge">temporary_c_vararg</code> is fancy placeholder for the <code class="language-plaintext highlighter-rouge">...</code> syntax for a C-variable-argument function. Since strings are represented by a small struct containing the length of the string and a point to its data, we must dereference the data pointer before we can pass it to <code class="language-plaintext highlighter-rouge">printf</code>.</p>
<h2 id="user-types">User-types</h2>
<p>For user-types, the language currently supports type-aliasing and structs:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">typealias</span> <span class="n">c_string</span> <span class="o">=</span> <span class="o">*</span><span class="n">uint8</span><span class="p">;</span>
<span class="kd">func</span> <span class="kd">@c_function</span> <span class="nf">printf</span><span class="p">(</span><span class="nv">fmt</span><span class="p">:</span> <span class="n">c_string</span><span class="p">,</span> <span class="n">temporary_c_vararg</span><span class="p">);</span>
<span class="kd">typealias</span> <span class="kt">FILE</span> <span class="o">=</span> <span class="n">void</span><span class="p">;</span>
<span class="kd">func</span> <span class="kd">@c_function</span> <span class="nf">fopen</span><span class="p">(</span><span class="nv">path</span><span class="p">:</span> <span class="n">c_string</span><span class="p">,</span> <span class="nv">mode</span><span class="p">:</span> <span class="n">c_string</span><span class="p">)</span> <span class="o">-></span> <span class="o">*</span><span class="kt">FILE</span><span class="p">;</span>
<span class="kd">func</span> <span class="kd">@c_function</span> <span class="nf">fclose</span><span class="p">(</span><span class="nv">file</span><span class="p">:</span> <span class="o">*</span><span class="kt">FILE</span><span class="p">)</span> <span class="o">-></span> <span class="n">int32</span><span class="p">;</span>
<span class="kd">struct</span> <span class="kt">Matrix</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">data</span><span class="p">:</span> <span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">4</span><span class="p">]</span> <span class="n">float</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">identity_matrix</span><span class="p">()</span> <span class="o">-></span> <span class="kt">Matrix</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">m</span><span class="p">:</span> <span class="kt">Matrix</span><span class="p">;</span>
<span class="n">m</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="mi">0</span><span class="p">][</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">m</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="mi">1</span><span class="p">][</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">m</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="mi">2</span><span class="p">][</span><span class="mi">2</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">m</span><span class="o">.</span><span class="n">data</span><span class="p">[</span><span class="mi">3</span><span class="p">][</span><span class="mi">3</span><span class="p">]</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="k">return</span> <span class="n">m</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Variables are zero-initialized by default in this language. There’s currently no way to declare an uninitialized variable, but that is on the list of things to do.
Structs may be populated by any other type of declaration, including functions. There’s currently no notion of member-functions, however, that’s another thing to come in the future.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">struct</span> <span class="kt">Matrix</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">data</span><span class="p">:</span> <span class="p">[</span><span class="mi">4</span><span class="p">][</span><span class="mi">4</span><span class="p">]</span> <span class="n">float</span><span class="p">;</span>
<span class="k">let</span> <span class="nv">SIZE</span> <span class="o">=</span> <span class="mi">16</span><span class="p">;</span>
<span class="kd">func</span> <span class="nf">ortho</span><span class="p">(</span><span class="nv">left</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">right</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">top</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">bottom</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">near</span><span class="p">:</span> <span class="n">float</span><span class="p">,</span> <span class="nv">far</span><span class="p">:</span> <span class="n">float</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Matrix</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">identity</span><span class="p">()</span> <span class="o">-></span> <span class="kt">Matrix</span> <span class="p">{</span>
<span class="c1">// ...</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">matrix</span> <span class="o">=</span> <span class="kt">Matrix</span><span class="o">.</span><span class="nf">identity</span><span class="p">();</span>
<span class="c1">// ...</span>
<span class="k">var</span> <span class="nv">size</span> <span class="o">=</span> <span class="kt">Matrix</span><span class="o">.</span><span class="kt">SIZE</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="static-if">Static-if</h2>
<p>Another borrowed feature from Jai, is a scope-aware static-if:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="cp">#if os(MacOSX) {</span>
<span class="k">var</span> <span class="nv">b</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">}</span>
<span class="cp">#if os(Windows) {</span>
<span class="k">var</span> <span class="nv">b</span> <span class="o">=</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
<span class="n">b</span> <span class="o">=</span> <span class="mi">3</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The usefulness of this is that whenever code in a disabled static-if block is changed, it is still being parsed, enabling syntax-specific errors to still fire. <code class="language-plaintext highlighter-rouge">os()</code> is a special construct that checks the input for a known operating-system name, then resolves to a Boolean literal if that operating system happens to be the target platform. This is not too dissimilar to how <code class="language-plaintext highlighter-rouge">sizeof()</code> works, except, in this case, “MacOSX” and “Windows” are special identifiers that <code class="language-plaintext highlighter-rouge">os()</code> recognizes. Due to the complexity of allowing arbitrary expressions in the <code class="language-plaintext highlighter-rouge">#if</code> condition, I’ve specifically disallowed arbitrary expressions. Only expressions that specifically fold or resolves to literal values may appear here; otherwise, even just allowing <code class="language-plaintext highlighter-rouge">let</code> constants in the condition causes a number of dependency issues relating to when that <code class="language-plaintext highlighter-rouge">let</code> exists in a scope that the <code class="language-plaintext highlighter-rouge">#if</code> can see. We cannot have <code class="language-plaintext highlighter-rouge">#if</code> depend on information that only exists after another <code class="language-plaintext highlighter-rouge">#if</code> or <code class="language-plaintext highlighter-rouge">#load</code> has resolved in order to maintain simplicity in the out-of-order compilation system.</p>
<h2 id="templates">Templates</h2>
<p>There’s currently limited support for function-templates. Struct-templates will will be on their way, eventually. Template declaration and resolution rules are similar to Swift’s: template argument names are declared between <code class="language-plaintext highlighter-rouge"><</code> and <code class="language-plaintext highlighter-rouge">></code>, the type of the template arguments are deduced by arguments passed to the template function.</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">let</span> <span class="nv">NEW_MEM_CHUNK_ELEMENT_COUNT</span> <span class="o">=</span> <span class="mi">16</span><span class="p">;</span>
<span class="kd">func</span> <span class="n">array_reserve</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="nv">array</span><span class="p">:</span> <span class="o">*</span><span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">_amount</span><span class="p">:</span> <span class="n">int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">amount</span> <span class="o">=</span> <span class="n">_amount</span><span class="p">;</span>
<span class="k">if</span> <span class="n">amount</span> <span class="o"><=</span> <span class="mi">0</span>
<span class="n">amount</span> <span class="o">=</span> <span class="kt">NEW_MEM_CHUNK_ELEMENT_COUNT</span><span class="p">;</span>
<span class="k">var</span> <span class="nv">new_mem</span> <span class="o">=</span> <span class="nf">cast</span><span class="p">(</span><span class="o">*</span><span class="kt">T</span><span class="p">)</span> <span class="nf">malloc</span><span class="p">(</span><span class="n">amount</span> <span class="o">*</span> <span class="nf">sizeof</span><span class="p">(</span><span class="kt">T</span><span class="p">));</span>
<span class="k">if</span> <span class="n">array</span><span class="o">.</span><span class="n">data</span> <span class="o">!=</span> <span class="n">null</span> <span class="p">{</span>
<span class="nf">memcpy</span><span class="p">(</span><span class="n">new_mem</span><span class="p">,</span> <span class="n">array</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="nf">cast</span><span class="p">(</span><span class="n">size_t</span><span class="p">)</span> <span class="p">(</span><span class="n">array</span><span class="o">.</span><span class="n">count</span> <span class="o">*</span> <span class="nf">sizeof</span><span class="p">(</span><span class="kt">T</span><span class="p">))</span> <span class="p">);</span>
<span class="nf">free</span><span class="p">(</span><span class="n">array</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="p">}</span>
<span class="n">array</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">new_mem</span><span class="p">;</span>
<span class="n">array</span><span class="o">.</span><span class="n">allocated</span> <span class="o">=</span> <span class="n">amount</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="n">array_resize</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="nv">array</span><span class="p">:</span> <span class="o">*</span><span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">_amount</span><span class="p">:</span> <span class="n">int</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">array_reserve</span><span class="p">(</span><span class="n">array</span><span class="p">,</span> <span class="n">_amount</span><span class="p">);</span>
<span class="n">array</span><span class="o">.</span><span class="n">count</span> <span class="o">=</span> <span class="n">_amount</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="n">array_add</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="nv">array</span><span class="p">:</span> <span class="o">*</span><span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="kt">T</span><span class="p">,</span> <span class="nv">item</span><span class="p">:</span> <span class="kt">T</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="n">array</span><span class="o">.</span><span class="n">count</span><span class="o">+</span><span class="mi">1</span> <span class="o">>=</span> <span class="n">array</span><span class="o">.</span><span class="n">allocated</span><span class="p">)</span> <span class="nf">array_reserve</span><span class="p">(</span><span class="n">array</span><span class="p">,</span> <span class="nf">cast</span><span class="p">(</span><span class="n">int</span><span class="p">)</span>
<span class="n">array</span><span class="o">.</span><span class="n">allocated</span> <span class="o">+</span> <span class="kt">NEW_MEM_CHUNK_ELEMENT_COUNT</span><span class="p">);</span>
<span class="n">array</span><span class="o">.</span><span class="n">count</span> <span class="o">=</span> <span class="n">array</span><span class="o">.</span><span class="n">count</span> <span class="o">+</span> <span class="mi">1</span><span class="p">;</span>
<span class="p">(</span><span class="o"><<</span><span class="n">array</span><span class="p">)[</span><span class="n">array</span><span class="o">.</span><span class="n">count</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="o">=</span> <span class="n">item</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="n">array_reset</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="nv">array</span><span class="p">:</span> <span class="o">*</span><span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="kt">T</span><span class="p">)</span> <span class="p">{</span>
<span class="n">array</span><span class="o">.</span><span class="n">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="n">array</span><span class="o">.</span><span class="n">allocated</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
<span class="k">if</span> <span class="n">array</span><span class="o">.</span><span class="n">data</span> <span class="o">!=</span> <span class="n">null</span> <span class="nf">free</span><span class="p">(</span><span class="n">array</span><span class="o">.</span><span class="n">data</span><span class="p">);</span>
<span class="n">array</span><span class="o">.</span><span class="n">data</span> <span class="o">=</span> <span class="n">null</span><span class="p">;</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">data</span><span class="p">:</span> <span class="p">[</span><span class="o">..</span><span class="p">]</span> <span class="n">float</span><span class="p">;</span>
<span class="nf">array_add</span><span class="p">(</span><span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="mf">1.0</span><span class="p">);</span>
<span class="nf">array_add</span><span class="p">(</span><span class="o">*</span><span class="n">data</span><span class="p">,</span> <span class="mf">2.0</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="compile-time-function-execution">Compile-Time Function Execution</h2>
<p>There’s rudimentary support for CTFE. One may run any program at compile-time by invoking the <code class="language-plaintext highlighter-rouge">-meta</code> flag on the command line: <code class="language-plaintext highlighter-rouge">jiyu -meta build.jyu</code>. Additionally, the <code class="language-plaintext highlighter-rouge">main</code> function may be marked by the tag <code class="language-plaintext highlighter-rouge">@metaprogram</code> to force the compiler to always run that program at compile-time. Just a small change to our first code example will cause the program to always be executed at compile-time:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">func</span> <span class="kd">@c_function</span> <span class="nf">printf</span><span class="p">(</span><span class="nv">fmt</span><span class="p">:</span> <span class="o">*</span><span class="n">uint8</span><span class="p">,</span> <span class="n">temporary_c_vararg</span><span class="p">)</span> <span class="o">-></span> <span class="n">int</span><span class="p">;</span>
<span class="kd">func</span> <span class="kd">@metaprogram</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">b</span> <span class="o">=</span> <span class="nf">cool_function</span><span class="p">(</span><span class="mi">2</span><span class="p">);</span>
<span class="nf">printf</span><span class="p">(</span><span class="err">“</span><span class="kt">Value</span> <span class="n">of</span> <span class="nv">b</span><span class="p">:</span> <span class="o">%</span><span class="n">f</span><span class="p">\</span><span class="n">n</span><span class="err">”</span><span class="o">.</span><span class="n">data</span><span class="p">,</span> <span class="n">b</span><span class="p">);</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">cool_function</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="n">float</span><span class="p">)</span> <span class="o">-></span> <span class="n">float</span> <span class="p">{</span>
<span class="k">return</span> <span class="n">a</span> <span class="o">*</span> <span class="mi">2</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<p>Compile-time code may also harness the compiler’s main driver functions to compile, or run, other code. I won’t delve too deeply into that, but here is a code sample:</p>
<div class="language-swift highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">#load "Compiler.jyu";</span>
<span class="kd">func</span> <span class="kd">@metaprogram</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">compiler</span> <span class="o">=</span> <span class="nf">create_compiler_instance</span><span class="p">();</span>
<span class="n">compiler</span><span class="o">.</span><span class="n">executable_name</span> <span class="o">=</span> <span class="s">"run_tree/game"</span><span class="p">;</span>
<span class="k">if</span> <span class="nf">compiler_load_file</span><span class="p">(</span><span class="n">compiler</span><span class="p">,</span> <span class="s">"src/main.jyu"</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="k">if</span> <span class="nf">compiler_typecheck_program</span><span class="p">(</span><span class="n">compiler</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="k">if</span> <span class="nf">compiler_generate_llvm_module</span><span class="p">(</span><span class="n">compiler</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="k">if</span> <span class="nf">compiler_emit_object_file</span><span class="p">(</span><span class="n">compiler</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="k">if</span> <span class="nf">compiler_run_default_link_command</span><span class="p">(</span><span class="n">compiler</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">true</span> <span class="k">return</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="conclusion">Conclusion</h2>
<p>This has been a brief look at the language. There are still a number of small issues to tackle (like specifying libraries the code depended on; currently the compiler has the linker command baked-in), but I plan to fix these within the coming weeks. Please see the <a href="https://github.com/machinamentum/jiyu_game">jiyu_game</a> project for more in-depth use of the language.</p>
<p>The code for the compiler can be found at: <a href="https://github.com/machinamentum/jiyu">jiyu</a>.
Pull requests, feature requests, and issue reports are all welcome.</p>Josh HuelsmanEvery so often, I am introduced to a new programming language or compiler project that, at the surface level, seems interesting, but leaves a lot, for me, to be desired. Several of these include relatively new, currently-used-in-production languages, such as Swift, where ideological constraints on the language design have made it difficult to write general purpose programs that exist outside the scope of the language’s primary, intended use. Additionally, I have some reservations about the language and compiler I work on professionally. I still yearn for something to meet my needs as a programmer. I still need to write programs that manually manage memory; I still need to write code that runs at CPU boot-time; I still need a lot of C++’s convenience.Proposition for a better OS2016-07-18T00:00:00+00:002016-07-18T00:00:00+00:00http://machinamentum.github.io/Proposition-for-a-better-OS<h2 id="introduction">Introduction</h2>
<p>Over the past few years I’ve been increasingly losing interest in interacting with major operating systems for my day-to-day needs. Major operating systems have become largely bloatware that is more intrusive to the user’s experience than it is useful. I will try to outline the surface features at this time. Features that are non-user facing (within the kernel, programming interface, etc..) will be outlined at a later time.</p>
<p>These are the basic philosophies for designing this new OS:</p>
<ol>
<li>Operating systems should be designed to help the user get from point A to point B or perform task XYZ with as little friction as possible.</li>
<li>A design choice should not compromise philosophy(1), or philosophy(2).</li>
<li>The OS should be stripped of all bloatware.</li>
<li>The OS should be as unintrusive to the user as possible.</li>
<li>Upgrading the OS should improve the user’s experience, not degrade it.</li>
<li>The OS should be as easy and as accessible as possible; it should support multiple points of interaction by default. Whether the user wants to use a keyboard and mouse, a touch screen, or even a gamepad, the OS should be agnostic to these common points of interaction and should provide a pleasant experience.</li>
</ol>
<h2 id="the-terminal">The Terminal</h2>
<p>Currently, command terminals support basic IO, command execution, and simple text rendering (coloring, italics, bold face, etc..). These aren’t bad features at all, this small feature set is what makes interacting with consoles still a pretty good experience. However, this limiting feature set induces poor implementation choices of software that uses the console as a primary user interface. A prime example of a such program is the GNU debugger. GDB is an otherwise good debugger, but it’s console-based user interface makes even the most trivial of debugging tasks impossible to efficiently get done. We could do better.</p>
<h4 id="bitmap-rendering">Bitmap rendering</h4>
<p>I first heard about this idea from Gary Bernhardt of Destroy All Software in his talk <a href="https://www.destroyallsoftware.com/talks/a-whole-new-world">A Whole New World</a>. Although Gary mentions a few interesting uses for terminal raster graphics, there’s much wider implications of what this feature would be capable of. This enables full-featured UI’s from within a terminal. A terminal app could render a webpage, draw game graphics, or display a powerpoint. Typically, a terminal app like (for example) <a href="http://gource.io/">gource</a> would have to open a separate window to draw its output. The user then has to exit the newly opened window the click back into the terminal. This is unneeded friction that does nothing but waste the user’s time.</p>
<h4 id="mouseagnostic-pointer-input">Mouse/agnostic pointer input</h4>
<p>Since we have to support philosophy(6). The terminal should be able to do more with a pointer device than just copy-paste. As a natural, harmonious progression with bitmap rendering, a terminal app should be able to capture basic pointer input like position and clicking/tapping.</p>
<h4 id="scripting-language">Scripting language</h4>
<p>The terminal should support a robust scripting language to allow the user to automate tasks or interact with the system. Although this is a current feature of most terminals, many terminal languages are designed to do most of their work in the form of executing other terminal programs. Scripts in this language should be native to the system; they should be able to work like any other program without having to invoke other terminal programs to perform a task.</p>
<h2 id="windowing-system">Windowing system</h2>
<p>Although the features proposed in <em>The Terminal</em> would make windowing obsolete, there’s still a major use for apps exclusively designed around a window system. The terminal is typically thought of as a power-user-y interface; it inherently requires a keyboard and a bit of learning to effectively use it. A windowing system still provides a smaller amount of friction than the terminal.</p>
<p>iOS and Window’s MetroUI are forward-thinking systems. They maximize simplicity while minimizing (or trying to) friction. A simple tile-based UI would be an ideal solution to support philosophy(6). It would allow the user to use a keyboard and mouse, a touch screen, a gamepad, or any other abstract input devices without any compromises. This could be further extended to allow navigating the entirety of the filesystem from this interface.</p>
<p>If well-executed, we could do away with desktop environments. Although they’re highly preferred now on desktop PC’s, I believe power-users will become accustomed to these low-friction systems.</p>
<h2 id="developer-tools">Developer Tools</h2>
<p>Developer tools for many OS’ tend to be bloated and not very user friendly. Although we can’t strictly avoid legacy toolchains, we can at least provide a better user-experience for developers as part of the OS ecosystem.</p>
<h4 id="debugger">Debugger</h4>
<p>One of the things Windows does right that Unix-based OS’ do wrong is that Windows provides debugging utilities as part of the kernel. Anyone wishing to implement a custom debugger can simply link against the kernel’s public interface library and can get language-agnostic debugging callbacks that any user program can easily interpret and manipulate. We can take this core idea of the debugger being a part of the OS a little further by having executable object parsing, op-code disassembling, and symbol information loading being shipped as part of the debugging API. User-built debuggers don’t have to rely on these OS provided utilities, but the advantage to having a standard API for these is that anyone trying to implement a reasonable debugger without large dependencies, can just depend on the OS provided libraries and they should just work.</p>
<h4 id="api-deprecation">API deprecation</h4>
<p>Some API designers tend to believe that deprecation is “mark for removal”. I don’t agree with this idea. A deprecated API should remain available as long as there is software to depend on it. If the API in question breaks one of the core philosophies, it may be justifiable to remove the API from the core OS, but it must still be accessible to any user who wishes to use it through some other means (such as a compatibility package).</p>
<h2 id="adoption">Adoption</h2>
<p>This will probably be the trickiest part to execute. If we look at Steam’s <a href="http://store.steampowered.com/hwsurvey">hardware survey</a> alone, Windows dominates the market at 95% of users. Although this is just based on gamers, I’m sure these numbers tip even more in favor of Windows for casual PC users and business users. I don’t believe Mac OSX is a real competitor in this space since the target for this OS would be PC users (where Mac OSX is solely designed for Mac devices). Although Linux is somewhat popular in the open source space, I don’t think it is a direct competitor. Adoption for Linux is still very small and still suffers from some of the problems I’ll outline below.</p>
<h4 id="gpu-drivers-and-games">GPU drivers and games</h4>
<p>This will be one of the most important aspects of the OS to get the gaming space to adopt. Unfortunately, the main issue here is a chicken and egg problem. In order to get GPU vendors to implement drivers for our OS we need to have a significant standing in the gaming space by having games and users. In order to have games and users, we need to have good driver support to get developers to even consider porting their games. Fortunately, we can still get the process started by implementing our own drivers for a subset of hardware (Intel’s integrated graphics for example have <a href="https://www.x.org/docs/intel/">open specifications</a>. Although this is less than ideal, this would be a step in the right direction.</p>
<h4 id="pre-installed-on-devices">Pre-installed on devices</h4>
<p>This would be a goal to reach much farther in development, but it is very important to get the OS established as software that is pre-installed on machines. This is one of the main aspects of Linux that causes its low adoption rate (although Ubuntu tried this for awhile and failed).</p>
<p>I’ll explain the importance of this with an analogy. When users purchase an Android device for example, most do not buy the device with the intention of side-loading a different flavor of Android. Most users purchase an Android phone and use the pre-installed version of Android because it is just there and there’s no friction involved in having to set it up. Likewise, if Android phones only shipped with vanilla versions of Android with the option of installing manufacturer versions, the install base for manufacturer-based versions (i.e., Samsung’s TouchWiz or HTC’s Sense) would be much lower, perhaps even near non-existent. To further expand on this thought, CyanogenMod (arguably the largest non-OEM Android version, which isn’t typically pre-installed to devices) claimed in <a href="https://www.instagram.com/p/6IUuRVNH_b/">August 2015 to have 50M+ users</a>. According to <a href="http://www.theverge.com/2015/8/20/9181269/gartner-q2-2015-smartphone-sales">The Verge</a>, Android phone sales had hit ~271M units <em>in just the quarter leading up to</em> August 2015. The number of Android devices with pre-installed versions far, <em>far</em> out weigh the number with custom OS versions installed.</p>Josh HuelsmanIntroduction Over the past few years I’ve been increasingly losing interest in interacting with major operating systems for my day-to-day needs. Major operating systems have become largely bloatware that is more intrusive to the user’s experience than it is useful. I will try to outline the surface features at this time. Features that are non-user facing (within the kernel, programming interface, etc..) will be outlined at a later time.