blob: 7496b78bb9cb504106da278e64378f9f9d7540ab [file] [log] [blame] [edit]
--
-- Copyright 2018, Data61
-- Commonwealth Scientific and Industrial Research Organisation (CSIRO)
-- ABN 41 687 119 230.
--
-- This software may be distributed and modified according to the terms of
-- the GNU General Public License version 2. Note that NO WARRANTY is provided.
-- See "LICENSE_GPLv2.txt" for details.
--
-- @TAG(DATA61_GPL)
--
{- LANGUAGE BangPatterns -}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiWayIf #-}
{-# LANGUAGE NamedFieldPuns #-}
{- LANGUAGE QuasiQuotes -}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{- LANGUAGE TemplateHaskell -}
{-# LANGUAGE TupleSections #-}
{-# OPTIONS_GHC -Wwarn #-}
module Main where
import Cogent.C as CG (cgen, printCTable, printATM)
import Cogent.Common.Syntax as SY (CoreFunName (..))
import Cogent.Compiler
import Cogent.Core as CC (getDefinitionId, isConFun, untypeD)
import Cogent.Desugar as DS (desugar)
#ifdef WITH_DOCGENT
import Cogent.DocGent as DG (docGent)
#endif
import Cogent.GetOpt
import Cogent.Glue as GL (GlState, GlueMode (..), defaultExts, defaultTypnames,
glue, mkGlState, parseFile, readEntryFuncs)
#ifdef WITH_HASKELL
import Cogent.Haskell.Shallow as HS
#endif
import Cogent.Inference as IN (retype, tc, tcConsts, tc_)
import Cogent.Interpreter as Repl (replWithState)
import Cogent.Isabelle as Isa
#ifdef WITH_LLVM
import Cogent.LLVM.Compile as LLVM
#endif
import Cogent.Mono as MN (mono, printAFM)
import Cogent.Normal as NF (normal, verifyNormal)
import Cogent.Parser as PA (parseCustTyGen, parseWithIncludes)
import Cogent.Preprocess as PR
import Cogent.PrettyPrint as PP (prettyPrint, prettyRE, prettyTWE)
import Cogent.Reorganizer as RO (reorganize)
import Cogent.Simplify as SM
import Cogent.SuParser as SU (parse)
import Cogent.Surface as SR (stripAllLoc)
import Cogent.TypeCheck as TC (tc)
import Cogent.TypeCheck.Base as TC
import Cogent.Util as UT
-- import BuildInfo_cogent (githash, buildtime)
import Control.Monad (forM, forM_, unless, when, (<=<))
import Control.Monad.Trans.Except (runExceptT)
-- import Control.Monad.Cont
-- import Control.Monad.Except (runExceptT)
-- import Control.Monad.Trans.Either (eitherT, runEitherT)
import Data.Binary (decodeFileOrFail, encodeFile)
import Data.Char (isSpace)
import Data.Either (fromLeft, isLeft)
import Data.Foldable (fold, foldrM)
import Data.List as L (find, intersect, isPrefixOf, nub, partition)
import Data.Map (empty, fromList)
import Data.Maybe (fromJust, isJust)
import Data.Monoid (getLast)
import Data.Time
import qualified Data.Traversable as T (forM)
-- import Isabelle.InnerAST (subSymStr)
-- import Language.Haskell.TH.Ppr ()
import Lens.Micro ((^.))
import Prelude hiding (mapM_)
import System.AtomicWrite.Writer.String (atomicWithFile)
-- import System.Console.GetOpt
import System.Directory
import System.Environment
import System.Exit hiding (exitFailure, exitSuccess)
import System.FilePath hiding ((</>))
import System.IO
import System.Process (readProcessWithExitCode)
import Text.PrettyPrint.ANSI.Leijen as LJ (Doc, displayIO, hPutDoc, plain)
#if MIN_VERSION_mainland_pretty(0,6,0)
import Text.PrettyPrint.Mainland as M (hPutDoc, line, string, (</>))
import Text.PrettyPrint.Mainland.Class as M (ppr)
#else
import Text.PrettyPrint.Mainland as M (hPutDoc, line, ppr, string, (</>))
#endif
import Text.Show.Pretty (ppShow)
-- import Debug.Trace
-- Major modes of operation.
data Mode = ModeAstC
| ModeStackUsage
| ModeCompiler
| ModeInterpreter
| ModeLLVM
| ModeAbout
deriving (Eq, Show)
type Verbosity = Int
-- Commands.
-- Multiple commands may be given, but they must all have the same Mode (wrt. getMode).
-- `!' means collective command
data Command = AstC
| StackUsage (Maybe FilePath)
| Compile Stage
| Interpret
| CodeGen
| LLVMGen
| ACInstall
| CorresSetup
| CorresProof
| Documentation
| Ast Stage
| Pretty Stage
| HsShallow
| HsShallowTuples
| HsFFIGen
| Deep Stage
| Shallow Stage
| ShallowTuples -- STGDesugar
| SCorres Stage
| ShallowConsts Stage
| ShallowConstsTuples -- STGDesugar
| TableCType
| NewTableCType
| TableAbsFuncMono
| TableAbsTypeMono
| TableShallow
| ShallowTuplesProof
| NormalProof
| MonoProof
| GraphGen
| TypeProof Stage
| AllRefine
| Root
| BuildInfo
| All -- ! (excl. Hs stuff)
| CRefinement -- !
| FunctionalCorrectness -- !
| QuickCheck -- !
| LibgumDir
| Help Verbosity
| Version
-- More
deriving (Eq, Show)
isAstC :: Command -> Bool
isAstC AstC = True
isAstC _ = False
isStackUsage :: Command -> Bool
isStackUsage (StackUsage _) = True
isStackUsage _ = False
isLLVMGen :: Command -> Bool
isLLVMGen LLVMGen = True
isLLVMGen _ = False
isDeep :: Stage -> Command -> Bool
isDeep s (Deep s') = s == s'
isDeep _ _ = False
isShallow :: Stage -> Command -> Bool
isShallow s (Shallow s') = s == s'
isShallow STGDesugar ShallowTuples = True
isShallow _ _ = False
isSCorres :: Stage -> Command -> Bool
isSCorres s (SCorres s') = s == s'
isSCorres _ _ = False
isShallowConsts :: Stage -> Command -> Bool
isShallowConsts s (ShallowConsts s') = s == s'
isShallowConsts STGDesugar ShallowConstsTuples = True
isShallowConsts _ _ = False
isHelp :: Command -> Bool
isHelp (Help _) = True
isHelp _ = False
addCommands :: [Command] -> Either String (Mode, [Command])
addCommands [] = Left "no command is given"
addCommands [c] = Right (getMode c, setActions c)
addCommands (c:cs) = foldrM addCommand (getMode c, setActions c) cs
addCommand :: Command -> (Mode, [Command]) -> Either String (Mode, [Command])
addCommand c = \(m',cs) -> if getMode c == m'
then case checkConflicts c cs of
Nothing -> Right $ (m', nub $ setActions c ++ cs)
Just err -> Left err
else Left $ "command conflicts with others: " ++ show c
getMode :: Command -> Mode
getMode AstC = ModeAstC
getMode (StackUsage _) = ModeStackUsage
getMode LibgumDir = ModeAbout
getMode (Help _) = ModeAbout
getMode Version = ModeAbout
getMode LLVMGen = ModeLLVM
getMode _ = ModeCompiler
ccStandalone :: Command -> [Command] -> Maybe Command
ccStandalone c cs | null cs = Nothing
| otherwise = Just c
checkConflicts :: Command -> [Command] -> Maybe String
checkConflicts c cs | isHelp c || c == Version || c == LibgumDir || c == Interpret
= fmap (("command conflicts with others: " ++) . show) $ ccStandalone c cs
checkConflicts c cs = Nothing
setActions :: Command -> [Command]
-- C
setActions c@AstC = [c]
-- Stack Usage
setActions c@(StackUsage x) = [c]
-- LLVM
setActions c@LLVMGen = setActions (Compile STGMono) ++ [c]
-- Cogent
setActions c@(Compile STGParse) = [c]
setActions c@(CodeGen ) = setActions (Compile STGCodeGen) ++ [c]
setActions c@(TableCType ) = setActions (Compile STGCodeGen) ++ [c]
setActions c@(NewTableCType) = setActions (Compile STGCodeGen) ++ [c]
setActions c@(Compile stg) = setActions (Compile $ pred stg) ++ [c]
setActions c@(Interpret ) = [c]
setActions c@(Ast stg) = setActions (Compile stg) ++ [c]
setActions c@(Documentation) = setActions (Compile STGParse) ++ [c]
setActions c@(Pretty stg) = setActions (Compile stg) ++ [c]
setActions c@(HsShallow ) = setActions (Compile STGDesugar) ++ [c]
setActions c@(HsShallowTuples) = setActions (Compile STGDesugar) ++ [c]
setActions c@(HsFFIGen ) = setActions (Compile STGCodeGen) ++ [c]
setActions c@(Deep stg) = setActions (Compile stg) ++ [c]
setActions c@(Shallow stg) = setActions (Compile stg) ++ [c]
setActions c@(ShallowTuples) = setActions (Compile STGDesugar) ++ [c]
setActions c@(SCorres stg) = setActions (Compile stg) ++ [c]
setActions c@(ShallowConsts stg) = setActions (Compile stg) ++ [c]
setActions c@ShallowConstsTuples = setActions (Compile STGDesugar) ++ [c]
setActions c@(TableShallow ) = setActions (Compile STGDesugar) ++ [c]
setActions c@(TypeProof stg) = setActions (Compile stg) ++ [c]
setActions c@ShallowTuplesProof = setActions (ShallowTuples) ++
setActions (ShallowConstsTuples) ++
setActions (Shallow STGDesugar) ++
setActions (ShallowConsts STGDesugar) ++
[c]
setActions c@(NormalProof ) = setActions (Compile STGNormal) ++
setActions (Shallow STGDesugar) ++
setActions (Shallow STGNormal) ++ [c]
setActions c@(MonoProof ) = setActions (Compile STGMono) ++ [c]
setActions c@(ACInstall ) = setActions (Compile STGMono) ++ [c]
setActions c@(CorresSetup ) = setActions (Compile STGMono) ++ [c]
setActions c@(CorresProof ) = setActions (Compile STGMono) ++ [c]
setActions c@(AllRefine ) = setActions (Compile STGMono) ++ [c]
setActions c@(Root ) = setActions (Compile STGMono) ++ [c] -- FIXME: can be earlier / zilinc
setActions c@(BuildInfo ) = [c]
setActions c@(GraphGen ) = setActions (Compile STGMono) ++ [c]
-- NOTE: The --c-refinement flag generates almost all the things C refinement proof needs, but the
-- proof is actually done in AllRefine, which also relies on the functional correctness proof. It
-- means that, unfortunately, we can't simply split up the thing into two halves cleanly. We have to generate
-- everything even when only part of it is needed. / zilinc
setActions c@(CRefinement ) = nub $ setActions (CodeGen) ++
setActions (Deep STGNormal) ++
setActions (Shallow STGNormal) ++
setActions (SCorres STGNormal) ++
setActions (TypeProof STGMono) ++
setActions (MonoProof) ++ -- although technically only needed for C-refinement,
-- it's only invoked in AllRefine.
setActions (TableCType) ++
setActions (NewTableCType) ++
setActions (Root) ++
[ACInstall, CorresSetup, CorresProof, BuildInfo]
setActions c@(FunctionalCorrectness) = nub $ setActions (ShallowTuplesProof) ++
setActions (NormalProof) ++
setActions (Root) ++
[BuildInfo]
setActions c@(QuickCheck ) = nub $ setActions (HsFFIGen) ++
setActions (CodeGen) ++
setActions (HsShallow) ++
setActions (HsShallowTuples) ++
setActions (ShallowTuplesProof) ++
[BuildInfo]
setActions c@(All ) = nub $ setActions (CodeGen) ++
setActions (CRefinement) ++
setActions (FunctionalCorrectness) ++
setActions (AllRefine)
setActions c = [c] -- -h, -v
type Flags = [IO ()]
stgMsg :: Stage -> String
stgMsg STGParse = "surface"
stgMsg STGTypeCheck = "type-checked surface"
stgMsg STGDesugar = "desugared core"
stgMsg STGNormal = "normalised core"
stgMsg STGSimplify = "simplified core"
stgMsg STGMono = "monomorphised core"
stgMsg STGCodeGen = "code generation"
stgCmd :: Stage -> String
stgCmd STGDesugar = "desugar"
stgCmd STGNormal = "normal"
stgCmd STGMono = "mono"
stgCmd _ = __impossible "stgCmd"
astMsg s = "display " ++ stgMsg s ++ " language AST"
prettyMsg s = "pretty-print " ++ stgMsg s ++ " language"
#ifdef WITH_HASKELL
hsShallowMsg s tup = "generate Haskell shallow embedding (" ++ stgMsg s ++
(if tup then ", with Haskell Tuples" else "") ++ ")"
#else
hsShallowMsg s tup = "generate Haskell shallow embedding (" ++ stgMsg s ++
(if tup then ", with Haskell Tuples" else "") ++ ") [disabled in this build]"
#endif
deepMsg s = "generate Isabelle deep embedding (" ++ stgMsg s ++ ")"
shallowMsg s tup = "generate Isabelle shallow embedding (" ++ stgMsg s ++
(if tup then ", with HOL tuples" else "") ++ ")"
scorresMsg s = "generate scorres (" ++ stgMsg s ++ ")"
embeddingMsg s = let s' = stgCmd s
in "implies --deep-" ++ s' ++ " --shallow-" ++ s' ++ " --scorres-" ++ s' ++ " --shallow-funcs-" ++ s'
shallowFuncsMsg s = "generate a list of function names for shallow embedding (" ++ stgMsg s ++ ")"
shallowConstsMsg s tup = "generate constant definitions for shallow embedding (" ++ stgMsg s ++
(if tup then ", with HOL tuples" else "") ++ ")"
options :: [OptDescr Command]
options = [
-- C
Option [] ["ast-c"] 3 (NoArg AstC) "parse C file with Cogent antiquotation and print AST"
-- stack usage
, Option [] ["stack-usage"] 3 (OptArg StackUsage "FILE") "parse stack usage .su file generated by gcc"
-- compilation
, Option [] ["parse"] 0 (NoArg $ Compile STGParse) "parse Cogent source code"
, Option ['t'] ["typecheck"] 0 (NoArg $ Compile STGTypeCheck) "typecheck surface program"
, Option ['d'] ["desugar"] 0 (NoArg $ Compile STGDesugar) "desugar surface program and re-type it"
, Option [] ["normal"] 0 (NoArg $ Compile STGNormal) "normalise core language and re-type it"
, Option [] ["simplify"] 1 (NoArg $ Compile STGSimplify) "simplify core language and re-type it"
, Option [] ["mono"] 0 (NoArg $ Compile STGMono) "monomorphise core language and re-type it"
, Option ['g'] ["code-gen"] 0 (NoArg CodeGen) "generate C code"
-- AST
, Option [] ["ast-parse"] 2 (NoArg $ Ast STGParse) (astMsg STGParse)
, Option [] ["ast-tc"] 2 (NoArg $ Ast STGTypeCheck) (astMsg STGTypeCheck)
, Option [] ["ast-desugar"] 2 (NoArg $ Ast STGDesugar) (astMsg STGDesugar)
, Option [] ["ast-normal"] 2 (NoArg $ Ast STGNormal) (astMsg STGNormal)
, Option [] ["ast-simpl"] 2 (NoArg $ Ast STGSimplify) (astMsg STGSimplify)
, Option [] ["ast-mono"] 2 (NoArg $ Ast STGMono) (astMsg STGMono)
-- interpreter
, Option ['i'] ["repl"] 1 (NoArg $ Interpret) "run Cogent REPL"
-- llvm
#ifdef WITH_LLVM
, Option [] ["llvm"] 0 (NoArg LLVMGen) "use the experimental LLVM backend"
#else
, Option [] ["llvm"] 0 (NoArg LLVMGen) "use the experimental LLVM backend [disabled in this build]"
#endif
-- documentation
#ifdef WITH_DOCGENT
, Option [] ["docgent"] 2 (NoArg $ Documentation) "generate HTML documentation"
#else
, Option [] ["docgent"] 2 (NoArg $ Documentation) "generate HTML documentation [disabled in this build]"
#endif
-- pretty
, Option [] ["pretty-parse"] 2 (NoArg $ Pretty STGParse) (prettyMsg STGParse)
, Option ['T'] ["pretty-tc"] 2 (NoArg $ Pretty STGTypeCheck) (prettyMsg STGTypeCheck)
, Option ['D'] ["pretty-desugar"] 2 (NoArg $ Pretty STGDesugar) (prettyMsg STGDesugar)
, Option [] ["pretty-normal"] 2 (NoArg $ Pretty STGNormal) (prettyMsg STGNormal)
, Option [] ["pretty-simpl"] 2 (NoArg $ Pretty STGSimplify) (prettyMsg STGSimplify)
, Option [] ["pretty-mono"] 2 (NoArg $ Pretty STGMono) (prettyMsg STGMono)
-- Haskell shallow
#ifdef WITH_HASKELL
, Option [] ["hs-shallow-desugar"] 2 (NoArg HsShallow ) (hsShallowMsg STGDesugar False)
, Option [] ["hs-shallow-desugar-tuples"] 2 (NoArg HsShallowTuples) (hsShallowMsg STGDesugar True )
-- FFI
, Option [] ["hs-ffi"] 2 (NoArg HsFFIGen) "generate Haskell FFI code to access generated C code (incl. a .hsc module for types and a .hs module for functions)"
#else
, Option [] ["hs-shallow-desugar"] 2 (NoArg HsShallow ) (hsShallowMsg STGDesugar False)
, Option [] ["hs-shallow-desugar-tuples"] 2 (NoArg HsShallowTuples) (hsShallowMsg STGDesugar True )
-- FFI
, Option [] ["hs-ffi"] 2 (NoArg HsFFIGen) "generate Haskell FFI code to access generated C code (incl. a .hsc module for types and a .hs module for functions) [disabled in this build]"
#endif
-- deep
, Option [] ["deep-desugar"] 1 (NoArg (Deep STGDesugar)) (deepMsg STGDesugar)
, Option [] ["deep-normal"] 1 (NoArg (Deep STGNormal )) (deepMsg STGNormal)
, Option [] ["deep-mono"] 1 (NoArg (Deep STGMono )) (deepMsg STGMono)
-- shallow
, Option [] ["shallow-desugar"] 1 (NoArg (Shallow STGDesugar)) (shallowMsg STGDesugar False)
, Option [] ["shallow-normal"] 1 (NoArg (Shallow STGNormal )) (shallowMsg STGNormal False)
, Option [] ["shallow-mono"] 1 (NoArg (Shallow STGMono )) (shallowMsg STGMono False)
, Option [] ["shallow-desugar-tuples"] 1 (NoArg ShallowTuples) (shallowMsg STGDesugar True)
-- s-corres
, Option [] ["scorres-desugar"] 1 (NoArg (SCorres STGDesugar)) (scorresMsg STGDesugar)
, Option [] ["scorres-normal"] 1 (NoArg (SCorres STGNormal )) (scorresMsg STGNormal)
, Option [] ["scorres-mono"] 1 (NoArg (SCorres STGMono )) (scorresMsg STGMono)
-- shallow consts
, Option [] ["shallow-consts-desugar"] 1 (NoArg (ShallowConsts STGDesugar)) (shallowConstsMsg STGDesugar False)
, Option [] ["shallow-consts-normal"] 1 (NoArg (ShallowConsts STGNormal )) (shallowConstsMsg STGNormal False)
, Option [] ["shallow-consts-mono"] 1 (NoArg (ShallowConsts STGMono )) (shallowConstsMsg STGMono False)
, Option [] ["shallow-consts-desugar-tuples"] 1 (NoArg ShallowConstsTuples) (shallowConstsMsg STGDesugar True)
-- tuples proof
, Option [] ["shallow-tuples-proof"] 1 (NoArg ShallowTuplesProof) "generate proof for shallow tuples embedding"
-- normalisation proof
, Option [] ["normal-proof"] 1 (NoArg NormalProof) "generate Isabelle proof of normalisation"
-- mono proof
, Option [] ["mono-proof"] 1 (NoArg MonoProof) "generate monomorphisation proof"
-- c refinement
, Option [] ["ac-install"] 1 (NoArg ACInstall) "generate an Isabelle theory to install AutoCorres"
, Option [] ["corres-setup"] 1 (NoArg CorresSetup) "generate Isabelle lemmas for c-refinement"
, Option [] ["corres-proof"] 1 (NoArg CorresProof) "generate Isabelle proof of c-refinement"
-- type proof
, Option [] ["type-proof-normal"] 1 (NoArg (TypeProof STGNormal)) "generate Isabelle proof of type correctness of normalised AST"
, Option [] ["type-proof"] 1 (NoArg (TypeProof STGMono )) "generate Isabelle proof of type correctness of normal-mono AST"
-- top-level theory
, Option [] ["all-refine"] 1 (NoArg AllRefine) "[COLLECTIVE] generate shallow-to-C refinement proof"
-- misc.
, Option [] ["root"] 1 (NoArg Root) ("generate Isabelle " ++ __cogent_root_name ++ " file")
, Option [] ["table-c-types"] 1 (NoArg TableCType) "generate a table of Cogent and C type correspondence"
, Option [] ["new-table-c-types"] 1 (NoArg NewTableCType) "generate a table of Cogent and C type correspondence, and getter/setter functions for Dargent"
, Option [] ["table-shallow"] 1 (NoArg TableShallow) "generate a table of type synonyms for shallow embedding"
, Option [] ["table-abs-func-mono"] 3 (NoArg TableAbsFuncMono) "generate a table of monomorphised abstract functions"
, Option [] ["table-abs-type-mono"] 3 (NoArg TableAbsTypeMono) "generate a table of monomorphised abstract types"
, Option ['G'] ["graph-gen"] 3 (NoArg GraphGen) "generate graph for graph-refine"
, Option [] ["build-info"] 0 (NoArg BuildInfo) ("log how cogent is being invoked by generating " ++ __cogent_build_info_name ++ " file; implied by any collective commands")
-- top level
, Option ['C'] ["c-refinement"] 0 (NoArg CRefinement) "[COLLECTIVE] generate all files needed for the C refinement proof"
, Option ['F'] ["functional-correctness"] 0 (NoArg FunctionalCorrectness) "[COLLECTIVE] generate all files needed for the functional correctness proof"
, Option ['A'] ["all"] 0 (NoArg All) "[COLLECTIVE] generate everything"
, Option ['Q'] ["quickcheck"] 1 (NoArg QuickCheck) "[COLLECTIVE] generate QuickCheck related artifacts"
-- info.
, Option [] ["libgum-dir"] 0 (NoArg LibgumDir) "display directory where libgum is installed (can be set by COGENT_LIBGUM_DIR environment variable)"
, Option ['h','?'] ["help"] 0 (OptArg (Help . maybe 1 read) "VERBOSITY") "display help message (VERBOSITY=0..4, default to 1)"
, Option ['v','V'] ["version"] 0 (NoArg Version) "show version number"
]
flags :: [OptDescr (IO ())]
flags =
[
-- names
Option ['o'] ["output-name"] 1 (ReqArg set_flag_outputName "NAME") "specify base name for output files (default is derived from source Cogent file)"
, Option [] ["proof-name"] 1 (ReqArg set_flag_proofName "NAME") "specify Isabelle theory file name (default is derived from source Cogent file)"
-- dir specification
, Option [] ["abs-type-dir"] 1 (ReqArg set_flag_absTypeDir "PATH") "abstract type definitions will be in $DIR/abstract/, which must exist (default=./)"
, Option [] ["dist-dir"] 1 (ReqArg set_flag_distDir "PATH") "specify path to all output files (default=./)"
, Option [] ["fake-header-dir"] 1 (ReqArg set_flag_fakeHeaderDir "PATH") "specify path to fake c header files"
, Option ['I'] ["include"] 1 (ReqArg add_flag_include "PATH") "specify directories to search for included cogent files"
, Option [] ["root-dir"] 1 (ReqArg set_flag_rootDir "PATH") "specify path to top-level directory (for imports in theory files only, default=./)"
-- config and other output files
, Option [] ["arch"] 2 (ReqArg set_flag_arch "ARCH") "set the target architecture; ARCH could be one of arm32 (default), x86_64, x86"
, Option [] ["cust-ty-gen"] 1 (ReqArg set_flag_custTyGen "FILE") "config file to customise type generation"
, Option [] ["entry-funcs"] 1 (ReqArg set_flag_entryFuncs "FILE") "give a list of Cogent functions that are only called from outside"
, Option [] ["ext-types"] 1 (ReqArg set_flag_extTypes "FILE") "give external type names to C parser"
, Option [] ["infer-c-funcs"] 1 (ReqArg (set_flag_inferCFunc . words) "FILE..") "infer Cogent abstract function definitions"
, Option [] ["infer-c-types"] 1 (ReqArg (set_flag_inferCType . words) "FILE..") "infer Cogent abstract type definitions"
, Option [] ["name-cache"] 1 (ReqArg set_flag_nameCache "FILE") "specify the name cache file to use"
, Option [] ["proof-input-c"] 1 (ReqArg set_flag_proofInputC "FILE") "specify input C file to generate proofs (default to the same base name as input Cogent file)"
, Option [] ["type-proof-timing"] 3 (NoArg set_flag_proofTiming) "Log type proof timings in the generated isabelle embedding to ~/TypeProofTacticTiming.json"
, Option [] ["prune-call-graph"] 2 (ReqArg set_flag_pruneCallGraph "FILE") "specify Cogent entry-point definitions"
-- external programs
, Option [] ["cogent-pp-args"] 2 (ReqArg (set_flag_cogentPpArgs) "ARG..") "arguments given to Cogent preprocessor (same as cpphs)"
, Option [] ["cpp"] 2 (ReqArg (set_flag_cpp) "PROG") "set which C-preprocessor to use (default to cpp)"
, Option [] ["cpp-args"] 2 (ReqArg (set_flag_cppArgs . words) "ARG..") "arguments given to C-preprocessor (default to $CPPIN -P -o $CPPOUT)"
-- debugging options
, Option [] ["ddump-smt"] 3 (NoArg set_flag_ddumpSmt) "dump verbose SMT-solving information"
, Option [] ["ddump-tc"] 3 (NoArg set_flag_ddumpTc) "dump (massive) surface typechecking internals"
, Option [] ["ddump-tc-ctx"] 3 (NoArg set_flag_ddumpTcCtx) "dump surface typechecking with context"
, Option [] ["ddump-tc-filter"] 3 (ReqArg set_flag_ddumpTcFilter "KEYWORDS") "a space-separated list of keywords to indicate which groups of info to display (gen, sol, post, tc)"
, Option [] ["ddump-to-file"] 3 (ReqArg set_flag_ddumpToFile "FILE") "dump debugging output to specific file instead of terminal"
, Option [] ["ddump-pretty-ds-no-tc"] 3 (NoArg set_flag_ddumpPrettyDsNoTc) "dump the pretty printed desugared expression before typechecking"
, Option [] ["ddump-pretty-normal-no-tc"] 3 (NoArg set_flag_ddumpPrettyNormalNoTc) "dump the pretty printed normalised expression before typechecking"
-- behaviour
, Option [] ["fcheck-undefined"] 2 (NoArg set_flag_fcheckUndefined) "(default) check for undefined behaviours in C"
, Option ['B'] ["fdisambiguate-pp"] 3 (NoArg set_flag_fdisambiguatePp) "when pretty-printing, also display internal representation as comments"
, Option [] ["fffi-c-functions"] 1 (NoArg set_flag_fffiCFunctions) "generate FFI functions in the C code (should be used when -Q)"
, Option [] ["fflatten-nestings"] 2 (NoArg set_flag_fflattenNestings) "flatten out nested structs in C code (does nothing)"
, Option [] ["ffncall-as-macro"] 3 (NoArg set_flag_ffncallAsMacro) "generate macros instead of real function calls"
, Option [] ["ffull-src-path"] 2 (NoArg set_flag_ffullSrcPath) "display full path for source file locations"
, Option [] ["ffunc-purity-attr"] 2 (NoArg set_flag_ffuncPurityAttr) "(default) generate GCC attributes to classify purity of Cogent functions"
, Option [] ["fgen-header"] 2 (NoArg set_flag_fgenHeader) "generate build info header in all output files, reverse of --fno-gen-header"
, Option [] ["fintermediate-vars"] 2 (NoArg set_flag_fintermediateVars) "(default) generate intermediate variables for Cogent expressions"
, Option [] ["flax-take-put"] 3 (NoArg set_flag_flaxTakePut) "allow take/put type operators on abstract datatypes"
, Option [] ["flet-in-if"] 2 (NoArg set_flag_fletInIf) "(default) put binding of a let inside an if-clause"
, Option [] ["fletbang-in-if"] 2 (NoArg set_flag_fletbangInIf) "(default) put binding of a let! inside an if-clause"
, Option [] ["fml-typing-tree"] 2 (NoArg set_flag_fmlTypingTree) "(default) generate ML typing tree in type proofs"
, Option [] ["fnormalisation"] 2 (OptArg set_flag_fnormalisation "NF") "(default) normalise the core language (NF=anf[default], knf, lnf)"
, Option [] ["fno-check-undefined"] 1 (NoArg set_flag_fnoCheckUndefined) "reverse of --fcheck-undefined"
, Option [] ["fno-flatten-nestings"] 2 (NoArg set_flag_fnoFlattenNestings) "(default) reverse of --fflatten-nestings"
, Option [] ["fno-fncall-as-macro"] 2 (NoArg set_flag_fnoFncallAsMacro) "(default) reverse of --ffncall-as-macro"
, Option [] ["fno-func-purity-attr"] 2 (NoArg set_flag_fnoFuncPurityAttr) "reverse of --ffunc-purity-attr"
, Option [] ["fno-gen-header"] 2 (NoArg set_flag_fnoGenHeader) "(default) don't generate build info header in any output files"
, Option [] ["fno-intermediate-vars"] 1 (NoArg set_flag_fnoIntermediateVars) "reverse of --fintermediate-vars"
, Option [] ["fno-lax-take-put"] 3 (NoArg set_flag_fnoLaxTakePut) "(default) reverse of --flax-take-put"
, Option [] ["fno-let-in-if"] 1 (NoArg set_flag_fnoLetInIf) "reverse of --flet-in-if"
, Option [] ["fno-letbang-in-if"] 1 (NoArg set_flag_fnoLetbangInIf) "reverse of --fletbang-in-if"
, Option [] ["fno-ml-typing-tree"] 2 (NoArg set_flag_fnoMlTypingTree) "reverse of --fml-typing-tree"
, Option [] ["fno-normalisation"] 1 (NoArg set_flag_fnoNormalisation) "reverse of --fnormalisation"
, Option [] ["fno-pragmas"] 1 (NoArg set_flag_fnoPragmas) "reverse of --fpragmas"
, Option [] ["fno-pretty-errmsgs"] 3 (NoArg set_flag_fnoPrettyErrmsgs) "reverse of --fpretty-errmsgs"
, Option [] ["fno-reverse-tc-errors"] 2 (NoArg set_flag_fnoReverseTcErrors) "(default) reverse of --freverse-tc-errors"
, Option [] ["fno-share-linear-vars"] 2 (NoArg set_flag_fnoShareLinearVars) "(default) reverse of --fshare-linear-vars"
, Option [] ["fno-show-types-in-pretty"] 2 (NoArg set_flag_fnoShowTypesInPretty) "(default) reverse of --fshow-types-in-pretty"
, Option [] ["fno-simplifier"] 2 (NoArg set_flag_fnoSimplifier) "(default) reverse of --fsimplifier"
, Option [] ["fno-static-inline"] 1 (NoArg set_flag_fnoStaticInline) "reverse of --fstatic-inline"
, Option [] ["fno-tc-ctx-constraints"] 3 (NoArg set_flag_ftcCtxConstraints) "(default) reverse of --ftc-ctx-constraints"
, Option [] ["fno-tp-with-bodies"] 1 (NoArg set_flag_fnoTpWithBodies) "reverse of --ftp-with-bodies"
, Option [] ["fno-tp-with-decls"] 1 (NoArg set_flag_fnoTpWithDecls) "reverse of --ftp-with-decls"
, Option [] ["fno-tuples-as-sugar"] 1 (NoArg set_flag_fnoTuplesAsSugar) "reverse of --ftuples-as-sugar"
, Option [] ["fno-union-for-variants"] 2 (NoArg set_flag_fnoUnionForVariants) "(default) reverse of --funion-for-variants"
, Option [] ["fno-untyped-func-enum"] 2 (NoArg set_flag_fnoUntypedFuncEnum) "reverse of --funtyped-func-enum"
, Option [] ["fno-use-compound-literals"] 1 (NoArg set_flag_fnoUseCompoundLiterals) "reverse of --fuse-compound-literals, it instead creates new variables"
, Option [] ["fno-wrap-put-in-let"] 2 (NoArg set_flag_fnoWrapPutInLet) "(default) reverse of --fwrap-put-in-let"
, Option [] ["fpragmas"] 2 (NoArg set_flag_fpragmas) "(default) preprocess pragmas"
, Option [] ["fpretty-errmsgs"] 3 (NoArg set_flag_fprettyErrmsgs) "(default) pretty-print error messages (requires ANSI support)"
, Option [] ["freverse-tc-errors"] 1 (NoArg set_flag_freverseTcErrors) "Print type errors in reverse order"
, Option [] ["fshare-linear-vars"] 2 (NoArg set_flag_fshareLinearVars) "reuse C variables for linear objects"
, Option [] ["fshow-types-in-pretty"] 2 (NoArg set_flag_fshowTypesInPretty) "show inferred types of each AST node when doing pretty-printing"
, Option [] ["fsimplifier"] 1 (NoArg set_flag_fsimplifier) "enable simplifier on core language"
, Option [] ["fsimplifier-level"] 1 (ReqArg (set_flag_fsimplifierIterations . read) "NUMBER") "number of iterations simplifier does (default=4)"
, Option [] ["fstatic-inline"] 2 (NoArg set_flag_fstaticInline) "(default) generate static-inlined functions in C"
, Option [] ["ftuples-as-sugar"] 2 (NoArg set_flag_ftuplesAsSugar) "(default) treat tuples as syntactic sugar to unboxed records, which gives better performance"
, Option [] ["ftc-ctx-constraints"] 3 (NoArg set_flag_ftcCtxConstraints) "display constraints in type errors"
, Option [] ["ftc-ctx-len"] 3 (ReqArg (set_flag_ftcCtxLen . read) "NUMBER") "set the depth for printing error context in typechecker (default=3)"
, Option [] ["ftp-with-bodies"] 2 (NoArg set_flag_ftpWithBodies) "(default) generate type proof with bodies"
, Option [] ["ftp-with-decls"] 2 (NoArg set_flag_ftpWithDecls) "(default) generate type proof with declarations"
, Option [] ["funion-for-variants"] 2 (NoArg set_flag_funionForVariants) "use union types for variants in C code (cannot be verified)"
, Option [] ["funtyped-func-enum"] 2 (NoArg set_flag_funtypedFuncEnum) "(default) use untyped function enum type"
, Option [] ["fuse-compound-literals"] 2 (NoArg set_flag_fuseCompoundLiterals) "(default) use compound literals when possible in C code"
, Option [] ["fwrap-put-in-let"] 1 (NoArg set_flag_fwrapPutInLet) "Put always appears in a Let-binding when normalised"
, Option ['O'] ["optimisation"] 0 (OptArg set_flag_O "LEVEL") "set optimisation level (0, 1, 2, d, n, s or u; default -Od)"
-- warning control
, Option [] ["Wall"] 1 (NoArg set_flag_Wall) "issue all warnings"
, Option ['E'] ["Werror"] 1 (NoArg set_flag_Werror) "make any warning into a fatal error"
, Option [] ["Wdodgy-take-put"] 2 (NoArg set_flag_WdodgyTakePut) "(default) enable warnings on ill-formed take or put in types"
, Option [] ["Wdynamic-variant-promotion"] 2 (NoArg set_flag_WdynamicVariantPromotion) "enable warnings on dynamic variant type promotion"
, Option [] ["Wimplicit-int-lit-promotion"] 2 (NoArg set_flag_WimplicitIntLitPromotion) "(default) enable warning on implicit integer literal promotion"
, Option [] ["Wmono"] 3 (NoArg set_flag_Wmono) "enable warnings during monomorphisation"
, Option [] ["Wunused-local-binds"] 2 (NoArg set_flag_WunusedLocalBinds) "warn about unused local binders"
, Option [] ["Wno-dodgy-take-put"] 2 (NoArg set_flag_WnoDodgyTakePut) "reverse of --Wdodgy-take-put"
, Option [] ["Wno-dynamic-variant-promotion"] 2 (NoArg set_flag_WnoDynamicVariantPromotion) "(default) reverse of --Wdynamic-variant-promotion"
, Option [] ["Wno-mono"] 3 (NoArg set_flag_WnoMono) "(default) reverse of --Wmono"
, Option [] ["Wno-implicit-int-lit-promotion"] 2 (NoArg set_flag_WnoImplicitIntLitPromotion) "reverse of --Wimplicit-int-lit-promotion"
, Option [] ["Wno-unused-local-binds"] 2 (NoArg set_flag_WnoUnusedLocalBinds) "(default) reverse of --Wunused-local-binds"
, Option ['w'] ["Wno-warn"] 1 (NoArg set_flag_w) "turn off all warnings"
, Option [] ["Wwarn"] 1 (NoArg set_flag_Wwarn) "(default) warnings are treated only as warnings, not as errors"
-- misc
, Option ['q'] ["quiet"] 1 (NoArg set_flag_quiet) "do not display compilation progress"
, Option ['x'] ["fdump-to-stdout"] 1 (NoArg set_flag_fdumpToStdout) "dump all output to stdout"
, Option [] ["interactive"] 3 (NoArg set_flag_interactive) "interactive compiler mode"
, Option [] ["type-proof-sorry-before"] 1 (ReqArg set_flag_type_proof_sorry_before "FUN_NAME") "bad hack: sorry all type proofs for functions that precede given function name"
]
parseArgs :: [String] -> IO ()
parseArgs args = case getOpt' Permute options args of
(cmds,xs,us,[]) -> case addCommands cmds of
Left err -> exitErr (err ++ "\n")
Right (_,cmds') -> withCommands (cmds',xs,us,args) -- XXX | noCommandError (cmds',xs,us,args)
(_,_,us,errs) -> exitErr (concat errs)
where
withCommands :: ([Command], [String], [String], [String]) -> IO ()
#ifndef WITH_HASKELL
withCommands (cs,_,_,_) | not . null $ [HsFFIGen, HsShallowTuples, HsShallow] `intersect` cs
= exitErr $ unlines [ "Haskell-related features are disabled in this build."
, "Try building the Cogent compiler with the flag `haskell-backend' on."]
#endif
#ifndef WITH_DOCGENT
withCommands (cs,_,_,_) | Documentation `elem` cs
= exitErr $ unlines [ "Cogent documentation generation is disabled in this build."
, "Try building the Cogent compiler with the flag `docgent' on."]
#endif
withCommands (cs,xs,us,args) = case getOpt Permute flags (filter (`elem` us ++ xs) args) of -- Note: this is to keep the order of arguments / zilinc
(flags,xs',[]) -> noFlagError (cs,flags,xs',args)
(_,_,errs) -> exitErr (concat errs)
noFlagError :: ([Command], Flags, [String], [String]) -> IO ()
noFlagError ([LibgumDir],_,_,_) = getLibgumDir >>= putStrLn >> exitSuccess_
noFlagError ([Help v],_,_,_) = putStr (usage v) >> exitSuccess_
noFlagError ([Version],_,_,_) = putStrLn versionInfo >> exitSuccess_
noFlagError ([Interpret],fs,_,_) = replWithState
noFlagError (_,_,[],_) = exitErr ("no Cogent file specified\n")
noFlagError (cs,fs,x:[],args) = oneFile (cs,fs,x,args)
noFlagError (_,_,xs,_) = exitErr ("only one Cogent file can be given\n")
oneFile :: ([Command], Flags, FilePath, [String]) -> IO ()
oneFile (cmds,flags,source,args) = do
sequence_ flags
runCompiler cmds source args
putProgress :: String -> IO ()
putProgress s = when (not __cogent_quiet) $ hPutStr stderr s
putProgressLn :: String -> IO ()
putProgressLn s = when (not __cogent_quiet) $ hPutStrLn stderr s
runCompiler :: [Command] -> FilePath -> [String] -> IO ()
runCompiler cmds source args =
if | Compile STGParse `elem` cmds -> do
preDump
utc <- getCurrentTime
zone <- getCurrentTimeZone
let zoned = utcToZonedTime zone utc
buildinfo =
"-----------------------------------------------------------------------------\n" ++
"This file is generated by " ++ versionInfo ++ "\n" ++
"with command ./cogent " ++ unwords args ++ "\n" ++
"at " ++ formatTime defaultTimeLocale "%a, %-d %b %Y %H:%M:%S %Z" zoned ++ "\n" ++
"-----------------------------------------------------------------------------\n"
log = if __cogent_fgen_header
then buildinfo
else "This file is generated by Cogent\n"
parse cmds source buildinfo log
| Just (AstC) <- find isAstC cmds -> c_parse cmds source
| Just (StackUsage p) <- find isStackUsage cmds -> stack_usage cmds p source
| otherwise -> exitSuccess
c_parse cmds source = do
putProgressLn "Parsing C file..."
let hl, hr :: forall a b. Show a => a -> IO b
hl err = hPutStrLn stderr (show err) >> exitFailure
hr defs = lessPretty stdout defs >> exitSuccess
exceptT hl hr $ GL.parseFile GL.defaultExts defaultTypnames source
stack_usage cmds p source = do
putProgressLn "Parsing .su file..."
let outf = case p of Nothing -> Just $ source ++ ".psu"
Just "-" -> Nothing
Just o -> Just o
SU.parse source >>= \case
Left err -> hPutStrLn stderr err >> exitFailure
Right sus -> writeFileMsg outf >> output outf (flip hPutStrLn (show sus)) >> exitSuccess
parse cmds source buildinfo log = do
let stg = STGParse
putProgressLn "Parsing..."
parseWithIncludes source __cogent_include >>= \case
Left err -> hPutStrLn stderr err >> exitFailure
Right (parsed,pragmas) -> do
prune <- T.forM __cogent_prune_call_graph simpleLineParser
putProgressLn "Resolving dependencies..."
case reorganize prune parsed of
Left err -> printError prettyRE [err] >> exitFailure
Right reorged -> do when (Ast stg `elem` cmds) $ genAst stg (map (stripAllLoc . thd3) reorged)
when (Pretty stg `elem` cmds) $ genPretty stg (map (stripAllLoc . thd3) reorged)
#ifdef WITH_DOCGENT
when (Documentation `elem` cmds) $ DG.docGent reorged
#endif
let noDocs (a,_,c) = (a,c)
when (Compile (succ stg) `elem` cmds) $ do
ctygen <- mapM parseCustTyGen __cogent_cust_ty_gen
case sequence ctygen of
Left err -> hPutStrLn stderr err >> exitFailure
Right ctygen' -> typecheck cmds (map noDocs reorged) (fold ctygen') source pragmas buildinfo log
exitSuccessWithBuildInfo cmds buildinfo
typecheck cmds reorged ctygen source pragmas buildinfo log = do
let stg = STGTypeCheck
putProgressLn "Typechecking..."
((mtc',tclog),tcst) <- TC.tc reorged ctygen
let (errs,warns) = partition (isLeft . snd) $ tclog^.errLog
when (not $ null errs) $ do
printError (prettyTWE __cogent_ftc_ctx_len) errs
when (and $ map (isWarnAsError . fromLeft undefined . snd) errs) $ hPutStrLn stderr "Failing due to --Werror."
exitFailure
case mtc' of
Nothing -> __impossible "main: typecheck"
Just (tced,ctygen') -> do
__assert (null errs) "no errors, only warnings"
unless (null $ warns) $ printError (prettyTWE __cogent_ftc_ctx_len) $ warns
when (Ast stg `elem` cmds) $ genAst stg tced
when (Pretty stg `elem` cmds) $ genPretty stg tced
when (Compile (succ stg) `elem` cmds) $ desugar cmds tced ctygen' tcst source (map pragmaOfLP pragmas) buildinfo log
exitSuccessWithBuildInfo cmds buildinfo
desugar cmds tced ctygen tcst source pragmas buildinfo log = do
let stg = STGDesugar
putProgressLn "Desugaring and typing..."
let ((desugared,ctygen'),typedefs) = DS.desugar tced ctygen pragmas
when __cogent_ddump_pretty_ds_no_tc $ pretty stdout desugared
case IN.tc desugared of
Left err -> hPutStrLn stderr ("Internal TC failed: " ++ err) >> exitFailure
Right (desugared',fts) -> do
when (Ast stg `elem` cmds) $ genAst stg desugared'
when (Pretty stg `elem` cmds) $ genPretty stg desugared'
when (Deep stg `elem` cmds) $ genDeep cmds source stg desugared' typedefs fts log
_ <- genShallow cmds source stg desugared' typedefs fts log (Shallow stg `elem` cmds,
SCorres stg `elem` cmds,
ShallowConsts stg `elem` cmds,
ShallowTuples `elem` cmds,
ShallowConstsTuples `elem` cmds,
ShallowTuplesProof `elem` cmds,
HsShallow `elem` cmds,
HsShallowTuples `elem` cmds)
when (TableShallow `elem` cmds) $ putProgressLn ("Generating shallow table...") >> putStrLn (printTable $ st desugared')
when (Compile (succ stg) `elem` cmds) $ normal cmds desugared' ctygen' source tced tcst typedefs fts buildinfo log
exitSuccessWithBuildInfo cmds buildinfo
normal cmds desugared ctygen source tced tcst typedefs fts buildinfo log = do
let stg = STGNormal
putProgress "Normalising..."
nfed' <- case __cogent_fnormalisation of
NoNF -> putProgressLn "Skipped." >> return desugared
nf -> do putProgressLn (show nf)
let nfed = NF.normal $ map untypeD desugared
if not $ verifyNormal nfed
then hPutStrLn stderr "Normalisation failed!" >> exitFailure
else do when __cogent_ddump_pretty_normal_no_tc $ pretty stdout nfed
putProgressLn "Re-typing NF..."
case IN.tc_ nfed of
Left err -> hPutStrLn stderr ("Re-typing NF failed: " ++ err) >> exitFailure
Right nfed' -> return nfed'
let thy = mkProofName source Nothing
when (Ast stg `elem` cmds) $ genAst stg nfed'
when (Pretty stg `elem` cmds) $ genPretty stg nfed'
when (Deep stg `elem` cmds) $ genDeep cmds source stg nfed' typedefs fts log
when (TypeProof STGNormal `elem` cmds) $ do
let suf = __cogent_suffix_of_type_proof ++ __cogent_suffix_of_stage STGNormal
tpfile = mkThyFileName source suf
tpthy = thy ++ suf
writeFileMsg tpfile
output tpfile $ flip LJ.hPutDoc $
deepTypeProof id __cogent_ftp_with_decls __cogent_ftp_with_bodies tpthy nfed' log
shallowTypeNames <-
genShallow cmds source stg nfed' typedefs fts log (Shallow stg `elem` cmds,
SCorres stg `elem` cmds,
ShallowConsts stg `elem` cmds,
False, False, False, False, False)
when (NormalProof `elem` cmds) $ do
let npfile = mkThyFileName source __cogent_suffix_of_normal_proof
writeFileMsg npfile
output npfile $ flip LJ.hPutDoc $ normalProof thy shallowTypeNames nfed' log
when (Compile (succ stg) `elem` cmds) $ simpl cmds nfed' ctygen source tced tcst typedefs fts buildinfo log
exitSuccessWithBuildInfo cmds buildinfo
simpl cmds nfed ctygen source tced tcst typedefs fts buildinfo log = do
let stg = STGSimplify
putProgressLn "Simplifying..."
simpled' <- case __cogent_fsimplifier of
False -> putProgressLn "Skipped" >> return nfed
True -> do putProgressLn ""
let simpled = map untypeD $ SM.simplify nfed
putProgressLn "Re-typing simplified AST..."
case IN.tc_ simpled of
Left err -> hPutStrLn stderr ("Re-typing simplified AST failed: " ++ err) >> exitFailure
Right simpled' -> return simpled'
when (Ast stg `elem` cmds) $ genAst stg simpled'
when (Pretty stg `elem` cmds) $ genPretty stg simpled'
when (Compile (succ stg) `elem` cmds) $ mono cmds simpled' ctygen source tced tcst typedefs fts buildinfo log
exitSuccessWithBuildInfo cmds buildinfo
mono cmds simpled ctygen source tced tcst typedefs fts buildinfo log = do
let stg = STGMono
putProgressLn "Monomorphising..."
efuns <- T.forM __cogent_entry_funcs $
return . (,empty) <=< (readEntryFuncs tced tcst typedefs fts) <=< simpleLineParser
entryFuncs <- case efuns of
Nothing -> return Nothing
Just (Nothing, _) -> exitFailure
Just (Just f, i) -> return $ Just (f, i)
let (insts,(warnings,monoed,ctygen')) = MN.mono simpled ctygen entryFuncs
when (TableAbsFuncMono `elem` cmds) $ do
let afmfile = mkFileName source Nothing __cogent_ext_of_afm
putProgressLn "Generating table for monomorphised abstract functions..."
writeFileMsg afmfile
output afmfile $ flip hPutStrLn (printAFM (fst insts) simpled)
putProgressLn "Re-typing monomorphic AST..."
case retype monoed of
Left err -> hPutStrLn stderr ("Re-typing monomorphic AST failed: " ++ err) >> exitFailure
Right monoed' -> do
printWarnings warnings
when (Ast stg `elem` cmds) $ lessPretty stdout monoed'
when (Pretty stg `elem` cmds) $ pretty stdout monoed'
when (Deep stg `elem` cmds) $ genDeep cmds source stg monoed' typedefs fts log
_ <- genShallow cmds source stg monoed' typedefs fts log (Shallow stg `elem` cmds,
SCorres stg `elem` cmds,
ShallowConsts stg `elem` cmds,
False, False, False, False, False)
-- LLVM Entrance
#ifdef WITH_LLVM
when (LLVMGen `elem` cmds) $ llvmg cmds monoed' ctygen' insts source tced tcst typedefs fts buildinfo log
#endif
when (Compile (succ stg) `elem` cmds) $ cg cmds monoed' ctygen' insts source tced tcst typedefs fts buildinfo log
c_refinement source monoed' insts log (ACInstall `elem` cmds, CorresSetup `elem` cmds, CorresProof `elem` cmds)
when (MonoProof `elem` cmds) $ do
let mpfile = mkThyFileName source __cogent_suffix_of_mono_proof
writeFileMsg mpfile
output mpfile $ flip LJ.hPutDoc $ monoProof source (fst insts) log
when (TypeProof STGMono `elem` cmds) $ do
let tpfile = mkThyFileName source __cogent_suffix_of_type_proof
tpthy = mkProofName source (Just __cogent_suffix_of_type_proof)
writeFileMsg tpfile
output tpfile $ flip LJ.hPutDoc $ deepTypeProof id __cogent_ftp_with_decls __cogent_ftp_with_bodies tpthy monoed' log
when (AllRefine `elem` cmds) $ do
let arfile = mkThyFileName source __cogent_suffix_of_all_refine
writeFileMsg arfile
output arfile $ flip LJ.hPutDoc $ allRefine source log
when (Root `elem` cmds) $ do
let rtfile = if __cogent_fdump_to_stdout then Nothing else Just $ __cogent_dist_dir `combine` __cogent_root_name
writeFileMsg rtfile
output rtfile $ flip hPutStrLn (unlines $ root source log)
when (GraphGen `elem` cmds) $ putProgressLn ("Generating graph...") >> graphGen monoed' log
exitSuccessWithBuildInfo cmds buildinfo
#ifdef WITH_LLVM
llvmg cmds monoed ctygen insts source tced tcst typedefs fts buildinfo log = do
putProgressLn "Now using the LLVM backend"
LLVM.to_llvm monoed source
#endif
cg cmds monoed ctygen insts source tced tcst typedefs fts buildinfo log = do
let hName = mkOutputName source Nothing <.> __cogent_ext_of_h
hscName = mkOutputName' toHsModName source (Just __cogent_suffix_of_ffi_types)
hsName = mkOutputName' toHsModName source (Just __cogent_suffix_of_ffi)
cNames = map (\n -> takeBaseName n ++ __cogent_suffix_of_pp ++ __cogent_suffix_of_inferred <.> __cogent_ext_of_c) __cogent_infer_c_func_files
(mcache, decodingFailed) <- case __cogent_name_cache of
Nothing -> return (Nothing, False)
Just cacheFile -> do
cacheExists <- doesFileExist cacheFile
if not cacheExists
then putProgressLn ("No name cache file found: " ++ cacheFile) >> return (Nothing, False)
else do putProgressLn ("Using existing name cache file: " ++ cacheFile)
decodeResult <- decodeFileOrFail cacheFile
case decodeResult of
Left (_, err) -> hPutStrLn stderr ("Decoding name cache file failed: " ++ err ++ ".\nNot using name cache.") >> return (Nothing, True)
Right cache -> return (Just cache, False)
let (h,c,atm,ct,ct',hsc,hs,genst) = cgen hName cNames hscName hsName monoed mcache ctygen log
when (TableAbsTypeMono `elem` cmds) $ do
let atmfile = mkFileName source Nothing __cogent_ext_of_atm
putProgressLn "Generating table for monomorphised asbtract types..."
writeFileMsg atmfile
output atmfile $ flip hPutStrLn (printATM atm)
when (TableCType `elem` cmds) $ do
let ctyfile = mkFileName source Nothing __cogent_ext_of_c_type_table
putProgressLn "Generating table for C-Cogent type correspondence..."
writeFileMsg ctyfile
output ctyfile $ \h -> fontSwitch h >>= \s -> printCTable h s ct log
when (NewTableCType `elem` cmds) $ do
let ctyfile' = mkFileName source Nothing (__cogent_ext_of_c_type_table ++ ".new")
putProgressLn "Generating (new) table for C-Cogent type correspondence..."
writeFileMsg ctyfile'
output ctyfile' $ \h -> fontSwitch h >>= \s -> printCTable h s ct' log
#ifdef WITH_HASKELL
when (HsFFIGen `elem` cmds) $ do
putProgressLn "Generating Hsc file..."
let hscf = mkHscFileName source __cogent_suffix_of_ffi_types
writeFileMsg hscf
output hscf $ flip LJ.hPutDoc hsc
putProgressLn "Generating Hs file..."
let hsf = mkHsFileName source __cogent_suffix_of_ffi
writeFileMsg hsf
output hsf $ flip hPutStrLn hs
#endif
when (CodeGen `elem` cmds) $ do
putProgressLn "Generating C code..."
let hf = mkFileName source Nothing __cogent_ext_of_h
cf = mkFileName source Nothing __cogent_ext_of_c
writeFileMsg hf
output hf $ flip M.hPutDoc (ppr h </> M.line) -- .h file gen
writeFileMsg cf
output cf $ flip M.hPutDoc (ppr c </> M.line) -- .c file gen
unless (null $ __cogent_infer_c_func_files ++ __cogent_infer_c_type_files) $
glue cmds tced tcst typedefs fts insts genst buildinfo log
forM_ __cogent_name_cache $ \cacheFile -> do
unless decodingFailed $ do
putProgressLn ("Writing name cache file: " ++ cacheFile)
encodeFile cacheFile genst
c_refinement source monoed insts log (False,False,False) = return ()
c_refinement source monoed insts log (ac,cs,cp) = do
let confns = map getDefinitionId $ filter isConFun monoed
acfile = mkThyFileName source __cogent_suffix_of_ac_install
csfile = mkThyFileName source __cogent_suffix_of_corres_setup
cpfile = mkThyFileName source __cogent_suffix_of_corres_proof
thy = mkProofName source Nothing
inputc = maybe (mkOutputName source Nothing <.> __cogent_ext_of_c) id __cogent_proof_input_c
when ac $ do
putProgressLn "Generating a theory file to install AutoCorres..."
let acInstallThy = acInstallDefault thy inputc log
writeFileMsg acfile
output acfile $ flip hPutStrLn (unlines acInstallThy)
when cs $ do
putProgressLn "Generating lemmas for C-refinement..."
let corresSetupThy = corresSetup thy inputc log
writeFileMsg csfile
output csfile $ flip LJ.hPutDoc corresSetupThy
when cp $ do
putProgressLn "Generating C-refinement proofs..."
ent <- T.forM __cogent_entry_funcs simpleLineParser -- a simple parser
let corresProofThy = corresProof thy inputc (map SY.CoreFunName confns) (map SY.CoreFunName <$> ent) log
writeFileMsg cpfile
output cpfile $ flip LJ.hPutDoc corresProofThy
glue cmds tced tcst typedefs fts insts genst buildinfo log = do
putProgressLn "Generating glue code..."
let glreader = GL.mkGlState tced tcst typedefs fts insts genst
runExceptT (GL.glue glreader defaultTypnames GL.TypeMode __cogent_infer_c_type_files) >>= \case
Left err -> hPutStrLn stderr ("Glue code (types) generation failed: \n" ++ err) >> exitFailure
Right infed -> do forM_ infed $ \(filename, defs) -> do
writeFileMsg $ Just filename
output (Just filename) $ flip M.hPutDoc (M.ppr defs </> M.line)
resAcFiles <- processAcFiles __cogent_infer_c_func_files glreader log
if not __cogent_interactive
then earlyExit resAcFiles
else processMoreAcFiles glreader resAcFiles log
where
processMoreAcFiles :: GL.GlState -> Bool -> String -> IO ()
processMoreAcFiles glreader resAcFiles log = do
hPutStrLn stderr $ "Cogenti: More ." ++ __cogent_ext_of_ac ++ " files (separated by space, empty to quit): "
morefiles <- words <$> hGetLine stdin
if null morefiles
then earlyExit resAcFiles
else do resMoreAcFiles <- processAcFiles morefiles glreader log
processMoreAcFiles glreader resMoreAcFiles log
processAcFiles :: [FilePath] -> GL.GlState -> String -> IO Bool
processAcFiles acfiles glreader log = do
funcfiles <- forM acfiles $ \funcfile -> do
let outfile = __cogent_dist_dir `combine` takeFileName (replaceBaseName funcfile (takeBaseName funcfile ++ __cogent_suffix_of_pp))
putProgressLn $ "Preprocessing C files..."
-- vvv This is needed because e.g. $(CPP) is defined to be `cc -E'.
-- The functions in the `process' module normally want the command and the arguments separated.
let cppcmd:cpparg = words __cogent_cpp
cppargs = cpparg ++ map (replace "$CPPIN" funcfile . replace "$CPPOUT" outfile) __cogent_cpp_args
(cppcode, cppout, cpperr) <- readProcessWithExitCode cppcmd cppargs []
when (not $ null cpperr) $ hPutStrLn stderr cpperr
when (cppcode /= ExitSuccess) $ exitFailure
writeFileMsg (Just outfile)
return outfile
runExceptT (GL.glue glreader defaultTypnames GL.FuncMode funcfiles) >>= \case
Left err -> hPutStrLn stderr ("Glue code (functions) generation failed: \n" ++ err) >> return False
Right infed -> do forM_ infed $ \(filename, defs) -> do
writeFileMsg (Just filename)
output (Just filename) $ flip M.hPutDoc (M.string ("/*\n" ++ log ++ "\n*/\n") </> M.ppr defs </> M.line)
return True
earlyExit :: Bool -> IO ()
earlyExit x = if x then return () else exitFailure
genAst stg defns = lessPretty stdout defns >> exitSuccess
genPretty stg defns = pretty stdout defns >> exitSuccess
genDeep cmds source stg defns typedefs fts log = do
let dpfile = mkThyFileName source (__cogent_suffix_of_deep ++ __cogent_suffix_of_stage stg)
thy = mkProofName source (Just $ __cogent_suffix_of_deep ++ __cogent_suffix_of_stage stg)
de = deep thy stg defns log
putProgressLn ("Generating deep embedding (" ++ stgMsg stg ++ ")...")
writeFileMsg dpfile
output dpfile $ flip LJ.hPutDoc de
genShallow cmds source stg defns typedefs fts log (False,False,False,False,False,False,False,False) = return empty
genShallow cmds source stg defns typedefs fts log (sh,sc,ks,sh_tup,ks_tup,tup_proof,shhs,shhs_tup) = do
-- Isabelle files
let shfile = mkThyFileName source (__cogent_suffix_of_shallow ++ __cogent_suffix_of_stage stg)
ssfile = mkThyFileName source (__cogent_suffix_of_shallow_shared)
scfile = mkThyFileName source (__cogent_suffix_of_scorres ++ __cogent_suffix_of_stage stg)
ksfile = mkThyFileName source (__cogent_suffix_of_shallow_consts ++ __cogent_suffix_of_stage stg)
sh_tupfile = mkThyFileName source (__cogent_suffix_of_shallow ++ __cogent_suffix_of_stage STGDesugar ++ __cogent_suffix_of_recover_tuples)
ss_tupfile = mkThyFileName source (__cogent_suffix_of_shallow_shared ++ __cogent_suffix_of_recover_tuples)
ks_tupfile = mkThyFileName source (__cogent_suffix_of_shallow_consts ++ __cogent_suffix_of_stage STGDesugar ++ __cogent_suffix_of_recover_tuples)
tup_prooffile = mkThyFileName source __cogent_suffix_of_shallow_tuples_proof
thy = mkProofName source Nothing
-- Run the generators
(shal ,shrd ,scorr,shallowTypeNames) = Isa.shallow False thy stg defns log
(shal_tup,shrd_tup,_ ,_ ) = Isa.shallow True thy STGDesugar defns log
constsTypeCheck = IN.tcConsts ((\(a,b,c) -> c) $ fromJust $ getLast typedefs) fts
#ifdef WITH_HASKELL
-- Haskell shallow embedding
hsShalName = mkOutputName' toHsModName source (Just $ __cogent_suffix_of_shallow ++ __cogent_suffix_of_stage stg)
hsShalTupName = mkOutputName' toHsModName source (Just $ __cogent_suffix_of_shallow ++ __cogent_suffix_of_stage STGDesugar ++ __cogent_suffix_of_recover_tuples)
hsShalFile = nameToFileName hsShalName __cogent_ext_of_hs
hsShalTupFile = nameToFileName hsShalTupName __cogent_ext_of_hs
hsShal = \consts -> HS.shallow False hsShalName stg defns consts log
hsShalTup = \consts -> HS.shallow True hsShalTupName stg defns consts log
#endif
tup_proof_thy = shallowTuplesProof thy
(mkProofName source (Just $ __cogent_suffix_of_shallow_shared))
(mkProofName source (Just $ __cogent_suffix_of_shallow ++ __cogent_suffix_of_stage stg))
(mkProofName source (Just $ __cogent_suffix_of_shallow_shared ++ __cogent_suffix_of_recover_tuples))
(mkProofName source (Just $ __cogent_suffix_of_shallow ++ __cogent_suffix_of_stage STGDesugar ++ __cogent_suffix_of_recover_tuples))
shallowTypeNames defns log
when sh $ do
putProgressLn ("Generating shallow embedding (" ++ stgMsg stg ++ ")...")
writeFileMsg ssfile
output ssfile $ flip LJ.hPutDoc shrd
writeFileMsg shfile
output shfile $ flip LJ.hPutDoc shal
#ifdef WITH_HASKELL
when shhs $ do
putProgressLn ("Generating Haskell shallow embedding (" ++ stgMsg stg ++ ")...")
case constsTypeCheck of
Left err -> hPutStrLn stderr ("Internal TC failed: " ++ err) >> exitFailure
Right (cs,_) -> do writeFileMsg hsShalFile
output hsShalFile $ flip hPutStrLn (hsShal cs)
#endif
when ks $ do
putProgressLn ("Generating shallow constants (" ++ stgMsg stg ++ ")...")
case constsTypeCheck of
Left err -> hPutStrLn stderr ("Internal TC failed: " ++ err) >> exitFailure
Right (cs,_) -> do writeFileMsg ksfile
output ksfile $ flip LJ.hPutDoc $ shallowConsts False thy stg cs defns log
when sc $ do
putProgressLn ("Generating scorres (" ++ stgMsg stg ++ ")...")
writeFileMsg scfile
output scfile $ flip LJ.hPutDoc scorr
when sh_tup $ do
putProgressLn ("Generating shallow embedding (with HOL tuples)...")
writeFileMsg ss_tupfile
output ss_tupfile $ flip LJ.hPutDoc shrd_tup
writeFileMsg sh_tupfile
output sh_tupfile $ flip LJ.hPutDoc shal_tup
#ifdef WITH_HASKELL
when shhs_tup $ do
putProgressLn ("Generating Haskell shallow embedding (with Haskell tuples)...")
case constsTypeCheck of
Left err -> hPutStrLn stderr ("Internal TC failed: " ++ err) >> exitFailure
Right (cs,_) -> do writeFileMsg hsShalTupFile
output hsShalTupFile $ flip hPutStrLn (hsShalTup cs)
#endif
when ks_tup $ do
putProgressLn ("Generating shallow constants (with HOL tuples)...")
case constsTypeCheck of
Left err -> hPutStrLn stderr ("Internal TC failed: " ++ err) >> exitFailure
Right (cs,_) -> do writeFileMsg ks_tupfile
output ks_tupfile $ flip LJ.hPutDoc $ shallowConsts True thy stg cs defns log
when tup_proof $ do
putProgressLn ("Generating shallow tuple proof...")
writeFileMsg tup_prooffile
output tup_prooffile $ flip LJ.hPutDoc tup_proof_thy
return shallowTypeNames
genBuildInfo cmds buildinfo =
when (BuildInfo `elem` cmds && not __cogent_fdump_to_stdout) $ do
let bifile = Just $ __cogent_dist_dir `combine` __cogent_build_info_name
writeFileMsg bifile
output bifile $ flip hPutStrLn buildinfo
-- ------------------------------------------------------------------------
-- Helper functions
printError f e = fontSwitch stderr >>= \s ->
displayIO stderr (prettyPrint s $ map f e) >>
hPutStrLn stderr ""
usage :: Verbosity -> String
usage 0 = "Usage: cogent COMMAND.. [FLAG..] FILENAME\n"
usage v = usage 0 ++
usageInfoImportant "COMMANDS:" v options ++ "\n" ++
usageInfoImportant "FLAGS:" v flags
versionInfo = UT.getCogentVersion
-- Depending on the target of output, switch on or off fonts
fontSwitch :: Handle -> IO (Doc -> Doc)
fontSwitch h = hIsTerminalDevice h >>= \isTerminal ->
return $ if isTerminal && __cogent_fpretty_errmsgs then id else plain
-- Commnad line parsing error
exitErr x = hPutStrLn stderr ("cogent: " ++ x ++ "(run `cogent -h' for help)") >> exitWith (ExitFailure 133) -- magic number, doesn't mean anything
-- Compilation success
exitSuccess_ = exitWith ExitSuccess
exitSuccess = putProgressLn "Compilation finished!" >> postDump >> exitWith ExitSuccess
exitSuccessWithBuildInfo cmds buildinfo = genBuildInfo cmds buildinfo >> exitSuccess
-- Compilation failure
exitFailure = hPutStrLn stderr "Compilation failed!" >> postDump >> exitWith (ExitFailure 134)
-- pretty-print
pretty h a = fontSwitch h >>= \s -> displayIO h (prettyPrint s a) >> hPutStrLn h ""
-- pretty AST
lessPretty h a = hPutStrLn h (ppShow a)
-- Warnings
printWarnings :: [Warning] -> IO ()
printWarnings ws | __cogent_wmono = hPutStr stderr $ unlines $ map ("Warning: " ++) ws
| otherwise = return ()
writeFileMsg :: Maybe FilePath -> IO ()
writeFileMsg mbfile = when (isJust mbfile) $ putProgressLn (" > Writing to file: " ++ fromJust mbfile)
output :: Maybe FilePath -> (Handle -> IO ()) -> IO ()
output Nothing f = f stdout
output (Just path) f = do
createDirectoryIfMissing True (takeDirectory path)
atomicWithFile path f
main :: IO ()
main = getArgs >>= parseArgs