packages feed

camfort-0.905: src/Camfort/Specification/Hoare/Translate.hs

{-# LANGUAGE ConstraintKinds       #-}
{-# LANGUAGE DataKinds             #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE LambdaCase            #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings     #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE TypeFamilies          #-}

{-# OPTIONS_GHC -Wall #-}

{-|

Translation from annotation syntax defined in
"Camfort.Specification.Hoare.Syntax" to strongly-typed meta-expressions defined
in "Language.Fortran.Model.Op.Meta".

-}
module Camfort.Specification.Hoare.Translate
  (
    -- * Meta Expression Types
    MetaExpr
  , MetaFormula
  , AllOps

    -- * Translation
  , translateBoolExpression
  , translateFormula

    -- * Combinators
  , intoMetaExpr
  ) where

import           Prelude                            hiding (span)

import           Control.Lens
import           Control.Monad.Except               (MonadError (..))

import qualified Language.Fortran.Analysis          as F
import qualified Language.Fortran.AST               as F

import           Language.Expression
import           Language.Expression.Choice
import           Language.Expression.Prop

import           Camfort.Helpers.TypeLevel
import           Language.Fortran.Model
import           Language.Fortran.Model.Singletons
import           Language.Fortran.Model.Translate
import           Language.Fortran.Model.Types.Match
import           Language.Fortran.Model.Vars

import           Camfort.Specification.Hoare.Syntax

--------------------------------------------------------------------------------
--  Lifting Logical Values
--------------------------------------------------------------------------------

type AllOps = '[HighOp, MetaOp, CoreOp]
type MetaExpr = HFree' AllOps
type MetaFormula = Prop (MetaExpr FortranVar)

--------------------------------------------------------------------------------
--  Translate
--------------------------------------------------------------------------------

-- | Translate an untyped logical formula into a strongly typed 'MetaFormula'.
translateFormula :: (Monad m) => PrimFormula (F.Analysis ann) -> TranslateT m (MetaFormula Bool)
translateFormula = \case
  PFExpr e -> do
    e' <- translateBoolExpression e
    return $ expr $ e'

  PFLogical x -> foldPrimLogic <$> traverse translateFormula x


-- | Translate a boolean-valued untyped Fortran expression into a strongly typed 'MetaExpr'.
translateBoolExpression
  :: (Monad m)
  => F.Expression (F.Analysis ann)
  -> TranslateT m (MetaExpr FortranVar Bool)
translateBoolExpression e = do
  SomePair d1 e' <- translateExpression e

  case matchPrimD d1 of
    Just (MatchPrimD (MatchPrim _ SBTLogical) prim1) -> return $
      case prim1 of
        PBool8  -> liftFortranExpr e'
        PBool16 -> liftFortranExpr e'
        PBool32 -> liftFortranExpr e'
        PBool64 -> liftFortranExpr e'
    _ -> throwError $ ErrUnexpectedType "formula" (Some (DPrim PBool8)) (Some d1)


foldPrimLogic :: PrimLogic (MetaFormula Bool) -> MetaFormula Bool
foldPrimLogic = \case
  PLAnd x y -> x *&& y
  PLOr x y -> x *|| y
  PLImpl x y -> x *-> y
  PLEquiv x y -> x *<-> y
  PLNot x -> pnot x
  PLLit x -> plit x


--------------------------------------------------------------------------------
--  Util
--------------------------------------------------------------------------------

-- | Convert an expression over 'HighOp', 'MetaOp' or 'CoreOp' into a 'MetaExpr'.
intoMetaExpr :: (ChooseOp op AllOps, HTraversable op) => HFree op v a -> MetaExpr v a
intoMetaExpr = HFree' . hduomapFirst' (review chooseOp)

liftFortranExpr :: (LiftD a b) => FortranExpr a -> MetaExpr FortranVar b
liftFortranExpr e =
  let e' = HWrap (HopLift (LiftDOp (HPure e)))
  in squashExpression e'