cpsa-4.4.3: src/CPSA/Coq/Main.hs
-- Main routine for cpsa4coq
-- Copyright (c) 2020 The MITRE Corporation
--
-- This program is free software: you can redistribute it and/or
-- modify it under the terms of the BSD License as published by the
-- University of California.
module Main (main) where
import System.IO
import Data.Char (toUpper)
import Data.List (intersperse)
import CPSA.Lib.Entry
import CPSA.Lib.Expand
import CPSA.Proc.Proc
main :: IO ()
main =
do
(p, (output, margin)) <- start filterOptions filterInterp
sexprs <- readSExprs p
items <- tryRun (parse sexprs)
h <- outputHandle output
tryRun (emit h margin items)
hClose h
tryRun :: IO a -> IO a
tryRun x =
do
y <- tryIO x
case y of
Right z -> return z
Left err -> abort err
-- Emitter
emit :: Handle -> Int -> [Item] -> IO ()
emit _ _ [] = fail "empty input"
emit h margin (Cmt _ comment : xs) =
do
hPutStrLn h ("(** " ++ comment ++ " *)")
hPutStrLn h ""
hPutStrLn h "Require Import Proc."
hPutStrLn h "Import List.ListNotations."
hPutStrLn h "Open Scope list_scope."
hPutStrLn h "Open Scope string."
emitProcs h margin xs
emit _ _ (Defproc pos _ : _) = fail (shows pos "Expecting a comment")
emitProcs :: Handle -> Int -> [Item] -> IO ()
emitProcs _ _ [] = return ()
emitProcs h margin (Cmt _ comment : x : xs) =
do
hPutStrLn h ""
hPutStrLn h ("(** " ++ comment ++ " *)")
hPutStrLn h ""
emitProc h margin x
emitProcs h margin xs
emitProcs _ _ [Cmt pos _] =
fail (shows pos "Expecting a comment followed by a defproc")
emitProcs _ _ (Defproc pos _ : _) = fail (shows pos "Expecting a comment")
emitProc :: Handle -> Int -> Item -> IO ()
emitProc h margin (Defproc _ proc) =
do
emitHeader h margin (name proc) (inputs proc)
mapM_ (emitStmt h margin) (stmts proc)
hPutStrLn h " ]."
emitProc _ _ (Cmt pos _) =
fail (shows pos "Expecting a defproc")
emitHeader :: Handle -> Int -> String -> [Decl] -> IO ()
emitHeader h margin name inputs =
do
hPutStrLn h ("Definition " ++ name ++ ": proc :=")
hPutStrLn h " mkProc"
emitInputs h margin (map emitInput inputs)
hPutStrLn h " ["
emitInput :: Decl -> String
emitInput (var, kind) =
"(" ++ ref var ++ ", " ++ toKind kind ++ ")"
ref :: String -> String
ref [] = []
ref (_ : xs) = xs
toKind :: String -> String
toKind [] = []
toKind (h : t) = toUpper h : t
emitInputs :: Handle -> Int -> [String] -> IO ()
emitInputs h _ [] =
hPutStrLn h " []"
emitInputs h _ xs =
do
hPutStr h " ["
mapM_ (hPutStr h) (intersperse "; " xs)
hPutStrLn h "]"
emitStmt :: Handle -> Int -> Stmt -> IO ()
emitStmt h _ (Bind (var, kind) expr) =
do
hPutStr h (" Bind (" ++ ref var ++ ", " ++ toKind kind ++ ") ")
emitExpr h expr
hPutStrLn h ";"
emitStmt h _ (Send _ chan msg) =
hPutStrLn h (" Send " ++ ref chan ++ " " ++ ref msg ++ ";")
emitStmt h _ (Same _ x y) =
hPutStrLn h (" Same " ++ ref x ++ " " ++ ref y ++ ";")
emitStmt h _ (Invp _ x y) =
hPutStrLn h (" Invp " ++ ref x ++ " " ++ ref y ++ ";")
emitStmt h margin (Return returns) =
do
hPutStr h " Return "
emitReturns h margin (map ref returns)
emitStmt h _ (Comment comment) =
hPutStrLn h (" (* " ++ comment ++ " *)")
emitExpr :: Handle -> Expr -> IO ()
emitExpr h (Call op args) =
do
hPutStr h "("
hPutStr h $ trim $ toKind op
mapM_ (emitArg h) args
hPutStr h ")"
emitExpr h (Tag x) =
hPutStr h ("(Quot_ \"" ++ x ++ "\")")
trim :: String -> String
trim [] = []
trim ('_' : _) = "_"
trim (x : xs) = x : trim xs
emitArg :: Handle -> String -> IO ()
emitArg h x =
hPutStr h (" " ++ ref x)
emitReturns :: Handle -> Int -> [String] -> IO ()
emitReturns h _ [] =
hPutStrLn h "[]"
emitReturns h _ xs =
do
hPutStr h "["
mapM_ (hPutStr h) (intersperse "; " xs)
hPutStrLn h "]"