Frank-0.3: keylog.fk
sig ReadLine
= peek [] Char
| nom
sig Abort
= aborting [] {}
abort [Abort] X
abort = aborting ! {}
default {[] X} [Abort ? X] [] X
default d [x] = x
default d [aborting ? k] = d!
{[Abort] X} / {[] X} [] {[] X}
e / d = {default d ? e!}
if Bool then {[] X} else {[] X} [] X
if tt then t else f = t!
if ff then t else f = f!
see Char [ReadLine, Abort] ()
see c = if (peek! =Char= c) then {()} else {abort!}
eat Char [ReadLine, Abort] ()
eat c = see c >> nom!
() >> Y [] Y
_ >> y = y
X << () [] X
x << _ = x
data List X
= nil
| X :: (List X)
data SExp
= atom (List Char)
| SExp & SExp
sexp [ReadLine, Abort] SExp
sexp =
({see '.' >> abort!} /
({eat '(' >> open!} /
({see ')' >> abort!} /
({eat ' ' >> sexp!} /
{atom (name!)}
))))!
open [ReadLine, Abort] SExp
open =
({see '.' >> abort!} /
({eat ' ' >> open!} /
({eat ')' >> atom nil} /
{sexp! & cdr!}
)))!
cdr [ReadLine, Abort] SExp
cdr =
({eat ' ' >> cdr!} /
({eat '.' >> (sexp! << close!)} /
{open!}
))!
close [ReadLine, Abort] ()
close =
({eat ' ' >> close!} /
({eat ')'} /
{abort!}
))!
elem Char (List Char) [] Bool
elem c nil = ff
elem c (c' :: cs) = if (c =Char= c') then {tt} else {elem c cs}
nameChar [ReadLine, Abort] Char
nameChar = if (elem (peek!) ('\n' :: (' ' :: ('(' :: (')' :: ('.' :: nil))))))
then {abort!}
else {(peek! << nom!)}
some {[ReadLine, Abort] X} [ReadLine, Abort] List X
some p = (p!) :: many p
many {[ReadLine, Abort] X} [ReadLine] List X
many p = ({some p} / {nil})!
name [ReadLine, Abort] List Char
name = some nameChar
data Maybe X = no | yes X
let X in {X -> [] Y} [] Y
let x in f = f x
noBS (Maybe Char) [ReadLine ? X] [Console] X
noBS _ [x] = x
noBS no [peek ? k] = let inch! in {c -> noBS (yes c) ? k c}
noBS (yes c) [peek ? k] = noBS (yes c) ? k c
noBS _ [nom ? k] = noBS no ? k ()
data Stk X
= (Stk X) -peek {Char -> [ReadLine, Abort] X}
| (Stk X) -nom
| root {[ReadLine, Abort] X}
withBS (Stk X) (Maybe Char) [ReadLine, Abort, {} ? X] [Console] X
withBS stk _ [x] = x
withBS stk no [peek ? k] = let inch! in
{ '\b' -> pop stk
| c -> withBS (stk -peek k) (yes c) ? k c
}
withBS stk (yes c) [peek ? k] = withBS stk (yes c) ? k c
withBS stk (yes c) [nom ? k] = ouch c >> withBS (stk -nom) no ? k ()
withBS stk _ [aborting ? l] = pop stk
note There's a need for indexing here, to prevent nom! before peek!
pop (Stk X) [Console] X
pop (stk -peek k) = withBS stk no ? k (peek!)
pop (stk -nom) = ouch '\b' >> (ouch ' ' >> (ouch '\b' >> pop stk))
pop (root r) = withBS (root r) no ? r!
main [Console] SExp
main = withBS (root {sexp!}) no ? sexp!
note
main [Console, Abort] SExp
main = noBS no ? sexp!