]> git.eli173.com Git - klapaucius/commitdiff
Adds documentation, some small fixes
authorElijah Cohen <eli@eli173.com>
Sun, 1 Dec 2024 23:17:03 +0000 (17:17 -0600)
committerElijah Cohen <eli@eli173.com>
Sun, 1 Dec 2024 23:17:03 +0000 (17:17 -0600)
demos.kl
doc/builtins.html [new file with mode: 0644]
doc/index.html [new file with mode: 0644]
doc/style.css [new file with mode: 0644]
src/builtins.c
src/builtins/meta.c
src/builtins/meta.h
src/repl.c
src/test.c
web/shell.html

index b724c213abaed9f0b23a0502abf6a0829e4d9a30..45960f9ec71624c509e028949133a8777f6e5ce0 100644 (file)
--- a/demos.kl
+++ b/demos.kl
@@ -14,6 +14,8 @@
 (def U (L O))
 (def F (E T T E T))
 
+(def if I)
+
 (def church-and (B W (B C) I))
 (def church-or (S I I))
 (def church-not (B C (C I) nil t))
diff --git a/doc/builtins.html b/doc/builtins.html
new file mode 100644 (file)
index 0000000..41016d4
--- /dev/null
@@ -0,0 +1,524 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<html>
+  <head>
+    <title>Builtins</title>
+               <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <body>
+    <div>
+                       <article>
+                               <h1>Builtins</h1>
+                               <p>The operations built in to the language are described here, roughly organized by topic and significance. Examples ought to be included.</p>
+                               <nav>
+                                       <h2>Contents</h2>
+                                       <ul>
+                                               <li><a class="rel" href="#core">core</a></li>
+                                               <li><a class="rel" href="#arithmetic">arithmetic</a></li>
+                                               <li><a class="rel" href="#combinators">combinators</a></li>
+                                               <li><a class="rel" href="#io">io</a></li>
+                                               <li><a class="rel" href="#strings">strings</a></li>
+                                               <li><a class="rel" href="#meta">meta</a></li>
+                                       </ul>
+                               </nav>
+                               <div id="core">
+                                       <h3>core</h3>
+                                       <p>These operations are generally the most basic and foundational parts of the language, that make the underlying bits work</p>
+                                       <div>
+                                               <a class="rel" href="#core_quote">quote</a>
+                                               <a class="rel" href="#core_cons">cons</a>
+                                               <a class="rel" href="#core_car">car</a>
+                                               <a class="rel" href="#core_cdr">cdr</a>
+                                               <a class="rel" href="#core_eq">eq</a>
+                                               <a class="rel" href="#core_not">not</a>
+                                               <a class="rel" href="#core_atom">atom</a>
+                                               <a class="rel" href="#core_rest">rest</a>
+                                               <a class="rel" href="#core_unquote">unquote</a>
+                                               <a class="rel" href="#core_type">type</a>
+                                               <a class="rel" href="#core_def">def</a>
+                                               <a class="rel" href="#core_exit">exit</a>
+                                               <a class="rel" href="#core_applyn">applyn</a>
+                                       </div>
+                                       <div id="core_quote">
+                                               <h4>quote</h4>
+                                               <p><code>quote</code> ought to function in much the same way it does in other lisps. Perhaps it's a bit more complicated and maybe a bit less well-defined, but the idea is the same. Applies to one argument, unevaluated, returns its quoted form. I might change things up with this for various reasons, just a heads up</p>
+                                               <pre>
+← (quote asdf)
+ → asdf
+← (quote (+ 4 5)
+ → (+ 4 5)</pre>
+                                       </div>
+                                       <div id="core_cons">
+                                               <h4>cons</h4>
+                                               <p><code>cons</code> is another standard from lisps, it combines two values into a cons cell. Applies to two arguments, returns the cons cell containing those two values.</p>
+                                               <pre>
+← (cons 4 5)
+ → (4 . 5)
+← (cons 4 (cons 5 (cons 6 nil)))
+ → (4 5 6)</pre>
+                                       </div>
+                                       <div id="core_car">
+                                               <h4>car</h4>
+                                               <p><code>car</code> takes a cons cell, returns the first element (the 'car') of the pairing. Applies to one argument.</p>
+                                               <pre>
+← (car (cons 4 5))
+ → 4
+← (car (cons (cons 4 5) 6))
+ → (4 . 5)
+← (car (list 1 2 3))
+ → 1</pre>
+                                       </div>
+                                       <div id="core_cdr">
+                                               <h4>cdr</h4>
+                                               <p><code>cdr</code> takes a cons cell, returns the second element (the 'cdr') of the pairing. Applies to one argument.</p>
+                                               <pre>
+← (cdr (cons 4 5))
+ → 5
+← (cdr (cons (cons 4 5) 6))
+ → 6
+← (cdr (list 1 2 3))
+ → (2 3)</pre>
+                                       </div>
+                                       <div id="core_eq">
+                                               <h4>eq</h4>
+                                               <p><code>eq</code> determines whether two things are equal. Applies to two arguments, returns <code>t</code> if equal and <code>nil</code> otherwise.</p>
+                                               <pre>
+← (eq 4 5)
+ → nil
+← (eq 5 (+ 2 3))
+ → t
+← (eq 5 "5")
+ → nil
+← (eq (list 1 2 3) (cons 1 (cons 2 (cons 3 nil))))
+ → t</pre>
+                                       </div>
+                                       <div id="core_not">
+                                               <h4>not</h4>
+                                               <p><code>not</code> applies to one argument. If that argument evaluates to <code>nil</code>, it returns <code>t</code>, otherwise it returns <code>nil</code>.</p>
+                                               <pre>
+← (not t)
+ → nil
+← (not nil)
+ → t
+← (not "truthy value")
+ → nil
+← (not (cdr (list 1)))
+ → t</pre>
+                                       </div>
+                                       <div id="core_atom">
+                                               <h4>atom</h4>
+                                               <p><code>atom</code> applies to one argument. If that argument evaluates to a cons cell, it returns <code>nil</code>, otherwise it returns <code>t</code></p>
+                                               <pre>
+← (atom 4)
+ → t
+← (atom (+ 4 5))
+ → t
+← (atom (list 1 2 3 4))
+ → nil
+← (atom (cons 3 4))
+ → nil</pre>
+                                       </div>
+                                       <div id="core_rest">
+                                               <h4>rest</h4>
+                                               <p><code>rest</code> is the first 'novel' operation in this language, and (as of now) is the only 'variadic' operation in the language. <code>rest</code> requires at least two arguments to evaluate. The first argument is a function, which is applied to the rest the arguments collected in a list. That is, <code>(rest f 1 2 3)</code> evaluates as if it were <code>(f (list 1 2 3))</code>. Is used to construct other variadic functions (such as <code>list</code> itself).</p>
+                                               <pre>
+← (rest quote 1 2 3)
+ → (1 2 3)
+← (rest car 1 2 3)
+ → 1
+← (rest car 1 2 3)
+ → (2 3)</pre>
+                                       </div>
+                                       <div id="core_unquote">
+                                               <h4>unquote</h4>
+                                               <p><code>unquote</code> takes things out of a quote (if applicable). Applies to a single argument, and functions somewhat as a pseudo-<code>eval</code>. To be used perhaps sparingly or delicately.</p>
+                                               <pre>
+← (unquote 5)
+ → 5
+← (unquote (quote 5))
+ → 5
+← (unquote (quote (+ 4 5)))
+ → 9</pre>
+                                       </div>
+                                       <div id="core_type">
+                                               <h4>type</h4>
+                                               <p><code>type</code> takes one argument and returns a string representing that argument's type. Perhaps not what I want a 'type' operator to do in the long run, but for the time being it's pretty swell.</p>
+                                               <pre>
+← (type 5)
+ → "uint"
+← (type "uint")
+ → "string"
+← (type nil)
+ → "nil"</pre>
+                                       </div>
+                                       <div id="core_def">
+                                               <h4>def</h4>
+                                               <p>It's how we set (global) variables. Applies to two arguments, a symbol and anything else, and sets the symbol to the value of anything else. The background implementation of this is liable to change, so the fun mysterious behaviours of not using this one as described may become more or less interesting.</p>
+                                               <pre>
+← (def six (+ 2 4))
+ → 6
+← (def five 5)
+ → 5
+← (def plus +)
+ → _512
+note: the prior line just shows how builtins might be represented in the language
+← (plus five six)
+ → 11</pre>
+                                       </div>
+                                       <div id="core_exit">
+                                               <h4>exit</h4>
+                                               <p>This one takes a single argument and <code>exit</code>s with the argument as the return value. <code>(exit 0)</code> is the standard way to exit a program or the interpreter without error.</p>
+                                       </div>
+                                       <div id="core_applyn">
+                                               <h4>applyn</h4>
+                                               <p>This is a secret mystery operation. It's not directly accessible, but is called upon tacitly when using uints as functions. It takes first a uint <span class="italic">n</span>, then a function, then a final argument, and applies the function to the argument <span class="italic">n</span> times.</p>
+                                               <pre>
+← (3 cdr (list 1 2 3 4))
+ → (4)
+← (4 (+ 5) 0)
+ → 20</pre>
+                                       </div>
+                               </div>
+                               <div id="arithmetic">
+                                       <h3>arithmetic</h3>
+                                       <p>Basic arithmetic operations</p>
+                                       <div>
+                                               <a class="rel" href="#arith_add">add</a>
+                                               <a class="rel" href="#arith_sub">sub</a>
+                                               <a class="rel" href="#arith_mul">mul</a>
+                                               <a class="rel" href="#arith_div">div</a>
+                                               <a class="rel" href="#arith_mod">mod</a>
+                                       </div>
+                                       <div id="arith_add">
+                                               <h4>+ (add)</h4>
+                                               <p>Applies to two uints, adds them, returns the sum.</p>
+                                               <pre>
+← (+ 4 5)
+ → 9</pre>
+                                       </div>
+                                       <div id="arith_sub">
+                                               <h4>- (subtract)</h4>
+                                               <p>Applies to two uints, subtracts them, returns the difference.</p>
+                                               <pre>
+← (- 8 5)
+ → 3</pre>
+                                       </div>
+                                       <div id="arith_mul">
+                                               <h4>* (multiply)</h4>
+                                               <p>Applies to two uints, multiplies them, returns the product.</p>
+                                               <pre>
+← (* 4 5)
+ → 20</pre>
+                                       </div>
+                                       <div id="arith_div">
+                                               <h4>/ (divide)</h4>
+                                               <p>Applies to two uints, does division on them, returns the unsigned integer quotient.</p>
+                                               <pre>
+← (/ 36 4)
+ → 9
+← (/ 37 5)
+-&gt 7</pre>
+                                       </div>
+                                       <div id="arith_mod">
+                                               <h4>% (modulus)</h4>
+                                               <p>Applies to two uints, calculates the value of the first modulo the second, returns it.</p>
+                                               <pre>
+← (% 10 3)
+ → 1
+← (% 30 7)
+ → 2</pre>
+                                       </div>
+                               </div>
+                               <div id="combinators">
+                                       <h3>combinators</h3>
+                                       <p>This might just be the heart of the language. It's the basics for how more complicated  functions are composed, and how things get moved around and operated on. Incredibly useful for many partial application of functions. Heavy inspiration from languages like APL, BQN, and related variants, as well as various Forths and other stack-based languages. They will typically be described in terms of how they transform a sequence of arguments. The bird names are also provided in parenthesis</p>
+                                       <div>
+                                               <a class="rel" href="#comb_i">I</a>
+                                               <a class="rel" href="#comb_s">S</a>
+                                               <a class="rel" href="#comb_k">K</a>
+                                               <a class="rel" href="#comb_b">B</a>
+                                               <a class="rel" href="#comb_c">C</a>
+                                               <a class="rel" href="#comb_w">W</a>
+                                               <a class="rel" href="#comb_phi">Phi</a>
+                                               <a class="rel" href="#comb_psi">Psi</a>
+                                               <a class="rel" href="#comb_z">Z</a>
+                                       </div>
+                                       <div id="comb_i">
+                                               <h4>I</h4>
+                                               <p>The <code>I</code> (Idiot) combinator is the identity, it returns whatever it is given. It takes <code>I a</code> to <code>a</code></p>
+                                               <pre>
+← (I 8)
+ → 8
+&lt; (I + 3 5)
+ → 8</pre>
+                                       </div>
+                                       <div id="comb_s">
+                                               <h4>S</h4>
+                                               <p>The <code>S</code> (Starling) combinator takes <code>S a b c</code> to <code>a c (b c)</code></p>
+                                               <pre>
+← (S * (+ 4) 3)
+ → 21
+← (S cons cdr (list 3 4))
+ → ((3 4) 4)</pre>
+                                       </div>
+                                       <div id="comb_k">
+                                               <h4>K</h4>
+                                               <p> The <code>K</code> (Kestrel) combinator takes two arguments and returns the first, or in other words <code>K a b</code> to <code>a</code></p>
+                                               <pre>
+← (K 4 5)
+ → 4</pre>
+                                       </div>
+                                       <div id="comb_b">
+                                               <h4>B</h4>
+                                               <p>The <code>B</code> (Bluebird) is the composition combinator which takes three arguments, and applies the first to the application of the second to the third. <code>B a b c</code> goes to <code>a (b c)</code></p>
+                                               <pre>
+← (B car cdr (list 1 2 3))
+ → 2
+← (B (eq 5) car (list 5 6 7))
+ → t</pre>
+                                       </div>
+                                       <div id="comb_c">
+                                               <h4>C</h4>
+                                               <p>The <code>C</code> (Cardinal) combinator swaps its second and third arguments, it takes <code>C a b c</code> to <code>a c b</code>
+                                                       <pre>
+← (C - 4 5)
+ → 1
+← (C cons 4 5)
+ → (5 . 4)</pre>
+                                       </div>
+                                       <div id="comb_w">
+                                               <h4>W</h4>
+                                               <p> The <code>W</code> (Warbler) combinator duplicates its second argument, taking <code>W a b</code> to <code>a b b</code></p>
+                                               <pre>
+← (W + 5)
+ → 10
+← (def square (W *))
+ → _261
+← (square 7)
+ → 49</pre>
+                                       </div>
+                                       <div id="comb_phi">
+                                               <h4>Phi</h4>
+                                               <p>The <code>Phi</code> (Phoenix) combinator takes <code>Phi a b c d</code> to <code>a (b d) (c d)</code>, and is very useful for restructuring lists and cons cells</p>
+                                               <pre>
+← (Phi cons cdr car (cons 4 5))
+ → (5 . 4)
+← (Phi * I (+ 1) 7)
+ → 56</pre>
+                                       </div>
+                                       <div id="comb_psi">
+                                               <h4>Psi</h4>
+                                               <p>The <code>Psi</code> combinator takes <code>Psi a b c d</code> to <code>a (b c) (b d)</code></p>
+                                               <pre>
+← (Psi * (+ 5) 2 3)
+ → 56
+← (Psi cons cdr (list 1 2 3) (list 3 4 5))
+ → ((2 3) 4 5)</pre>
+                                       </div>
+                                       <div id="comb_z">
+                                               <h4>Z</h4>
+                                               <p>The <code>Z</code> combinator is probably the most complicated and the most crucial combinator here. It allows for recursion, by taking <code>Z g v</code> to <code>g (Z g) v</code>. It is incredibly useful, but also rather difficult to use given the context of the rest of the language at this point. So, enjoy the example below, which is a non-optimized implementation of factorial</p>
+                                               <pre>
+← (def fac (Z ((B B) S (C (eq 0) 1) ((B B) S * (C B (C - 1))))))
+ → _264
+← (fac 5)
+ → 120</pre>
+                                       </div>
+                               </div>
+                               <div id="io">
+                                       <h3>io</h3>
+                                       <p>Operations for printing strings, reading and writing files, things of that nature, all very platform-dependent I'm sure</p>
+                                       <div>
+                                               <a class="rel" href="#io_print">print</a>
+                                               <a class="rel" href="#io_printstr">printstr</a>
+                                               <a class="rel" href="#io_pb">pb</a>
+                                               <a class="rel" href="#io_readfile">readfile</a>
+                                               <a class="rel" href="#io_writefile">writefile</a>
+                                       </div>
+                                       <div id="io_print">
+                                               <h4>print</h4>
+                                               <p><code>print</code> takes one argument, and prints it to standard output, then returns true if it successfuly did so</p>
+                                               <pre>
+← (print (list 1 2 3 4 5))
+(1 2 3 4 5)
+ → t
+← (print "hello, world!")
+"hello, world!"
+ → t</pre>
+                                       </div>
+                                       <div id="io_printstr">
+                                               <h4>printstr</h4>
+                                               <p><code>printstr</code> prints a string to standard output (without the quotation marks), returns <code>t</code> if successfully done, and returns <code>nil</code> otherwise (or if passed something that's not a string)</p>
+                                               <pre>
+← printstr "hello, world!"
+hello, world!
+ → t
+← printstr 45
+ → nil</pre>
+                                       </div>
+                                       <div id="io_pb">
+                                               <h4>pb</h4>
+                                               <p><code>pb</code> prints a builtin with any arguments partially applied in reverse order. Pretty handy for debugging and such, but should probably be avoided otherwise
+                                                       <pre>
+← (pb +)
+ → _+&lt;nil&gt;
+← (pb (+ 5))
+ → _+&lt;(5)&gt;
+← (pb (+ 5 4))
+ → 9</pre>
+                                       </div>
+                                       <div id="io_readfile">
+                                               <h4>readfile</h4>
+                                               <p><code>readfile</code> applies to one argument, a string representing the path to a file. If the string does not match a file or cannot open it, it returns <code>nil</code>, otherwise it returns a string containing the file's contents. Doesn't yet do anything fancy with path expansions or anything like that, gotta be specific</p>
+                                               <pre>
+← (readfile "myfile.txt")
+ → "these are the contents of 'myfile.txt"</pre>
+                                       </div>
+                                       <div id="io_writefile">
+                                               <h4>writefile</h4>
+                                               <p><code>writefile</code> applies to two arguments, a string representing the path to a file, and a string to write into that file. If the file string does not match a file or cannot open or write to it, it returns <code>nil</code>, otherwise it the number of bytes written. Again, doesn't yet do anything fancy with path expansions or anything like that, gotta be specific</p>
+                                               <pre>
+← (writefile "myfile.txt" "writing\na\nstring\nto\nfile")
+ → 24</pre>
+                                       </div>
+                               </div>
+                               <div id="strings">
+                                       <h3>strings</h3>
+                                       <p>Operations on strings, nothing more to it</p>
+                                       <div>
+                                               <a class="rel" href="#strings_strlen">strlen</a>
+                                               <a class="rel" href="#strings_strcat">strcat</a>
+                                               <a class="rel" href="#strings_strat">strat</a>
+                                               <a class="rel" href="#strings_strexpand">strexpand</a>
+                                               <a class="rel" href="#strings_substr">substr</a>
+                                               <a class="rel" href="#strings_strtok">strtok</a>
+                                               <a class="rel" href="#strings_tostr">tostr</a>
+                                       </div>
+                                       <div id="strings_strlen">
+                                               <p><code>strlen</code> takes a string and returns its length</p>
+                                               <pre>
+← (strlen "hello, world!")
+ → 13
+← (strlen "escape\ncharacters")
+ → 17</pre>
+                                       </div>
+                                       <div id="strings_strcat">
+                                               <h4>strcat</h4>
+                                               <p><code>strcat</code> concatenates two strings, simple as that</p>
+                                               <pre>
+← (strcat "hello, " "world!")
+ → "hello, world!"</pre>
+                                       </div>
+                                       <div id="strings_strat">
+                                               <h4>strat</h4>
+                                               <p><code>strat</code> takes a number <span class="italic">n</span> and a string, and returns the <span class="italic">n</span>th character of the string. Poorly named, I know</p>
+                                               <pre>
+← (strat 3 "test")
+ → "s"</pre>
+                                       </div>
+                                       <div id="strings_strexpand">
+                                               <p><code>strexpand</code> takes a string, and returns a list of its characters. Breaks down with unicode</p>
+                                               <pre>
+← (strexpand "test")
+ → ("t" "e" "s" "t")</pre>
+                                       </div>
+                                       <div id="strings_substr">
+                                               <h4>substr</h4>
+                                               <p><code>substr</code> takes two strings, and returns a list of indexes where the first string begins in the second</p>
+                                               <pre>
+← (substr "hi" "chili")
+ → (2)
+← (substr "oo" "loooong woords")
+ → (2 3 4 10)</pre>
+                                       </div>
+                                       <div id="strings_strtok">
+                                               <h4>strtok</h4>
+                                               <p><code>strtok</code> takes a two strings, and returns a list of substrings of the second string separated by characters in the first</p>
+                                               <pre>
+← (strtok " " "hello world")
+ → ("hello" "world")
+← (strtok " \n" "showing how\nthis works")
+ → ("showing" "how" "this" "works")</pre>
+                                       </div>
+                                       <div id="strings_tostr">
+                                               <h4>tostr</h4>
+                                               <p><code>tostr</code> takes one argument and returns its representation as a string</p>
+                                               <pre>
+← (tostr (cons 45 "hi")
+ → "(45 . "hi")"
+                                       </div>
+                               </div>
+                               <div id="meta">
+                                       <h3>meta</h3>
+                                       <p>This is the messy stuff, if you wanna break things keep reading. Maybe the most interesting bits of messing and extending the language</p>
+                                       <div>
+                                               <a class="rel" href="#meta_utob">utob</a>
+                                               <a class="rel" href="#meta_btou">btou</a>
+                                               <a class="rel" href="#meta_parse">parse</a>
+                                               <a class="rel" href="#meta_lookup">lookup</a>
+                                               <a class="rel" href="#meta_getargs">getargs</a>
+                                               <a class="rel" href="#meta_getenv">getenv</a>
+                                               <a class="rel" href="#meta_setenv">setenv</a>
+                                       </div>
+                                       <div id="meta_utob">
+                                               <h4>utob</h4>
+                                               <p><code>utob</code> takes a uint, and returns a builtin whose operation corresponds with the value passed. The numbers will most likely be subject to change with rearrangements or additions</p>
+                                               <pre>
+← (utob 512)
+ → _512
+← ((utob 512) 4 5)
+ → 9</pre>
+                                       </div>
+                                       <div id="meta_btou">
+                                               <h4>btou</h4>
+                                               <p><code>btou</code> takes a builtin operation and returns the uint whose value corresponds with the operation. A sort of 'opcode', if you will</p>
+                                               <pre>
+← (btou +)
+ → 512
+← (btou (+ 5))
+ → 512</pre>
+                                       </div>
+                                       <div id="meta_parse">
+                                               <h4>parse</h4>
+                                               <p><code>parse</code> parses a string into an s-expression, the same way the repl does it pretty much</p>
+                                               <pre>
+← (parse "(cons 4 5)")
+ → ((cons 4 5))</pre>
+                                       </div>
+                                       <div id="meta_getargs">
+                                               <h4>getargs</h4>
+                                               <p><code>getargs</code> takes a builtin, and returns any arguments partially applied to it. These arguments are almost surely unevaluated</p>
+                                               <pre>
+← (getargs (+ 5))
+ → (5)
+← (getargs (S + (+ 4)))
+ → ((+ 4) +)</pre>
+                                       </div>
+                                       <div id="meta_lookup">
+                                               <h4>lookup</h4>
+                                               <p><code>lookup</code> looks into the environment to see if the passed argument is defined. Returns nil if undefined, returns a single-element list with its value as the car if it is</p>
+                                               <pre>
+← (lookup +)
+ → (_512)
+← (lookup notdefined)
+→ nil
+← (lookup nil)
+→ (nil)</pre>
+                                       </div>
+                                       <div id="meta_getenv">
+                                               <h4>getenv</h4>
+                                               <p><code>getenv</code> returns the current environment, that is, all the definitions, as an s-expression (which, incidentally, is its internal representation). Must pass it a <code>t</code> for it to work</p>
+                                               <pre>
+← (getenv t)
+ → &lt;some big long list of things&gt;</pre>
+                                       </div>
+                                       <div id="meta_setenv">
+                                               <h4>setenv</h4>
+                                               <p>Here there be monsters. <code>setenv</code> allows you to overwrite the environment completely. This is dangerous and you may end up without any sort of meaningfully functional repl if you ever do this. Have fun!</p>
+                                       </div>
+                               </div>
+                       </article>
+               </div>
+  </body>
+</html>
diff --git a/doc/index.html b/doc/index.html
new file mode 100644 (file)
index 0000000..c3525c3
--- /dev/null
@@ -0,0 +1,131 @@
+<!doctype html>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<html>
+  <head>
+    <title>klaupacius</title>
+               <link href="style.css" rel="stylesheet" type="text/css" />
+  </head>
+  <body>
+    <div>
+                       <article>
+                               <h2>klaupacius</h2>
+                               <p>A language so inspired by lisps, forths and array languages that it resembles none of these.</p>
+                               <p>A combinator-based, concatenative, tacit lisp with automatic memory management, immutability, partial application, some church encodings, without variables or lambdas, where everything is a function.</p>
+                               <!-- note: maybe a picture or something here instead of just space? -->
+                               <div id="setting_out">
+                                       <h3>Setting Out</h3>
+                                       <p>This language emerged as a result of thinking about computing on stack machines. I wanted to spawn some sort of convergence of lisp-like and forth-like languages, I wanted to take the point-free style one gets in forths, and bring it into something with a structure based more upon s-expressions. It's a take on stack-based programming, but where we work from the other direction in a sense.</p>
+                                       <p>To demonstrate, let's break down something simple, like <code>(+ 4 5)</code>. If one has some experience with other lisps, this code might appear pretty obvious, and even without that experience, if one were to look at a plus, a four, and a five arranged like so, one might guess that this program adds four and five, returning <code>9</code>. And yes, that's exactly what happens, but understanding how we get there sheds light on how we can understand this language. It's already been stated  that everything is a function, but it might be helpful to think of everything as a monadic function, a function that takes only one argument (which generally holds true, save for a particularly exciting and useful exception). But isn't the above-mentioned <code>+</code> a function that takes two values? Sort of! In this case, it is reasonable to think of <code>+</code> as a function that takes one argument <span class="italic">n</span>, and returns another function, which takes one argument <span class="italic">m</span> and returns <span class="italic">n + m</span>. Breaking this down a bit further reveals some aspects of the underlying system.</p>
+                                       <p>How might we think about <code>+</code> being a monadic function that returns a function? Well let's start by breaking our example into 'simpler' pieces. Let's start with just <code>(+)</code>. If we type that into our <a href="link to repl plz TODO">repl</a> and hit enter, we get <code>_512</code> in return. What is this? You're right to ask. Things prefixed with an underscore like that are just how internal operations are printed, the underscore followed by a numeric value, here 512 corresponds to our plus. So let's call this function now. Type in <code>(+ 4)</code>, and you get <code>_512</code> in return. The same thing? What happened to the 4? I promise it's still in there, it's just printed like that to not overwhelm the output when dealing with more complicated matters. You can even get the four back out, doing <code>getargs (+ 4)</code> returns a list of arguments applied to any builtin operation (here, we'd get <code>(4)</code>).</p>
+                                       <p>So, if you're still with me, now we have a nice new function <code>(+ 4)</code>. Let's call this function now. Give it <code>((+ 4) 5)</code>, and indeed you'll get a <code>9</code> in return! When it's parenthesized this way, I feel it's easier to understand that <code>(+ 4)</code> is itself a function, and can be applied to a number to get the sum of that number and four. So now is there a difference between <code>((+ 4) 5)</code> and <code>(+ 4 5)</code>? Practically speaking they're the same. When the interpreter evaluates a statement like <code>(a b c d)</code>, it takes <code>a</code> and <code>b</code> off the top of the list, appplies <code>a</code> to <code>b</code>, and sticks that (let's call it <code>ab</code>) to the beginning of the list and starts over again. So <code>(a b c d)</code> becomes <code>(ab c d)</code> which in turn becomes <code>(abc d)</code>, which goes to <code>(abcd)</code>, and now since there aren't any more arguments, it drops the parenthesis giving us <code>abcd</code>. This gives us a decent amount of leeway with the use of parenthesis in a way that's different from other lisps. The expressions
+                                               <pre>(+ 4 5)
+((+ 4) 5)
+(((+) 4) 5)
+(((+ ((4)) 5)))</pre>
+                                               all evaluate to the same thing, in (practically) the same way. This allows us to use parenthesis for refactoring or to make code clearer. It also allows a nice trick in the repl: we can just drop the outmost parenthesis, so instead of any of those examples we can just write <code>+ 4 5</code>! Doing this feels so nice to me, and since I haven't encountered it in other lisps before, I consider this to be the most significant idea other lisps could learn from.</p>
+                                       <p>One thing to note about this style is that as it currently stands, this makes this language a bit lazier than most languages. That is, the arguments to functions are only evaluated when there's enough information to completely evaluate the function. So, say, if one were to use the function <code>(+ &lt;a&gt;)</code>, the argument <code>a</code> will only be evaluated when the function is passed another value. This will always be in the language, though I do imagine the introduction of a way to more eagerly evaluate arguments.</p>
+                               </div>
+                               <div id="combinators">
+                                       <h3>Combinators</h3>
+                                       <p>Quite a bit is needed to make a language as tacit as this one, and the method I've selected to do so is through the use and overuse of combinators. One can think of the use of combinators here as a form of rewriting expressions. Let's take as an example the <span class="italic">C</span> combinator. <code>(C a b c)</code> takes its three arguments and gives back <code>(a c b)</code>. Let's look at how this can work in a more practical example:
+                                               <pre>
+← C - 1 5
+ = - 5 1
+ → 4</pre>
+                                               so if one were interested in a function that subtracts one from a number, there you have it, in <code>(C - 1)</code>.</p>
+                                       <p>Another often-useful combinator is the <span class="italic">B</span> combinator, sometimes called the composition combinator. This one takes <code>(B a b c)</code> to <code>(a (b c))</code>. An example one might come across frequently is:
+                                               <pre>
+← B car cdr (list 1 2 3 4)
+ = car (cdr (list 1 2 3 4))
+ → 2</pre>
+                                               which is commonly called <code>cadr</code> in many other lisps. A decent amount of other compositions of <code>car</code> and <code>cdr</code> can also easily be defined, but we'll leave that for later.</p>
+                                       <p>This language has all the combinators from the <span class="italic">I S K</span> and <span class="italic">B C K W</span> combinator calculi. From the composition of these, many other useful combinators can be made. Two combinators provided are the phi and psi combinators, where <code>Phi a b c d</code> gives you <code>a (b d) (c d)</code>, and where <code>Psi a b c d</code> gives you <code>a (b c) (b d)</code>, both very useful in general, and phi particularly useful for processing lists. For more, I encourage you to check out <a href="https://combinatorylogic.com/table.html">this</a> and <a href="https://wiki.xxiivv.com/site/logic.html#ref">this</a> link for many nice examples of other combinators and their uses.</p>
+                                       <p>There is one further built-in combinator, incredibly powerful and used for recursion. The <span class="italic">Z</span> combinator. It is quite cumbersome at this point to work with, but it can power most anything you might want to do that requires any sort of iteration. The <span class="italic">Z</span> combinator takes <code>Z g v</code> to <code>g (Z g) v</code>, enabling recursion. One major implementation difference is that <code>Z</code> evaluates its second argument rather than just reproducing the symbols in the desired order, for the sake of performance (this may change at some point).</p>
+                                       <p>Okay, we've described it, now let's see how we might work with it. Please note that this is currently the least pleasant part of the language, and the brunt of the work going forward will likely be how to make actually implementing things comfortable. But let's think about implementing the factorial function (please note that this implementation is not tail-recursive, so it's not the most practical implementation). My process has been starting with an expression with variables, and abstracting them out (getting them to be the last things in the expression). So, the process starts with
+                                               <pre>(if (eq 0 n) 1 (* n (fac (- n 1))))</pre>
+                                               and our goal is to extract the <code>n</code> and <code>fib</code> terms, in that order, to get something usable with the <span class="italic">Z</span> combinator. There are several different things we could do first, but let's start with something we've already seen before, with getting a function to subtract one from something. We just replace below
+                                               <pre>(if (eq 0 n) 1 (* n (fac ((C - 1) n))))</pre>
+                                               Next we can use the <span class="italic">B</span> combinator to come to
+                                               <pre>(if (eq 0 n) 1 (* n (B fac (C - 1) n)))</pre>
+                                               At this point, it's pretty useful to remember how much freedom we have in using parenthesis to help us refactor things, and group a couple different things up to get
+                                               <pre>(if ((eq 0) n) 1 (* n ((B fac (C - 1)) n)))</pre>
+                                               Now, we get to use the <span class="italic">S</span> combinator, which takes <code>S a b c</code> to <code>a c b c</code>. If we put it right in front of the multiplication, we get
+                                               <pre>(if ((eq 0) n) 1 (S * (B fac (C - 1)) n))</pre>
+                                               which reduces the number of times <span class="italic">n</span> appears in the expression. The next several steps will be applications of the same replacements we've already done (including reparenthesizing), but in different places. Try and follow along!
+                                               <pre>(if ((eq 0) n) 1 (S * (B fac (C - 1)) n))
+(if ((eq 0) n) 1 ((S * (B fac (C - 1))) n))
+((B if (eq 0) n) 1 ((S * (B fac (C - 1))) n))
+(((B if (eq 0)) n) 1 ((S * (B fac (C - 1))) n))</pre>
+                                               The next tool we have in our bag of tricks is another way of messing with parenthesis, which has been alluded to earlier. Since <code>((a b) (c d))</code> functions the same as <code>(a b (c d))</code>, we can remove parenthesis that start expressions (though not ones in the middle of expressions, because calling <span class="italic">c</span> on <span class="italic">d</span> needs to happen before being used as the argument for <code>(a b)</code>). So, we can rewrite our latest expression:
+                                               <pre>(((B if (eq 0)) n) 1 ((S * (B fac (C - 1))) n))
+((B if (eq 0)) n 1 ((S * (B fac (C - 1))) n))</pre>
+                                               This gives us more power for refactoring and reorganizing code in general. We continue on:
+                                               <pre>((B if (eq 0)) n 1 ((S * (B fac (C - 1))) n))
+(C (B if (eq 0)) 1 n ((S * (B fac (C - 1))) n))
+((C (B if (eq 0)) 1) n ((S * (B fac (C - 1))) n))
+(S (C (B if (eq 0)) 1) (S * (B fac (C - 1))) n)
+(S (C (B if (eq 0)) 1) (S * (B fac (C - 1)))) n
+</pre>
+                                               At this point, <span class="italic">n</span> is the last term in this expression, so we can consider it factored out, and then proceed to do the same thing for <span class="italic">fac</span>
+                                               <pre>
+(S (C (B if (eq 0)) 1) (S * (B fac (C - 1))))
+(S (C (B if (eq 0)) 1) (S * (C B (C - 1) fac)))
+(S (C (B if (eq 0)) 1) ((S *) ((C B (C - 1)) fac)))
+(S (C (B if (eq 0)) 1) (B (S *) (C B (C - 1)) fac))
+((S (C (B if (eq 0)) 1)) ((B (S *) (C B (C - 1))) fac))
+(B (S (C (B if (eq 0)) 1)) (B (S *) (C B (C - 1))) fac)
+(B (S (C (B if (eq 0)) 1)) (B (S *) (C B (C - 1)))) fac
+(B (S (C (B if (eq 0)) 1)) (B (S *) (C B (C - 1))))
+</pre>
+                                               And now we have factored out our recursive call. What do we do with this now? Now we get to use the <span class="italic">Z</span> combinator. We've just figured out the <span class="italic">g</span> we want to pass it, and since this is a factorial function, the <span class="italic">v</span> we need is just whatever iteger we want the factorial of. So,
+                                               <pre>
+← Z (B (S (C (B if (eq 0)) 1)) (B (S *) (C B (C - 1)))) 5
+ → 120</pre>
+                                               Wonderful! Now, if we wanted to use factorial more often, we'd just assign it a (global) name, like so:
+                                               <pre>
+← def factorial (Z (B (S (C (B if (eq 0)) 1)) (B (S *) (C B (C - 1)))))
+ → _264
+← factorial 7
+ → 5040
+← factorial 0
+→ 1</pre>
+                                       </p>
+                                       <p>One might think all this to be a bit much to get something as simple as factorial. I'd probably agree. Aside from fixing various pain points and adding practical features, the majority of effort that will go into this language will be toward making writing things like recursive functions much easier.</p>
+                               </div>
+                               <div id="church">
+                                       <h3>Church Encodings</h3>
+                                       <p>Everything in this language is a function. That includes numbers, strings, and everything else. Most things, including strings, are pretty unexciting, a string is just a function that returns itself. But, for unsigned integers, <code>t</code>, and <code>nil</code>, we get some exciting behaviours. When <code>t</code> is applied as a function, it takes two arguments and returns the first, and <code>nil</code> takes two and returns the second (these are represented in combinators as <code>K</code> and <code>K I</code> respectively). Numbers are pretty nice here, when treated as a function, <span class="italic">n</span> takes two arguments, and applies the first to the second <span class="italic">n</span> times. So, the code <code>(4 f v)</code> turns into the code <code>(f (f (f (f v))))</code></p>
+                                       <p>Particularly for numbers, this is a nice way to iterate things. A couple simpler examples include multiplication and exponentiation:
+                                               <pre>
+← 5 (+ 3) 0
+ → 15
+← 6 (C - 4) 100
+ → 76
+← 4 (* 5) 1
+ → 625
+← 4 3 (+ 1) 0
+ → 81
+← 7 2 (+ 1) 0
+ → 128</pre>
+                                               These are certainly not the most efficient ways to calculate these values, but they illustrate how one might use numbers as functions. Another more practical and exciting use of numbers can come in the form of composition of <code>car</code> and <code>cdr</code>, like the <code>cadr</code> mentioned above. We can define <code>cadddr</code> as <code>(B car (3 cdr))</code> and so on.</p>
+                                       <p>The use of <code>t</code> and <code>nil</code> as functions isn't quite so broad in its uses, but the combination of them can really make code more compact. Consider any sort of expression that evaluates to a boolean, such as <code>(eq 4 n)</code>. If it evaluates to true, it'll function as the <code>t</code> function, so passing it two arguments returns the first. If it evaluates to false, it'll function as <code>nil</code>, so passing it two arguments returns the second. So, the following examples work the same way:
+                                               <pre>
+if (eq 6 n) "n was six" "n was not six"
+(eq 6 n) "n was six" "n was not six"</pre>
+                                               So 'if' is generally superfluous and not needed. In fact, using the <span class="italic">I</span> combinator (which takes <span class="italic">I a</span> to <span class="italic">a</span>), one can define (and I have, though I don't actually use it that much) 'if' with the following statement: <code>(def if I)</code>. Simple as that. All this is the biggest use of Church encodings so far, though I may play around with doing some more useful and interesting things.</p>
+                               </div>
+                               <div>
+                                       <h3>rest</h3>
+                                       <p>The last fairly significant thing I want to tell you about here is <code>rest</code>. This operation could probably be considered the most 'improper' thing in this language. This is how we can do variadic functions. <code>rest</code> is passed a function that takes a function that operates on a list. <code>rest</code> takes that function, and applies it to all the rest of the arguments in that statement. So, one could implement a more commonly lisp-style variadic addition:
+                                               <pre>
+← def +/ (rest (fold +))
+ → _7
+← +/ 1 2 3 4 5
+ → 15</pre>
+                                       which gives us a nice variadic addition.</p>
+                               </div>
+                       </article>
+               </div>
+  </body>
+</html>
diff --git a/doc/style.css b/doc/style.css
new file mode 100644 (file)
index 0000000..07e8b67
--- /dev/null
@@ -0,0 +1,202 @@
+/* yo imma do this /mobile first/ */
+
+body {
+               background-color: #e0e0f0;
+}
+
+ul {
+               list-style-type: "- ";
+}
+
+pre {
+               white-space: pre-wrap;
+               background-color: #f0f0f0;
+               padding: 2px;
+}
+
+code {
+               white-space: nowrap;
+               background-color: #f0f0f0;
+               padding: 2px;
+}
+
+p {
+               font-family: serif;
+}
+
+h1 {
+               font-size: xx-large;
+               font-weight: bold;
+}
+
+h2 {
+               font-size: x-large;
+               font-weight: bold;
+               font-variant: small-caps;
+               border-bottom: 1px solid grey;
+}
+h3 {
+               font-variant: small-caps;
+               /*border-bottom: 1px solid grey;*/
+               text-decoration: underline;
+}
+
+nav {
+               background-color: #f9f9f9;
+}
+
+aside {
+               /*border: 1px solid red;*/
+               border-left: 2px solid #c0c0c0;
+               color: black;
+               background-color: #f6f6f6;
+               border-radius: 3px;
+               padding-left: 5px;
+               padding-top: 2px;
+               padding-bottom: 2px;
+               font-size: smaller;
+               margin-left: 2em;
+               margin-right: 2em;
+}
+
+.italic {
+               font-style: italic;
+}
+
+.fn {
+               white-space: nowrap;
+               position: relative;
+}
+
+.close {
+               position: absolute;
+               right: 20px;
+               font-size: x-large;
+}
+
+.foot {
+               visibility: hidden;
+               display: flex;
+               position: fixed;
+               margin-bottom: 30px;
+               margin-bottom: 2px;
+               min-height: 40px;
+               white-space: normal;
+               bottom: 0px;
+               background-color: #f0f0f0;
+               border: 2px solid #c0c0c0;
+               width: 90%;
+}
+
+.foottxt {
+               width: 90%;
+               margin: 2px;
+               font-size: larger;
+}
+
+.fn:hover .foot {
+               /*color: green;*/
+               /*background-color: red;*/
+               visibility: visible;
+}
+
+.foot:target {
+               visibility: visible;
+}
+
+.hover {
+               white-space: normal;
+               position: absolute;
+               visibility: hidden;
+               /*background-color: orange;*/
+               width: 300px;
+               top: -20px;
+}
+.hoverbox {
+               background-color: #f0f0f0;
+               border: 2px solid #c0c0c0;
+               border-radius: 3px;
+               position: absolute;
+               max-width: 300px;
+               padding: 3px;
+}
+.hovertxt {
+               padding: 2px;
+}
+
+
+.codeblock {
+               display: block;
+               /*white-space: pre-wrap;*/
+               margin-bottom: 1em;
+}
+
+figure {
+               text-align: center;
+}
+img {
+                               width: 90%;
+}
+figcaption {
+               font-size: small;
+               font-style: italic;
+}
+
+figure.quote {
+               background-color: #f0f0f0;
+               border-radius: 10px;
+               border-left: solid 4px #d0d0d0;
+}
+blockquote {
+               padding-top: 4px;
+               padding-bot: 2px;
+}
+
+table {
+               width: 100%;
+               overflow-x: scroll;
+               display: block;
+               border-collapse: collapse;
+}
+
+td {
+               border: 1px solid #909090;
+}
+th {
+               border: 1px solid #a0a0a0;
+               background-color: #f0f0f0;
+}
+
+@media screen and (min-width: 1000px) {
+               article {
+                               max-width: 800px;
+                               margin: 0 auto;
+               }
+               aside {
+                               margin-left: 6em;
+               }
+               .fn:hover .hover {
+                               visibility: visible;
+               }
+               .fn:hover .foot {
+                               /*color: green;*/
+                               visibility: hidden;
+               }
+               .foot:target {
+                               visibility: hidden;
+               }
+               pre {
+                               width: 80%;
+                               margin: 0 auto;
+               }
+               figure {
+                               width: 70%;
+                               margin: 0 auto;
+               }
+               blockquote {
+                               width: 70%;
+                               margin: 0 auto;
+                               padding-bottom: 4px;
+               }
+       
+}
index adc1da6760725562983677403c03fbf338381d80..840eac5a0e33a41b76cf27a548a096b07959cd6f 100644 (file)
@@ -248,6 +248,8 @@ char* lookup_builtin(Sexpr* b) {
                        return META_PARSE_STR;
                case META_GETARGS:
                        return META_GETARGS_STR;
+               case META_LOOKUP:
+                       return META_LOOKUP_STR;
                case META_GETENV:
                        return META_GETENV_STR;
                case META_SETENV:
index cf8ed886d33e27081f690990c48cbb101846afc1..15ce7d74277a5f2e482ced537c39c17b09187c75 100644 (file)
@@ -90,6 +90,16 @@ Sexpr* m_getargs(Sexpr* b, Sexpr* rest, Sexpr* env) {
        return cons(from_quote(args), rest);
 }
 
+Sexpr* m_lookup(Sexpr* b, Sexpr* rest, Sexpr* env) {
+       if(META_LOOKUP_ARGS != u64_get_num_args(b)) {
+               return cons(b, rest);
+       }
+       Sexpr* args = b->value.b.args;
+       Sexpr* lookedup = lookup(env, car(args));
+       sexpr_free(b);
+       return cons(from_quote(lookedup), rest);
+}
+
 Sexpr* m_getenv(Sexpr* b, Sexpr* rest, Sexpr* env) {
        // lol what kind of argument would even be appropriate here?
        // maybe i should just only accept t, to limit misuse (lol)
@@ -145,6 +155,8 @@ Sexpr* x_meta_dispatch(Sexpr* b, Sexpr* rest, Sexpr* env) {
                return m_parse(b, rest, env);
        case META_GETARGS:
                return m_getargs(b, rest, env);
+       case META_LOOKUP:
+               return m_lookup(b, rest, env);
        case META_GETENV:
                return m_getenv(b, rest, env);
        case META_SETENV:
@@ -161,6 +173,7 @@ Sexpr* load_meta_env(Sexpr* env) {
        load_builtin(META_BTOU_STR, (META_PREFIX << 8) | META_BTOU, env);
        load_builtin(META_PARSE_STR, (META_PREFIX << 8) | META_PARSE, env);
        load_builtin(META_GETARGS_STR, (META_PREFIX << 8) | META_GETARGS, env);
+       load_builtin(META_LOOKUP_STR, (META_PREFIX << 8) | META_LOOKUP, env);
        load_builtin(META_GETENV_STR, (META_PREFIX << 8) | META_GETENV, env);
        load_builtin(META_SETENV_STR, (META_PREFIX << 8) | META_SETENV, env);
 
index 070c3183c821a47e47d0aeb18868f42c88d12c34..7539ee3a66252d5c0d7a827cdb218cf871ab375d 100644 (file)
 #define META_GETARGS 0x03
 #define META_GETARGS_ARGS 1
 #define META_GETARGS_STR "getargs"
-#define META_GETENV 0x04
+#define META_LOOKUP 0x04
+#define META_LOOKUP_ARGS 1
+#define META_LOOKUP_STR "lookup"
+#define META_GETENV 0x05
 #define META_GETENV_ARGS 1
 #define META_GETENV_STR "getenv"
-#define META_SETENV 0x05
+#define META_SETENV 0x06
 #define META_SETENV_ARGS 1
 #define META_SETENV_STR "setenv"
 
index d1c79408c6a8a6de565a4c2b9c463a349e7c6b6c..fab25e01098764ea1346d5ed877f52616d2f6528 100644 (file)
@@ -48,7 +48,7 @@ int main(int argc, char** argv) {
        
        char* input = NULL;
        while(1) {
-               input = readline("> ");
+               input = readline(" ");
                if(input == NULL)
                        return 0;
                add_history(input);
@@ -67,7 +67,7 @@ int main(int argc, char** argv) {
                        //printf("- -%s\n", sprint_sexpr(in));
                        Sexpr* out = eval(clone(in), env);
                        char* outstr = sprint_sexpr(out);
-                       PRINTMV(" - ", outstr);
+                       PRINTMV("  ", outstr);
                        //printf(" - %s\n", outstr);
                        sexpr_free(in);
                        sexpr_free(out);
index 817882b3f0cbfc9fab5b3d08faf87f0f4f06a73c..ecbf8fae949a00063ec4cbbe519fe797dcf020d5 100644 (file)
@@ -22,7 +22,7 @@ void assert_eq(Sexpr* env, char* a, char* b) {
                printf("\033[32mpassed\033[0m\n");
        }
        else {
-               printf("\033[1m\033[31mfailed\033[0m\n");
+               printf("\033[1m\033[31mFAILED\033[0m: %s != %s\n", a, b);
        }
        sexpr_free(av);
        sexpr_free(bv);
@@ -33,13 +33,13 @@ void assert_eq(Sexpr* env, char* a, char* b) {
 }
 
 void run_eval_test(char* str) {
-       printf("<- %s\n", str);
+       printf(" %s\n", str);
        Sexpr* env = init_dict();
        env = load_env(env);
        Sexpr* parsed = parse(str);
        Sexpr* val = eval(parsed, env);
        char* out = sprint_sexpr(val);
-       printf(" -> %s\n", out);
+       printf("  %s\n", out);
        free(out);
        //sexpr_free(parsed);
        sexpr_free(val);
@@ -458,7 +458,7 @@ void run_tests(){
        //isolating_problem();
        //test_string_parsing();
        eval_tests();
-       //many_asserts();
+       many_asserts();
        //memtest_eval();
        //mem_testing();
        //mem_parser();
index 3226da49d849e48ccb08fca6427a1b135e2bd1bc..c2d5282851d37d4440eb8ef97b8513bba403bd8d 100644 (file)
                <script type='text/javascript'>
                        var Module = {
                                        print: (function() {
-                                                       var element = document.getElementById('output');
+                                                       var element = document.getElementById('replout');
                                                        if (element) element.textContent = 'loading...';
                                                        return (...args) => {
                                                                        var text = args.join(' ');
                                                                        console.log(text);
                                                                        if (element) {
-                                                                                       element.textContent += text + "\n";
+                                                                                       let printelt = document.createElement('div');
+                                                                                       printelt.textContent += text + "\n";
+                                                                                       element.appendChild(printelt);
                                                                        }
                                                        };
                                        })(),
                        document.getElementById("replform").addEventListener("submit", e => {
                                        e.preventDefault();
                                        let outzone = document.getElementById("replout");
-                                       let newelt = document.createElement('div');
                                        let inelt = document.createElement('div');
                                        let input = e.target[0].value
                                        inelt.textContent += "<- " + input + "\n"
+                                       outzone.appendChild(inelt);
                                        let outelt = document.createElement('div');
                                        let output = Module.ccall("ems_eval", 'string', ['string'], [input])
                                        outelt.textContent += " -> " + output + "\n"
-                                       newelt.appendChild(inelt);
-                                       newelt.appendChild(outelt);
-                                       outzone.appendChild(newelt);
+                                       outzone.appendChild(outelt);
                                        document.getElementById('replin').value = ""
                        });
                        </script>