{-# OPTIONS --guardedness --sized-types #-}
module IODA where
open import Parser public
module IODAThings where
record IODA {π π π π π} : Set (lsuc (π β π β π β π β π)) where
constructor mkIODA
field
{State} : Set π
{Label} : Set π
{Input} : Set π
{Output} : Set π
initialState : State
_ββ¨_,_β©_,_ : State β Label β Input β State β Output β Set π
transition : State β Label β Input β Maybe (State Γ Output)
correctness : β q l x qβ² y β q ββ¨ l , x β© qβ² , y β transition q l x β‘ just (qβ² , y)
simMachine : State β βMachine (Label Γ Input) (Maybe (State Γ Output))
simMachine q .on (l , x) with transition q l x
... | just (qβ² , y) = just (qβ² , y) , just (simMachine qβ²)
... | nothing = nothing , nothing
record TUI-IODA {π π π π π β―β β―β} : Set (lsuc (π β π β π β π β π β β―β β β―β)) where
constructor mkTUI-IODA
field
ioda : IODA {π} {π} {π} {π} {π}
{LabelParserErr} : Set β―β
{InputParserErr} : Set β―β
open IODA ioda public
LabelParser : Set (π β β―β)
LabelParser = βMachine Term (Either LabelParserErr Label)
InputParser : Set (π β β―β)
InputParser = βMachine Term (Either InputParserErr Input)
field
showDot : String
showState : State β String
showLabel : Label β String
showInput : Input β String
showOutput : Output β String
showLabelParserErr : LabelParserErr β String
showInputParserErr : InputParserErr β String
awaitLabel : LabelParser
awaitInput : InputParser
parseLabel : Term β Either LabelParserErr Label
parseLabel tm = βMachineThings.GetEither.step awaitLabel tm
parseInput : Term β Either InputParserErr Input
parseInput tm = βMachineThings.GetEither.step awaitInput tm
open IODA public
open IODAThings public using (IODA ; mkIODA ; TUI-IODA ; mkTUI-IODA)
module TUIInterpreter-IODA {π} (tui : TUI-IODA {π}) where
open StdIO public using (_>>=_ ; _>>_)
open TUI-IODA tui
data Err : Set where
badTerm : TermParserErr β Err
badInput : InputParserErr β Err
badLabel : LabelParserErr β Err
badCmd : Term β Err
badTransition : Err
showErr : Err β String
showErr (badTerm err) = showTermParserErr err
showErr (badInput err) = showInputParserErr err
showErr (badLabel err) = showLabelParserErr err
showErr (badCmd tm) = "invalid command '" ++ showTerm tm ++ "'"
showErr badTransition = "invalid transition"
data Cmd : Set where
quit : Cmd
reset : Cmd
put : Label β Input β Cmd
readPutCmd : Term β Either Err Cmd
readPutCmd (list (tmβ β· tmβ β· [])) with parseLabel tmβ | parseInput tmβ
... | fail err | _ = fail (badLabel err)
... | ok _ | fail err = fail (badInput err)
... | ok l | ok x = ok (put l x)
readPutCmd tm = fail (badCmd tm)
readCmd : String β Either Err Cmd
readCmd str with parseTerm (lex str)
... | fail err = fail (badTerm err)
... | ok (atom ":quit" β· []) = ok quit
... | ok (atom ":reset" β· []) = ok reset
... | ok (tm β· []) = readPutCmd tm
... | ok tms = readPutCmd (list tms)
data Action : Set where
prompt : State β Action
get : Output β Action
warn : Err β Action
doAction : Action β IO Unit
doAction (prompt q) = do putStrLn ""
putStrLn (showState q)
putStr "> "
doAction (get y) = putStrLn (showOutput y)
doAction (warn err) = putStrLn ("error: " ++ showErr err)
stringFrom : List Char β String
stringFrom acc = String.fromList (reverse acc)
Interpreter : Set
Interpreter = βMachine Char (List Action)
mutual
awaitCmd : State β List Char β Interpreter
awaitCmd q acc .on '\n' with readCmd (stringFrom acc)
... | fail err = continue [ warn err ] q
... | ok quit = [] , nothing
... | ok reset = continue [] initialState
... | ok (put l x) with transition q l x
... | just (qβ² , y) = continue [ get y ] qβ²
... | nothing = continue [ warn badTransition ] q
awaitCmd q acc .on c = [] , just (awaitCmd q (c β· acc))
continue : List Action β State β List Action Γ Maybe Interpreter
continue as q = as Listβ².++ [ prompt q ] , just (awaitCmd q [])
handleTUI : IO Polyunit
handleTUI = do setBuffering stdout noBuffering
flush stdout
putStrLn showDot
cs β getChars
comapMβ² (mapM doAction) ([ prompt initialState ] β· β―
corun (awaitCmd initialState []) cs)