From 124c67645cb6f1b9f06d7104c5398fa4732e2f25 Mon Sep 17 00:00:00 2001 From: "Kartik K. Agaram" Date: Tue, 20 Jun 2017 10:40:07 -0700 Subject: 3934 --- html/061text.mu.html | 12 +- html/063array.mu.html | 8 +- html/070table.mu.html | 16 +- html/075channel.mu.html | 886 ++++++++++++++++--------------- html/081print.mu.html | 10 +- html/084console.mu.html | 2 +- html/088file.mu.html | 6 +- html/090scenario_filesystem_test.mu.html | 16 +- html/092socket.mu.html | 8 +- html/channel.mu.html | 2 +- html/chessboard.mu.html | 28 +- html/filesystem.mu.html | 2 +- html/http-server.mu.html | 2 +- html/real-files.mu.html | 2 +- 14 files changed, 510 insertions(+), 490 deletions(-) diff --git a/html/061text.mu.html b/html/061text.mu.html index b047154b..f380a9d3 100644 --- a/html/061text.mu.html +++ b/html/061text.mu.html @@ -190,17 +190,17 @@ if ('onhashchange' in window) { 128 data:&:@:_elem 129 ] 130 - 131 def new-buffer capacity:num -> result:&:buffer:_elem [ + 131 def new-buffer capacity:num -> result:&:buffer:_elem [ 132 local-scope 133 load-ingredients 134 result <- new {(buffer _elem): type} 135 *result <- put *result, length:offset, 0 136 { - 137 ¦ break-if capacity + 137 ¦ break-if capacity 138 ¦ # capacity not provided - 139 ¦ capacity <- copy 10 + 139 ¦ capacity <- copy 10 140 } - 141 data:&:@:_elem <- new _elem:type, capacity + 141 data:&:@:_elem <- new _elem:type, capacity 142 *result <- put *result, data:offset, data 143 return result 144 ] @@ -231,8 +231,8 @@ if ('onhashchange' in window) { 169 load-ingredients 170 len:num <- get *in, length:offset 171 s:&:@:_elem <- get *in, data:offset - 172 capacity:num <- length *s - 173 result <- greater-or-equal len, capacity + 172 capacity:num <- length *s + 173 result <- greater-or-equal len, capacity 174 ] 175 176 # most broadly applicable definition of append to a buffer diff --git a/html/063array.mu.html b/html/063array.mu.html index f4c97ebb..8ec4072b 100644 --- a/html/063array.mu.html +++ b/html/063array.mu.html @@ -76,20 +76,20 @@ if ('onhashchange' in window) { 15 # create an array out of a list of args 16 def new-array -> result:&:@:_elem [ 17 local-scope - 18 capacity:num <- copy 0 + 18 capacity:num <- copy 0 19 { 20 ¦ # while read curr-value 21 ¦ curr-value:_elem, exists?:bool <- next-ingredient 22 ¦ break-unless exists? - 23 ¦ capacity <- add capacity, 1 + 23 ¦ capacity <- add capacity, 1 24 ¦ loop 25 } - 26 result <- new _elem:type, capacity + 26 result <- new _elem:type, capacity 27 rewind-ingredients 28 i:num <- copy 0 29 { 30 ¦ # while read curr-value - 31 ¦ done?:bool <- greater-or-equal i, capacity + 31 ¦ done?:bool <- greater-or-equal i, capacity 32 ¦ break-if done? 33 ¦ curr-value:_elem, exists?:bool <- next-ingredient 34 ¦ assert exists?, [error in rewinding ingredients to new-array] diff --git a/html/070table.mu.html b/html/070table.mu.html index 603e9997..c5d0c6ac 100644 --- a/html/070table.mu.html +++ b/html/070table.mu.html @@ -105,7 +105,7 @@ if ('onhashchange' in window) { 43 44 container table:_key:_value [ 45 length:num - 46 capacity:num + 46 capacity:num 47 data:&:@:table-row:_key:_value 48 ] 49 @@ -115,12 +115,12 @@ if ('onhashchange' in window) { 53 value:_value 54 ] 55 - 56 def new-table capacity:num -> result:&:table:_key:_value [ + 56 def new-table capacity:num -> result:&:table:_key:_value [ 57 local-scope 58 load-ingredients 59 result <- new {(table _key _value): type} - 60 data:&:@:table-row:_key:_value <- new {(table-row _key _value): type}, capacity - 61 *result <- merge 0/length, capacity, data + 60 data:&:@:table-row:_key:_value <- new {(table-row _key _value): type}, capacity + 61 *result <- merge 0/length, capacity, data 62 ] 63 64 # todo: tag results as /required so that call-sites are forbidden from ignoring them @@ -130,8 +130,8 @@ if ('onhashchange' in window) { 68 load-ingredients 69 hash:num <- hash key 70 hash <- abs hash - 71 capacity:num <- get *table, capacity:offset - 72 _, hash-key:num <- divide-with-remainder hash, capacity + 71 capacity:num <- get *table, capacity:offset + 72 _, hash-key:num <- divide-with-remainder hash, capacity 73 hash-key <- abs hash-key # in case hash overflows from a double into a negative integer inside 'divide-with-remainder' above 74 table-data:&:@:table-row:_key:_value <- get *table, data:offset 75 x:table-row:_key:_value <- index *table-data, hash-key @@ -147,8 +147,8 @@ if ('onhashchange' in window) { 85 load-ingredients 86 hash:num <- hash key 87 hash <- abs hash - 88 capacity:num <- get *table, capacity:offset - 89 _, hash-key:num <- divide-with-remainder hash, capacity + 88 capacity:num <- get *table, capacity:offset + 89 _, hash-key:num <- divide-with-remainder hash, capacity 90 hash-key <- abs hash-key # in case hash overflows from a double into a negative integer inside 'divide-with-remainder' above 91 table-data:&:@:table-row:_key:_value <- get *table, data:offset 92 x:table-row:_key:_value <- index *table-data, hash-key diff --git a/html/075channel.mu.html b/html/075channel.mu.html index d6705535..6cc72808 100644 --- a/html/075channel.mu.html +++ b/html/075channel.mu.html @@ -82,7 +82,7 @@ if ('onhashchange' in window) { 18 run [ 19 ¦ local-scope 20 ¦ source:&:source:num, sink:&:sink:num <- new-channel 3/capacity - 21 ¦ sink <- write sink, 34 + 21 ¦ sink <- write sink, 34 22 ¦ 10:num/raw, 11:bool/raw, source <- read source 23 ] 24 memory-should-contain [ @@ -96,8 +96,8 @@ if ('onhashchange' in window) { 32 first-full:num # for write 33 first-free:num # for read 34 # A circular buffer contains values from index first-full up to (but not - 35 # including) index first-empty. The reader always modifies it at first-full, - 36 # while the writer always modifies it at first-empty. + 35 # including) index first-free. The reader always modifies it at first-full, + 36 # while the writer always modifies it at first-free. 37 data:&:@:_elem 38 ] 39 @@ -112,14 +112,14 @@ if ('onhashchange' in window) { 48 chan:&:channel:_elem 49 ] 50 - 51 def new-channel capacity:num -> in:&:source:_elem, out:&:sink:_elem [ + 51 def new-channel capacity:num -> in:&:source:_elem, out:&:sink:_elem [ 52 local-scope 53 load-ingredients 54 result:&:channel:_elem <- new {(channel _elem): type} 55 *result <- put *result, first-full:offset, 0 56 *result <- put *result, first-free:offset, 0 - 57 capacity <- add capacity, 1 # unused slot for 'full?' below - 58 data:&:@:_elem <- new _elem:type, capacity + 57 capacity <- add capacity, 1 # unused slot for 'full?' below + 58 data:&:@:_elem <- new _elem:type, capacity 59 *result <- put *result, data:offset, data 60 in <- new {(source _elem): type} 61 *in <- put *in, chan:offset, result @@ -127,439 +127,459 @@ if ('onhashchange' in window) { 63 *out <- put *out, chan:offset, result 64 ] 65 - 66 def write out:&:sink:_elem, val:_elem -> out:&:sink:_elem [ - 67 local-scope - 68 load-ingredients - 69 assert out, [write to null channel] - 70 chan:&:channel:_elem <- get *out, chan:offset - 71 <channel-write-initial> - 72 # block until lock is acquired AND queue has room - 73 lock:location <- get-location *chan, lock:offset - 74 #? $print [write], 10/newline - 75 { - 76 #? $print [trying to acquire lock for writing], 10/newline - 77 ¦ wait-for-reset-then-set lock - 78 #? $print [lock acquired for writing], 10/newline - 79 ¦ full?:bool <- channel-full? chan - 80 ¦ break-unless full? - 81 #? $print [but channel is full; relinquishing lock], 10/newline - 82 ¦ # channel is full; relinquish lock and give a reader the opportunity to - 83 ¦ # create room on it - 84 ¦ reset lock - 85 ¦ current-routine-is-blocked - 86 ¦ switch # avoid spinlocking - 87 ¦ loop - 88 } - 89 current-routine-is-unblocked - 90 #? $print [performing write], 10/newline - 91 # store a deep copy of val - 92 circular-buffer:&:@:_elem <- get *chan, data:offset - 93 free:num <- get *chan, first-free:offset - 94 val-copy:_elem <- deep-copy val # on this instruction rests all Mu's concurrency-safety - 95 *circular-buffer <- put-index *circular-buffer, free, val-copy - 96 # mark its slot as filled - 97 free <- add free, 1 - 98 { - 99 ¦ # wrap free around to 0 if necessary -100 ¦ len:num <- length *circular-buffer -101 ¦ at-end?:bool <- greater-or-equal free, len -102 ¦ break-unless at-end? -103 ¦ free <- copy 0 -104 } -105 # write back -106 *chan <- put *chan, first-free:offset, free -107 #? $print [relinquishing lock after writing], 10/newline -108 reset lock -109 ] -110 -111 def read in:&:source:_elem -> result:_elem, eof?:bool, in:&:source:_elem [ -112 local-scope -113 load-ingredients -114 assert in, [read on null channel] -115 eof? <- copy 0/false # default result -116 chan:&:channel:_elem <- get *in, chan:offset -117 # block until lock is acquired AND queue has data -118 lock:location <- get-location *chan, lock:offset -119 #? $print [read], 10/newline -120 { -121 #? $print [trying to acquire lock for reading], 10/newline -122 ¦ wait-for-reset-then-set lock -123 #? $print [lock acquired for reading], 10/newline -124 ¦ empty?:bool <- channel-empty? chan -125 ¦ break-unless empty? -126 #? $print [but channel is empty; relinquishing lock], 10/newline -127 ¦ # channel is empty; relinquish lock and give a writer the opportunity to -128 ¦ # add to it -129 ¦ reset lock -130 ¦ current-routine-is-blocked -131 ¦ <channel-read-empty> -132 ¦ switch # avoid spinlocking -133 ¦ loop -134 } -135 current-routine-is-unblocked -136 # pull result off -137 full:num <- get *chan, first-full:offset -138 circular-buffer:&:@:_elem <- get *chan, data:offset -139 result <- index *circular-buffer, full -140 # clear the slot -141 empty:&:_elem <- new _elem:type -142 *circular-buffer <- put-index *circular-buffer, full, *empty -143 # mark its slot as empty -144 full <- add full, 1 -145 { -146 ¦ # wrap full around to 0 if necessary -147 ¦ len:num <- length *circular-buffer -148 ¦ at-end?:bool <- greater-or-equal full, len -149 ¦ break-unless at-end? -150 ¦ full <- copy 0 -151 } -152 # write back -153 *chan <- put *chan, first-full:offset, full -154 #? $print [relinquishing lock after reading], 10/newline -155 reset lock -156 ] -157 -158 # todo: create a notion of iterator and iterable so we can read/write whole -159 # aggregates (arrays, lists, ..) of _elems at once. -160 -161 def clear in:&:source:_elem -> in:&:source:_elem [ -162 local-scope -163 load-ingredients -164 chan:&:channel:_elem <- get *in, chan:offset -165 { -166 ¦ empty?:bool <- channel-empty? chan -167 ¦ break-if empty? -168 ¦ _, _, in <- read in -169 } -170 ] -171 -172 scenario channel-initialization [ -173 run [ -174 ¦ local-scope -175 ¦ source:&:source:num <- new-channel 3/capacity -176 ¦ chan:&:channel:num <- get *source, chan:offset -177 ¦ 10:num/raw <- get *chan, first-full:offset -178 ¦ 11:num/raw <- get *chan, first-free:offset -179 ] -180 memory-should-contain [ -181 ¦ 10 <- 0 # first-full -182 ¦ 11 <- 0 # first-free -183 ] -184 ] -185 -186 scenario channel-write-increments-free [ -187 local-scope -188 _, sink:&:sink:num <- new-channel 3/capacity -189 run [ -190 ¦ sink <- write sink, 34 -191 ¦ chan:&:channel:num <- get *sink, chan:offset -192 ¦ 10:num/raw <- get *chan, first-full:offset -193 ¦ 11:num/raw <- get *chan, first-free:offset -194 ] -195 memory-should-contain [ -196 ¦ 10 <- 0 # first-full -197 ¦ 11 <- 1 # first-free -198 ] -199 ] -200 -201 scenario channel-read-increments-full [ -202 local-scope -203 source:&:source:num, sink:&:sink:num <- new-channel 3/capacity -204 sink <- write sink, 34 -205 run [ -206 ¦ _, _, source <- read source -207 ¦ chan:&:channel:num <- get *source, chan:offset -208 ¦ 10:num/raw <- get *chan, first-full:offset -209 ¦ 11:num/raw <- get *chan, first-free:offset -210 ] -211 memory-should-contain [ -212 ¦ 10 <- 1 # first-full -213 ¦ 11 <- 1 # first-free -214 ] -215 ] -216 -217 scenario channel-wrap [ -218 local-scope -219 # channel with just 1 slot -220 source:&:source:num, sink:&:sink:num <- new-channel 1/capacity -221 chan:&:channel:num <- get *source, chan:offset -222 # write and read a value -223 sink <- write sink, 34 -224 _, _, source <- read source -225 run [ -226 ¦ # first-free will now be 1 -227 ¦ 10:num/raw <- get *chan, first-free:offset -228 ¦ 11:num/raw <- get *chan, first-free:offset -229 ¦ # write second value, verify that first-free wraps -230 ¦ sink <- write sink, 34 -231 ¦ 20:num/raw <- get *chan, first-free:offset -232 ¦ # read second value, verify that first-full wraps -233 ¦ _, _, source <- read source -234 ¦ 30:num/raw <- get *chan, first-full:offset -235 ] -236 memory-should-contain [ -237 ¦ 10 <- 1 # first-free after first write -238 ¦ 11 <- 1 # first-full after first read -239 ¦ 20 <- 0 # first-free after second write, wrapped -240 ¦ 30 <- 0 # first-full after second read, wrapped -241 ] -242 ] -243 -244 scenario channel-new-empty-not-full [ -245 run [ -246 ¦ local-scope -247 ¦ source:&:source:num <- new-channel 3/capacity -248 ¦ chan:&:channel:num <- get *source, chan:offset -249 ¦ 10:bool/raw <- channel-empty? chan -250 ¦ 11:bool/raw <- channel-full? chan -251 ] -252 memory-should-contain [ -253 ¦ 10 <- 1 # empty? -254 ¦ 11 <- 0 # full? -255 ] -256 ] -257 -258 scenario channel-write-not-empty [ -259 local-scope -260 source:&:source:num, sink:&:sink:num <- new-channel 3/capacity -261 chan:&:channel:num <- get *source, chan:offset -262 run [ -263 ¦ sink <- write sink, 34 -264 ¦ 10:bool/raw <- channel-empty? chan -265 ¦ 11:bool/raw <- channel-full? chan -266 ] -267 memory-should-contain [ -268 ¦ 10 <- 0 # empty? -269 ¦ 11 <- 0 # full? -270 ] -271 ] -272 -273 scenario channel-write-full [ -274 local-scope -275 source:&:source:num, sink:&:sink:num <- new-channel 1/capacity -276 chan:&:channel:num <- get *source, chan:offset -277 run [ -278 ¦ sink <- write sink, 34 -279 ¦ 10:bool/raw <- channel-empty? chan -280 ¦ 11:bool/raw <- channel-full? chan -281 ] -282 memory-should-contain [ -283 ¦ 10 <- 0 # empty? -284 ¦ 11 <- 1 # full? -285 ] -286 ] -287 -288 scenario channel-read-not-full [ -289 local-scope -290 source:&:source:num, sink:&:sink:num <- new-channel 1/capacity -291 chan:&:channel:num <- get *source, chan:offset -292 sink <- write sink, 34 -293 run [ -294 ¦ _, _, source <- read source -295 ¦ 10:bool/raw <- channel-empty? chan -296 ¦ 11:bool/raw <- channel-full? chan -297 ] -298 memory-should-contain [ -299 ¦ 10 <- 1 # empty? -300 ¦ 11 <- 0 # full? -301 ] -302 ] -303 -304 ## cancelling channels -305 -306 # every channel comes with a boolean signifying if it's been closed -307 # initially this boolean is false -308 container channel:_elem [ -309 closed?:bool + 66 # write a value to a channel + 67 def write out:&:sink:_elem, val:_elem -> out:&:sink:_elem [ + 68 local-scope + 69 load-ingredients + 70 assert out, [write to null channel] + 71 chan:&:channel:_elem <- get *out, chan:offset + 72 <channel-write-initial> + 73 # block until lock is acquired AND queue has room + 74 lock:location <- get-location *chan, lock:offset + 75 #? $print [write], 10/newline + 76 { + 77 #? $print [trying to acquire lock for writing], 10/newline + 78 ¦ wait-for-reset-then-set lock + 79 #? $print [lock acquired for writing], 10/newline + 80 ¦ full?:bool <- channel-full? chan + 81 ¦ break-unless full? + 82 #? $print [but channel is full; relinquishing lock], 10/newline + 83 ¦ # channel is full; relinquish lock and give a reader the opportunity to + 84 ¦ # create room on it + 85 ¦ reset lock + 86 ¦ current-routine-is-blocked + 87 ¦ switch # avoid spinlocking + 88 ¦ loop + 89 } + 90 current-routine-is-unblocked + 91 #? $print [performing write], 10/newline + 92 # store a deep copy of val + 93 circular-buffer:&:@:_elem <- get *chan, data:offset + 94 free:num <- get *chan, first-free:offset + 95 val-copy:_elem <- deep-copy val # on this instruction rests all Mu's concurrency-safety + 96 *circular-buffer <- put-index *circular-buffer, free, val-copy + 97 # mark its slot as filled + 98 free <- add free, 1 + 99 { +100 ¦ # wrap free around to 0 if necessary +101 ¦ len:num <- length *circular-buffer +102 ¦ at-end?:bool <- greater-or-equal free, len +103 ¦ break-unless at-end? +104 ¦ free <- copy 0 +105 } +106 # write back +107 *chan <- put *chan, first-free:offset, free +108 #? $print [relinquishing lock after writing], 10/newline +109 reset lock +110 ] +111 +112 # read a value from a channel +113 def read in:&:source:_elem -> result:_elem, eof?:bool, in:&:source:_elem [ +114 local-scope +115 load-ingredients +116 assert in, [read on null channel] +117 eof? <- copy 0/false # default result +118 chan:&:channel:_elem <- get *in, chan:offset +119 # block until lock is acquired AND queue has data +120 lock:location <- get-location *chan, lock:offset +121 #? $print [read], 10/newline +122 { +123 #? $print [trying to acquire lock for reading], 10/newline +124 ¦ wait-for-reset-then-set lock +125 #? $print [lock acquired for reading], 10/newline +126 ¦ empty?:bool <- channel-empty? chan +127 ¦ break-unless empty? +128 #? $print [but channel is empty; relinquishing lock], 10/newline +129 ¦ # channel is empty; relinquish lock and give a writer the opportunity to +130 ¦ # add to it +131 ¦ reset lock +132 ¦ current-routine-is-blocked +133 ¦ <channel-read-empty> +134 ¦ switch # avoid spinlocking +135 ¦ loop +136 } +137 current-routine-is-unblocked +138 # pull result off +139 full:num <- get *chan, first-full:offset +140 circular-buffer:&:@:_elem <- get *chan, data:offset +141 result <- index *circular-buffer, full +142 # clear the slot +143 empty:&:_elem <- new _elem:type +144 *circular-buffer <- put-index *circular-buffer, full, *empty +145 # mark its slot as empty +146 full <- add full, 1 +147 { +148 ¦ # wrap full around to 0 if necessary +149 ¦ len:num <- length *circular-buffer +150 ¦ at-end?:bool <- greater-or-equal full, len +151 ¦ break-unless at-end? +152 ¦ full <- copy 0 +153 } +154 # write back +155 *chan <- put *chan, first-full:offset, full +156 #? $print [relinquishing lock after reading], 10/newline +157 reset lock +158 ] +159 +160 # todo: create a notion of iterator and iterable so we can read/write whole +161 # aggregates (arrays, lists, ..) of _elems at once. +162 +163 scenario channel-initialization [ +164 run [ +165 ¦ local-scope +166 ¦ source:&:source:num <- new-channel 3/capacity +167 ¦ chan:&:channel:num <- get *source, chan:offset +168 ¦ 10:num/raw <- get *chan, first-full:offset +169 ¦ 11:num/raw <- get *chan, first-free:offset +170 ] +171 memory-should-contain [ +172 ¦ 10 <- 0 # first-full +173 ¦ 11 <- 0 # first-free +174 ] +175 ] +176 +177 scenario channel-write-increments-free [ +178 local-scope +179 _, sink:&:sink:num <- new-channel 3/capacity +180 run [ +181 ¦ sink <- write sink, 34 +182 ¦ chan:&:channel:num <- get *sink, chan:offset +183 ¦ 10:num/raw <- get *chan, first-full:offset +184 ¦ 11:num/raw <- get *chan, first-free:offset +185 ] +186 memory-should-contain [ +187 ¦ 10 <- 0 # first-full +188 ¦ 11 <- 1 # first-free +189 ] +190 ] +191 +192 scenario channel-read-increments-full [ +193 local-scope +194 source:&:source:num, sink:&:sink:num <- new-channel 3/capacity +195 sink <- write sink, 34 +196 run [ +197 ¦ _, _, source <- read source +198 ¦ chan:&:channel:num <- get *source, chan:offset +199 ¦ 10:num/raw <- get *chan, first-full:offset +200 ¦ 11:num/raw <- get *chan, first-free:offset +201 ] +202 memory-should-contain [ +203 ¦ 10 <- 1 # first-full +204 ¦ 11 <- 1 # first-free +205 ] +206 ] +207 +208 scenario channel-wrap [ +209 local-scope +210 # channel with just 1 slot +211 source:&:source:num, sink:&:sink:num <- new-channel 1/capacity +212 chan:&:channel:num <- get *source, chan:offset +213 # write and read a value +214 sink <- write sink, 34 +215 _, _, source <- read source +216 run [ +217 ¦ # first-free will now be 1 +218 ¦ 10:num/raw <- get *chan, first-free:offset +219 ¦ 11:num/raw <- get *chan, first-free:offset +220 ¦ # write second value, verify that first-free wraps +221 ¦ sink <- write sink, 34 +222 ¦ 20:num/raw <- get *chan, first-free:offset +223 ¦ # read second value, verify that first-full wraps +224 ¦ _, _, source <- read source +225 ¦ 30:num/raw <- get *chan, first-full:offset +226 ] +227 memory-should-contain [ +228 ¦ 10 <- 1 # first-free after first write +229 ¦ 11 <- 1 # first-full after first read +230 ¦ 20 <- 0 # first-free after second write, wrapped +231 ¦ 30 <- 0 # first-full after second read, wrapped +232 ] +233 ] +234 +235 scenario channel-new-empty-not-full [ +236 run [ +237 ¦ local-scope +238 ¦ source:&:source:num <- new-channel 3/capacity +239 ¦ chan:&:channel:num <- get *source, chan:offset +240 ¦ 10:bool/raw <- channel-empty? chan +241 ¦ 11:bool/raw <- channel-full? chan +242 ] +243 memory-should-contain [ +244 ¦ 10 <- 1 # empty? +245 ¦ 11 <- 0 # full? +246 ] +247 ] +248 +249 scenario channel-write-not-empty [ +250 local-scope +251 source:&:source:num, sink:&:sink:num <- new-channel 3/capacity +252 chan:&:channel:num <- get *source, chan:offset +253 run [ +254 ¦ sink <- write sink, 34 +255 ¦ 10:bool/raw <- channel-empty? chan +256 ¦ 11:bool/raw <- channel-full? chan +257 ] +258 memory-should-contain [ +259 ¦ 10 <- 0 # empty? +260 ¦ 11 <- 0 # full? +261 ] +262 ] +263 +264 scenario channel-write-full [ +265 local-scope +266 source:&:source:num, sink:&:sink:num <- new-channel 1/capacity +267 chan:&:channel:num <- get *source, chan:offset +268 run [ +269 ¦ sink <- write sink, 34 +270 ¦ 10:bool/raw <- channel-empty? chan +271 ¦ 11:bool/raw <- channel-full? chan +272 ] +273 memory-should-contain [ +274 ¦ 10 <- 0 # empty? +275 ¦ 11 <- 1 # full? +276 ] +277 ] +278 +279 scenario channel-read-not-full [ +280 local-scope +281 source:&:source:num, sink:&:sink:num <- new-channel 1/capacity +282 chan:&:channel:num <- get *source, chan:offset +283 sink <- write sink, 34 +284 run [ +285 ¦ _, _, source <- read source +286 ¦ 10:bool/raw <- channel-empty? chan +287 ¦ 11:bool/raw <- channel-full? chan +288 ] +289 memory-should-contain [ +290 ¦ 10 <- 1 # empty? +291 ¦ 11 <- 0 # full? +292 ] +293 ] +294 +295 scenario channel-clear [ +296 local-scope +297 # create a channel with a few items +298 source:&:source:num, sink:&:sink:num <- new-channel 3/capacity +299 chan:&:channel:num <- get *sink, chan:offset +300 write sink, 30 +301 write sink, 31 +302 write sink, 32 +303 run [ +304 ¦ clear source +305 ¦ 10:bool/raw <- channel-empty? chan +306 ] +307 memory-should-contain [ +308 ¦ 10 <- 1 # after the call to 'clear', the channel should be empty +309 ] 310 ] 311 -312 # a channel can be closed from either the source or the sink -313 # both routines can modify the 'closed?' bit, but they can only ever set it, so this is a benign race -314 def close x:&:source:_elem -> x:&:source:_elem [ -315 local-scope -316 load-ingredients -317 chan:&:channel:_elem <- get *x, chan:offset -318 *chan <- put *chan, closed?:offset, 1/true -319 ] -320 def close x:&:sink:_elem -> x:&:sink:_elem [ -321 local-scope -322 load-ingredients -323 chan:&:channel:_elem <- get *x, chan:offset -324 *chan <- put *chan, closed?:offset, 1/true -325 ] -326 -327 # once a channel is closed from one side, no further operations are expected from that side -328 # if a channel is closed for reading, -329 # no further writes will be let through -330 # if a channel is closed for writing, -331 # future reads continue until the channel empties, -332 # then the channel is also closed for reading -333 after <channel-write-initial> [ -334 closed?:bool <- get *chan, closed?:offset -335 return-if closed? -336 ] -337 after <channel-read-empty> [ -338 closed?:bool <- get *chan, closed?:offset -339 { -340 ¦ break-unless closed? -341 ¦ empty-result:&:_elem <- new _elem:type -342 ¦ current-routine-is-unblocked -343 ¦ return *empty-result, 1/true -344 } +312 def clear in:&:source:_elem -> in:&:source:_elem [ +313 local-scope +314 load-ingredients +315 chan:&:channel:_elem <- get *in, chan:offset +316 { +317 ¦ empty?:bool <- channel-empty? chan +318 ¦ break-if empty? +319 ¦ _, _, in <- read in +320 ¦ loop +321 } +322 ] +323 +324 ## cancelling channels +325 +326 # every channel comes with a boolean signifying if it's been closed +327 # initially this boolean is false +328 container channel:_elem [ +329 closed?:bool +330 ] +331 +332 # a channel can be closed from either the source or the sink +333 # both routines can modify the 'closed?' bit, but they can only ever set it, so this is a benign race +334 def close x:&:source:_elem -> x:&:source:_elem [ +335 local-scope +336 load-ingredients +337 chan:&:channel:_elem <- get *x, chan:offset +338 *chan <- put *chan, closed?:offset, 1/true +339 ] +340 def close x:&:sink:_elem -> x:&:sink:_elem [ +341 local-scope +342 load-ingredients +343 chan:&:channel:_elem <- get *x, chan:offset +344 *chan <- put *chan, closed?:offset, 1/true 345 ] 346 -347 ## helpers -348 -349 # An empty channel has first-empty and first-full both at the same value. -350 def channel-empty? chan:&:channel:_elem -> result:bool [ -351 local-scope -352 load-ingredients -353 # return chan.first-full == chan.first-free -354 full:num <- get *chan, first-full:offset -355 free:num <- get *chan, first-free:offset -356 result <- equal full, free -357 ] -358 -359 # A full channel has first-empty just before first-full, wasting one slot. -360 # (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction) -361 def channel-full? chan:&:channel:_elem -> result:bool [ -362 local-scope -363 load-ingredients -364 # tmp = chan.first-free + 1 -365 tmp:num <- get *chan, first-free:offset -366 tmp <- add tmp, 1 -367 { -368 ¦ # if tmp == chan.capacity, tmp = 0 -369 ¦ len:num <- capacity chan -370 ¦ at-end?:bool <- greater-or-equal tmp, len -371 ¦ break-unless at-end? -372 ¦ tmp <- copy 0 -373 } -374 # return chan.first-full == tmp -375 full:num <- get *chan, first-full:offset -376 result <- equal full, tmp +347 # once a channel is closed from one side, no further operations are expected from that side +348 # if a channel is closed for reading, +349 # no further writes will be let through +350 # if a channel is closed for writing, +351 # future reads continue until the channel empties, +352 # then the channel is also closed for reading +353 after <channel-write-initial> [ +354 closed?:bool <- get *chan, closed?:offset +355 return-if closed? +356 ] +357 after <channel-read-empty> [ +358 closed?:bool <- get *chan, closed?:offset +359 { +360 ¦ break-unless closed? +361 ¦ empty-result:&:_elem <- new _elem:type +362 ¦ current-routine-is-unblocked +363 ¦ return *empty-result, 1/true +364 } +365 ] +366 +367 ## helpers +368 +369 # An empty channel has first-free and first-full both at the same value. +370 def channel-empty? chan:&:channel:_elem -> result:bool [ +371 local-scope +372 load-ingredients +373 # return chan.first-full == chan.first-free +374 full:num <- get *chan, first-full:offset +375 free:num <- get *chan, first-free:offset +376 result <- equal full, free 377 ] 378 -379 def capacity chan:&:channel:_elem -> result:num [ -380 local-scope -381 load-ingredients -382 q:&:@:_elem <- get *chan, data:offset -383 result <- length *q -384 ] -385 -386 ## helpers for channels of characters in particular -387 -388 def buffer-lines in:&:source:char, buffered-out:&:sink:char -> buffered-out:&:sink:char, in:&:source:char [ -389 local-scope -390 load-ingredients -391 # repeat forever -392 eof?:bool <- copy 0/false -393 { -394 ¦ line:&:buffer:char <- new-buffer 30 -395 ¦ # read characters from 'in' until newline, copy into line -396 ¦ { -397 ¦ ¦ +next-character -398 ¦ ¦ c:char, eof?:bool, in <- read in -399 ¦ ¦ break-if eof? -400 ¦ ¦ # drop a character on backspace -401 ¦ ¦ { -402 ¦ ¦ ¦ # special-case: if it's a backspace -403 ¦ ¦ ¦ backspace?:bool <- equal c, 8 -404 ¦ ¦ ¦ break-unless backspace? -405 ¦ ¦ ¦ # drop previous character -406 ¦ ¦ ¦ { -407 ¦ ¦ ¦ ¦ buffer-length:num <- get *line, length:offset -408 ¦ ¦ ¦ ¦ buffer-empty?:bool <- equal buffer-length, 0 -409 ¦ ¦ ¦ ¦ break-if buffer-empty? -410 ¦ ¦ ¦ ¦ buffer-length <- subtract buffer-length, 1 -411 ¦ ¦ ¦ ¦ *line <- put *line, length:offset, buffer-length -412 ¦ ¦ ¦ } -413 ¦ ¦ ¦ # and don't append this one -414 ¦ ¦ ¦ loop +next-character -415 ¦ ¦ } -416 ¦ ¦ # append anything else -417 ¦ ¦ line <- append line, c -418 ¦ ¦ line-done?:bool <- equal c, 10/newline -419 ¦ ¦ break-if line-done? -420 ¦ ¦ loop -421 ¦ } -422 ¦ # copy line into 'buffered-out' -423 ¦ i:num <- copy 0 -424 ¦ line-contents:text <- get *line, data:offset -425 ¦ max:num <- get *line, length:offset -426 ¦ { -427 ¦ ¦ done?:bool <- greater-or-equal i, max -428 ¦ ¦ break-if done? -429 ¦ ¦ c:char <- index *line-contents, i -430 ¦ ¦ buffered-out <- write buffered-out, c -431 ¦ ¦ i <- add i, 1 -432 ¦ ¦ loop -433 ¦ } -434 ¦ { -435 ¦ ¦ break-unless eof? -436 ¦ ¦ buffered-out <- close buffered-out -437 ¦ ¦ return -438 ¦ } -439 ¦ loop -440 } -441 ] -442 -443 scenario buffer-lines-blocks-until-newline [ -444 run [ -445 ¦ local-scope -446 ¦ source:&:source:char, sink:&:sink:char <- new-channel 10/capacity -447 ¦ _, buffered-stdin:&:sink:char/buffered-stdin <- new-channel 10/capacity -448 ¦ buffered-chan:&:channel:char <- get *buffered-stdin, chan:offset -449 ¦ empty?:bool <- channel-empty? buffered-chan -450 ¦ assert empty?, [ -451 F buffer-lines-blocks-until-newline: channel should be empty after init] -452 ¦ # buffer stdin into buffered-stdin, try to read from buffered-stdin -453 ¦ buffer-routine:num <- start-running buffer-lines, source, buffered-stdin -454 ¦ wait-for-routine-to-block buffer-routine -455 ¦ empty? <- channel-empty? buffered-chan -456 ¦ assert empty?:bool, [ -457 F buffer-lines-blocks-until-newline: channel should be empty after buffer-lines bring-up] -458 ¦ # write 'a' -459 ¦ sink <- write sink, 97/a -460 ¦ restart buffer-routine -461 ¦ wait-for-routine-to-block buffer-routine -462 ¦ empty? <- channel-empty? buffered-chan -463 ¦ assert empty?:bool, [ -464 F buffer-lines-blocks-until-newline: channel should be empty after writing 'a'] -465 ¦ # write 'b' -466 ¦ sink <- write sink, 98/b -467 ¦ restart buffer-routine -468 ¦ wait-for-routine-to-block buffer-routine -469 ¦ empty? <- channel-empty? buffered-chan -470 ¦ assert empty?:bool, [ -471 F buffer-lines-blocks-until-newline: channel should be empty after writing 'b'] -472 ¦ # write newline -473 ¦ sink <- write sink, 10/newline -474 ¦ restart buffer-routine -475 ¦ wait-for-routine-to-block buffer-routine -476 ¦ empty? <- channel-empty? buffered-chan -477 ¦ data-emitted?:bool <- not empty? -478 ¦ assert data-emitted?, [ -479 F buffer-lines-blocks-until-newline: channel should contain data after writing newline] -480 ¦ trace 1, [test], [reached end] -481 ] -482 trace-should-contain [ -483 ¦ test: reached end -484 ] -485 ] -486 -487 def drain source:&:source:char -> result:text, source:&:source:char [ -488 local-scope -489 load-ingredients -490 buf:&:buffer:char <- new-buffer 30 -491 { -492 ¦ c:char, done?:bool <- read source -493 ¦ break-if done? -494 ¦ buf <- append buf, c -495 ¦ loop -496 } -497 result <- buffer-to-array buf -498 ] +379 # A full channel has first-free just before first-full, wasting one slot. +380 # (Other alternatives: https://www.snellman.net/blog/archive/2016-12-13-ring-buffers) +381 def channel-full? chan:&:channel:_elem -> result:bool [ +382 local-scope +383 load-ingredients +384 # tmp = chan.first-free + 1 +385 tmp:num <- get *chan, first-free:offset +386 tmp <- add tmp, 1 +387 { +388 ¦ # if tmp == chan.capacity, tmp = 0 +389 ¦ len:num <- capacity chan +390 ¦ at-end?:bool <- greater-or-equal tmp, len +391 ¦ break-unless at-end? +392 ¦ tmp <- copy 0 +393 } +394 # return chan.first-full == tmp +395 full:num <- get *chan, first-full:offset +396 result <- equal full, tmp +397 ] +398 +399 def capacity chan:&:channel:_elem -> result:num [ +400 local-scope +401 load-ingredients +402 q:&:@:_elem <- get *chan, data:offset +403 result <- length *q +404 ] +405 +406 ## helpers for channels of characters in particular +407 +408 def buffer-lines in:&:source:char, buffered-out:&:sink:char -> buffered-out:&:sink:char, in:&:source:char [ +409 local-scope +410 load-ingredients +411 # repeat forever +412 eof?:bool <- copy 0/false +413 { +414 ¦ line:&:buffer:char <- new-buffer 30 +415 ¦ # read characters from 'in' until newline, copy into line +416 ¦ { +417 ¦ ¦ +next-character +418 ¦ ¦ c:char, eof?:bool, in <- read in +419 ¦ ¦ break-if eof? +420 ¦ ¦ # drop a character on backspace +421 ¦ ¦ { +422 ¦ ¦ ¦ # special-case: if it's a backspace +423 ¦ ¦ ¦ backspace?:bool <- equal c, 8 +424 ¦ ¦ ¦ break-unless backspace? +425 ¦ ¦ ¦ # drop previous character +426 ¦ ¦ ¦ { +427 ¦ ¦ ¦ ¦ buffer-length:num <- get *line, length:offset +428 ¦ ¦ ¦ ¦ buffer-empty?:bool <- equal buffer-length, 0 +429 ¦ ¦ ¦ ¦ break-if buffer-empty? +430 ¦ ¦ ¦ ¦ buffer-length <- subtract buffer-length, 1 +431 ¦ ¦ ¦ ¦ *line <- put *line, length:offset, buffer-length +432 ¦ ¦ ¦ } +433 ¦ ¦ ¦ # and don't append this one +434 ¦ ¦ ¦ loop +next-character +435 ¦ ¦ } +436 ¦ ¦ # append anything else +437 ¦ ¦ line <- append line, c +438 ¦ ¦ line-done?:bool <- equal c, 10/newline +439 ¦ ¦ break-if line-done? +440 ¦ ¦ loop +441 ¦ } +442 ¦ # copy line into 'buffered-out' +443 ¦ i:num <- copy 0 +444 ¦ line-contents:text <- get *line, data:offset +445 ¦ max:num <- get *line, length:offset +446 ¦ { +447 ¦ ¦ done?:bool <- greater-or-equal i, max +448 ¦ ¦ break-if done? +449 ¦ ¦ c:char <- index *line-contents, i +450 ¦ ¦ buffered-out <- write buffered-out, c +451 ¦ ¦ i <- add i, 1 +452 ¦ ¦ loop +453 ¦ } +454 ¦ { +455 ¦ ¦ break-unless eof? +456 ¦ ¦ buffered-out <- close buffered-out +457 ¦ ¦ return +458 ¦ } +459 ¦ loop +460 } +461 ] +462 +463 scenario buffer-lines-blocks-until-newline [ +464 run [ +465 ¦ local-scope +466 ¦ source:&:source:char, sink:&:sink:char <- new-channel 10/capacity +467 ¦ _, buffered-stdin:&:sink:char/buffered-stdin <- new-channel 10/capacity +468 ¦ buffered-chan:&:channel:char <- get *buffered-stdin, chan:offset +469 ¦ empty?:bool <- channel-empty? buffered-chan +470 ¦ assert empty?, [ +471 F buffer-lines-blocks-until-newline: channel should be empty after init] +472 ¦ # buffer stdin into buffered-stdin, try to read from buffered-stdin +473 ¦ buffer-routine:num <- start-running buffer-lines, source, buffered-stdin +474 ¦ wait-for-routine-to-block buffer-routine +475 ¦ empty? <- channel-empty? buffered-chan +476 ¦ assert empty?:bool, [ +477 F buffer-lines-blocks-until-newline: channel should be empty after buffer-lines bring-up] +478 ¦ # write 'a' +479 ¦ sink <- write sink, 97/a +480 ¦ restart buffer-routine +481 ¦ wait-for-routine-to-block buffer-routine +482 ¦ empty? <- channel-empty? buffered-chan +483 ¦ assert empty?:bool, [ +484 F buffer-lines-blocks-until-newline: channel should be empty after writing 'a'] +485 ¦ # write 'b' +486 ¦ sink <- write sink, 98/b +487 ¦ restart buffer-routine +488 ¦ wait-for-routine-to-block buffer-routine +489 ¦ empty? <- channel-empty? buffered-chan +490 ¦ assert empty?:bool, [ +491 F buffer-lines-blocks-until-newline: channel should be empty after writing 'b'] +492 ¦ # write newline +493 ¦ sink <- write sink, 10/newline +494 ¦ restart buffer-routine +495 ¦ wait-for-routine-to-block buffer-routine +496 ¦ empty? <- channel-empty? buffered-chan +497 ¦ data-emitted?:bool <- not empty? +498 ¦ assert data-emitted?, [ +499 F buffer-lines-blocks-until-newline: channel should contain data after writing newline] +500 ¦ trace 1, [test], [reached end] +501 ] +502 trace-should-contain [ +503 ¦ test: reached end +504 ] +505 ] +506 +507 def drain source:&:source:char -> result:text, source:&:source:char [ +508 local-scope +509 load-ingredients +510 buf:&:buffer:char <- new-buffer 30 +511 { +512 ¦ c:char, done?:bool <- read source +513 ¦ break-if done? +514 ¦ buf <- append buf, c +515 ¦ loop +516 } +517 result <- buffer-to-array buf +518 ] diff --git a/html/081print.mu.html b/html/081print.mu.html index 01a5dd12..c32c880f 100644 --- a/html/081print.mu.html +++ b/html/081print.mu.html @@ -167,7 +167,7 @@ if ('onhashchange' in window) { 104 # (handle special cases exactly like in the real screen) 105 width:num <- get *screen, num-columns:offset 106 height:num <- get *screen, num-rows:offset -107 capacity:num <- multiply width, height +107 capacity:num <- multiply width, height 108 row:num <- get *screen, cursor-row:offset 109 column:num <- get *screen, cursor-column:offset 110 buf:&:@:screen-cell <- get *screen, data:offset @@ -297,8 +297,8 @@ if ('onhashchange' in window) { 234 ¦ loop 235 } 236 # top-idx now same as next-top-idx; wrap around if necessary -237 capacity:num <- multiply width, height -238 _, top-idx <- divide-with-remainder, top-idx, capacity +237 capacity:num <- multiply width, height +238 _, top-idx <- divide-with-remainder, top-idx, capacity 239 *screen <- put *screen, top-idx:offset, top-idx 240 ] 241 @@ -309,8 +309,8 @@ if ('onhashchange' in window) { 246 load-ingredients 247 result <- multiply width, row 248 result <- add result, column, top-idx -249 capacity:num <- multiply width, height -250 _, result <- divide-with-remainder result, capacity +249 capacity:num <- multiply width, height +250 _, result <- divide-with-remainder result, capacity 251 ] 252 253 scenario print-character-at-top-left [ diff --git a/html/084console.mu.html b/html/084console.mu.html index 8e1b7952..9c043adf 100644 --- a/html/084console.mu.html +++ b/html/084console.mu.html @@ -140,7 +140,7 @@ if ('onhashchange' in window) { 79 ¦ break-if quit? 80 ¦ assert c, [invalid event, expected text] 81 ¦ screen <- print screen, c - 82 ¦ chan <- write chan, c + 82 ¦ chan <- write chan, c 83 ¦ loop 84 } 85 chan <- close chan diff --git a/html/088file.mu.html b/html/088file.mu.html index e6fad2a8..5ba2c541 100644 --- a/html/088file.mu.html +++ b/html/088file.mu.html @@ -140,7 +140,7 @@ if ('onhashchange' in window) { 79 { 80 ¦ c:char, eof?:bool <- $read-from-file file 81 ¦ break-if eof? - 82 ¦ sink <- write sink, c + 82 ¦ sink <- write sink, c 83 ¦ loop 84 } 85 sink <- close sink @@ -156,7 +156,7 @@ if ('onhashchange' in window) { 95 ¦ done?:bool <- greater-or-equal i, len 96 ¦ break-if done? 97 ¦ c:char <- index *contents, i - 98 ¦ sink <- write sink, c + 98 ¦ sink <- write sink, c 99 ¦ i <- add i, 1 100 ¦ loop 101 } @@ -198,7 +198,7 @@ if ('onhashchange' in window) { 137 ¦ done?:bool <- greater-or-equal i, len 138 ¦ break-if done? 139 ¦ c:char <- index *contents, i -140 ¦ sink-file <- write sink-file, c +140 ¦ sink-file <- write sink-file, c 141 ¦ i <- add i, 1 142 ¦ loop 143 } diff --git a/html/090scenario_filesystem_test.mu.html b/html/090scenario_filesystem_test.mu.html index 43f6a5e8..111095f9 100644 --- a/html/090scenario_filesystem_test.mu.html +++ b/html/090scenario_filesystem_test.mu.html @@ -85,8 +85,8 @@ if ('onhashchange' in window) { 27 assume-resources [ 28 ] 29 sink:&:sink:char, writer:num/routine <- start-writing resources, [a] -30 sink <- write sink, 120/x -31 sink <- write sink, 121/y +30 sink <- write sink, 120/x +31 sink <- write sink, 121/y 32 close sink 33 wait-for-routine writer 34 contents-read-back:text <- slurp resources, [a] @@ -104,8 +104,8 @@ if ('onhashchange' in window) { 46 ¦ ] 47 ] 48 sink:&:sink:char, writer:num/routine <- start-writing resources, [b] -49 sink <- write sink, 120/x -50 sink <- write sink, 121/y +49 sink <- write sink, 120/x +50 sink <- write sink, 121/y 51 close sink 52 wait-for-routine writer 53 contents-read-back:text <- slurp resources, [b] @@ -121,8 +121,8 @@ if ('onhashchange' in window) { 63 ¦ [a] <- [] 64 ] 65 sink:&:sink:char, writer:num/routine <- start-writing resources, [a] -66 sink <- write sink, 120/x -67 sink <- write sink, 121/y +66 sink <- write sink, 120/x +67 sink <- write sink, 121/y 68 close sink 69 wait-for-routine writer 70 contents-read-back:text <- slurp resources, [a] @@ -141,8 +141,8 @@ if ('onhashchange' in window) { 83 ¦ ] 84 ] 85 sink:&:sink:char, writer:num/routine <- start-writing resources, [a] -86 sink <- write sink, 120/x -87 sink <- write sink, 121/y +86 sink <- write sink, 120/x +87 sink <- write sink, 121/y 88 close sink 89 wait-for-routine writer 90 contents-read-back:text <- slurp resources, [a] diff --git a/html/092socket.mu.html b/html/092socket.mu.html index 48903000..a12f5e3a 100644 --- a/html/092socket.mu.html +++ b/html/092socket.mu.html @@ -77,7 +77,7 @@ if ('onhashchange' in window) { 15 ¦ handler-routine:number <- start-running serve-one-request socket, example-handler 16 ] 17 source:&:source:char <- start-reading-from-network 0/real-resources, [localhost/], port - 18 response:text <- drain source + 18 response:text <- drain source 19 10:@:char/raw <- copy *response 20 memory-should-contain [ 21 ¦ 10:array:character <- [abc] @@ -104,7 +104,7 @@ if ('onhashchange' in window) { 42 run [ 43 ¦ source:&:source:char <- start-reading-from-network resources, [example.com/] 44 ] - 45 contents:text <- drain source + 45 contents:text <- drain source 46 10:@:char/raw <- copy *contents 47 memory-should-contain [ 48 ¦ 10:array:character <- [abc @@ -122,7 +122,7 @@ if ('onhashchange' in window) { 60 F - example-server-test: $accept failed] 61 contents:&:source:char, sink:&:sink:char <- new-channel 30 62 start-running receive-from-socket session, sink - 63 query:text <- drain contents + 63 query:text <- drain contents 64 response:text <- call request-handler, query 65 write-to-socket session, response 66 session <- $close-socket session @@ -173,7 +173,7 @@ if ('onhashchange' in window) { 111 ¦ break-if error 112 ¦ { 113 ¦ ¦ break-unless found? -114 ¦ ¦ sink <- write sink, c +114 ¦ ¦ sink <- write sink, c 115 ¦ } 116 ¦ { 117 ¦ ¦ break-if found? diff --git a/html/channel.mu.html b/html/channel.mu.html index bb0808f1..8144078a 100644 --- a/html/channel.mu.html +++ b/html/channel.mu.html @@ -72,7 +72,7 @@ if ('onhashchange' in window) { 12 ¦ # other threads might get between these prints 13 ¦ $print [produce: ], n, [ 14 ] -15 ¦ sink <- write sink, n +15 ¦ sink <- write sink, n 16 ¦ n <- add n, 1 17 ¦ loop 18 } diff --git a/html/chessboard.mu.html b/html/chessboard.mu.html index e4c4b112..ddc76c22 100644 --- a/html/chessboard.mu.html +++ b/html/chessboard.mu.html @@ -139,7 +139,7 @@ if ('onhashchange' in window) { 75 start-running send-keys-to-channel, console, stdin-out, screen 76 # buffer lines in stdin 77 buffered-stdin-in:&:source:char, buffered-stdin-out:&:sink:char <- new-channel 10/capacity - 78 start-running buffer-lines, stdin-in, buffered-stdin-out + 78 start-running buffer-lines, stdin-in, buffered-stdin-out 79 { 80 ¦ print screen, [Stupid text-mode chessboard. White pieces in uppercase; black pieces in lowercase. No checking for legal moves. 81 ] @@ -156,7 +156,7 @@ if ('onhashchange' in window) { 92 ¦ ¦ screen <- print screen, [move: ] 93 ¦ ¦ m:&:move, quit:bool, error:bool <- read-move buffered-stdin-in, screen 94 ¦ ¦ break-if quit, +quit - 95 ¦ ¦ buffered-stdin-in <- clear buffered-stdin-in # cleanup after error. todo: test this? + 95 ¦ ¦ buffered-stdin-in <- clear buffered-stdin-in # cleanup after error. todo: test this? 96 ¦ ¦ loop-if error 97 ¦ } 98 ¦ board <- make-move board, m @@ -442,7 +442,7 @@ if ('onhashchange' in window) { 378 ¦ assert waiting?, [ 379 F read-move-blocking: routine failed to pause after coming up (before any keys were pressed)] 380 ¦ # press 'a' -381 ¦ sink <- write sink, 97/a +381 ¦ sink <- write sink, 97/a 382 ¦ restart read-move-routine 383 ¦ # 'read-move' still waiting for input 384 ¦ wait-for-routine-to-block read-move-routine @@ -451,7 +451,7 @@ if ('onhashchange' in window) { 387 ¦ assert waiting?, [ 388 F read-move-blocking: routine failed to pause after rank 'a'] 389 ¦ # press '2' -390 ¦ sink <- write sink, 50/'2' +390 ¦ sink <- write sink, 50/'2' 391 ¦ restart read-move-routine 392 ¦ # 'read-move' still waiting for input 393 ¦ wait-for-routine-to-block read-move-routine @@ -460,7 +460,7 @@ if ('onhashchange' in window) { 396 ¦ assert waiting?, [ 397 F read-move-blocking: routine failed to pause after file 'a2'] 398 ¦ # press '-' -399 ¦ sink <- write sink, 45/'-' +399 ¦ sink <- write sink, 45/'-' 400 ¦ restart read-move-routine 401 ¦ # 'read-move' still waiting for input 402 ¦ wait-for-routine-to-block read-move-routine @@ -469,7 +469,7 @@ if ('onhashchange' in window) { 405 ¦ assert waiting?, [ 406 F read-move-blocking: routine failed to pause after hyphen 'a2-'] 407 ¦ # press 'a' -408 ¦ sink <- write sink, 97/a +408 ¦ sink <- write sink, 97/a 409 ¦ restart read-move-routine 410 ¦ # 'read-move' still waiting for input 411 ¦ wait-for-routine-to-block read-move-routine @@ -478,7 +478,7 @@ if ('onhashchange' in window) { 414 ¦ assert waiting?, [ 415 F read-move-blocking: routine failed to pause after rank 'a2-a'] 416 ¦ # press '4' -417 ¦ sink <- write sink, 52/'4' +417 ¦ sink <- write sink, 52/'4' 418 ¦ restart read-move-routine 419 ¦ # 'read-move' still waiting for input 420 ¦ wait-for-routine-to-block read-move-routine @@ -487,7 +487,7 @@ if ('onhashchange' in window) { 423 ¦ assert waiting?, [ 424 F read-move-blocking: routine failed to pause after file 'a2-a4'] 425 ¦ # press 'newline' -426 ¦ sink <- write sink, 10 # newline +426 ¦ sink <- write sink, 10 # newline 427 ¦ restart read-move-routine 428 ¦ # 'read-move' now completes 429 ¦ wait-for-routine-to-block read-move-routine @@ -515,7 +515,7 @@ if ('onhashchange' in window) { 451 ¦ assert waiting?, [ 452 F read-move-quit: routine failed to pause after coming up (before any keys were pressed)] 453 ¦ # press 'q' -454 ¦ sink <- write sink, 113/q +454 ¦ sink <- write sink, 113/q 455 ¦ restart read-move-routine 456 ¦ # 'read-move' completes 457 ¦ wait-for-routine-to-block read-move-routine @@ -542,7 +542,7 @@ if ('onhashchange' in window) { 478 ¦ waiting?:bool <- not-equal read-move-state, 2/discontinued 479 ¦ assert waiting?, [ 480 F read-move-illegal-file: routine failed to pause after coming up (before any keys were pressed)] -481 ¦ sink <- write sink, 50/'2' +481 ¦ sink <- write sink, 50/'2' 482 ¦ restart read-move-routine 483 ¦ wait-for-routine-to-block read-move-routine 484 ] @@ -564,8 +564,8 @@ if ('onhashchange' in window) { 500 ¦ waiting?:bool <- not-equal read-move-state, 2/discontinued 501 ¦ assert waiting?, [ 502 F read-move-illegal-rank: routine failed to pause after coming up (before any keys were pressed)] -503 ¦ sink <- write sink, 97/a -504 ¦ sink <- write sink, 97/a +503 ¦ sink <- write sink, 97/a +504 ¦ sink <- write sink, 97/a 505 ¦ restart read-move-routine 506 ¦ wait-for-routine-to-block read-move-routine 507 ] @@ -587,8 +587,8 @@ if ('onhashchange' in window) { 523 ¦ waiting?:bool <- not-equal read-move-state, 2/discontinued 524 ¦ assert waiting?, [ 525 F read-move-empty: routine failed to pause after coming up (before any keys were pressed)] -526 ¦ sink <- write sink, 10/newline -527 ¦ sink <- write sink, 97/a +526 ¦ sink <- write sink, 10/newline +527 ¦ sink <- write sink, 97/a 528 ¦ restart read-move-routine 529 ¦ wait-for-routine-to-block read-move-routine 530 ] diff --git a/html/filesystem.mu.html b/html/filesystem.mu.html index 40703554..13db4aef 100644 --- a/html/filesystem.mu.html +++ b/html/filesystem.mu.html @@ -70,7 +70,7 @@ if ('onhashchange' in window) { 10 { 11 ¦ c:char, done?:bool, source-file <- read source-file 12 ¦ break-if done? -13 ¦ sink-file <- write sink-file, c +13 ¦ sink-file <- write sink-file, c 14 ¦ loop 15 } 16 close sink-file diff --git a/html/http-server.mu.html b/html/http-server.mu.html index 21ee77c7..c8aa3c67 100644 --- a/html/http-server.mu.html +++ b/html/http-server.mu.html @@ -73,7 +73,7 @@ if ('onhashchange' in window) { 15 session:num <- $accept socket 16 contents:&:source:char, sink:&:sink:char <- new-channel 30 17 sink <- start-running receive-from-socket session, sink -18 query:text <- drain contents +18 query:text <- drain contents 19 $print [Done reading from socket.], 10/newline 20 write-to-socket session, [HTTP/1.0 200 OK 21 Content-type: text/plain diff --git a/html/real-files.mu.html b/html/real-files.mu.html index 6b1d9130..c72cb608 100644 --- a/html/real-files.mu.html +++ b/html/real-files.mu.html @@ -69,7 +69,7 @@ if ('onhashchange' in window) { 12 f <- $close-file f 13 $print [file after closing: ], f, 10/newline 14 f <- $open-file-for-writing [/tmp/mu-y] -15 $print [file to write to: ], f, 10/newline +15 $print [file to write to: ], f, 10/newline 16 $write-to-file f, c 17 f <- $close-file f 18 ] -- cgit 1.4.1-2-gfad0