packages feed

cpsa-4.4.1: src/CPSA/Proc/Proc.hs

-- Reader for defproc

-- 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.Proc.Proc (
  parse, Var, Kind, Decl, Stmt(..), Expr(..),
  Proc, mkProc, name, inputs, outputs, stmts, Item(..)) where

import CPSA.Lib.SExpr

-- Abstract syntax for the input language

-- Variable
type Var = String

type Kind = String

-- A declaration, is a variable and a kind
type Decl = (Var, Kind)

-- A procedure
data Proc
  = Proc { name :: String,
           inputs :: [Decl],
           outputs :: [Kind],
           stmts :: [Stmt] }

mkProc :: String  -> [Decl] -> [Kind] -> [Stmt] -> Proc
mkProc name inputs outputs stmts =
  Proc { name = name,
         inputs = inputs,
         outputs = outputs,
         stmts = stmts }

-- A statement
data Stmt
  = Send String Var Var         -- Send a message
  | Bind Decl Expr              -- Bind a variable to an expression
  | Same String Var Var         -- Are two values the same?
  | Ltkp String Var Var Var     -- Vars related by the ltk function?
  | Invp String Var Var         -- Vars related by the invk function?
  | Namp String Var Var         -- Vars related by the pubk function?
  | Nm2p String Var Var Var     -- Vars related by the pubk2 function?
  | Return [Var]                -- Return values from the procedure
  | Comment String              -- Insert a comment

-- Expressions
data Expr
  = Call Var [Var]
  | Tag String

data Item
  = Cmt Pos String
  | Defproc Pos Proc

parse :: [SExpr Pos] -> IO [Item]
parse xs = mapM parseItem xs

parseItem :: SExpr Pos -> IO Item
parseItem (L pos [S _ "comment", Q _ comment]) =
  return $ Cmt pos comment
parseItem (L pos (S _ "defproc" : S _ name : L _ inputs :
               L _ outputs : xs)) =
  do
    inputs <- mapM parseDecl inputs
    outputs <- mapM parseString outputs
    stmts <- mapM parseStmt xs
    return $ Defproc pos $ mkProc name inputs outputs stmts
parseItem x =
  fail (shows (annotation x) "Unrecogized S-Expression")

parseDecl :: SExpr Pos -> IO Decl
parseDecl (L _ [S _ name, S _ kind]) =
  return (name, kind)
parseDecl x =
  fail (shows (annotation x) "Expecting a declaration")

parseString :: SExpr Pos -> IO String
parseString (S _ kind) =
  return kind
parseString x =
  fail (shows (annotation x) "Expecting a string")

parseStmt :: SExpr Pos -> IO Stmt
parseStmt (L _ [S _ "let", L _ [S _ var, S _ kind], expr]) =
  do
    expr <- parseExpr expr
    return $ Bind (var, kind) expr
parseStmt (L _ [S _ op, S _ chan, S _ msg])
  | prefix "send_" op =
    return $ Send op chan msg
parseStmt (L _ [S _ op, S _ x, S _ y])
  | prefix "same_" op =
    return $ Same op x y
parseStmt (L _ [S _ "ltkp", S _ x, S _ y, S _ z]) =
    return $ Ltkp "ltkp" x y z
parseStmt (L _ [S _ op, S _ x, S _ y])
  | prefix "invp_" op =
    return $ Invp op x y
parseStmt (L _ [S _ op, S _ x, S _ y])
  | prefix "namp_" op =
    return $ Namp op x y
parseStmt (L _ [S _ op, S _ x, S _ y, S _ z])
  | prefix "nm2p_" op =
    return $ Nm2p op x y z
parseStmt (L _ (S _ "return" : xs)) =
  do
    returns <- mapM parseString xs
    return $ Return returns
parseStmt (L _ [S _ "comment", Q _ comment]) =
  return $ Comment comment
parseStmt x =
  fail (shows (annotation x) "Malformed statement")

prefix :: String -> String -> Bool
prefix [] _ = True
prefix _ [] = False
prefix (x : xs) (y : ys) = x == y && prefix xs ys

parseExpr :: SExpr Pos -> IO Expr
parseExpr (Q _ tag) =
  return $ Tag tag
parseExpr (L _ (x : xs)) =
  do
    string <- parseString x
    strings <- mapM parseString xs
    return $ Call string strings
parseExpr x =
  fail (shows (annotation x) "Malformed expression")