cpsa-4.4.1: src/CPSA/Roletran/Emitter.hs
-- Emits generated code
-- 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 CPSA.Roletran.Emitter (
Kind(..), kind, Proc, mkProc, name, pos,
Vari, Decl, Stmt(..), Expr(..),
emit, displayPos) where
import CPSA.Lib.SExpr
import CPSA.Lib.Pretty
import CPSA.Roletran.Algebra (Term(..))
useFineTyping :: Bool
useFineTyping = False
data Kind
= KText -- Plaintext
| KData -- Data
| KName -- Name
| KSkey -- Symmetric key
| KAkey -- Public asymmetric key
| KIkey -- Private asymmetric key
| KMesg -- Message -- top kind for terms
| KQuot -- Tag
| KPair -- Pair
| KSenc -- Symmetric encryption
| KAenc -- Asymmetric encryption
| KIenc -- Sign
| KHash -- Hash
| KChan -- Channels -- not allowed
deriving (Show, Eq) -- in terms in events
-- Return the kind of a term.
kind :: Term -> Kind
kind (Txt _) = KText
kind (Dta _) = KData
kind (Nam _) = KName
kind (Sky _) = KSkey
kind (Aky _) = KAkey
kind (Iky _) = KIkey
kind (Msg _) = KMesg
kind (Tag _) = KQuot
kind (Pr _ _) = KPair
kind (En _ (Aky _)) = KAenc
kind (En _ (Iky _)) = KIenc
kind (En _ _) = KSenc
kind (Hsh _) = KHash
kind (Chn _) = KChan
-- When true, add the kind of a let bound variable
showBindKind :: Bool
showBindKind = True
-- Variable index
type Vari = Int
-- A declaration, comprising an index for a variable and the kind of
-- that variable
type Decl = (Vari, Kind)
-- A procedure
data Proc
= Proc { name :: String,
pos :: Pos,
inputs :: [Decl],
firstVar :: Vari,
outputs :: [Kind],
stmts :: [Stmt] }
mkProc :: String -> Pos -> [Decl] -> [Kind] -> [Stmt] -> Proc
mkProc name pos inputs outputs stmts =
Proc { name = name,
pos = pos,
inputs = inputs,
firstVar = length inputs,
outputs = outputs,
stmts = stmts }
-- A statement
data Stmt
= Recv Decl Vari -- Receive a message
| Send Vari Decl -- Send a message
| Bind Decl Expr -- Bind a variable to an expression
| Same Kind Vari Vari -- Are two values the same?
| Ltkp Vari Vari Vari -- Values related by the ltk function?
| Invp Kind Vari Vari -- Values related by the invk function?
| Namp Kind Vari Vari -- Values related by the pubk function?
| Nm2p Kind Vari Vari Vari -- Values related by the pubk2 function?
| Return [Vari] -- Return values from the procedure
| Comment String -- Insert a comment
-- For Invp, Namp, and Nm2p, the kind is associated with the first
-- variable. A name is associated with the second two variables in
-- Ltkp, the second variable in Namp, and the third variable in Nm2p.
-- A tag is associated with the second variable in Nm2p.
-- Expressions -- The kind is associated with the returned value
data Expr
= Pair Decl Decl -- Construct a pair
| Frst Kind Vari -- project first component of pair
| Scnd Kind Vari -- project second component of pair
| Encr Decl Decl -- Encrypt plain text
| Decr Kind Vari Decl -- Decrypt cipher text
| Quot String -- Construct a tag
| Hash Decl -- Construct a hash
| Frsh Kind -- Generate a fresh nonce
-- Emit code as a pretty printed S-expression
emit :: Int -> Proc -> Pretty
emit indent proc =
grp indent (displayHeader indent proc :
displayStmts (firstVar proc) (stmts proc))
displayHeader :: Int -> Proc -> Pretty
displayHeader indent proc =
blo (2 * indent)
[str "(defproc ", str (dehyphen $ name proc),
brk 1, str "(", grp 0 (displayInputs (firstVar proc) (inputs proc)),
brk 1, str "(", grp 0 (displayOutputs (outputs proc))]
dehyphen :: String -> String
dehyphen [] = []
dehyphen ('-' : cs) = '_' : dehyphen cs
dehyphen (c : cs) = c : dehyphen cs
displayInputs :: Vari -> [Decl] -> [Pretty]
displayInputs _ [] = [str ")"]
displayInputs first (d : ds) =
displayInput first d : foldr f [str ")"] ds
where
f d ps = brk 1 : displayInput first d : ps
displayInput :: Vari -> Decl -> Pretty
displayInput first (x, s) =
str ("(" ++ var first x ++ " " ++ displayKind s ++ ")")
displayOutputs :: [Kind] -> [Pretty]
displayOutputs [] = [str ")"]
displayOutputs (s : ss) =
str (displayKind s) : foldr f [str ")"] ss
where
f s ps = brk 1 : str (displayKind s) : ps
displayStmts :: Vari -> [Stmt] -> [Pretty]
displayStmts _ [] = [str ")"]
displayStmts first (s : ss) =
brk 1 : str (displayStmt first s) : displayStmts first ss
displayStmt :: Vari -> Stmt -> String
displayStmt first (Recv d c) =
"(let " ++ bvar first d ++ mark " (recv" [snd d] ++
" " ++ var first c ++ "))"
displayStmt first (Send c (x, s)) =
mark "(send" [s] ++ " " ++ var first c ++
" " ++ var first x ++ ")"
displayStmt first (Bind d e) =
"(let " ++ bvar first d ++ " " ++
displayExpr first e ++ ")"
displayStmt first (Same s x y) =
mark "(same" [s] ++ " " ++ var first x ++
" " ++ var first y ++ ")"
displayStmt first (Ltkp x y z) =
"(ltkp " ++ var first x ++ " " ++ var first y ++
" " ++ var first z ++ ")"
displayStmt first (Invp s x y) =
mark "(invp" [s] ++ " " ++ var first x ++
" " ++ var first y ++ ")"
displayStmt first (Namp s x y) =
mark "(namp" [s] ++ " " ++ var first x ++
" " ++ var first y ++ ")"
displayStmt first (Nm2p s x y z) =
mark "(nm2p" [s] ++ " " ++ var first x ++
" " ++ var first y ++ " " ++ var first z ++ ")"
displayStmt first (Return vs) =
"(return" ++ foldr f ")" vs
where
f v str = " " ++ var first v ++ str
displayStmt _ (Comment cmt) =
"(comment \"" ++ cmt ++ "\")"
displayExpr :: Vari -> Expr -> String
displayExpr first (Pair (x, s) (y, t)) =
mark "(pair" [s, t] ++ " " ++
var first x ++ " " ++ var first y ++ ")"
displayExpr first (Frst s x) =
mark "(frst" [s] ++ " " ++ var first x ++ ")"
displayExpr first (Scnd s x) =
mark "(scnd" [s] ++ " " ++ var first x ++ ")"
displayExpr first (Encr (x, s) (y, t)) =
mark "(encr" [s, t] ++ " " ++
var first x ++ " " ++ var first y ++ ")"
displayExpr first (Decr s x (y, t)) =
mark "(decr" [s, inv t] ++ " " ++
var first x ++ " " ++ var first y ++ ")"
displayExpr _ (Quot s) = "\"" ++ s ++ "\""
displayExpr first (Hash (x, s)) =
mark "(hash" [s] ++ " " ++ var first x ++ ")"
displayExpr _ (Frsh s) =
mark "(frsh" [s] ++ ")"
-- Display parameters with variables that start with 'p'.
-- Display let bound variables starting with 'v'.
var :: Vari -> Vari -> String
var first v
| v < first = 'p' : show v
| otherwise = 'v' : show v
-- Maybe show kind for a let bound variable.
bvar :: Vari -> Decl -> String
bvar first (v, s)
| showBindKind =
"(" ++ var first v ++ " " ++ displayKind s ++ ")"
| otherwise = var first v
-- Mark a symbol with some kind abbeviations.
mark :: String -> [Kind] -> String
mark sym kinds =
sym ++ "_" ++ map abbrev kinds
displayKind :: Kind -> String
displayKind KText = "text"
displayKind KData = "data"
displayKind KName = "name"
displayKind KSkey = "skey"
displayKind KAkey = "akey"
displayKind KIkey = "ikey"
displayKind KChan = "chan"
displayKind KQuot | useFineTyping = "quot"
displayKind KPair | useFineTyping = "pair"
displayKind KSenc | useFineTyping = "senc"
displayKind KAenc | useFineTyping = "aenc"
displayKind KIenc | useFineTyping = "ienc"
displayKind KHash | useFineTyping = "hash"
displayKind _ = "mesg"
abbrev :: Kind -> Char
abbrev KText = 't'
abbrev KData = 'd'
abbrev KName = 'n'
abbrev KSkey = 's'
abbrev KAkey = 'a'
abbrev KIkey = 'i'
abbrev KChan = 'c'
abbrev KQuot | useFineTyping = 'q'
abbrev KPair | useFineTyping = 'p'
abbrev KSenc | useFineTyping = 'e'
abbrev KAenc | useFineTyping = 'y'
abbrev KIenc | useFineTyping = 'z'
abbrev KHash | useFineTyping = 'h'
abbrev _ = 'm'
-- The inverse kind of a kind
inv :: Kind -> Kind
inv KAkey = KIkey
inv KIkey = KAkey
inv k = k
-- Trim last two characters when showing a Pos.
displayPos :: Pos -> String
displayPos pos =
f $ show pos
where
f "" = ""
f ": " = ""
f (c : cs) = c : f cs