90 lines
1.9 KiB
Go
90 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"unicode"
|
|
)
|
|
|
|
func main() {
|
|
owp(os.Stdout, bytes.NewBufferString("what,is,the;meaning,of:life."))
|
|
fmt.Println()
|
|
owp(os.Stdout, bytes.NewBufferString("we,are;not,in,kansas;any,more."))
|
|
fmt.Println()
|
|
}
|
|
|
|
type Coroutine struct {
|
|
out <-chan Coroutine
|
|
in chan<- byte
|
|
}
|
|
|
|
func owp(dst io.Writer, src io.Reader) {
|
|
byte_in := func () (byte, error) {
|
|
bs := make([]byte, 1)
|
|
_, err := src.Read(bs)
|
|
return bs[0], err
|
|
}
|
|
byte_out := func (b byte) { dst.Write([]byte{b}) }
|
|
|
|
var f, r Coroutine
|
|
|
|
f = func () Coroutine {
|
|
out := make(chan Coroutine)
|
|
in := make(chan byte)
|
|
var fwd func (byte) byte
|
|
fwd = func (c byte) (z byte) {
|
|
if unicode.IsLetter(rune(c)) {
|
|
byte_out(c)
|
|
out <- f
|
|
z = fwd(<- in)
|
|
} else {
|
|
z = c
|
|
}
|
|
return
|
|
}
|
|
go func () {
|
|
for {
|
|
x, ok := <- in
|
|
if !ok { break }
|
|
byte_out(fwd(x))
|
|
out <- r
|
|
}
|
|
} ()
|
|
return Coroutine{ out, in }
|
|
} ()
|
|
r = func () Coroutine {
|
|
out := make(chan Coroutine)
|
|
in := make(chan byte)
|
|
var rev func (byte) byte
|
|
rev = func (c byte) (z byte) {
|
|
if unicode.IsLetter(rune(c)) {
|
|
out <- r
|
|
z = rev(<- in)
|
|
byte_out(c)
|
|
} else {
|
|
z = c
|
|
}
|
|
return
|
|
}
|
|
go func () {
|
|
for {
|
|
x, ok := <- in
|
|
if !ok { break }
|
|
byte_out(rev(x))
|
|
out <- f
|
|
}
|
|
} ()
|
|
return Coroutine{ out, in }
|
|
} ()
|
|
|
|
for coro := f; ; coro = <- coro.out {
|
|
c, err := byte_in()
|
|
if err != nil { break }
|
|
coro.in <- c
|
|
}
|
|
close(f.in)
|
|
close(r.in)
|
|
}
|