<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>Mu - edit/005-sandbox.mu</title>
<meta name="Generator" content="Vim/7.4">
<meta name="plugin-version" content="vim7.4_v2">
<meta name="syntax" content="none">
<meta name="settings" content="number_lines,use_css,pre_wrap,no_foldcolumn,expand_tabs,line_ids,prevent_copy=">
<meta name="colorscheme" content="minimal">
<style type="text/css">
<!--
pre { white-space: pre-wrap; font-family: monospace; color: #aaaaaa; background-color: #080808; }
body { font-size: 12pt; font-family: monospace; color: #aaaaaa; background-color: #080808; }
a { color:#eeeeee; text-decoration: none; }
a:hover { text-decoration: underline; }
* { font-size: 12pt; font-size: 1em; }
.muRecipe { color: #ff8700; }
.muScenario { color: #00af00; }
.Special { color: #c00000; }
.Conceal { color: #4e4e4e; }
.Delimiter { color: #800080; }
.SalientComment { color: #00ffff; }
.Constant { color: #00a0a0; }
.LineNr { color: #444444; }
.Comment { color: #9090ff; }
.Comment a { color:#0000ee; text-decoration:underline; }
.muControl { color: #c0a020; }
.muData { color: #ffff00; }
-->
</style>
<script type='text/javascript'>
<!--
/* function to open any folds containing a jumped-to line before jumping to it */
function JumpToLine()
{
var lineNum;
lineNum = window.location.hash;
lineNum = lineNum.substr(1); /* strip off '#' */
if (lineNum.indexOf('L') == -1) {
lineNum = 'L'+lineNum;
}
lineElem = document.getElementById(lineNum);
/* Always jump to new location even if the line was hidden inside a fold, or
* we corrected the raw number to a line ID.
*/
if (lineElem) {
lineElem.scrollIntoView(true);
}
return true;
}
if ('onhashchange' in window) {
window.onhashchange = JumpToLine;
}
-->
</script>
</head>
<body onload='JumpToLine();'>
<pre id='vimCodeElement'>
<span id="L1" class="LineNr"> 1 </span><span class="SalientComment">## running code from the editor and creating sandboxes</span>
<span id="L2" class="LineNr"> 2 </span><span class="Comment">#</span>
<span id="L3" class="LineNr"> 3 </span><span class="Comment"># Running code in the sandbox editor prepends its contents to a list of</span>
<span id="L4" class="LineNr"> 4 </span><span class="Comment"># (non-editable) sandboxes below the editor, showing the result and maybe a</span>
<span id="L5" class="LineNr"> 5 </span><span class="Comment"># few other things (later layers).</span>
<span id="L6" class="LineNr"> 6 </span><span class="Comment">#</span>
<span id="L7" class="LineNr"> 7 </span><span class="Comment"># This layer draws the menubar buttons in non-editable sandboxes but they</span>
<span id="L8" class="LineNr"> 8 </span><span class="Comment"># don't do anything yet. Later layers implement each button.</span>
<span id="L9" class="LineNr"> 9 </span>
<span id="L10" class="LineNr"> 10 </span><span class="muRecipe">def!</span> main [
<span id="L11" class="LineNr"> 11 </span> <span class="Constant">local-scope</span>
<span id="L12" class="LineNr"> 12 </span> open-console
<span id="L13" class="LineNr"> 13 </span> <a href='../081print.mu.html#L33'>clear-screen</a> <span class="Constant">0/screen</span> <span class="Comment"># non-scrolling app</span>
<span id="L14" class="LineNr"> 14 </span> env:&:environment <span class="Special"><-</span> <a href='004-programming-environment.mu.html#L21'>new-programming-environment</a> <span class="Constant">0/filesystem</span>, <span class="Constant">0/screen</span>
<span id="L15" class="LineNr"> 15 </span> env <span class="Special"><-</span> <a href='005-sandbox.mu.html#L440'>restore-sandboxes</a> env
<span id="L16" class="LineNr"> 16 </span> <a href='004-programming-environment.mu.html#L393'>render-all</a> <span class="Constant">0/screen</span>, env, <a href='001-editor.mu.html#L122'>render</a>
<span id="L17" class="LineNr"> 17 </span> <a href='004-programming-environment.mu.html#L39'>event-loop</a> <span class="Constant">0/screen</span>, <span class="Constant">0/console</span>, env, <span class="Constant">0/filesystem</span>
<span id="L18" class="LineNr"> 18 </span>]
<span id="L19" class="LineNr"> 19 </span>
<span id="L20" class="LineNr"> 20 </span><span class="muData">container</span> environment [
<span id="L21" class="LineNr"> 21 </span> sandbox:&:sandbox <span class="Comment"># list of sandboxes, from top to bottom. TODO: switch to &:list:sandbox</span>
<span id="L22" class="LineNr"> 22 </span> render-from:num
<span id="L23" class="LineNr"> 23 </span> number-of-sandboxes:num
<span id="L24" class="LineNr"> 24 </span>]
<span id="L25" class="LineNr"> 25 </span>
<span id="L26" class="LineNr"> 26 </span><span class="muRecipe">after</span> <span class="Constant"><a href='004-programming-environment.mu.html#L36'><programming-environment-initialization></a></span> [
<span id="L27" class="LineNr"> 27 </span> *result <span class="Special"><-</span> put *result, <span class="Constant">render-from:offset</span>,<span class="Constant"> -1</span>
<span id="L28" class="LineNr"> 28 </span>]
<span id="L29" class="LineNr"> 29 </span>
<span id="L30" class="LineNr"> 30 </span><span class="muData">container</span> sandbox [
<span id="L31" class="LineNr"> 31 </span> data:text
<span id="L32" class="LineNr"> 32 </span> response:text
<span id="L33" class="LineNr"> 33 </span> <span class="Comment"># coordinates to track clicks</span>
<span id="L34" class="LineNr"> 34 </span> <span class="Comment"># constraint: will be 0 for sandboxes at positions before env.render-from</span>
<span id="L35" class="LineNr"> 35 </span> starting-row-on-screen:num
<span id="L36" class="LineNr"> 36 </span> code-ending-row-on-screen:num <span class="Comment"># past end of code</span>
<span id="L37" class="LineNr"> 37 </span> <a href='../081print.mu.html#L4'>screen</a>:&:<a href='../081print.mu.html#L4'>screen</a> <span class="Comment"># prints in the sandbox go here</span>
<span id="L38" class="LineNr"> 38 </span> next-sandbox:&:sandbox
<span id="L39" class="LineNr"> 39 </span>]
<span id="L40" class="LineNr"> 40 </span>
<span id="L41" class="LineNr"> 41 </span><span class="muScenario">scenario</span> run-and-show-results [
<span id="L42" class="LineNr"> 42 </span> <span class="Constant">local-scope</span>
<span id="L43" class="LineNr"> 43 </span> trace-until <span class="Constant">100/app</span> <span class="Comment"># trace too long</span>
<span id="L44" class="LineNr"> 44 </span> assume-screen <span class="Constant">100/width</span>, <span class="Constant">15/height</span>
<span id="L45" class="LineNr"> 45 </span> <span class="Comment"># recipe editor is empty</span>
<span id="L46" class="LineNr"> 46 </span> assume-resources [
<span id="L47" class="LineNr"> 47 </span> ]
<span id="L48" class="LineNr"> 48 </span> <span class="Comment"># sandbox editor contains an instruction without storing outputs</span>
<span id="L49" class="LineNr"> 49 </span> env:&:environment <span class="Special"><-</span> <a href='004-programming-environment.mu.html#L21'>new-programming-environment</a> <a href='../088file.mu.html#L11'>resources</a>, <a href='../081print.mu.html#L4'>screen</a>, <span class="Constant">[divide-with-remainder 11, 3]</span>
<span id="L50" class="LineNr"> 50 </span> <span class="Comment"># run the code in the editors</span>
<span id="L51" class="LineNr"> 51 </span> assume-console [
<span id="L52" class="LineNr"> 52 </span> <span class="Conceal">¦</span> press F4
<span id="L53" class="LineNr"> 53 </span> ]
<span id="L54" class="LineNr"> 54 </span> run [
<span id="L55" class="LineNr"> 55 </span> <span class="Conceal">¦</span> <a href='004-programming-environment.mu.html#L39'>event-loop</a> <a href='../081print.mu.html#L4'>screen</a>, <a href='../084console.mu.html#L23'>console</a>, env, <a href='../088file.mu.html#L11'>resources</a>
<span id="L56" class="LineNr"> 56 </span> ]
<span id="L57" class="LineNr"> 57 </span> <span class="Comment"># check that screen prints the results</span>
<span id="L58" class="LineNr"> 58 </span> screen-should-contain [
<span id="L59" class="LineNr"> 59 </span> <span class="Conceal">¦</span><span class="Constant"> . run (F4) .</span>
<span id="L60" class="LineNr"> 60 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎ .</span>
<span id="L61" class="LineNr"> 61 </span><span class="Constant"> </span><span class="Conceal">¦</span><span class="Constant"> .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.</span>
<span id="L62" class="LineNr"> 62 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎0 edit copy delete .</span>
<span id="L63" class="LineNr"> 63 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎divide-with-remainder 11, 3 .</span>
<span id="L64" class="LineNr"> 64 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎3 .</span>
<span id="L65" class="LineNr"> 65 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎2 .</span>
<span id="L66" class="LineNr"> 66 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎─────────────────────────────────────────────────.</span>
<span id="L67" class="LineNr"> 67 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎ .</span>
<span id="L68" class="LineNr"> 68 </span> ]
<span id="L69" class="LineNr"> 69 </span> screen-should-contain-in-color <span class="Constant">7/white</span>, [
<span id="L70" class="LineNr"> 70 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L71" class="LineNr"> 71 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L72" class="LineNr"> 72 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L73" class="LineNr"> 73 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L74" class="LineNr"> 74 </span> <span class="Conceal">¦</span><span class="Constant"> . divide-with-remainder 11, 3 .</span>
<span id="L75" class="LineNr"> 75 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L76" class="LineNr"> 76 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L77" class="LineNr"> 77 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L78" class="LineNr"> 78 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L79" class="LineNr"> 79 </span> ]
<span id="L80" class="LineNr"> 80 </span> screen-should-contain-in-color <span class="Constant">245/grey</span>, [
<span id="L81" class="LineNr"> 81 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L82" class="LineNr"> 82 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎ .</span>
<span id="L83" class="LineNr"> 83 </span><span class="Constant"> </span><span class="Conceal">¦</span><span class="Constant"> .╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╎─────────────────────────────────────────────────.</span>
<span id="L84" class="LineNr"> 84 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎ .</span>
<span id="L85" class="LineNr"> 85 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎ .</span>
<span id="L86" class="LineNr"> 86 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎3 .</span>
<span id="L87" class="LineNr"> 87 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎2 .</span>
<span id="L88" class="LineNr"> 88 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎─────────────────────────────────────────────────.</span>
<span id="L89" class="LineNr"> 89 </span> <span class="Conceal">¦</span><span class="Constant"> . ╎ .</span>
<span id="L90" class="LineNr"> 90 </span> ]
<span id="L91" class="LineNr"> 91 </span> <span class="Comment"># sandbox menu in reverse video</span>
<span id="L92" class="LineNr"> 92 </span> screen-should-contain-in-color <span class="Constant">232/black</span>, [
<span id="L93" class="LineNr"> 93 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L94" class="LineNr"> 94 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L95" class="LineNr"> 95 </span> <span class="Conceal">¦</span><span class="Constant"> . .</span>
<span id="L96" class="LineNr"> 96 </span> <span class="Conceal">¦</span><span class="Constant"> . 0 edit copy delete .</span>
<span id="L97" class="LineNr"> 97 </span> ]
<span id="L98" class="LineNr"> 98 </span> <span class="Comment"># run another command</span>
<span id="L99" class="LineNr"> 99 </span> assume-console [
<span id="L100" class="LineNr"> 100 </span> <span class="Conceal">¦</span> left-click<span class="Constant"> 1</spanpre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight .c { color: #888888 } /* Comment */
.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */
.highlight .k { color: #008800; font-weight: bold } /* Keyword */
.highlight .ch { color: #888888 } /* Comment.Hashbang */
.highlight .cm { color: #888888 } /* Comment.Multiline */
.highlight .cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
.highlight .cpf { color: #888888 } /* Comment.PreprocFile */
.highlight .c1 { color: #888888 } /* Comment.Single */
.highlight .cs { color: #cc0000; font-weight: bold; background-color: #fff0f0 } /* Comment.Special */
.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .ges { font-weight: bold; font-style: italic } /* Generic.EmphStrong */
.highlight .gr { color: #aa0000 } /* Generic.Error */
.highlight .gh { color: #333333 } /* Generic.Heading */
.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
.highlight .go { color: #888888 } /* Generic.Output */
.highlight .gp { color: #555555 } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #666666 } /* Generic.Subheading */
.highlight .gt { color: #aa0000 } /* Generic.Traceback */
.highlight .kc { color: #008800; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008800; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008800; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008800 } /* Keyword.Pseudo */
.highlight .kr { color: #008800; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #888888; font-weight: bold } /* Keyword.Type */
.highlight .m { color: #0000DD; font-weight: bold } /* Literal.Number */
.highlight .s { color: #dd2200; background-color: #fff0f0 } /* Literal.String */
.highlight .na { color: #336699 } /* Name.Attribute */
.highlight .nb { color: #003388 } /* Name.Builtin */
.highlight .nc { color: #bb0066; font-weight: bold } /* Name.Class */
.highlight .no { color: #003366; font-weight: bold } /* Name.Constant */
.highlight .nd { color: #555555 } /* Name.Decorator */
.highlight .ne { color: #bb0066; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0066bb; font-weight: bold } /* Name.Function */
.highlight .nl { color: #336699; font-style: italic } /* Name.Label */
.highlight .nn { color: #bb0066; font-weight: bold } /* Name.Namespace */
.highlight .py { color: #336699; font-weight: bold } /* Name.Property */
.highlight .nt { color: #bb0066; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #336699 } /* Name.Variable */
.highlight .ow { color: #008800 } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #0000DD; font-weight: bold } /* Literal.Number.Bin */
.highlight .mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
.highlight .mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
.highlight .mi { color: #0000DD; font-weight: bold } /* Literal.Number.Integer */
.highlight .mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
.highlight .sa { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Affix */
.highlight .sb { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Backtick */
.highlight .sc { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Char */
.highlight .dl { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Delimiter */
.highlight .sd { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Doc */
.highlight .s2 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Double */
.highlight .se { color: #0044dd; background-color: #fff0f0 } /* Literal.String.Escape */
.highlight .sh { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Heredoc */
.highlight .si { color: #3333bb; background-color: #fff0f0 } /* Literal.String.Interpol */
.highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */
.highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */
.highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */
.highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */
.highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */
.highlight .vc { color: #336699 } /* Name.Variable.Class */
.highlight .vg { color: #dd7700 } /* Name.Variable.Global */
.highlight .vi { color: #3333bb } /* Name.Variable.Instance */
.highlight .vm { color: #336699 } /* Name.Variable.Magic */
.highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */== code
# instruction effective address register displacement immediate
# . op subop mod rm32 base index scale r32
# . 1-3 bytes 3 bits 2 bits 3 bits 3 bits 3 bits 2 bits 2 bits 0/1/2/4 bytes 0/1/2/4 bytes
# read bytes from 'f' until (and including) a newline and store them into 's'
# 's' fails to grow if and only if no data found
# just abort if 's' is too small
read-line-buffered: # f: (addr buffered-file), s: (addr stream byte)
# pseudocode:
# while true
# if (s->write >= s->size) abort
# if (f->read >= f->write) populate stream from file
# if (f->write == 0) break
# AL = f->data[f->read]
# s->data[s->write] = AL
# ++f->read
# ++s->write
# if (AL == '\n') break
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
56/push-esi
57/push-edi
# esi = f
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
# ecx = f->read
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # copy *(esi+8) to ecx
# edi = s
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
# edx = s->write
8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx
$read-line-buffered:loop:
# if (s->write >= s->size) abort
3b/compare 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # compare edx with *(edi+8)
7d/jump-if->= $read-line-buffered:abort/disp8
# if (f->read >= f->write) populate stream from file
3b/compare 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # compare ecx with *(esi+4)
7c/jump-if-< $read-line-buffered:from-stream/disp8
# . clear-stream(stream = f+4)
# . . push args
8d/copy-address 1/mod/*+disp8 6/rm32/esi . . . 0/r32/eax 4/disp8 . # copy esi+4 to eax
50/push-eax
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . f->read must now be 0; update its cache at ecx
31/xor 3/mod/direct 1/rm32/ecx . . . 1/r32/ecx . . # clear ecx
# . eax = read(f->fd, stream = f+4)
# . . push args
50/push-eax
ff 6/subop/push 0/mod/indirect 6/rm32/esi . . . . . . # push *esi
# . . call
e8/call read/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# if (f->write == 0) break
# since f->read was initially 0, eax is the same as f->write
# . if (eax == 0) return true
3d/compare-eax-and 0/imm32
74/jump-if-= $read-line-buffered:end/disp8
$read-line-buffered:from-stream:
# AL = f->data[f->read]
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0x10/disp8 . # copy byte at *(esi+ecx+16) to AL
# s->data[s->write] = AL
88/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 0/r32/AL 0xc/disp8 . # copy AL to *(edi+edx+12)
# ++f->read
41/increment-ecx
# ++s->write
42/increment-edx
# if (AL == '\n') return
3d/compare-eax-and 0xa/imm32/newline
75/jump-if-!= $read-line-buffered:loop/disp8
$read-line-buffered:end:
# save f->read
89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 8/disp8 . # copy ecx to *(esi+8)
# save s->write
89/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy edx to *edi
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
$read-line-buffered:abort:
# . _write(2/stderr, error)
# . . push args
68/push "read-line-buffered: line too long\n"/imm32
68/push 2/imm32/stderr
# . . call
e8/call _write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . syscall(exit, 1)
bb/copy-to-ebx 1/imm32
e8/call syscall_exit/disp32
# never gets here
test-read-line-buffered:
# - check that read-line-buffered stops at a newline
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . clear-stream($_test-buffered-file->buffer)
# . . push args
68/push $_test-buffered-file->buffer/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . clear-stream(_test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "ab\ncd")
# . . push args
68/push "ab\ncd"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# read a line from _test-stream (buffered by _test-buffered-file) into _test-tmp-stream
# . eax = read-line-buffered(_test-buffered-file, _test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
68/push _test-buffered-file/imm32
# . . call
e8/call read-line-buffered/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-next-stream-line-equal(_test-tmp-stream, "ab", msg)
# . . push args
68/push "F - test-read-line-buffered"/imm32
68/push "ab"/imm32
68/push _test-tmp-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# end
c3/return
test-read-line-buffered-reads-final-line-until-Eof:
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . clear-stream($_test-buffered-file->buffer)
# . . push args
68/push $_test-buffered-file->buffer/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . clear-stream(_test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "cd")
# . . push args
68/push "cd"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# read a line from _test-stream (buffered by _test-buffered-file) into _test-tmp-stream
# . eax = read-line-buffered(_test-buffered-file, _test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
68/push _test-buffered-file/imm32
# . . call
e8/call read-line-buffered/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-stream-equal(_test-tmp-stream, "cd", msg)
# . . push args
68/push "F - test-read-line-buffered-reads-final-line-until-Eof"/imm32
68/push "cd"/imm32
68/push _test-tmp-stream/imm32
# . . call
e8/call check-stream-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# end
c3/return
# read bytes from 'f' until (and including) a newline and store them into 's'
# 's' fails to grow if and only if no data found
# just abort if 's' is too small
read-line: # f: (addr stream byte), s: (addr stream byte)
# pseudocode:
# while true
# if (s->write >= s->size) abort
# if (f->read >= f->write) break
# AL = f->data[f->read]
# s->data[s->write] = AL
# ++f->read
# ++s->write
# if (AL == '\n') break
# . prologue
55/push-ebp
89/copy 3/mod/direct 5/rm32/ebp . . . 4/r32/esp . . # copy esp to ebp
# . save registers
50/push-eax
51/push-ecx
52/push-edx
56/push-esi
57/push-edi
# esi = f
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 6/r32/esi 8/disp8 . # copy *(ebp+8) to esi
# ecx = f->read
8b/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy *(esi+4) to ecx
# edi = s
8b/copy 1/mod/*+disp8 5/rm32/ebp . . . 7/r32/edi 0xc/disp8 . # copy *(ebp+12) to edi
# edx = s->write
8b/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy *edi to edx
$read-line:loop:
# if (s->write >= s->size) abort
3b/compare 1/mod/*+disp8 7/rm32/edi . . . 2/r32/edx 8/disp8 . # compare edx with *(edi+8)
0f 8d/jump-if->= $read-line:abort/disp32
# if (f->read >= f->write) break
3b/compare 0/mod/indirect 6/rm32/esi . . . 1/r32/ecx . . # compare ecx with *esi
7d/jump-if->= $read-line:end/disp8
# AL = f->data[f->read]
31/xor 3/mod/direct 0/rm32/eax . . . 0/r32/eax . . # clear eax
8a/copy-byte 1/mod/*+disp8 4/rm32/sib 6/base/esi 1/index/ecx . 0/r32/AL 0xc/disp8 . # copy byte at *(esi+ecx+12) to AL
# s->data[s->write] = AL
88/copy-byte 1/mod/*+disp8 4/rm32/sib 7/base/edi 2/index/edx . 0/r32/AL 0xc/disp8 . # copy AL to *(edi+edx+12)
# ++f->read
41/increment-ecx
# ++s->write
42/increment-edx
# if (AL == '\n') return
3d/compare-eax-and 0xa/imm32/newline
0f 85/jump-if-!= $read-line:loop/disp32
$read-line:end:
# save f->read
89/copy 1/mod/*+disp8 6/rm32/esi . . . 1/r32/ecx 4/disp8 . # copy ecx to *(esi+4)
# save s->write
89/copy 0/mod/indirect 7/rm32/edi . . . 2/r32/edx . . # copy edx to *edi
# . restore registers
5f/pop-to-edi
5e/pop-to-esi
5a/pop-to-edx
59/pop-to-ecx
58/pop-to-eax
# . epilogue
89/copy 3/mod/direct 4/rm32/esp . . . 5/r32/ebp . . # copy ebp to esp
5d/pop-to-ebp
c3/return
$read-line:abort:
# . _write(2/stderr, error)
# . . push args
68/push "read-line: line too long\n"/imm32
68/push 2/imm32/stderr
# . . call
e8/call _write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# . syscall(exit, 1)
bb/copy-to-ebx 1/imm32
e8/call syscall_exit/disp32
# never gets here
test-read-line:
# - check that read-line stops at a newline
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . clear-stream(_test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "ab\ncd")
# . . push args
68/push "ab\ncd"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# read a line from _test-stream into _test-tmp-stream
# . eax = read-line(_test-stream, _test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
68/push _test-stream/imm32
# . . call
e8/call read-line/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-next-stream-line-equal(_test-tmp-stream, "ab", msg)
# . . push args
68/push "F - test-read-line"/imm32
68/push "ab"/imm32
68/push _test-tmp-stream/imm32
# . . call
e8/call check-next-stream-line-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# end
c3/return
test-read-line-reads-final-line-until-Eof:
# setup
# . clear-stream(_test-stream)
# . . push args
68/push _test-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# . clear-stream(_test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
# . . call
e8/call clear-stream/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 4/imm32 # add to esp
# write(_test-stream, "cd")
# . . push args
68/push "cd"/imm32
68/push _test-stream/imm32
# . . call
e8/call write/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# read a line from _test-stream into _test-tmp-stream
# . eax = read-line(_test-stream, _test-tmp-stream)
# . . push args
68/push _test-tmp-stream/imm32
68/push _test-stream/imm32
# . . call
e8/call read-line/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 8/imm32 # add to esp
# check-stream-equal(_test-tmp-stream, "cd", msg)
# . . push args
68/push "F - test-read-line-reads-final-line-until-Eof"/imm32
68/push "cd"/imm32
68/push _test-tmp-stream/imm32
# . . call
e8/call check-stream-equal/disp32
# . . discard args
81 0/subop/add 3/mod/direct 4/rm32/esp . . . . . 0xc/imm32 # add to esp
# end
c3/return
# . . vim:nowrap:textwidth=0