# Part of http://akkartik.name/coroutines-in-mu # # Version 2: parser as caller, decompressor as callee # # 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/version2.mu # $ ./mu version2.mu exclusive-container token [ word:text punc:char ] def decompressor src:&:source:num, repchar:char, replen:num -> repchar:char, replen:num, src:&:source:num [ local-scope load-inputs { in-rep?:bool <- greater-than replen, 0 break-unless in-rep? replen <- subtract replen, 1 return } x:num, eof?:bool, src <- read src return-if eof?, 4/EOF c:char <- copy x $print [decompress: ] c 10/newline repeat-tag?:bool <- equal c, 255 return-unless repeat-tag?, c, 0/replen # repeat tag replen <- read src x <- read src repchar <- copy x $print [run: ] repchar [*] replen 10/newline replen <- subtract replen, 1 # already returning repchar once this time ] def parser src:&:source:num, dest:&:sink:token -> src:&:source:num, dest:&:sink:token [ local-scope load-inputs buf:&:buffer:char <- new-buffer 5 c:char, replen:num <- copy 0, 0 { c, replen <- decompressor src, c, replen eof?:bool <- equal c, 4/EOF break-if eof? { alpha?:bool <- isalpha c break-unless alpha? { buf <- append buf, c c, replen <- decompressor src, c, replen eof?:bool <- equal c, 4/EOF break-if eof? alpha?:bool <- isalpha c loop-if alpha? } word:text <- buffer-to-array buf out:token <- merge 0/word, word dest <- write dest, out put *buf, length:offset, 0 # clear break-if eof?, +end } out:token <- merge 1/punc, c dest <- write dest, out loop } +end close dest ] 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 $print [run] 10/newline parser number-source, token-sink $print [done] 10/newline # 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 } # Expected output: # word: 7 97 97 97 97 98 98 98 ("aaaabbb") # punc: 44 (',') # punc: 44 (',') # word: 5 99 99 99 100 100 ("cccdd") # punc: 59 (';') # word: 1 101 ("e") ]