diff options
Diffstat (limited to 'html/071channel.mu.html')
-rw-r--r-- | html/071channel.mu.html | 387 |
1 files changed, 0 insertions, 387 deletions
diff --git a/html/071channel.mu.html b/html/071channel.mu.html deleted file mode 100644 index 3c5bbc04..00000000 --- a/html/071channel.mu.html +++ /dev/null @@ -1,387 +0,0 @@ -<!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 - 071channel.mu</title> -<meta name="Generator" content="Vim/7.3"> -<meta name="plugin-version" content="vim7.3_v6"> -<meta name="syntax" content="none"> -<meta name="settings" content="use_css"> -<style type="text/css"> -<!-- -pre { font-family: monospace; color: #eeeeee; background-color: #080808; } -body { font-size: 12pt; font-family: monospace; color: #eeeeee; background-color: #080808; } -.SalientComment { color: #00ffff; } -.muControl { color: #c0a020; } -.Delimiter { color: #800080; } -.muRecipe { color: #ff8700; } -.muData { color: #ffff00; } -.Special { color: #c00000; } -.Constant { color: #00a0a0; } -.muScenario { color: #00af00; } -.Comment { color: #9090ff; } ---> -</style> -</head> -<body> -<pre> -<span class="Comment"># Mu synchronizes using channels rather than locks, like Erlang and Go.</span> -<span class="Comment">#</span> -<span class="Comment"># The two ends of a channel will usually belong to different routines, but</span> -<span class="Comment"># each end should only be used by a single one. Don't try to read from or</span> -<span class="Comment"># write to it from multiple routines at once.</span> -<span class="Comment">#</span> -<span class="Comment"># The key property of channels is that writing to a full channel or reading</span> -<span class="Comment"># from an empty one will put the current routine in 'waiting' state until the</span> -<span class="Comment"># operation can be completed.</span> - -<span class="muScenario">scenario</span> channel [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - <span class="Constant">2</span>:character, <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:shared:channel - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">34</span> - ] -] - -<span class="muData">container</span> channel [ - <span class="Comment"># To avoid locking, writer and reader will never write to the same location.</span> - <span class="Comment"># So channels will include fields in pairs, one for the writer and one for the</span> - <span class="Comment"># reader.</span> - first-full:number <span class="Comment"># for write</span> - first-free:number <span class="Comment"># for read</span> - <span class="Comment"># A circular buffer contains values from index first-full up to (but not</span> - <span class="Comment"># including) index first-empty. The reader always modifies it at first-full,</span> - <span class="Comment"># while the writer always modifies it at first-empty.</span> - data:address:shared:array:character -] - -<span class="muRecipe">def</span> new-channel capacity:number<span class="muRecipe"> -> </span>result:address:shared:channel [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - result<span class="Special"> <- </span>new <span class="Constant">channel:type</span> - <span class="Comment"># result.first-full = 0</span> - full:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">first-full:offset</span> - *full<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Comment"># result.first-free = 0</span> - free:address:number<span class="Special"> <- </span>get-address *result, <span class="Constant">first-free:offset</span> - *free<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Comment"># result.data = new location[ingredient+1]</span> - capacity<span class="Special"> <- </span>add capacity, <span class="Constant">1</span> <span class="Comment"># unused slot for 'full?' below</span> - dest:address:address:shared:array:character<span class="Special"> <- </span>get-address *result, <span class="Constant">data:offset</span> - *dest<span class="Special"> <- </span>new <span class="Constant">character:type</span>, capacity -] - -<span class="muRecipe">def</span> write chan:address:shared:channel, val:character<span class="muRecipe"> -> </span>chan:address:shared:channel [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - <span class="Delimiter">{</span> - <span class="Comment"># block if chan is full</span> - full:boolean<span class="Special"> <- </span>channel-full? chan - <span class="muControl">break-unless</span> full - full-address:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-full:offset</span> - wait-for-location *full-address - <span class="Delimiter">}</span> - <span class="Comment"># store val</span> - circular-buffer:address:shared:array:character<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> - free:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-free:offset</span> - dest:address:character<span class="Special"> <- </span>index-address *circular-buffer, *free - *dest<span class="Special"> <- </span>copy val - <span class="Comment"># mark its slot as filled</span> - *free<span class="Special"> <- </span>add *free, <span class="Constant">1</span> - <span class="Delimiter">{</span> - <span class="Comment"># wrap free around to 0 if necessary</span> - len:number<span class="Special"> <- </span>length *circular-buffer - at-end?:boolean<span class="Special"> <- </span>greater-or-equal *free, len - <span class="muControl">break-unless</span> at-end? - *free<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">def</span> read chan:address:shared:channel<span class="muRecipe"> -> </span>result:character, chan:address:shared:channel [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - <span class="Delimiter">{</span> - <span class="Comment"># block if chan is empty</span> - empty?:boolean<span class="Special"> <- </span>channel-empty? chan - <span class="muControl">break-unless</span> empty? - free-address:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-free:offset</span> - wait-for-location *free-address - <span class="Delimiter">}</span> - <span class="Comment"># read result</span> - full:address:number<span class="Special"> <- </span>get-address *chan, <span class="Constant">first-full:offset</span> - circular-buffer:address:shared:array:character<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> - result<span class="Special"> <- </span>index *circular-buffer, *full - <span class="Comment"># mark its slot as empty</span> - *full<span class="Special"> <- </span>add *full, <span class="Constant">1</span> - <span class="Delimiter">{</span> - <span class="Comment"># wrap full around to 0 if necessary</span> - len:number<span class="Special"> <- </span>length *circular-buffer - at-end?:boolean<span class="Special"> <- </span>greater-or-equal *full, len - <span class="muControl">break-unless</span> at-end? - *full<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Delimiter">}</span> -] - -<span class="muRecipe">def</span> clear-channel chan:address:shared:channel<span class="muRecipe"> -> </span>chan:address:shared:channel [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - <span class="Delimiter">{</span> - empty?:boolean<span class="Special"> <- </span>channel-empty? chan - <span class="muControl">break-if</span> empty? - _, chan<span class="Special"> <- </span>read chan - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> channel-initialization [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-full:offset</span> - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-free:offset</span> - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-free</span> - ] -] - -<span class="muScenario">scenario</span> channel-write-increments-free [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-full:offset</span> - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-free:offset</span> - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-free</span> - ] -] - -<span class="muScenario">scenario</span> channel-read-increments-full [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - _, <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:shared:channel - <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-full:offset</span> - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-free:offset</span> - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-full</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-free</span> - ] -] - -<span class="muScenario">scenario</span> channel-wrap [ - run [ - <span class="Comment"># channel with just 1 slot</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> - <span class="Comment"># write and read a value</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - _, <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:shared:channel - <span class="Comment"># first-free will now be 1</span> - <span class="Constant">2</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-free:offset</span> - <span class="Constant">3</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-free:offset</span> - <span class="Comment"># write second value, verify that first-free wraps</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - <span class="Constant">4</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-free:offset</span> - <span class="Comment"># read second value, verify that first-full wraps</span> - _, <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:shared:channel - <span class="Constant">5</span>:number<span class="Special"> <- </span>get *<span class="Constant">1</span>:address:shared:channel, <span class="Constant">first-full:offset</span> - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-free after first write</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># first-full after first read</span> - <span class="Constant">4</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-free after second write, wrapped</span> - <span class="Constant">5</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># first-full after second read, wrapped</span> - ] -] - -<span class="SalientComment">## helpers</span> - -<span class="Comment"># An empty channel has first-empty and first-full both at the same value.</span> -<span class="muRecipe">def</span> channel-empty? chan:address:shared:channel<span class="muRecipe"> -> </span>result:boolean [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - <span class="Comment"># return chan.first-full == chan.first-free</span> - full:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> - free:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> - result<span class="Special"> <- </span>equal full, free -] - -<span class="Comment"># A full channel has first-empty just before first-full, wasting one slot.</span> -<span class="Comment"># (Other alternatives: <a href="https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)">https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction)</a></span> -<span class="muRecipe">def</span> channel-full? chan:address:shared:channel<span class="muRecipe"> -> </span>result:boolean [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - <span class="Comment"># tmp = chan.first-free + 1</span> - tmp:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-free:offset</span> - tmp<span class="Special"> <- </span>add tmp, <span class="Constant">1</span> - <span class="Delimiter">{</span> - <span class="Comment"># if tmp == chan.capacity, tmp = 0</span> - len:number<span class="Special"> <- </span>channel-capacity chan - at-end?:boolean<span class="Special"> <- </span>greater-or-equal tmp, len - <span class="muControl">break-unless</span> at-end? - tmp<span class="Special"> <- </span>copy <span class="Constant">0</span> - <span class="Delimiter">}</span> - <span class="Comment"># return chan.first-full == tmp</span> - full:number<span class="Special"> <- </span>get *chan, <span class="Constant">first-full:offset</span> - result<span class="Special"> <- </span>equal full, tmp -] - -<span class="muRecipe">def</span> channel-capacity chan:address:shared:channel<span class="muRecipe"> -> </span>result:number [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - q:address:shared:array:character<span class="Special"> <- </span>get *chan, <span class="Constant">data:offset</span> - result<span class="Special"> <- </span>length *q -] - -<span class="muScenario">scenario</span> channel-new-empty-not-full [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:shared:channel - <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:shared:channel - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># empty?</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># full?</span> - ] -] - -<span class="muScenario">scenario</span> channel-write-not-empty [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">3/capacity</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:shared:channel - <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:shared:channel - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty?</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># full?</span> - ] -] - -<span class="muScenario">scenario</span> channel-write-full [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:shared:channel - <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:shared:channel - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># empty?</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># full?</span> - ] -] - -<span class="muScenario">scenario</span> channel-read-not-full [ - run [ - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>new-channel <span class="Constant">1/capacity</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">34</span> - _, <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>read <span class="Constant">1</span>:address:shared:channel - <span class="Constant">2</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">1</span>:address:shared:channel - <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-full? <span class="Constant">1</span>:address:shared:channel - ] - memory-should-contain [ - <span class="Constant">2</span><span class="Special"> <- </span><span class="Constant">1</span> <span class="Comment"># empty?</span> - <span class="Constant">3</span><span class="Special"> <- </span><span class="Constant">0</span> <span class="Comment"># full?</span> - ] -] - -<span class="Comment"># helper for channels of characters in particular</span> -<span class="muRecipe">def</span> buffer-lines in:address:shared:channel, out:address:shared:channel<span class="muRecipe"> -> </span>out:address:shared:channel, in:address:shared:channel [ - <span class="Constant">local-scope</span> - <span class="Constant">load-ingredients</span> - <span class="Comment"># repeat forever</span> - <span class="Delimiter">{</span> - line:address:shared:buffer<span class="Special"> <- </span>new-buffer <span class="Constant">30</span> - <span class="Comment"># read characters from 'in' until newline, copy into line</span> - <span class="Delimiter">{</span> -<span class="Constant"> +next-character</span> - c:character, in<span class="Special"> <- </span>read in - <span class="Comment"># drop a character on backspace</span> - <span class="Delimiter">{</span> - <span class="Comment"># special-case: if it's a backspace</span> - backspace?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">8</span> - <span class="muControl">break-unless</span> backspace? - <span class="Comment"># drop previous character</span> - <span class="Delimiter">{</span> - buffer-length:address:number<span class="Special"> <- </span>get-address *line, <span class="Constant">length:offset</span> - buffer-empty?:boolean<span class="Special"> <- </span>equal *buffer-length, <span class="Constant">0</span> - <span class="muControl">break-if</span> buffer-empty? - *buffer-length<span class="Special"> <- </span>subtract *buffer-length, <span class="Constant">1</span> - <span class="Delimiter">}</span> - <span class="Comment"># and don't append this one</span> - <span class="muControl">loop</span> <span class="Constant">+next-character:label</span> - <span class="Delimiter">}</span> - <span class="Comment"># append anything else</span> - line<span class="Special"> <- </span>append line, c - line-done?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">10/newline</span> - <span class="muControl">break-if</span> line-done? - <span class="Comment"># stop buffering on eof (currently only generated by fake console)</span> - eof?:boolean<span class="Special"> <- </span>equal c, <span class="Constant">0/eof</span> - <span class="muControl">break-if</span> eof? - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="Comment"># copy line into 'out'</span> - i:number<span class="Special"> <- </span>copy <span class="Constant">0</span> - line-contents:address:shared:array:character<span class="Special"> <- </span>get *line, <span class="Constant">data:offset</span> - max:number<span class="Special"> <- </span>get *line, <span class="Constant">length:offset</span> - <span class="Delimiter">{</span> - done?:boolean<span class="Special"> <- </span>greater-or-equal i, max - <span class="muControl">break-if</span> done? - c:character<span class="Special"> <- </span>index *line-contents, i - out<span class="Special"> <- </span>write out, c - i<span class="Special"> <- </span>add i, <span class="Constant">1</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> - <span class="muControl">loop</span> - <span class="Delimiter">}</span> -] - -<span class="muScenario">scenario</span> buffer-lines-blocks-until-newline [ - run [ - <span class="Constant">1</span>:address:shared:channel/stdin<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> - <span class="Constant">2</span>:address:shared:channel/buffered-stdin<span class="Special"> <- </span>new-channel <span class="Constant">10/capacity</span> - <span class="Constant">3</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:shared:channel/buffered-stdin - assert <span class="Constant">3</span>:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> init] - <span class="Comment"># buffer stdin into buffered-stdin, try to read from buffered-stdin</span> - <span class="Constant">4</span>:number/buffer-routine<span class="Special"> <- </span>start-running buffer-lines, <span class="Constant">1</span>:address:shared:channel/stdin, <span class="Constant">2</span>:address:shared:channel/buffered-stdin - wait-for-routine <span class="Constant">4</span>:number/buffer-routine - <span class="Constant">5</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:shared:channel/buffered-stdin - assert <span class="Constant">5</span>:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> buffer-lines bring-up] - <span class="Comment"># write 'a'</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">97/a</span> - restart <span class="Constant">4</span>:number/buffer-routine - wait-for-routine <span class="Constant">4</span>:number/buffer-routine - <span class="Constant">6</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:shared:channel/buffered-stdin - assert <span class="Constant">6</span>:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> writing 'a'] - <span class="Comment"># write 'b'</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">98/b</span> - restart <span class="Constant">4</span>:number/buffer-routine - wait-for-routine <span class="Constant">4</span>:number/buffer-routine - <span class="Constant">7</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:shared:channel/buffered-stdin - assert <span class="Constant">7</span>:boolean, [ -F buffer-lines-blocks-until-newline: channel should be empty <span class="muRecipe">after</span> writing 'b'] - <span class="Comment"># write newline</span> - <span class="Constant">1</span>:address:shared:channel<span class="Special"> <- </span>write <span class="Constant">1</span>:address:shared:channel, <span class="Constant">10/newline</span> - restart <span class="Constant">4</span>:number/buffer-routine - wait-for-routine <span class="Constant">4</span>:number/buffer-routine - <span class="Constant">8</span>:boolean<span class="Special"> <- </span>channel-empty? <span class="Constant">2</span>:address:shared:channel/buffered-stdin - <span class="Constant">9</span>:boolean/completed?<span class="Special"> <- </span>not <span class="Constant">8</span>:boolean - assert <span class="Constant">9</span>:boolean/completed?, [ -F buffer-lines-blocks-until-newline: channel should contain data <span class="muRecipe">after</span> writing newline] - trace <span class="Constant">1</span>, <span class="Constant">[test]</span>, <span class="Constant">[reached end]</span> - ] - trace-should-contain [ - test: reached end - ] -] -</pre> -</body> -</html> |