1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-11 13:55:55 +03:00
mal/docs/cheatsheet.html
Nicolas Boulenguez 26ced15b31 Remove gensym, inc and or from step files.
* Move `gensym` and `inc` from step files to `lib/trivial.mal`.
* Move `or` from step files to `lib/test_cascade.mal`.
  Shorten it because `(first ())` returns `nil`
* Update process and tests accordingly (not the figures yet).
2019-07-09 14:05:29 +02:00

258 lines
16 KiB
HTML

<html>
<head>
<style>
h2 {
text-align: center;
}
table {
font-size: 11px;
border-width: 0px;
border-collapse: collapse;
}
table tr {
border: none;
}
table td,th {
border-left: solid 1px #008;
}
table td:first-child, th:first-child {
border-left: none;
}
table td {
vertical-align: top;
padding: 2px;
}
pre {
background: #FCFCF9;
padding: 3px;
border-width: 1px;
border-style: solid;
border-color: lightgrey;
}
.file {
font-weight: 700;
color: #338833;
}
.var {
font-weight: 700;
color: #BB8855;
}
.function {
font-weight: 700;
color: #887744;
}
.object {
font-weight: 700;
color: #DD7744;
}
.malsym {
font-weight: 600;
color: #883333;
}
.string {
font-weight: 400;
color: #994444;
}
</style>
</head>
<body>
<h2>Make-A-Lisp Cheatsheet</h2>
<table align=left>
<tr>
<th>Step 1</th> <th>Step 6</th>
<tr>
<td width=50%>
<!--
<pre><code><span class=file>step0_repl.EXT</span>:
<span class=function>READ</span></span>(<span class=var>ast</span>): passthrough <span class=var>ast</span>
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>): passthrough <span class=var>ast</span>
<span class=function>PRINT</span>(<span class=var>ast</span>): passthrough <span class=var>ast</span>
<span class=function>main</span>(<span class=var>args</span>): loop: <span class=function>writeline</span> <span class=function>PRINT</span>(<span class=function>EVAL</span>(<span class=function>READ</span>(<span class=function>readline</span>()), <span class=string>""</span>))
</code></pre>
-->
<pre><code><span class=file>reader.EXT</span>:
<span class=object>Reader</span>(<span class=var>tokens</span>) object: <span class=var>position</span>, <span class=function>next</span>(), <span class=function>peek</span>()
<span class=function>tokenize</span>: <span class=string>/[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/</span>
<span class=function>read_atom</span>: int, float, string (escaped), keyword, nil, true, false, symbol
<span class=function>read_list</span>: repeatedly <span class=function>read_form</span> until end token (<span class=object>EOF</span> is error)
<span class=function>read_form</span>: expand reader macros, <span class=function>read_list</span> (vector/maps too), or <span class=function>read_atom</span>
<span class=function>read_str</span>: <span class=function>tokenize</span>, error if no tokens, call <span class=function>read_form</span>(<span class=object>Reader</span>(<span class=var>tokens</span>))
<span class=file>printer.EXT</span>:
<span class=function>pr_str</span>(<span class=var>ast</span>, <span class=var>print_readably</span>):
- map <span class=function>pr_str</span> across collections
- unescape strings if <span class=var>print_readably</span>
<span class=file>step1_read_print.EXT</span>:
<span class=function>main</span>(<span class=var>args</span>): loop: <span class=function>writeline</span> <span class=function>PRINT</span>(<span class=function>EVAL</span>(<span class=function>READ</span>(<span class=function>readline</span>()), <span class=string>""</span>))
</code></pre>
</td>
<td width=50%>
<pre><code><span class=file>core.EXT</span>:
<span class=function>read-string</span>: call <span class=function>reader.read_str</span>
<span class=function>slurp</span>: return file content as a string
<span class=function>atom</span>, <span class=function>atom?</span>, <span class=function>deref</span>, <span class=function>reset!</span>, <span class=function>swap!</span>: atom functions
<span class=file>step6_file.EXT</span>:
<span class=function>main</span>(<span class=var>args</span>):
- add <span class=malsym>eval</span> and <span class=malsym>*ARGV*</span> to <span class=var>repl_env</span>
- define <span class=malsym>load-file</span> using <span class=function>rep</span>
- if <span class=var>args</span>, set <span class=malsym>*ARGV*</span> to rest(<span class=var>args</span>) and call <span class=malsym>load-file</span> with <span class=var>arg</span>s[0]
</code></pre>
</td>
<tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<tr>
<th>Step 2</th> <th>Step 7</th>
<tr>
<td width=50%>
<pre><code><span class=file>step2_eval.EXT</span>:
<span class=function>eval_ast</span>(<span class=var>ast</span>, <span class=var>env</span>): lookup symbols in <span class=var>env</span>, map <span class=function>EVAL</span> across collections
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- if not list?(<span class=var>ast</span>), return <span class=function>eval_ast</span>(<span class=var>ast</span>, <span class=var>env</span>)
- otherwise apply (<span class=var>ast</span> is a list):
<span class=var>el</span> = <span class=function>eval_ast</span>(<span class=var>ast</span>, <span class=var>env</span>)
return <span class=var>el</span>[0](rest(<span class=var>el</span>))
<span class=function>main</span>(<span class=var>args</span>): loop: <span class=function>writeline</span> <span class=function>PRINT</span>(<span class=function>EVAL</span>(<span class=function>READ</span>(<span class=function>readline</span>()), {<span class=malsym>+</span>: <span class=function>add</span>, ...}))
</code></pre>
</td>
<td width=50%>
<pre><code><span class=file>core.EXT</span>:
<span class=function>cons</span>, <span class=function>concat</span>: sequence functions
<span class=file>step7_quote.EXT</span>:
<span class=function>quasiquote</span>(ast):
- <span class=var>ast</span> is empty or not a list -> (<span class=malsym>quote</span> <span class=var>ast</span>)
- (<span class=malsym>unquote</span> FOO) -> FOO
- ((<span class=malsym>splice-unquote</span> FOO) BAR..) -> (<span class=malsym>concat</span> FOO <span class=function>quasiquote</span>(BAR...))</span>
- (FOO BAR...) -> (<span class=malsym>cons</span> FOO <span class=function>quasiquote</span>(BAR...))</span>
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- <span class=malsym>quote</span> -> return <span class=var>ast</span>[1]
- <span class=malsym>quasiquote</span> -> set <span class=var>ast</span> to <span class=function>quasiquote</span>(<span class=var>ast</span>[1]), loop
</code></pre>
</td>
<tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<tr>
<th>Step 3</th> <th>Step 8</th>
<tr>
<td width=50%>
<pre><code><span class=file>env.EXT</span>:
<span class=object>Env</span>(<span class=var>outer</span>) object: <span class=var>data</span>, <span class=function>set</span>(<span class=var>k</span>, <span class=var>v</span>), <span class=function>find</span>(<span class=var>k</span>), <span class=function>get</span>(<span class=var>k</span>)
<span class=file>step3_env.EXT</span>:
<span class=function>eval_ast</span>(<span class=var>ast</span>, <span class=var>env</span>): switch to <span class=var>env</span>.<span class=function>get</span> for symbol lookup
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- <span class=malsym>def!</span> -> return <span class=var>env</span>.<span class=function>set</span>(<span class=var>ast</span>[1], <span class=function>EVAL</span>(<span class=var>ast</span>[2], <span class=var>env</span>))
- <span class=malsym>let*</span> -> create new env <span class=var>let_env</span>
for each ODD/EVEN pair in <span class=var>ast[1]</span>:
<span class=var>let_env</span>.<span class=function>set</span>(ODD, <span class=function>EVAL</span>(EVEN, <span class=var>let_env</span>))
return <span class=function>EVAL</span>(<span class=var>ast</span>[2], <span class=var>let_env</span>)
<span class=function>main</span>(<span class=var>args</span>): populate <span class=var>repl_env</span> with numeric functions using <span class=var>repl_env</span>.<span class=function>set</span>
</code></pre>
</td>
<td width=50%>
<pre><code><span class=file>core.EXT</span>:
<span class=function>nth</span>, <span class=function>first</span>, <span class=function>rest</span>: sequence functions
<span class=file>step8_macros.EXT</span>:
<span class=function>macroexpand</span>(<span class=var>ast</span>, <span class=var>env</span>):
- while <span class=var>env</span>.<span class=function>get</span>(<span class=var>ast</span>[0]) is a macro: <span class=var>ast</span> = <span class=var>env</span>.<span class=function>get</span>(<span class=var>ast</span>[0])(rest(<span class=var>ast</span>))
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- before apply section, add <span class=var>ast</span> = <span class=function>macroexpand</span>(<span class=var>ast</span>, <span class=var>env</span>)
- <span class=malsym>defmacro!</span> -> same as <span class=malsym>def!</span>, but set mal function macro flag
- <span class=malsym>macroexpand</span> -> return <span class=function>macroexpand</span>(<span class=var>ast</span>[1], <span class=var>env</span>)
</code></pre>
</td>
<tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<tr>
<th>Step 4</th> <th>Step 9</th>
<tr>
<td width=50%>
<pre><code><span class=file>env.EXT</span>:
<span class=object>Env</span>(<span class=var>outer</span>, <span class=var>binds</span>, <span class=var>exprs</span>) object: map <span class=var>binds</span> to <span class=var>exprs</span>, handle <span class=string>"&amp;"</span> as variadic
<span class=file>core.EXT</span>:
<span class=function>=</span>: recursive compare of collections
<span class=function>pr-str</span>, <span class=function>str</span>: return <span class=function>pr_str</span>(<span class=function>arg</span>, true) join <span class=string>" "</span>, <span class=function>pr_str</span>(<span class=function>arg</span>, false) join <span class=string>""</span>
<span class=function>prn</span>, <span class=function>println</span>: print <span class=function>pr_str</span>(<span class=function>arg</span>, true) join <span class=string>""</span>, <span class=function>pr_str</span>(<span class=function>arg</span>, false) join <span class=string>""</span>
<span class=function><</span>, <span class=function><=</span>, <span class=function>></span>, <span class=function>>=</span>, <span class=function>+</span>, <span class=function>-</span>, <span class=function>*</span>, <span class=function>/</span>: numeric comparison and numeric operations
<span class=function>list</span>, <span class=function>list?</span>, <span class=function>empty?</span>, <span class=function>count</span>: sequence functions
<span class=file>step4_do_if_fn.EXT</span>:
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- <span class=malsym>do</span> -> return last element of <span class=function>eval_ast</span>(<span class=var>ast</span>, <span class=var>env</span>)
- <span class=malsym>if</span> -> if <span class=function>EVAL</span>(<span class=var>ast[1]</span>, <span class=var>env</span>): return <span class=function>EVAL</span>(<span class=var>ast[2]</span>, <span class=var>env</span>)
else : return <span class=function>EVAL</span>(<span class=var>ast[3]</span>, <span class=var>env</span>)
- <span class=malsym>fn*</span> -> return closure:
(<span class=var>args</span>) -> <span class=function>EVAL</span>(<span class=var>ast</span>[2], new <span class=object>Env</span>(<span class=var>env</span>, <span class=var>ast</span>[1], <span class=var>args</span>))
<span class=function>main</span>(<span class=var>args</span>): populate <span class=var>repl_env</span> with core functions, define not using <span class=function>rep</span>()
</code></pre>
</td>
<td width=50%>
<pre><code><span class=file>core.EXT</span>:
<span class=function>throw</span>: raise mal value as exception (maybe wrap in native exception)
<span class=function>vector</span>, <span class=function>vector?</span>: sequence functions
<span class=function>hash-map</span>, <span class=function>get</span>, <span class=function>contains?</span>, <span class=function>keys</span>, <span class=function>vals</span>: hash-map functions
<span class=function>assoc</span>, <span class=function>dissoc</span>: immutable hash-map transform functions
<span class=function>apply</span>(<span class=var>f</span>, <span class=var>args...</span>, <span class=var>last</span>): return <span class=function>f</span>(<span class=function>concat</span>(<span class=var>args</span>, <span class=var>last</span>))
<span class=function>map</span>(<span class=var>f</span>, <span class=var>args</span>): return list of mapping <span class=function>f</span> on each <span class=var>args</span>
<span class=file>step9_try.EXT</span>:
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- <span class=malsym>try*</span> -> try <span class=function>EVAL</span>(<span class=var>ast</span>[1], <span class=var>env</span>)
catch exception <span class=var>exc</span> (unwrap if necessary):
new <span class=var>err_env</span> with <span class=var>ast</span>[2][1] symbol bound to <span class=var>exc</span>
<span class=function>EVAL</span>(<span class=var>ast</span>[2][2], <span class=var>err_env</span>)
</code></pre>
</td>
<tr>
<th>&nbsp;</th> <th>&nbsp;</th>
<tr>
<th>Step 5</th> <th>Step A</th>
<tr>
<td width=50%>
<pre><code><span class=file>step5_tco.EXT</span>:
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- top level loop in <span class=function>EVAL</span>
- <span class=malsym>let*</span> -> set <span class=var>env</span> to <span class=var>let_env</span>, set <span class=var>ast</span> to <span class=var>ast</span>[2], loop
- <span class=malsym>do</span> -> <span class=function>eval_ast</span> of middle elements, sets <span class=var>ast</span> to last element, loop
- <span class=malsym>if</span> -> set <span class=var>ast</span> to <span class=var>ast</span>[2] or <span class=var>ast</span>[3] (or <span class=malsym>nil</span>) depending condition, loop
- <span class=malsym>fn*</span> -> return new mal function type <span class=var>f</span> with:
<span class=var>f</span>.<span class=var>ast</span>=<span class=var>ast</span>[2], <span class=var>f</span>.<span class=var>params</span>=<span class=var>ast</span>[1], <span class=var>f</span>.<span class=var>env</span>=<span class=var>env</span>
- apply -> <span class=var>el</span> = <span class=function>eval_ast</span>(<span class=var>ast</span>, <span class=var>env</span>)
<span class=var>f</span> = <span class=var>el</span>[0]
if <span class=var>f</span> is a mal function: <span class=var>ast</span> = <span class=var>f</span>.<span class=var>ast</span> and <span class=var>env</span> = <span class=var>f</span>.<span class=var>env</span>, loop
else : return <span class=var>el</span>[0](rest(<span class=var>el</span>))
</code></pre>
</td>
<td width=50%>
<pre><code><span class=file>core.EXT</span>:
<span class=function>string?</span>: true if string
<span class=function>readline</span>: prompt and read a line of input (synchronous)
<span class=function>time-ms</span>: return milliseconds since epoch (1970-1-1)
<span class=function>conj</span>, <span class=function>seq</span>: type specific sequence functions
<span class=function>meta</span>, <span class=function>with-meta</span>: metadata functions
<span class=file>step9_try.EXT</span>:
<span class=function>EVAL</span>(<span class=var>ast</span>, <span class=var>env</span>):
- set <span class=malsym>*host-language*</span> in <span class=var>repl_env</span> to host language name
<span class=function>main</span>(<span class=var>args</span>): <span class=function>rep</span>(<span class=string>"(println (str \"Mal [\" <span class=malsym>*host-language*</span> \"]\"))"</span>)
</code></pre>
</td>
<tr>
<th>&nbsp;</th> <th>&nbsp;</th>
</table>
</body>
</html>