diff options
-rw-r--r-- | 056recipe_header.cc | 4 | ||||
-rw-r--r-- | 070string.mu | 205 | ||||
-rw-r--r-- | 071channel.mu | 56 | ||||
-rw-r--r-- | 076stream.mu | 27 | ||||
-rw-r--r-- | 081print.mu | 243 | ||||
-rw-r--r-- | 084console.mu | 47 | ||||
-rw-r--r-- | channel.mu | 8 | ||||
-rw-r--r-- | chessboard.mu | 74 | ||||
-rw-r--r-- | edit/001-editor.mu | 6 |
9 files changed, 283 insertions, 387 deletions
diff --git a/056recipe_header.cc b/056recipe_header.cc index c7b361d6..e918074d 100644 --- a/056recipe_header.cc +++ b/056recipe_header.cc @@ -145,9 +145,7 @@ void check_reply_instructions_against_header(const recipe_ordinal r) { for (long long int i = 0; i < SIZE(caller_recipe.steps); ++i) { const instruction& inst = caller_recipe.steps.at(i); if (inst.name != "reply") continue; - if (SIZE(caller_recipe.products) != SIZE(inst.ingredients)) - raise_error << maybe(caller_recipe.name) << "tried to reply the wrong number of products in '" << inst.to_string() << "'\n" << end(); - for (long long int i = 0; i < SIZE(caller_recipe.products); ++i) { + for (long long int i = 0; i < SIZE(inst.ingredients); ++i) { if (!types_match(caller_recipe.products.at(i), inst.ingredients.at(i))) raise_error << maybe(caller_recipe.name) << "replied with the wrong type at '" << inst.to_string() << "'\n" << end(); } diff --git a/070string.mu b/070string.mu index 854e27a9..640a85c8 100644 --- a/070string.mu +++ b/070string.mu @@ -1,10 +1,9 @@ # Some useful helpers for dealing with strings. -recipe string-equal [ +recipe string-equal a:address:array:character, b:address:array:character -> result:boolean [ local-scope - a:address:array:character <- next-ingredient + load-ingredients a-len:number <- length *a - b:address:array:character <- next-ingredient b-len:number <- length *b # compare lengths { @@ -103,21 +102,20 @@ container buffer [ data:address:array:character ] -recipe new-buffer [ +recipe new-buffer capacity:number -> result:address:buffer [ local-scope - result:address:buffer <- new buffer:type + load-ingredients + result <- new buffer:type len:address:number <- get-address *result, length:offset *len:address:number <- copy 0 s:address:address:array:character <- get-address *result, data:offset - capacity:number, found?:boolean <- next-ingredient - assert found?, [new-buffer must get a capacity argument] *s <- new character:type, capacity reply result ] -recipe grow-buffer [ +recipe grow-buffer in:address:buffer -> in:address:buffer [ local-scope - in:address:buffer <- next-ingredient + load-ingredients # double buffer size x:address:address:array:character <- get-address *in, data:offset oldlen:number <- length **x @@ -135,33 +133,29 @@ recipe grow-buffer [ i <- add i, 1 loop } - reply in ] -recipe buffer-full? [ +recipe buffer-full? in:address:buffer -> result:boolean [ local-scope - in:address:buffer <- next-ingredient + load-ingredients len:number <- get *in, length:offset s:address:array:character <- get *in, data:offset capacity:number <- length *s - result:boolean <- greater-or-equal len, capacity - reply result + result <- greater-or-equal len, capacity ] -# in <- buffer-append in:address:buffer, c:character -recipe buffer-append [ +recipe buffer-append in:address:buffer, c:character -> in:address:buffer [ local-scope - in:address:buffer <- next-ingredient - c:character <- next-ingredient + load-ingredients len:address:number <- get-address *in, length:offset { # backspace? just drop last character if it exists and return backspace?:boolean <- equal c, 8/backspace break-unless backspace? empty?:boolean <- lesser-or-equal *len, 0 - reply-if empty?, in/same-as-ingredient:0 + reply-if empty? *len <- subtract *len, 1 - reply in/same-as-ingredient:0 + reply } { # grow buffer if necessary @@ -173,7 +167,6 @@ recipe buffer-append [ dest:address:character <- index-address *s, *len *dest <- copy c *len <- add *len, 1 - reply in/same-as-ingredient:0 ] scenario buffer-append-works [ @@ -232,14 +225,14 @@ scenario buffer-append-handles-backspace [ ] # result:address:array:character <- integer-to-decimal-string n:number -recipe integer-to-decimal-string [ +recipe integer-to-decimal-string n:number -> result:address:array:character [ local-scope - n:number <- next-ingredient - # is it zero? + load-ingredients + # is n zero? { break-if n - result:address:array:character <- new [0] - reply result + result <- new [0] + reply } # save sign negate-result:boolean <- copy 0 @@ -268,7 +261,7 @@ recipe integer-to-decimal-string [ # reverse buffer into string result len:number <- get *tmp, length:offset buf:address:array:character <- get *tmp, data:offset - result:address:array:character <- new character:type, len + result <- new character:type, len i:number <- subtract len, 1 # source index, decreasing j:number <- copy 0 # destination index, increasing { @@ -283,12 +276,11 @@ recipe integer-to-decimal-string [ j <- add j, 1 loop } - reply result ] -recipe buffer-to-array [ +recipe buffer-to-array in:address:buffer -> result:address:array:character [ local-scope - in:address:buffer <- next-ingredient + load-ingredients { # propagate null buffer break-if in @@ -297,7 +289,7 @@ recipe buffer-to-array [ len:number <- get *in, length:offset s:address:array:character <- get *in, data:offset # we can't just return s because it is usually the wrong length - result:address:array:character <- new character:type, len + result <- new character:type, len i:number <- copy 0 { done?:boolean <- greater-or-equal i, len @@ -308,7 +300,6 @@ recipe buffer-to-array [ i <- add i, 1 loop } - reply result ] scenario integer-to-decimal-digit-zero [ @@ -343,16 +334,14 @@ scenario integer-to-decimal-digit-negative [ ] ] -# result:address:array:character <- string-append a:address:array:character, b:address:array:character -recipe string-append [ +recipe string-append a:address:array:character, b:address:array:character -> result:address:array:character [ local-scope + load-ingredients # result = new character[a.length + b.length] - a:address:array:character <- next-ingredient a-len:number <- length *a - b:address:array:character <- next-ingredient b-len:number <- length *b result-len:number <- add a-len, b-len - result:address:array:character <- new character:type, result-len + result <- new character:type, result-len # copy a into result result-idx:number <- copy 0 i:number <- copy 0 @@ -382,7 +371,6 @@ recipe string-append [ result-idx <- add result-idx, 1 loop } - reply result ] scenario string-append-1 [ @@ -408,11 +396,9 @@ scenario replace-character-in-string [ ] ] -recipe string-replace [ +recipe string-replace s:address:array:character, oldc:character, newc:character -> s:address:array:character [ local-scope - s:address:array:character <- next-ingredient - oldc:character <- next-ingredient - newc:character <- next-ingredient + load-ingredients from:number, _ <- next-ingredient # default to 0 len:number <- length *s i:number <- find-next s, oldc, from @@ -422,7 +408,6 @@ recipe string-replace [ *dest <- copy newc i <- add i, 1 s <- string-replace s, oldc, newc, i - reply s/same-as-ingredient:0 ] scenario replace-character-at-start [ @@ -470,15 +455,14 @@ scenario replace-all-characters [ ] # replace underscores in first with remaining args -# result:address:array:character <- interpolate template:address:array:character, ... -recipe interpolate [ +recipe interpolate template:address:array:character -> result:address:array:character [ local-scope - template:address:array:character <- next-ingredient + load-ingredients # consume just the template # compute result-len, space to allocate for result tem-len:number <- length *template result-len:number <- copy tem-len { - # while arg received + # while ingredients remain a:address:array:character, arg-received?:boolean <- next-ingredient break-unless arg-received? # result-len = result-len + arg.length - 1 (for the 'underscore' being replaced) @@ -545,7 +529,6 @@ recipe interpolate [ result-idx <- add result-idx, 1 loop } - reply result ] scenario interpolate-works [ @@ -586,72 +569,70 @@ scenario interpolate-at-end [ ] # result:boolean <- space? c:character -recipe space? [ +recipe space? c:character -> result:boolean [ local-scope - c:character <- next-ingredient + load-ingredients # most common case first - result:boolean <- equal c, 32/space - reply-if result, result + result <- equal c, 32/space + reply-if result result <- equal c, 10/newline - reply-if result, result + reply-if result result <- equal c, 9/tab - reply-if result, result + reply-if result result <- equal c, 13/carriage-return - reply-if result, result + reply-if result # remaining uncommon cases in sorted order # http://unicode.org code-points in unicode-set Z and Pattern_White_Space result <- equal c, 11/ctrl-k - reply-if result, result + reply-if result result <- equal c, 12/ctrl-l - reply-if result, result + reply-if result result <- equal c, 133/ctrl-0085 - reply-if result, result + reply-if result result <- equal c, 160/no-break-space - reply-if result, result + reply-if result result <- equal c, 5760/ogham-space-mark - reply-if result, result + reply-if result result <- equal c, 8192/en-quad - reply-if result, result + reply-if result result <- equal c, 8193/em-quad - reply-if result, result + reply-if result result <- equal c, 8194/en-space - reply-if result, result + reply-if result result <- equal c, 8195/em-space - reply-if result, result + reply-if result result <- equal c, 8196/three-per-em-space - reply-if result, result + reply-if result result <- equal c, 8197/four-per-em-space - reply-if result, result + reply-if result result <- equal c, 8198/six-per-em-space - reply-if result, result + reply-if result result <- equal c, 8199/figure-space - reply-if result, result + reply-if result result <- equal c, 8200/punctuation-space - reply-if result, result + reply-if result result <- equal c, 8201/thin-space - reply-if result, result + reply-if result result <- equal c, 8202/hair-space - reply-if result, result + reply-if result result <- equal c, 8206/left-to-right - reply-if result, result + reply-if result result <- equal c, 8207/right-to-left - reply-if result, result + reply-if result result <- equal c, 8232/line-separator - reply-if result, result + reply-if result result <- equal c, 8233/paragraph-separator - reply-if result, result + reply-if result result <- equal c, 8239/narrow-no-break-space - reply-if result, result + reply-if result result <- equal c, 8287/medium-mathematical-space - reply-if result, result + reply-if result result <- equal c, 12288/ideographic-space - reply result ] -# result:address:array:character <- trim s:address:array:character -recipe trim [ +recipe trim s:address:array:character -> result:address:array:character [ local-scope - s:address:array:character <- next-ingredient + load-ingredients len:number <- length *s # left trim: compute start start:number <- copy 0 @@ -659,8 +640,8 @@ recipe trim [ { at-end?:boolean <- greater-or-equal start, len break-unless at-end? - result:address:array:character <- new character:type, 0 - reply result + result <- new character:type, 0 + reply } curr:character <- index *s, start whitespace?:boolean <- space? curr @@ -697,7 +678,6 @@ recipe trim [ j <- add j, 1 loop } - reply result ] scenario trim-unmodified [ @@ -756,8 +736,7 @@ scenario trim-newline-tab [ ] ] -# next-index:number <- find-next text:address:array:character, pattern:character, idx:number -recipe find-next [ +recipe find-next text:address:array:character, pattern:character, idx:number -> next-index:number [ local-scope text:address:array:character <- next-ingredient pattern:character <- next-ingredient @@ -855,14 +834,11 @@ scenario string-find-next-second [ ] ] -# next-index:number <- find-substring text:address:array:character, pattern:address:array:character, idx:number # like find-next, but searches for multiple characters # fairly dumb algorithm -recipe find-substring [ +recipe find-substring text:address:array:character, pattern:address:array:character, idx:number -> next-idx:number [ local-scope - text:address:array:character <- next-ingredient - pattern:address:array:character <- next-ingredient - idx:number <- next-ingredient + load-ingredients first:character <- index *pattern, 0 # repeatedly check for match at current idx len:number <- length *text @@ -935,13 +911,10 @@ scenario find-substring-suffix-match-2 [ ] ] -# result:boolean <- match-at text:address:array:character, pattern:address:array:character, idx:number # checks if substring matches at index 'idx' -recipe match-at [ +recipe match-at text:address:array:character, pattern:address:array:character, idx:number -> result:boolean [ local-scope - text:address:array:character <- next-ingredient - pattern:address:array:character <- next-ingredient - idx:number <- next-ingredient + load-ingredients pattern-len:number <- length *pattern # check that there's space left for the pattern { @@ -1067,18 +1040,16 @@ scenario match-at-inside-bounds-2 [ ] ] -# result:address:array:address:array:character <- split s:address:array:character, delim:character -recipe split [ +recipe split s:address:array:character, delim:character -> result:address:array:address:array:character [ local-scope - s:address:array:character <- next-ingredient - delim:character <- next-ingredient + load-ingredients # empty string? return empty array len:number <- length *s { empty?:boolean <- equal len, 0 break-unless empty? - result:address:array:address:array:character <- new location:type, 0 - reply result + result <- new location:type, 0 + reply } # count #pieces we need room for count:number <- copy 1 # n delimiters = n+1 pieces @@ -1092,7 +1063,7 @@ recipe split [ loop } # allocate space - result:address:array:address:array:character <- new location:type, count + result <- new location:type, count # repeatedly copy slices start..end until delimiter into result[curr-result] curr-result:number <- copy 0 start:number <- copy 0 @@ -1109,7 +1080,6 @@ recipe split [ curr-result <- add curr-result, 1 loop } - reply result ] scenario string-split-1 [ @@ -1197,11 +1167,9 @@ scenario string-split-empty-piece [ ] ] -# x:address:array:character, y:address:array:character <- split-first text:address:array:character, delim:character -recipe split-first [ +recipe split-first text:address:array:character, delim:character -> x:address:array:character, y:address:array:character [ local-scope - text:address:array:character <- next-ingredient - delim:character <- next-ingredient + load-ingredients # empty string? return empty strings len:number <- length *text { @@ -1209,13 +1177,12 @@ recipe split-first [ break-unless empty? x:address:array:character <- new [] y:address:array:character <- new [] - reply x, y + reply } idx:number <- find-next text, delim, 0 x:address:array:character <- string-copy text, 0, idx idx <- add idx, 1 y:address:array:character <- string-copy text, idx, len - reply x, y ] scenario string-split-first [ @@ -1231,13 +1198,10 @@ scenario string-split-first [ ] ] -# result:address:array:character <- string-copy buf:address:array:character, start:number, end:number # todo: make this generic -recipe string-copy [ +recipe string-copy buf:address:array:character, start:number, end:number -> result:address:array:character [ local-scope - buf:address:array:character <- next-ingredient - start:number <- next-ingredient - end:number <- next-ingredient + load-ingredients # if end is out of bounds, trim it len:number <- length *buf end:number <- min len, end @@ -1257,7 +1221,6 @@ recipe string-copy [ dest-idx <- add dest-idx, 1 loop } - reply result ] scenario string-copy-copies-substring [ @@ -1293,10 +1256,9 @@ scenario string-copy-out-of-bounds-2 [ ] ] -recipe min [ +recipe min x:number, y:number -> z:number [ local-scope - x:number <- next-ingredient - y:number <- next-ingredient + load-ingredients { return-x?:boolean <- lesser-than x, y break-if return-x? @@ -1305,10 +1267,9 @@ recipe min [ reply x ] -recipe max [ +recipe max x:number, y:number -> z:number [ local-scope - x:number <- next-ingredient - y:number <- next-ingredient + load-ingredients { return-x?:boolean <- greater-than x, y break-if return-x? diff --git a/071channel.mu b/071channel.mu index c8ca6cc9..d0dc3f88 100644 --- a/071channel.mu +++ b/071channel.mu @@ -32,10 +32,10 @@ container channel [ ] # result:address:channel <- new-channel capacity:number -recipe new-channel [ +recipe new-channel capacity:number -> result:address:channel [ local-scope - # result = new channel - result:address:channel <- new channel:type + load-ingredients + result <- new channel:type # result.first-full = 0 full:address:number <- get-address *result, first-full:offset *full <- copy 0 @@ -43,18 +43,14 @@ recipe new-channel [ free:address:number <- get-address *result, first-free:offset *free <- copy 0 # result.data = new location[ingredient+1] - capacity:number <- next-ingredient capacity <- add capacity, 1 # unused slot for 'full?' below dest:address:address:array:character <- get-address *result, data:offset *dest <- new character:type, capacity - reply result ] -# chan <- write chan:address:channel, val:character -recipe write [ +recipe write chan:address:channel, val:character -> chan:address:channel [ local-scope - chan:address:channel <- next-ingredient - val:character <- next-ingredient + load-ingredients { # block if chan is full full:boolean <- channel-full? chan @@ -76,13 +72,11 @@ recipe write [ break-unless at-end? *free <- copy 0 } - reply chan/same-as-ingredient:0 ] -# result:character, chan <- read chan:address:channel -recipe read [ +recipe read chan:address:channel -> result:character, chan:address:channel [ local-scope - chan:address:channel <- next-ingredient + load-ingredients { # block if chan is empty empty?:boolean <- channel-empty? chan @@ -93,7 +87,7 @@ recipe read [ # read result full:address:number <- get-address *chan, first-full:offset circular-buffer:address:array:character <- get *chan, data:offset - result:character <- index *circular-buffer, *full + result <- index *circular-buffer, *full # mark its slot as empty *full <- add *full, 1 { @@ -103,18 +97,16 @@ recipe read [ break-unless at-end? *full <- copy 0 } - reply result, chan/same-as-ingredient:0 ] -recipe clear-channel [ +recipe clear-channel chan:address:channel -> chan:address:channel [ local-scope - chan:address:channel <- next-ingredient + load-ingredients { empty?:boolean <- channel-empty? chan break-if empty? _, chan <- read chan } - reply chan/same-as-ingredient:0 ] scenario channel-initialization [ @@ -184,21 +176,20 @@ scenario channel-wrap [ ## helpers # An empty channel has first-empty and first-full both at the same value. -recipe channel-empty? [ +recipe channel-empty? chan:address:channel -> result:boolean [ local-scope - chan:address:channel <- next-ingredient + load-ingredients # return chan.first-full == chan.first-free full:number <- get *chan, first-full:offset free:number <- get *chan, first-free:offset - result:boolean <- equal full, free - reply result + result <- equal full, free ] # A full channel has first-empty just before first-full, wasting one slot. # (Other alternatives: https://en.wikipedia.org/wiki/Circular_buffer#Full_.2F_Empty_Buffer_Distinction) -recipe channel-full? [ +recipe channel-full? chan:address:channel -> result:boolean [ local-scope - chan:address:channel <- next-ingredient + load-ingredients # tmp = chan.first-free + 1 tmp:number <- get *chan, first-free:offset tmp <- add tmp, 1 @@ -211,17 +202,15 @@ recipe channel-full? [ } # return chan.first-full == tmp full:number <- get *chan, first-full:offset - result:boolean <- equal full, tmp - reply result + result <- equal full, tmp ] # result:number <- channel-capacity chan:address:channel -recipe channel-capacity [ +recipe channel-capacity chan:address:channel -> result:number [ local-scope - chan:address:channel <- next-ingredient + load-ingredients q:address:array:character <- get *chan, data:offset - result:number <- length *q - reply result + result <- length *q ] scenario channel-new-empty-not-full [ @@ -277,11 +266,9 @@ scenario channel-read-not-full [ ] # helper for channels of characters in particular -# out <- buffer-lines in:address:channel, out:address:channel -recipe buffer-lines [ +recipe buffer-lines in:address:channel, out:address:channel -> out:address:channel, in:address:channel [ local-scope - in:address:channel <- next-ingredient - out:address:channel <- next-ingredient + load-ingredients # repeat forever { line:address:buffer <- new-buffer, 30 @@ -327,7 +314,6 @@ recipe buffer-lines [ } loop } - reply out/same-as-ingredient:1 ] scenario buffer-lines-blocks-until-newline [ diff --git a/076stream.mu b/076stream.mu index 0ee3e2c1..bb441ade 100644 --- a/076stream.mu +++ b/076stream.mu @@ -4,41 +4,38 @@ container stream [ data:address:array:character ] -recipe new-stream [ +recipe new-stream s:address:array:character -> result:address:stream [ local-scope - result:address:stream <- new stream:type + load-ingredients + result <- new stream:type i:address:number <- get-address *result, index:offset *i <- copy 0 d:address:address:array:character <- get-address *result, data:offset - *d <- next-ingredient - reply result + *d <- copy s ] -recipe rewind-stream [ +recipe rewind-stream in:address:stream -> in:address:stream [ local-scope - in:address:stream <- next-ingredient + load-ingredients x:address:number <- get-address *in, index:offset *x <- copy 0 - reply in/same-as-arg:0 ] -recipe read-line [ +recipe read-line in:address:stream -> result:address:array:character, in:address:stream [ local-scope - in:address:stream <- next-ingredient + load-ingredients idx:address:number <- get-address *in, index:offset s:address:array:character <- get *in, data:offset next-idx:number <- find-next s, 10/newline, *idx - result:address:array:character <- string-copy s, *idx, next-idx + result <- string-copy s, *idx, next-idx *idx <- add next-idx, 1 # skip newline - reply result ] -recipe end-of-stream? [ +recipe end-of-stream? in:address:stream -> result:boolean [ local-scope - in:address:stream <- next-ingredient + load-ingredients idx:number <- get *in, index:offset s:address:array:character <- get *in, data:offset len:number <- length *s - result:boolean <- greater-or-equal idx, len - reply result + result <- greater-or-equal idx, len ] diff --git a/081print.mu b/081print.mu index c3d08180..a0c39e9f 100644 --- a/081print.mu +++ b/081print.mu @@ -14,13 +14,14 @@ container screen-cell [ color:number ] -recipe new-fake-screen [ +recipe new-fake-screen w:number, h:number -> result:address:screen [ local-scope - result:address:screen <- new screen:type + load-ingredients + result <- new screen:type width:address:number <- get-address *result, num-columns:offset - *width <- next-ingredient + *width <- copy w height:address:number <- get-address *result, num-rows:offset - *height <- next-ingredient + *height <- copy h row:address:number <- get-address *result, cursor-row:offset *row <- copy 0 column:address:number <- get-address *result, cursor-column:offset @@ -28,18 +29,17 @@ recipe new-fake-screen [ bufsize:number <- multiply *width, *height buf:address:address:array:screen-cell <- get-address *result, data:offset *buf <- new screen-cell:type, bufsize - clear-screen result - reply result + result <- clear-screen result ] -recipe clear-screen [ +recipe clear-screen screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists { - break-unless sc + break-unless screen # clear fake screen - buf:address:array:screen-cell <- get *sc, data:offset + buf:address:array:screen-cell <- get *screen, data:offset max:number <- length *buf i:number <- copy 0 { @@ -54,32 +54,31 @@ recipe clear-screen [ loop } # reset cursor - x:address:number <- get-address *sc, cursor-row:offset + x:address:number <- get-address *screen, cursor-row:offset *x <- copy 0 - x <- get-address *sc, cursor-column:offset + x <- get-address *screen, cursor-column:offset *x <- copy 0 - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen clear-display - reply sc/same-as-ingredient:0 ] -recipe sync-screen [ +recipe sync-screen screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient + screen:address:screen <- next-ingredient { - break-if sc + break-if screen sync-display } # do nothing for fake screens ] -recipe fake-screen-is-empty? [ +recipe fake-screen-is-empty? screen:address:screen -> result:boolean [ local-scope - sc:address:screen <- next-ingredient - reply-unless sc, 1/true - buf:address:array:screen-cell <- get *sc, data:offset + load-ingredients + reply-unless screen, 1/true + buf:address:array:screen-cell <- get *screen, data:offset i:number <- copy 0 len:number <- length *buf { @@ -95,10 +94,9 @@ recipe fake-screen-is-empty? [ reply 1/true ] -recipe print-character [ +recipe print-character screen:address:screen, c:character -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient - c:character <- next-ingredient + load-ingredients color:number, color-found?:boolean <- next-ingredient { # default color to white @@ -115,20 +113,20 @@ recipe print-character [ { # if x exists # (handle special cases exactly like in the real screen) - break-unless sc - width:number <- get *sc, num-columns:offset - height:number <- get *sc, num-rows:offset + break-unless screen + width:number <- get *screen, num-columns:offset + height:number <- get *screen, num-rows:offset # if cursor is out of bounds, silently exit - row:address:number <- get-address *sc, cursor-row:offset + row:address:number <- get-address *screen, cursor-row:offset legal?:boolean <- greater-or-equal *row, 0 - reply-unless legal?, sc + reply-unless legal? legal? <- lesser-than *row, height - reply-unless legal?, sc - column:address:number <- get-address *sc, cursor-column:offset + reply-unless legal? + column:address:number <- get-address *screen, cursor-column:offset legal? <- greater-or-equal *column, 0 - reply-unless legal?, sc + reply-unless legal? legal? <- lesser-than *column, width - reply-unless legal?, sc + reply-unless legal? # special-case: newline { newline?:boolean <- equal c, 10/newline @@ -142,12 +140,12 @@ recipe print-character [ *column <- copy 0 *row <- add *row, 1 } - reply sc/same-as-ingredient:0 + reply } # save character in fake screen index:number <- multiply *row, width index <- add index, *column - buf:address:array:screen-cell <- get *sc, data:offset + buf:address:array:screen-cell <- get *screen, data:offset len:number <- length *buf # special-case: backspace { @@ -166,7 +164,7 @@ recipe print-character [ cursor-color:address:number <- get-address *cursor, color:offset *cursor-color <- copy 7/white } - reply sc/same-as-ingredient:0 + reply } cursor:address:screen-cell <- index-address *buf, index cursor-contents:address:character <- get-address *cursor, contents:offset @@ -180,11 +178,10 @@ recipe print-character [ break-if at-right? *column <- add *column, 1 } - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen print-character-to-display c, color, bg-color - reply sc/same-as-ingredient:0 ] scenario print-character-at-top-left [ @@ -340,63 +337,58 @@ scenario print-at-bottom-right [ ] ] -recipe clear-line [ +recipe clear-line screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, clear line in fake screen { - break-unless sc - width:number <- get *sc, num-columns:offset - column:address:number <- get-address *sc, cursor-column:offset + break-unless screen + width:number <- get *screen, num-columns:offset + column:address:number <- get-address *screen, cursor-column:offset original-column:number <- copy *column # space over the entire line { right:number <- subtract width, 1 done?:boolean <- greater-or-equal *column, right break-if done? - print-character sc, [ ] # implicitly updates 'column' + print-character screen, [ ] # implicitly updates 'column' loop } # now back to where the cursor was *column <- copy original-column - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen clear-line-on-display - reply sc/same-as-ingredient:0 ] -recipe cursor-position [ +recipe cursor-position screen:address:screen -> row:number, column:number [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, lookup cursor in fake screen { - break-unless sc - row:number <- get *sc, cursor-row:offset - column:number <- get *sc, cursor-column:offset - reply row, column, sc/same-as-ingredient:0 + break-unless screen + row:number <- get *screen, cursor-row:offset + column:number <- get *screen, cursor-column:offset + reply } row, column <- cursor-position-on-display - reply row, column, sc/same-as-ingredient:0 ] -recipe move-cursor [ +recipe move-cursor screen:address:screen, new-row:number, new-column:number -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient - new-row:number <- next-ingredient - new-column:number <- next-ingredient + load-ingredients # if x exists, move cursor in fake screen { - break-unless sc - row:address:number <- get-address *sc, cursor-row:offset + break-unless screen + row:address:number <- get-address *screen, cursor-row:offset *row <- copy new-row - column:address:number <- get-address *sc, cursor-column:offset + column:address:number <- get-address *screen, cursor-column:offset *column <- copy new-column - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen move-cursor-on-display new-row, new-column - reply sc/same-as-ingredient:0 ] scenario clear-line-erases-printed-characters [ @@ -429,193 +421,180 @@ scenario clear-line-erases-printed-characters [ ] ] -recipe cursor-down [ +recipe cursor-down screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, move cursor in fake screen { - break-unless sc + break-unless screen { # increment row unless it's already all the way down - height:number <- get *sc, num-rows:offset - row:address:number <- get-address *sc, cursor-row:offset + height:number <- get *screen, num-rows:offset + row:address:number <- get-address *screen, cursor-row:offset max:number <- subtract height, 1 at-bottom?:boolean <- greater-or-equal *row, max break-if at-bottom? *row <- add *row, 1 } - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen move-cursor-down-on-display - reply sc/same-as-ingredient:0 ] -recipe cursor-up [ +recipe cursor-up screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, move cursor in fake screen { - break-unless sc + break-unless screen { # decrement row unless it's already all the way up - row:address:number <- get-address *sc, cursor-row:offset + row:address:number <- get-address *screen, cursor-row:offset at-top?:boolean <- lesser-or-equal *row, 0 break-if at-top? *row <- subtract *row, 1 } - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen move-cursor-up-on-display - reply sc/same-as-ingredient:0 ] -recipe cursor-right [ +recipe cursor-right screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, move cursor in fake screen { - break-unless sc + break-unless screen { # increment column unless it's already all the way to the right - width:number <- get *sc, num-columns:offset - column:address:number <- get-address *sc, cursor-column:offset + width:number <- get *screen, num-columns:offset + column:address:number <- get-address *screen, cursor-column:offset max:number <- subtract width, 1 at-bottom?:boolean <- greater-or-equal *column, max break-if at-bottom? *column <- add *column, 1 } - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen move-cursor-right-on-display - reply sc/same-as-ingredient:0 ] -recipe cursor-left [ +recipe cursor-left screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, move cursor in fake screen { - break-unless sc + break-unless screen { # decrement column unless it's already all the way to the left - column:address:number <- get-address *sc, cursor-column:offset + column:address:number <- get-address *screen, cursor-column:offset at-top?:boolean <- lesser-or-equal *column, 0 break-if at-top? *column <- subtract *column, 1 } - reply sc/same-as-ingredient:0 + reply } # otherwise, real screen move-cursor-left-on-display - reply sc/same-as-ingredient:0 ] -recipe cursor-to-start-of-line [ +recipe cursor-to-start-of-line screen:address:screen -> screen:address:screen [ local-scope - sc:address:screen <- next-ingredient - row:number, _, sc <- cursor-position sc + load-ingredients + row:number <- cursor-position screen column:number <- copy 0 - sc <- move-cursor sc, row, column - reply sc/same-as-ingredient:0 + screen <- move-cursor screen, row, column ] -recipe cursor-to-next-line [ +recipe cursor-to-next-line screen:address:screen -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient + load-ingredients screen <- cursor-down screen screen <- cursor-to-start-of-line screen - reply screen/same-as-ingredient:0 ] -recipe screen-width [ +recipe screen-width screen:address:screen -> width:number [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, move cursor in fake screen { - break-unless sc - width:number <- get *sc, num-columns:offset - reply width + break-unless screen + width <- get *screen, num-columns:offset + reply } # otherwise, real screen - width:number <- display-width - reply width + width <- display-width ] -recipe screen-height [ +recipe screen-height screen:address:screen -> height:number [ local-scope - sc:address:screen <- next-ingredient + load-ingredients # if x exists, move cursor in fake screen { - break-unless sc - height:number <- get *sc, num-rows:offset - reply height + break-unless screen + height <- get *screen, num-rows:offset + reply } # otherwise, real screen - height:number <- display-height - reply height + height <- display-height ] -recipe hide-cursor [ +recipe hide-cursor screen:address:screen -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient + load-ingredients # if x exists (not real display), do nothing { break-unless screen - reply screen + reply } # otherwise, real screen hide-cursor-on-display - reply screen ] -recipe show-cursor [ +recipe show-cursor screen:address:screen -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient + load-ingredients # if x exists (not real display), do nothing { break-unless screen - reply screen + reply } # otherwise, real screen show-cursor-on-display - reply screen ] -recipe hide-screen [ +recipe hide-screen screen:address:screen -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient + load-ingredients # if x exists (not real display), do nothing # todo: help test this { break-unless screen - reply screen + reply } # otherwise, real screen hide-display - reply screen ] -recipe show-screen [ +recipe show-screen screen:address:screen -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient + load-ingredients # if x exists (not real display), do nothing # todo: help test this { break-unless screen - reply screen + reply } # otherwise, real screen show-display - reply screen ] -recipe print-string [ +recipe print-string screen:address:screen, s:address:array:character -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - s:address:array:character <- next-ingredient + load-ingredients color:number, color-found?:boolean <- next-ingredient { # default color to white @@ -638,7 +617,6 @@ recipe print-string [ i <- add i, 1 loop } - reply screen/same-as-ingredient:0 ] scenario print-string-stops-at-right-margin [ @@ -661,7 +639,7 @@ scenario print-string-stops-at-right-margin [ ] ] -recipe print-integer [ +recipe print-integer screen:address:screen, n:number -> screen:address:screen [ local-scope screen:address:screen <- next-ingredient n:number <- next-ingredient @@ -679,6 +657,5 @@ recipe print-integer [ } # todo: other bases besides decimal s:address:array:character <- integer-to-decimal-string n - print-string screen, s, color, bg-color - reply screen/same-as-ingredient:0 + screen <- print-string screen, s, color, bg-color ] diff --git a/084console.mu b/084console.mu index e713462b..3176b82b 100644 --- a/084console.mu +++ b/084console.mu @@ -25,45 +25,45 @@ container console [ data:address:array:event ] -recipe new-fake-console [ +recipe new-fake-console events:address:array:event -> result:address:console [ local-scope + load-ingredients result:address:console <- new console:type buf:address:address:array:event <- get-address *result, data:offset - *buf <- next-ingredient + *buf <- copy events idx:address:number <- get-address *result, index:offset *idx <- copy 0 - reply result ] -recipe read-event [ +recipe read-event console:address:console -> result:event, console:address:console, found?:boolean, quit?:boolean [ local-scope - x:address:console <- next-ingredient + load-ingredients { - break-unless x - idx:address:number <- get-address *x, index:offset - buf:address:array:event <- get *x, data:offset + break-unless console + idx:address:number <- get-address *console, index:offset + buf:address:array:event <- get *console, data:offset { max:number <- length *buf done?:boolean <- greater-or-equal *idx, max break-unless done? dummy:address:event <- new event:type - reply *dummy, x/same-as-ingredient:0, 1/found, 1/quit + reply *dummy, console/same-as-ingredient:0, 1/found, 1/quit } - result:event <- index *buf, *idx + result <- index *buf, *idx *idx <- add *idx, 1 - reply result, x/same-as-ingredient:0, 1/found, 0/quit + reply result, console/same-as-ingredient:0, 1/found, 0/quit } switch # real event source is infrequent; avoid polling it too much result:event, found?:boolean <- check-for-interaction - reply result, x/same-as-ingredient:0, found?, 0/quit + reply result, console/same-as-ingredient:0, found?, 0/quit ] # variant of read-event for just keyboard events. Discards everything that # isn't unicode, so no arrow keys, page-up/page-down, etc. But you still get # newlines, tabs, ctrl-d.. -recipe read-key [ +recipe read-key console:address:console -> result:character, console:address:console, found?:boolean, quit?:boolean [ local-scope - console:address:console <- next-ingredient + load-ingredients x:event, console, found?:boolean, quit?:boolean <- read-event console reply-if quit?, 0, console/same-as-ingredient:0, found?, quit? reply-unless found?, 0, console/same-as-ingredient:0, found?, quit? @@ -72,11 +72,9 @@ recipe read-key [ reply *c, console/same-as-ingredient:0, 1/found, 0/quit ] -recipe send-keys-to-channel [ +recipe send-keys-to-channel console:address:console, chan:address:channel, screen:address:screen -> console:address:console, chan:address:channel, screen:address:screen [ local-scope - console:address:console <- next-ingredient - chan:address:channel <- next-ingredient - screen:address:screen <- next-ingredient + load-ingredients { c:character, console, found?:boolean, quit?:boolean <- read-key console loop-unless found? @@ -86,28 +84,25 @@ recipe send-keys-to-channel [ chan <- write chan, c loop } - reply console/same-as-ingredient:0, chan/same-as-ingredient:1, screen/same-as-ingredient:2 ] -recipe wait-for-event [ +recipe wait-for-event console:address:console -> console:address:console [ local-scope - console:address:console <- next-ingredient + load-ingredients { _, console, found?:boolean <- read-event console loop-unless found? } - reply console/same-as-ingredient:0 ] # use this helper to skip rendering if there's lots of other events queued up -recipe has-more-events? [ +recipe has-more-events? console:address:console -> result:boolean [ local-scope - console:address:console <- next-ingredient + load-ingredients { break-unless console # fake consoles should be plenty fast; never skip reply 0/false } - result:boolean <- interactions-left? - reply result + result <- interactions-left? ] diff --git a/channel.mu b/channel.mu index bc6ee44c..5c3ea735 100644 --- a/channel.mu +++ b/channel.mu @@ -1,9 +1,9 @@ # example program: communicating between routines using channels -recipe producer [ +recipe producer chan:address:channel -> chan:address:channel [ # produce characters 1 to 5 on a channel local-scope - chan:address:channel <- next-ingredient + load-ingredients # n = 0 n:character <- copy 0 { @@ -18,10 +18,10 @@ recipe producer [ } ] -recipe consumer [ +recipe consumer chan:address:channel -> chan:address:channel [ # consume and print integers from a channel local-scope - chan:address:channel <- next-ingredient + load-ingredients { # read an integer from the channel n:character, chan:address:channel <- read chan diff --git a/chessboard.mu b/chessboard.mu index 669e096f..77ce8adb 100644 --- a/chessboard.mu +++ b/chessboard.mu @@ -17,7 +17,7 @@ recipe main [ # # Here the console and screen are both 0, which usually indicates real # hardware rather than a fake for testing as you'll see below. - 0/screen, 0/console <- chessboard 0/screen, 0/console + chessboard 0/screen, 0/console close-console # cleanup screen, keyboard and mouse ] @@ -66,10 +66,9 @@ scenario print-board-and-read-move [ ## Here's how 'chessboard' is implemented. -recipe chessboard [ +recipe chessboard screen:address:screen, console:address:console -> screen:address:screen, console:address:console [ local-scope - screen:address:screen <- next-ingredient - console:address:console <- next-ingredient + load-ingredients board:address:array:address:array:character <- initial-position # hook up stdin stdin:address:channel <- new-channel 10/capacity @@ -94,14 +93,14 @@ recipe chessboard [ { cursor-to-next-line screen msg <- new [move: ] - print-string screen, msg + screen <- print-string screen, msg m:address:move, quit:boolean, error:boolean <- read-move buffered-stdin, screen break-if quit, +quit:label buffered-stdin <- clear-channel buffered-stdin # cleanup after error. todo: test this? loop-if error } board <- make-move board, m - clear-screen screen + screen <- clear-screen screen loop } +quit @@ -109,15 +108,15 @@ recipe chessboard [ ## a board is an array of files, a file is an array of characters (squares) -recipe new-board [ +recipe new-board initial-position:address:array:character -> board:address:array:address:array:character [ local-scope - initial-position:address:array:character <- next-ingredient + load-ingredients # assert(length(initial-position) == 64) len:number <- length *initial-position correct-length?:boolean <- equal len, 64 assert correct-length?, [chessboard had incorrect size] # board is an array of pointers to files; file is an array of characters - board:address:array:address:array:character <- new location:type, 8 + board <- new location:type, 8 col:number <- copy 0 { done?:boolean <- equal col, 8 @@ -127,15 +126,13 @@ recipe new-board [ col <- add col, 1 loop } - reply board ] -recipe new-file [ +recipe new-file position:address:array:character, index:number -> result:address:array:character [ local-scope - position:address:array:character <- next-ingredient - index:number <- next-ingredient + load-ingredients index <- multiply index, 8 - result:address:array:character <- new character:type, 8 + result <- new character:type, 8 row:number <- copy 0 { done?:boolean <- equal row, 8 @@ -146,13 +143,11 @@ recipe new-file [ index <- add index, 1 loop } - reply result ] -recipe print-board [ +recipe print-board screen:address:screen, board:address:array:address:array:character -> screen:address:screen [ local-scope - screen:address:screen <- next-ingredient - board:address:array:address:array:character <- next-ingredient + load-ingredients row:number <- copy 7 # start printing from the top of the board # print each row { @@ -188,8 +183,7 @@ recipe print-board [ screen <- cursor-to-next-line screen ] -# board:address:array:address:array:character <- initial-position -recipe initial-position [ +recipe initial-position -> board:address:array:address:array:character [ local-scope # layout in memory (in raster order): # R P _ _ _ _ p r @@ -209,8 +203,7 @@ recipe initial-position [ #? 66/B, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 98/b, #? 78/N, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 110/n, #? 82/R, 80/P, 32/blank, 32/blank, 32/blank, 32/blank, 112/p, 114/r - board:address:array:address:array:character <- new-board initial-position - reply board + board <- new-board initial-position ] scenario printing-the-board [ @@ -246,12 +239,10 @@ container move [ to-rank:number ] -# result:address:move, quit?:boolean, error?:boolean <- read-move stdin:address:channel, screen:address:screen # prints only error messages to screen -recipe read-move [ +recipe read-move stdin:address:channel, screen:address:screen -> result:address:move, quit?:boolean, error?:boolean [ local-scope - stdin:address:channel <- next-ingredient - screen:address:screen <- next-ingredient + load-ingredients from-file:number, quit?:boolean, error?:boolean <- read-file stdin, screen reply-if quit?, 0/dummy, quit?, error? reply-if error?, 0/dummy, quit?, error? @@ -278,12 +269,10 @@ recipe read-move [ reply result, quit?, error? ] -# file:number, quit:boolean, error:boolean <- read-file stdin:address:channel, screen:address:screen # valid values for file: 0-7 -recipe read-file [ +recipe read-file stdin:address:channel, screen:address:screen -> file:number, quit:boolean, error:boolean [ local-scope - stdin:address:channel <- next-ingredient - screen:address:screen <- next-ingredient + load-ingredients c:character, stdin <- read stdin { q-pressed?:boolean <- equal c, 81/Q @@ -329,12 +318,10 @@ recipe read-file [ reply file, 0/quit, 0/error ] -# rank:number <- read-rank stdin:address:channel, screen:address:screen # valid values: 0-7, -1 (quit), -2 (error) -recipe read-rank [ +recipe read-rank stdin:address:channel, screen:address:screen -> rank:number, quit?:boolean, error?:boolean, stdin:address:channel, screen:address:screen [ local-scope - stdin:address:channel <- next-ingredient - screen:address:screen <- next-ingredient + load-ingredients c:character, stdin <- read stdin { q-pressed?:boolean <- equal c, 8/Q @@ -376,11 +363,9 @@ recipe read-rank [ # read a character from the given channel and check that it's what we expect # return true on error -recipe expect-from-channel [ +recipe expect-from-channel stdin:address:channel, expected:character, screen:address:screen -> result:boolean [ local-scope - stdin:address:channel <- next-ingredient - expected:character <- next-ingredient - screen:address:screen <- next-ingredient + load-ingredients c:character, stdin <- read stdin { match?:boolean <- equal c, expected @@ -388,8 +373,7 @@ recipe expect-from-channel [ s:address:array:character <- new [expected character not found] print-string screen, s } - result:boolean <- not match? - reply result + result <- not match? ] scenario read-move-blocking [ @@ -556,21 +540,19 @@ F read-move-file: routine failed to pause after coming up (before any keys were ] ] -recipe make-move [ +recipe make-move board:address:array:address:array:character, m:address:move -> board:address:array:address:array:character [ local-scope - b:address:array:address:array:character <- next-ingredient - m:address:move <- next-ingredient + load-ingredients from-file:number <- get *m, from-file:offset from-rank:number <- get *m, from-rank:offset to-file:number <- get *m, to-file:offset to-rank:number <- get *m, to-rank:offset - f:address:array:character <- index *b, from-file + f:address:array:character <- index *board, from-file src:address:character/square <- index-address *f, from-rank - f <- index *b, to-file + f <- index *board, to-file dest:address:character/square <- index-address *f, to-rank *dest <- copy *src *src <- copy 32/space - reply b/same-as-ingredient:0 ] scenario making-a-move [ diff --git a/edit/001-editor.mu b/edit/001-editor.mu index c74e6ac4..ae9e5219 100644 --- a/edit/001-editor.mu +++ b/edit/001-editor.mu @@ -47,7 +47,7 @@ container editor-data [ # creates a new editor widget and renders its initial appearance to screen # top/left/right constrain the screen area available to the new editor # right is exclusive -recipe new-editor s:address:array:character, screen:address:screen, left:number, right:number -> result:address:editor-data [ +recipe new-editor s:address:array:character, screen:address:screen, left:number, right:number -> result:address:editor-data, screen:address:screen [ local-scope load-ingredients # no clipping of bounds @@ -224,13 +224,13 @@ recipe render screen:address:screen, editor:address:editor-data -> last-row:numb reply row, column, screen/same-as-ingredient:0, editor/same-as-ingredient:1 ] -recipe clear-line-delimited screen:address:screen, column:number, right:number [ +recipe clear-line-delimited screen:address:screen, column:number, right:number -> screen:address:screen [ local-scope load-ingredients { done?:boolean <- greater-than column, right break-if done? - print-character screen, 32/space + screen <- print-character screen, 32/space column <- add column, 1 loop } |