packages feed

crucible-syntax-0.4.1: src/Lang/Crucible/Syntax/Prog.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE ImplicitParams #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeOperators #-}

module Lang.Crucible.Syntax.Prog
  ( assertNoExterns
  , assertNoForwardDecs
  , doParseCheck
  ) where

import Control.Monad

import qualified Data.Map as Map
import Data.Map (Map)
import Data.Text (Text)
import qualified Data.Text.IO as T
import qualified Prettyprinter as PP
import System.IO
import System.Exit
import Text.Megaparsec as MP

import Data.Parameterized.Nonce
import Data.Parameterized.Some (Some(Some))

import qualified Lang.Crucible.CFG.Core as C
import Lang.Crucible.CFG.Extension (IsSyntaxExtension)
import Lang.Crucible.CFG.Reg
import Lang.Crucible.CFG.SSAConversion

import Lang.Crucible.Syntax.Concrete
import Lang.Crucible.Syntax.SExpr
import Lang.Crucible.Syntax.Atoms

import Lang.Crucible.Analysis.Postdom
import Lang.Crucible.FunctionHandle

import What4.FunctionName

assertNoExterns :: Map GlobalName (Some GlobalVar) -> IO ()
assertNoExterns externs =
  unless (Map.null externs) $
  do putStrLn "Externs not currently supported"
     exitFailure

assertNoForwardDecs :: Map FunctionName SomeHandle -> IO ()
assertNoForwardDecs fds =
  unless (Map.null fds) $
  do putStrLn "Forward declarations not currently supported"
     exitFailure

-- | The main loop body, useful for both the program and for testing.
doParseCheck
   :: (IsSyntaxExtension ext, ?parserHooks :: ParserHooks ext)
   => FilePath -- ^ The name of the input (appears in source locations)
   -> Text     -- ^ The contents of the input
   -> Bool     -- ^ Whether to pretty-print the input data as well
   -> Handle   -- ^ A handle that will receive the output
   -> IO ()
doParseCheck fn theInput pprint outh =
  do Some ng <- newIONonceGenerator
     ha <- newHandleAllocator
     case MP.parse (skipWhitespace *> many (sexp atom) <* eof) fn theInput of
       Left err ->
         do putStrLn $ errorBundlePretty err
            exitFailure
       Right v ->
         do when pprint $
              forM_ v $
                \e -> T.hPutStrLn outh (printExpr e) >> hPutStrLn outh ""
            cs <- top ng ha [] $ prog v
            case cs of
              Left err -> hPutStrLn outh (show (PP.pretty err))
              Right (ParsedProgram{ parsedProgCFGs = ok
                                  , parsedProgExterns = externs
                                  , parsedProgForwardDecs = fds
                                  }) -> do
                assertNoExterns externs
                assertNoForwardDecs fds
                forM_ ok $
                 \(AnyCFG theCfg) ->
                   do C.SomeCFG ssa <- return $ toSSA theCfg
                      hPutStrLn outh $ show $ cfgHandle theCfg
                      hPutStrLn outh $ show $ C.ppCFG' True (postdomInfo ssa) ssa