Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Coq translator: fix array literal support #1815

Merged
merged 2 commits into from
Feb 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion cryptol-saw-core/src/Verifier/SAW/TypedTerm.hs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import Cryptol.Utils.PP (pretty)
import qualified Cryptol.Utils.Ident as C (mkIdent)
import qualified Cryptol.Utils.RecordMap as C (recordFromFields)

import Verifier.SAW.Cryptol (scCryptolType)
import Verifier.SAW.Cryptol (scCryptolType, Env, importKind, importSchema)
import Verifier.SAW.FiniteValue
import Verifier.SAW.Recognizer (asExtCns)
import Verifier.SAW.SharedTerm
Expand Down Expand Up @@ -49,6 +49,13 @@ data TypedTermType
deriving Show


-- | Convert the 'ttTerm' field of a 'TypedTerm' to a SAW core term
ttTypeAsTerm :: SharedContext -> Env -> TypedTerm -> IO Term
ttTypeAsTerm sc env (TypedTerm (TypedTermSchema schema) _) =
importSchema sc env schema
ttTypeAsTerm sc _ (TypedTerm (TypedTermKind k) _) = importKind sc k
ttTypeAsTerm _ _ (TypedTerm (TypedTermOther tp) _) = return tp

ttTermLens :: Functor f => (Term -> f Term) -> TypedTerm -> f TypedTerm
ttTermLens f tt = tt `seq` fmap (\x -> tt{ttTerm = x}) (f (ttTerm tt))

Expand Down
35 changes: 20 additions & 15 deletions saw-core-coq/src/Verifier/SAW/Translation/Coq.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,13 @@ import Verifier.SAW.Module
import Verifier.SAW.SharedTerm
import Verifier.SAW.Term.Functor
-- import Verifier.SAW.Term.CtxTerm
import qualified Verifier.SAW.Translation.Coq.CryptolModule as CryptolModuleTranslation
import qualified Verifier.SAW.Translation.Coq.CryptolModule as CMT
import qualified Verifier.SAW.Translation.Coq.SAWModule as SAWModuleTranslation
import Verifier.SAW.Translation.Coq.Monad
import Verifier.SAW.Translation.Coq.SpecialTreatment
import qualified Verifier.SAW.Translation.Coq.Term as TermTranslation
import Verifier.SAW.TypedTerm
import Verifier.SAW.Cryptol (Env)
--import Verifier.SAW.Term.Pretty
-- import qualified Verifier.SAW.UntypedAST as Un

Expand Down Expand Up @@ -92,8 +93,11 @@ traceTerm ctx t a = trace (ctx ++ ": " ++ showTerm t) a
text :: String -> Doc ann
text = pretty

-- | Eventually, different modules may want different preambles. For now,
-- we hardcode a sufficient set of imports for all our purposes.
-- | Generate a preamble for a Coq file, containing a list of Coq imports. This
-- includes standard imports, one of which is the @VectorNotations@ module to
-- support the vector literals used to translate SAW core array values, along
-- with any user-supplied imports in the 'postPreamble' field of the
-- supplied 'TranslationConfiguration'.
preamble :: TranslationConfiguration -> Doc ann
preamble (TranslationConfiguration { vectorModule, postPreamble }) = text [i|
(** Mandatory imports from saw-core-coq *)
Expand All @@ -102,7 +106,7 @@ From Coq Require Import String.
From Coq Require Import Vectors.Vector.
From CryptolToCoq Require Import SAWCoreScaffolding.
From CryptolToCoq Require Import #{vectorModule}.
Import ListNotations.
Import VectorNotations.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be worth expanding the Haddock to state why we import VectorNotations here: it's because we rely on this notation when translating array values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, that makes sense


(** Post-preamble section specified by you *)
#{postPreamble}
Expand All @@ -111,15 +115,17 @@ Import ListNotations.
|]

translateTermAsDeclImports ::
TranslationConfiguration -> Coq.Ident -> Term -> Either (TranslationError Term) (Doc ann)
translateTermAsDeclImports configuration name t = do
TranslationConfiguration -> Coq.Ident -> Term -> Term ->
Either (TranslationError Term) (Doc ann)
translateTermAsDeclImports configuration name t tp = do
doc <-
TermTranslation.translateDefDoc
configuration
(TermTranslation.TranslationReader Nothing)
[] name t
[] name t tp
return $ vcat [preamble configuration, hardline <> doc]

-- | Translate a SAW core module to a Coq module
translateSAWModule :: TranslationConfiguration -> Module -> Doc ann
translateSAWModule configuration m =
let name = show $ translateModuleName (moduleName m)
Expand All @@ -134,21 +140,20 @@ translateSAWModule configuration m =
, ""
]

-- | Translate a Cryptol module to a Coq module
translateCryptolModule ::
SharedContext -> Env ->
Coq.Ident {- ^ Section name -} ->
TranslationConfiguration ->
-- | List of already translated global declarations
[String] ->
CryptolModule ->
Either (TranslationError Term) (Doc ann)
translateCryptolModule nm configuration globalDecls m =
let decls = CryptolModuleTranslation.translateCryptolModule
configuration
globalDecls
m
in
Coq.ppDecl . Coq.Section nm <$> decls
IO (Either (TranslationError Term) (Doc ann))
translateCryptolModule sc env nm configuration globalDecls m =
fmap (fmap (Coq.ppDecl . Coq.Section nm)) $
CMT.translateCryptolModule sc env configuration globalDecls m

-- | Extract out the 'String' name of a declaration in a SAW core module
moduleDeclName :: ModuleDecl -> Maybe String
moduleDeclName (TypeDecl (DataType { dtName })) = Just (identName dtName)
moduleDeclName (DefDecl (Def { defIdent })) = Just (identName defIdent)
Expand Down
45 changes: 27 additions & 18 deletions saw-core-coq/src/Verifier/SAW/Translation/Coq/CryptolModule.hs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,26 @@ import Cryptol.ModuleSystem.Name (Name, nameIdent)
import Cryptol.Utils.Ident (unpackIdent)
import qualified Language.Coq.AST as Coq
import Verifier.SAW.Term.Functor (Term)
import Verifier.SAW.SharedTerm (SharedContext)
import Verifier.SAW.Translation.Coq.Monad
import qualified Verifier.SAW.Translation.Coq.Term as TermTranslation
import Verifier.SAW.TypedTerm
import Verifier.SAW.Cryptol (Env)



-- | Translate a list of named terms with their types to a Coq definitions
translateTypedTermMap ::
TermTranslation.TermTranslationMonad m => Map.Map Name TypedTerm -> m [Coq.Decl]
translateTypedTermMap tm = forM (Map.assocs tm) translateAndRegisterEntry
TermTranslation.TermTranslationMonad m => [(Name,Term,Term)] -> m [Coq.Decl]
translateTypedTermMap defs = forM defs translateAndRegisterEntry
where
translateAndRegisterEntry (name, symbol) = do
let t = ttTerm symbol
translateAndRegisterEntry (name, t, tp) = do
let nameStr = unpackIdent (nameIdent name)
term <- TermTranslation.withLocalTranslationState $ do
modify $ set TermTranslation.localEnvironment [nameStr]
TermTranslation.translateTerm t
let decl = TermTranslation.mkDefinition nameStr term
decl <-
TermTranslation.withLocalTranslationState $
do modify $ set TermTranslation.localEnvironment [nameStr]
t_trans <- TermTranslation.translateTerm t
tp_trans <- TermTranslation.translateTerm tp
return $ TermTranslation.mkDefinition nameStr t_trans tp_trans
modify $ over TermTranslation.globalDeclarations (nameStr :)
return decl

Expand All @@ -37,16 +40,22 @@ translateTypedTermMap tm = forM (Map.assocs tm) translateAndRegisterEntry
-- terms, and accumulating the translated declarations of all top-level
-- declarations encountered.
translateCryptolModule ::
SharedContext -> Env ->
TranslationConfiguration ->
-- | List of already translated global declarations
[String] ->
CryptolModule ->
Either (TranslationError Term) [Coq.Decl]
translateCryptolModule configuration globalDecls (CryptolModule _ tm) =
reverse . view TermTranslation.topLevelDeclarations . snd
<$> TermTranslation.runTermTranslationMonad
configuration
(TermTranslation.TranslationReader Nothing) -- TODO: this should be Just no?
globalDecls
[]
(translateTypedTermMap tm)
IO (Either (TranslationError Term) [Coq.Decl])
translateCryptolModule sc env configuration globalDecls (CryptolModule _ tm) =
do defs <-
forM (Map.assocs tm) $ \(nm, t) ->
do tp <- ttTypeAsTerm sc env t
return (nm, ttTerm t, tp)
return
(reverse . view TermTranslation.topLevelDeclarations . snd <$>
TermTranslation.runTermTranslationMonad
configuration
(TermTranslation.TranslationReader Nothing) -- TODO: this should be Just no?
globalDecls
[]
(translateTypedTermMap defs))
49 changes: 34 additions & 15 deletions saw-core-coq/src/Verifier/SAW/Translation/Coq/Term.hs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE PatternGuards #-}
{-# LANGUAGE TupleSections #-}

{- |
Module : Verifier.SAW.Translation.Coq
Expand Down Expand Up @@ -240,7 +241,8 @@ translateConstant ec maybe_body =
Just body ->
-- If the definition has a body, add it as a definition
do b <- withTopTranslationState $ translateTermLet body
modify $ over topLevelDeclarations $ (mkDefinition renamed b :)
tp <- withTopTranslationState $ translateTermLet (ecType ec)
modify $ over topLevelDeclarations $ (mkDefinition renamed b tp :)
Nothing ->
-- If not, add it as a Coq Variable declaration
do tp <- withTopTranslationState $ translateTermLet (ecType ec)
Expand Down Expand Up @@ -338,7 +340,8 @@ flatTermFToExpr tf = -- traceFTermF "flatTermFToExpr" tf $
[Coq.NatLit (intValue w), Coq.ZLit (BV.asSigned w bv)])
ArrayValue _ vec -> do
elems <- Vector.toList <$> mapM translateTerm vec
return (Coq.App (Coq.Var "Vector.of_list") [Coq.List elems])
-- NOTE: with VectorNotations, this is actually a Coq vector literal
return $ Coq.List elems
StringLit s -> pure (Coq.Scope (Coq.StringLit (Text.unpack s)) "string")

ExtCns ec -> translateConstant ec Nothing
Expand Down Expand Up @@ -425,9 +428,20 @@ withTopTranslationState m =
modify $ set nextSharedName "var__0"
m

mkDefinition :: Coq.Ident -> Coq.Term -> Coq.Decl
mkDefinition name (Coq.Lambda bs t) = Coq.Definition name bs Nothing t
mkDefinition name t = Coq.Definition name [] Nothing t
-- | Generate a Coq @Definition@ with a given name, body, and type, using the
-- lambda-bound variable names for the variables if they are available
mkDefinition :: Coq.Ident -> Coq.Term -> Coq.Term -> Coq.Decl
mkDefinition name (Coq.Lambda bs t) (Coq.Pi bs' tp)
| length bs' == length bs =
Ptival marked this conversation as resolved.
Show resolved Hide resolved
-- NOTE: there are a number of cases where length bs /= length bs', such as
-- where the type of a definition is computed from some input (so might not
-- have any explicit pi-abstractions), or where the body of a definition is
-- a partially applied function (so might not have any lambdas). We could in
-- theory try to handle these more complex cases by assigning names to some
-- of the arguments, but it's not really necessary for the translation to be
-- correct, so we just do the simple thing here.
Coq.Definition name bs (Just tp) t
mkDefinition name t tp = Coq.Definition name [] (Just tp) t

-- | Make sure a name is not used in the current environment, adding
-- or incrementing a numeric suffix until we find an unused name. When
Expand Down Expand Up @@ -661,31 +675,36 @@ defaultTermForType typ = do

_ -> Except.throwError $ CannotCreateDefaultValue typ

-- | Translate a SAW core term along with its type to a Coq term and its Coq
-- type, and pass the results to the supplied function
translateTermToDocWith ::
TranslationConfiguration ->
TranslationReader ->
[String] ->
[String] ->
(Coq.Term -> Doc ann) ->
Term ->
[String] -> -- ^ globals that have already been translated
[String] -> -- ^ string names of local variables in scope
(Coq.Term -> Coq.Term -> Doc ann) ->
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Worth stating in a comment what these two Terms represent, since it's not obvious unless you stare at the code a bit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ooh, good point. In fact, there probably needs to be even more haddock as well...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does Haddock now support -- ^ after the arrow correctly?

Term -> Term ->
Either (TranslationError Term) (Doc ann)
translateTermToDocWith configuration r globalDecls localEnv f t = do
(term, state) <-
runTermTranslationMonad configuration r globalDecls localEnv (translateTermLet t)
translateTermToDocWith configuration r globalDecls localEnv f t tp_trm = do
((term, tp), state) <-
runTermTranslationMonad configuration r globalDecls localEnv
((,) <$> translateTermLet t <*> translateTermLet tp_trm)
let decls = view topLevelDeclarations state
return $
vcat $
[ (vcat . intersperse hardline . map Coq.ppDecl . reverse) decls
, if null decls then mempty else hardline
, f term
, f term tp
]

-- | Translate a SAW core 'Term' and its type (given as a 'Term') to a Coq
-- definition with the supplied name
translateDefDoc ::
TranslationConfiguration ->
TranslationReader ->
[String] ->
Coq.Ident -> Term ->
Coq.Ident -> Term -> Term ->
Either (TranslationError Term) (Doc ann)
translateDefDoc configuration r globalDecls name =
translateTermToDocWith configuration r globalDecls [name]
(Coq.ppDecl . mkDefinition name)
(\ t tp -> Coq.ppDecl $ mkDefinition name t tp)
11 changes: 8 additions & 3 deletions src/SAWScript/Prover/Exporter.hs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ import Prettyprinter.Render.Text

import Lang.JVM.ProcessUtils (readProcessExitIfFailure)

import Verifier.SAW.CryptolEnv (initCryptolEnv, loadCryptolModule, ImportPrimitiveOptions(..))
import Verifier.SAW.CryptolEnv (initCryptolEnv, loadCryptolModule,
ImportPrimitiveOptions(..), mkCryEnv)
import Verifier.SAW.Cryptol.Prelude (cryptolModule, scLoadPreludeModule, scLoadCryptolModule)
import Verifier.SAW.ExternalFormat(scWriteExternal)
import Verifier.SAW.FiniteValue
Expand Down Expand Up @@ -455,7 +456,9 @@ writeCoqTerm name notations skips path t = do
withImportCryptolPrimitivesForSAWCore $
withImportSAWCorePrelude $
coqTranslationConfiguration notations skips
case Coq.translateTermAsDeclImports configuration name t of
sc <- getSharedContext
tp <- io $ scTypeOf sc t
case Coq.translateTermAsDeclImports configuration name t tp of
Left err -> throwTopLevel $ "Error translating: " ++ show err
Right doc -> io $ case path of
"" -> print doc
Expand Down Expand Up @@ -496,7 +499,9 @@ writeCoqCryptolModule inputFile outputFile notations skips = io $ do
withImportSAWCorePrelude $
coqTranslationConfiguration notations skips
let nm = takeBaseName inputFile
case Coq.translateCryptolModule nm configuration cryptolPreludeDecls cm of
cry_env <- mkCryEnv env
res <- Coq.translateCryptolModule sc cry_env nm configuration cryptolPreludeDecls cm
case res of
Left e -> putStrLn $ show e
Right cmDoc ->
writeFile outputFile
Expand Down