mirror of
https://github.com/GaloisInc/cryptol.git
synced 2024-11-27 11:13:48 +03:00
861e9e9651
* Adds a stub executable to cabal file for checking docs * [WIP] Adds check-exercises executable A program that checks that the exercises in Programming Cryptol actual work when executed against an Cryptol REPL. Instead of using \begin{Verbatim}, we use \begin{REPL} in both the exercise and the answer, which is rendered the same but gets checked by this program. This is a WIP -- we still need to do a number of things, including (but not limited to): * Move the "REPL" macro out of CrashCourse.tex and into some including latex file * Change many of the "Verbatim"s into "REPL"s to test if this approach works in general * Several updates * Moves REPL command definitions into main latex file * Generalizes repl commands * Several improvements: * documentation of CheckExercises.hs * factoring out addReplData, addReplin, addReplout, nextLine functions * took the IO out of P monad (shouldn't have been there) * worked on annotating repls for many exercises/examples in crash course * Adds a README for check-exercises * Uses cryptol's -e option to detect errors * updates ProgrammingCryptol.pdf * Fixes main function After changing to use the -e option to detect errors, I used cabal v2-exec which apparently does not rebuild anything, but I thought it did. This just fixes the code so it builds again.
124 lines
3.6 KiB
Haskell
124 lines
3.6 KiB
Haskell
#!/usr/bin/env runhaskell
|
|
{-# Language RecordWildCards #-}
|
|
module Main(main) where
|
|
|
|
import Data.List(isPrefixOf)
|
|
|
|
|
|
main :: IO ()
|
|
main = interact (pp . findExercises)
|
|
where
|
|
pp (es,as) = unlines $ ppMany "Exercises" es ++
|
|
ppMany "Answers" as
|
|
ppMany h xs = h : "-------------" : map ppEnv xs
|
|
ppEnv Env { .. } = envName ++ ":" ++ show envStart ++ "--" ++ show envEnd ++
|
|
"(" ++ show (info envLines) ++ ")"
|
|
info = length . findVerbatim
|
|
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
data Line = Line { lineNo :: Int, lineText :: String }
|
|
|
|
data Env = Env
|
|
{ envName :: String
|
|
, envStart, envEnd :: Int -- location in latex, includes \begin \end
|
|
, envLines :: [Line]
|
|
}
|
|
|
|
findExercises :: String -> ([Env],[Env])
|
|
findExercises = noEx [] [] () . zipWith toLine [1..] . lines
|
|
where toLine lineNo lineText = Line { .. }
|
|
|
|
type ExS s = [Env] -> [Env] -> s -> [Line] -> ([Env],[Env])
|
|
|
|
noEx :: ExS ()
|
|
noEx es as _ xs =
|
|
case xs of
|
|
[] -> (es,as)
|
|
Line { .. } : more
|
|
| Just nm <- startExercise lineText -> inEx es as (lineNo, nm, []) more
|
|
| Just nm <- startAnswer lineText -> inAns es as (lineNo, nm, []) more
|
|
| otherwise -> noEx es as () more
|
|
|
|
inEx :: ExS (Int,String,[Line])
|
|
inEx es as (envStart,envName,ls) xs =
|
|
case xs of
|
|
[] -> error $ unwords [ show envStart ++ ":"
|
|
, "Unterminated exercise", show envName ]
|
|
l : more
|
|
| endExercise (lineText l) ->
|
|
let ex = Env { envLines = reverse ls, envEnd = lineNo l, .. }
|
|
in noEx (ex : es) as () more
|
|
| otherwise -> inEx es as (envStart,envName,l:ls) more
|
|
|
|
inAns :: ExS (Int,String,[Line])
|
|
inAns es as (envStart,envName,ls) xs =
|
|
case xs of
|
|
[] -> error $ unwords [ show envStart ++ ":"
|
|
, "Unterminated answer", show envName ]
|
|
l : more
|
|
| endAnswer (lineText l) ->
|
|
let ex = Env { envLines = reverse ls, envEnd = lineNo l, .. }
|
|
in noEx es (ex : as) () more
|
|
| otherwise -> inAns es as (envStart,envName,l:ls) more
|
|
|
|
|
|
findVerbatim :: [Line] -> [Env]
|
|
findVerbatim ls =
|
|
case break (startVerbatim . lineText) ls of
|
|
(_,l:more) ->
|
|
case break (endVerbatim . lineText) more of
|
|
(ls,e:rest) ->
|
|
Env { envName = "Verbatim"
|
|
, envStart = lineNo l
|
|
, envEnd = lineNo e
|
|
, envLines = ls
|
|
} : findVerbatim rest
|
|
_ -> error (show (lineNo l) ++ ": Unterminated verbatim")
|
|
_ -> []
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
--------------------------------------------------------------------------------
|
|
startVerbatim :: String -> Bool
|
|
startVerbatim x = pref `isPrefixOf` x
|
|
where
|
|
pref = "\\begin{Verbatim}"
|
|
|
|
endVerbatim :: String -> Bool
|
|
endVerbatim x = pref `isPrefixOf` x
|
|
where
|
|
pref = "\\end{Verbatim}"
|
|
|
|
startExercise :: String -> Maybe String
|
|
startExercise x
|
|
| pref `isPrefixOf` x = Just name
|
|
| otherwise = Nothing
|
|
where
|
|
pref = "\\begin{Exercise}\\label{ex:"
|
|
name = takeWhile (/= '}') (drop (length pref) x)
|
|
|
|
endExercise :: String -> Bool
|
|
endExercise x = pref `isPrefixOf` x
|
|
where
|
|
pref = "\\end{Exercise}"
|
|
|
|
|
|
startAnswer :: String -> Maybe String
|
|
startAnswer x
|
|
| pref `isPrefixOf` x = Just name
|
|
| otherwise = Nothing
|
|
where
|
|
pref = "\\begin{Answer}\\ansref{ex:"
|
|
name = takeWhile (/= '}') (drop (length pref) x)
|
|
|
|
endAnswer :: String -> Bool
|
|
endAnswer x = pref `isPrefixOf` x
|
|
where
|
|
pref = "\\end{Answer}"
|
|
|