# Part of http://akkartik.name/coroutines-in-mu # # Version 3b: coroutines set up by parser # # To run: # $ git clone https://github.com/akkartik/mu1 # $ cd mu1 # $ git checkout 4a48bedcd1 # state as of this writing; later versions may be incompatible # $ wget http://akkartik.name/coroutines-in-mu/version3b.mu # $ ./mu version3b.mu exclusive-container token [ word:text punc:char ] def decompressor src:&:source:num -> src:&:source:num [ local-scope load-inputs { x:num, eof?:bool <- read src break-if eof? c:char <- copy x $print [decompress: ] c 10/newline repeat-tag?:bool <- equal c, 255 { break-unless repeat-tag? len:num <- read src x:num <- read src c:char <- copy x $print [run: ] c [*] len 10/newline i:num <- copy 0 { done?:bool <- equal i, len break-if done? emit c i <- add i, 1 loop } } { break-if repeat-tag? emit c } loop } emit 4/eof ] def parser src:&:source:num, dest:&:sink:token -> src:&:source:num, dest:&:sink:token [ local-scope load-inputs getchar:continuation <- call-with-continuation-mark decompressor, src { getchar, c:char <- call getchar eof?:bool <- equal c, 4/EOF break-if eof? { alpha?:bool <- isalpha c break-unless alpha? buf:&:buffer:char <- new-buffer 5 { buf <- append buf, c getchar, c <- call getchar eof? <- equal c, 4/EOF break-if eof? alpha? <- isalpha c loop-if alpha? } word:text <- buffer-to-array buf out:token <- merge 0/word, word dest <- write dest, out break-if eof?, +end } out:token <- merge 1/punc, c dest <- write dest, out loop } +end close dest ] def emit c:char [ local-scope load-inputs return-continuation-until-mark c ] def isalpha c:char -> result:bool [ local-scope load-inputs # 'a' <= c <= 'z' || 'A' <= c <= 'Z' b1:bool <- greater-or-equal c, 65/A b2:bool <- lesser-or-equal c, 90/Z uppercase?:bool <- and b1, b2 return-if uppercase?, 1/true b1 <- greater-or-equal c, 97/a b2 <- lesser-or-equal c, 122/z lowercase?:bool <- and b1, b2 return lowercase? ] # test def main [ local-scope # Make channel capacities large enough to never block; we don't use # concurrency in this example. number-source:&:source:num, in:&:sink:num <- new-channel 30 out:&:source:token, token-sink:&:sink:token <- new-channel 30 # set up input ["aaaabbb,,cccdd;e"] write in, 255 write in, 4/len write in, 97/a write in, 255 write in, 3/len write in, 98/b write in, 255 write in, 2/len write in, 44/comma write in, 255 write in, 3/len write in, 99/c write in, 255 write in, 2/len write in, 100/d write in, 59/semi-colon write in, 101/e close in # run parser number-source, token-sink # read out result { t:token, done?:bool <- read out break-if done? { w:text, match?:bool <- maybe-convert t, word:variant break-unless match? $print [word: ] *w 10/newline } { p:char, match?:bool <- maybe-convert t, punc:variant break-unless match? $print [punc: ] p 10/newline } loop } ]