packages feed

cpsa-4.4.6: src/CPSA/RoleCoq/Main.hs

-- Main routine for cpsa4rolecoq

-- 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.Map (toAscList)
import CPSA.Lib.Entry
import CPSA.Lib.Expand
import CPSA.Roletran.Algebra
import CPSA.Roletran.Protocol
import CPSA.Roletran.Loader
import CPSA.Roletran.Emitter (displayPos)
import CPSA.Lib.Pretty

main :: IO ()
main =
    do
      (p, (output, margin)) <- start filterOptions filterInterp
      sexprs <- readSExprs p
      prot <- tryRun (loadSExprs sexprs)
      h <- outputHandle output
      tryRun (emit h margin prot)
      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 a protocol
emit :: Handle -> Int -> Prot -> IO ()
emit h margin prot =
  do
    hPutStrLn h ("(** Protocol: " ++ pname prot ++
                  " (" ++ displayPos (ppos prot) ++ ") *)")
    hPutStrLn h ""
    hPutStrLn h "From Stdlib Require Import String List."
    hPutStrLn h "Require Import Alg Role."
    hPutStrLn h "Import List.ListNotations."
    hPutStrLn h "Open Scope list_scope."
    hPutStrLn h "Open Scope string."
    mapM_ (emitRole h margin) (roles prot)

-- Emit a role
emitRole :: Handle -> Int -> Role -> IO ()
emitRole h margin role =
  do
    hPutStrLn h ""
    hPutStrLn h ("(** Role: " ++  rname role ++
                 " (" ++ displayPos (rpos role) ++ ") *)")
    hPutStrLn h ""
    hPutStrLn h ("Definition " ++ (dehyphen $ rname role) ++ "_role: role :=")
    hPutStrLn h "  mkRole"
    let env = makeEnv $ rvars role
    hPutStrLn h (pretty margin $ map (event env) (rtrace role))
    hPutStrLn h (pretty margin $ map (term env) (map fst $ runiques role))
    hPutStrLn h (pretty margin $ map (term env) (rinputs role))
    hPutStr h (pretty margin $ map (term env) (routputs role))
    hPutStrLn h "."

dehyphen :: String -> String
dehyphen [] = []
dehyphen ('-' : cs) = '_' : dehyphen cs
dehyphen (c : cs) = c : dehyphen cs

type Env = [(String, Int)]

makeEnv :: VarEnv -> Env
makeEnv env =
  zip (map fst $ toAscList env) [0 ..]

event :: Env -> Event -> Pretty
event env (In _ ch x) =
  blo 0 [str "Rv ", chan env ch, str " (", term env x, str ")"]
event env (Out _ ch x) =
  blo 0 [str "Sd ", chan env ch, str " (", term env x, str ")"]

chan :: Env -> Term -> Pretty
chan env (Chn v) = str (var env v)
chan _ _ = str "-1"             -- This should never happen

term :: Env -> Term -> Pretty
term env (Txt v) = str ("Tx " ++ var env v)
term env (Dta v) = str ("Dt " ++ var env v)
term env (Nam v) = str ("Nm " ++ var env v)
term env (Sky k) = skey env k
term env (Aky k) = akey env k
term env (Iky k) = ikey env k
term env (Msg v) = str ("Mg " ++ var env v)
term _ (Tag s) = str ("Tg \"" ++ s ++ "\"")
term env (Pr x y) =
  blo 3 [str "Pr (", term env x, str ")",
         brk 1, str "(", term env y, str ")"]
term env (En x y) =
  blo 3 [str "En (", term env x, str ")",
         brk 1, str "(", term env y, str ")"]
term env (Hsh x) = blo 0 [str "Hs (", term env x, str ")"]
term env (Chn v) = str ("Ch " ++ var env v)

skey :: Env -> Skey -> Pretty
skey env (SVar v) = str ("Sk (Sv " ++ var env v ++ ")")
skey env (Ltk v w) =
  str ("Sk (Lt " ++ var env v ++ " " ++ var env w ++ ")")

akey :: Env -> Akey -> Pretty
akey env (AVar v) = str ("Ak (Av " ++ var env v ++ ")")
akey env (Pubk v) = str ("Ak (Pb " ++ var env v ++ ")")
akey env (Pubk2 s v) =
  str ("Ak (Pb2 \"" ++ s ++ "\" " ++ var env v ++ ")")

ikey :: Env -> Akey -> Pretty
ikey env (AVar v) = str ("Ik (Av " ++ var env v ++ ")")
ikey env (Pubk v) = str ("Ik (Pb " ++ var env v ++ ")")
ikey env (Pubk2 s v) =
  str ("Ik (Pb2 \"" ++ s ++ "\" " ++ var env v ++ ")")

var :: Env -> Var -> String
var env v =
  case lookup v env of
    Just i -> show i
    Nothing -> "-1"             -- This should never happen

-- Print a list in which a break cause all breaks to be taken.
list :: [Pretty] -> Pretty
list [] = str "  []"
list (x: xs) =
  grp 3 (str "  [" : x : loop xs)
  where
    loop [] = [str "]"]
    loop (x : xs) = str ";" : brk 1 : x : loop xs

pretty :: Int -> [Pretty] -> String
pretty margin xs =
  pr margin (list xs) ""