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

Allow importing Cryptol foreign functions #1920

Merged
merged 11 commits into from
Sep 1, 2023
120 changes: 75 additions & 45 deletions cryptol-saw-core/src/Verifier/SAW/Cryptol.hs
Original file line number Diff line number Diff line change
Expand Up @@ -744,15 +744,20 @@ importPrimitive sc primOpts env n sch
-- Optionally, create an opaque constant representing the primitive
-- if it doesn't match one of the ones we know about.
| Just _ <- C.asPrim n, allowUnknownPrimitives primOpts =
do t <- importSchema sc env sch
nmi <- importName n
scOpaqueConstant sc nmi t
importOpaque sc env n sch

-- Panic if we don't know the given primitive (TODO? probably shouldn't be a panic)
| Just nm <- C.asPrim n = panic "Unknown Cryptol primitive name" [show nm]

| otherwise = panic "Improper Cryptol primitive name" [show n]

-- | Create an opaque constant with the given name and schema
importOpaque :: SharedContext -> Env -> C.Name -> C.Schema -> IO Term
importOpaque sc env n sch = do
t <- importSchema sc env sch
nmi <- importName n
scOpaqueConstant sc nmi t


allPrims :: Map C.PrimIdent (SharedContext -> IO Term)
allPrims = prelPrims <> arrayPrims <> floatPrims <> suiteBPrims <> primeECPrims
Expand Down Expand Up @@ -1385,31 +1390,42 @@ importName cnm =
-- definitions. (With subterm sharing, this is not as bad as it might
-- seem.) We might want to think about generating let or where
-- expressions instead.
--
-- For Cryptol @foreign@ declarations, we import them as regular
-- cryptol expressions if a cryptol implementation exists, and as an
qsctr marked this conversation as resolved.
Show resolved Hide resolved
-- opaque constant otherwise.
importDeclGroup :: DeclGroupOptions -> SharedContext -> Env -> C.DeclGroup -> IO Env

importDeclGroup declOpts sc env (C.Recursive [decl]) =
case C.dDefinition decl of
C.DPrim ->
panic "importDeclGroup" ["Primitive declarations cannot be recursive:", show (C.dName decl)]

C.DForeign {} ->
error "`foreign` imports may not be used in SAW specifications"

C.DExpr expr ->
do env1 <- bindName sc (C.dName decl) (C.dSignature decl) env
t' <- importSchema sc env (C.dSignature decl)
e' <- importExpr' sc env1 (C.dSignature decl) expr
let x = nameToLocalName (C.dName decl)
f' <- scLambda sc x t' e'
rhs <- scGlobalApply sc "Prelude.fix" [t', f']
rhs' <- case declOpts of
TopLevelDeclGroup _ ->
do nmi <- importName (C.dName decl)
scConstant' sc nmi rhs t'
NestedDeclGroup -> return rhs
let env' = env { envE = Map.insert (C.dName decl) (rhs', 0) (envE env)
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env) }
return env'
C.DForeign _ mexpr ->
case mexpr of
Nothing -> panic "importDeclGroup"
[ "Foreign declaration without cryptol body in recursive group:"
qsctr marked this conversation as resolved.
Show resolved Hide resolved
, show (C.dName decl) ]
Just expr -> addExpr expr

C.DExpr expr -> addExpr expr

where
addExpr expr =
do env1 <- bindName sc (C.dName decl) (C.dSignature decl) env
t' <- importSchema sc env (C.dSignature decl)
e' <- importExpr' sc env1 (C.dSignature decl) expr
let x = nameToLocalName (C.dName decl)
f' <- scLambda sc x t' e'
rhs <- scGlobalApply sc "Prelude.fix" [t', f']
rhs' <- case declOpts of
TopLevelDeclGroup _ ->
do nmi <- importName (C.dName decl)
scConstant' sc nmi rhs t'
NestedDeclGroup -> return rhs
let env' = env { envE = Map.insert (C.dName decl) (rhs', 0) (envE env)
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env) }
return env'


-- - A group of mutually-recursive declarations -
Expand Down Expand Up @@ -1440,8 +1456,13 @@ importDeclGroup declOpts sc env (C.Recursive decls) =
let extractDeclExpr decl =
case C.dDefinition decl of
C.DExpr expr -> importExpr' sc env2 (C.dSignature decl) expr
C.DForeign {} ->
error "`foreign` imports may not be used in SAW specifications"
C.DForeign _ mexpr ->
case mexpr of
Nothing -> panic "importDeclGroup"
[ "Foreign declaration without cryptol body in recursive group:"
, show (C.dName decl) ]
qsctr marked this conversation as resolved.
Show resolved Hide resolved
Just expr ->
importExpr' sc env2 (C.dSignature decl) expr
C.DPrim ->
panic "importDeclGroup"
[ "Primitive declarations cannot be recursive:"
Expand Down Expand Up @@ -1477,32 +1498,41 @@ importDeclGroup declOpts sc env (C.Recursive decls) =
}
return env'

importDeclGroup declOpts sc env (C.NonRecursive decl) =
case C.dDefinition decl of
C.DForeign {} ->
error "`foreign` imports may not be used in SAW specifications"
importDeclGroup declOpts sc env (C.NonRecursive decl) = do

rhs <- case C.dDefinition decl of
C.DForeign _ mexpr
| TopLevelDeclGroup _ <- declOpts ->
case mexpr of
Nothing -> importOpaque sc env (C.dName decl) (C.dSignature decl)
Just expr ->
importConstant =<< importExpr' sc env (C.dSignature decl) expr
| otherwise ->
panic "importDeclGroup"
["Foreign declarations only allowed at top-level:", show (C.dName decl)]

C.DPrim
| TopLevelDeclGroup primOpts <- declOpts -> do
rhs <- importPrimitive sc primOpts env (C.dName decl) (C.dSignature decl)
let env' = env { envE = Map.insert (C.dName decl) (rhs, 0) (envE env)
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env)
}
return env'
| otherwise -> do
| TopLevelDeclGroup primOpts <- declOpts ->
importPrimitive sc primOpts env (C.dName decl) (C.dSignature decl)
| otherwise -> do
panic "importDeclGroup" ["Primitive declarations only allowed at top-level:", show (C.dName decl)]

C.DExpr expr -> do
rhs <- importExpr' sc env (C.dSignature decl) expr
rhs' <- case declOpts of
TopLevelDeclGroup _ ->
do nmi <- importName (C.dName decl)
t <- importSchema sc env (C.dSignature decl)
scConstant' sc nmi rhs t
NestedDeclGroup -> return rhs
let env' = env { envE = Map.insert (C.dName decl) (rhs', 0) (envE env)
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env) }
return env'
rhs <- importExpr' sc env (C.dSignature decl) expr
case declOpts of
TopLevelDeclGroup _ -> importConstant rhs
NestedDeclGroup -> return rhs

pure env { envE = Map.insert (C.dName decl) (rhs, 0) (envE env)
, envC = Map.insert (C.dName decl) (C.dSignature decl) (envC env)
}

where
importConstant rhs = do
nmi <- importName (C.dName decl)
t <- importSchema sc env (C.dSignature decl)
scConstant' sc nmi rhs t
qsctr marked this conversation as resolved.
Show resolved Hide resolved


data ImportPrimitiveOptions =
ImportPrimitiveOptions
Expand Down Expand Up @@ -1714,7 +1744,7 @@ importMatches sc env (C.Let decl : matches) =
case C.dDefinition decl of

C.DForeign {} ->
error "`foreign` imports may not be used in SAW specifications"
panic "importMatches" ["Foreign declarations not allowed in 'let':", show (C.dName decl)]

C.DPrim -> do
panic "importMatches" ["Primitive declarations not allowed in 'let':", show (C.dName decl)]
Expand Down
2 changes: 1 addition & 1 deletion deps/cryptol
Submodule cryptol updated 45 files
+8 −0 CHANGES.md
+1 −1 cryptol-remote-api/src/CryptolServer/Data/Expression.hs
+16 −0 docs/RefMan/FFI.rst
+14 −13 src/Cryptol/Backend/FFI.hs
+6 −4 src/Cryptol/Backend/FFI/Error.hs
+2 −3 src/Cryptol/Backend/Monad.hs
+35 −16 src/Cryptol/Eval.hs
+12 −11 src/Cryptol/Eval/FFI.hs
+8 −3 src/Cryptol/Eval/Reference.lhs
+1 −1 src/Cryptol/IR/FreeVars.hs
+1 −1 src/Cryptol/IR/TraverseNames.hs
+39 −28 src/Cryptol/ModuleSystem/Base.hs
+42 −18 src/Cryptol/ModuleSystem/Env.hs
+3 −0 src/Cryptol/ModuleSystem/Monad.hs
+5 −2 src/Cryptol/ModuleSystem/Renamer.hs
+2 −2 src/Cryptol/Parser.y
+26 −5 src/Cryptol/Parser/AST.hs
+39 −35 src/Cryptol/Parser/ExpandPropGuards.hs
+14 −8 src/Cryptol/Parser/Names.hs
+69 −27 src/Cryptol/Parser/NoPat.hs
+10 −6 src/Cryptol/Parser/ParserUtils.hs
+41 −0 src/Cryptol/REPL/Monad.hs
+14 −9 src/Cryptol/Transform/MonoValues.hs
+4 −4 src/Cryptol/Transform/Specialize.hs
+1 −1 src/Cryptol/TypeCheck.hs
+23 −13 src/Cryptol/TypeCheck/AST.hs
+82 −75 src/Cryptol/TypeCheck/Infer.hs
+2 −1 src/Cryptol/TypeCheck/Parseable.hs
+12 −7 src/Cryptol/TypeCheck/Sanity.hs
+3 −3 src/Cryptol/TypeCheck/Subst.hs
+5 −0 tests/ffi/ffi-fallback-rec.c
+5 −0 tests/ffi/ffi-fallback-rec.cry
+3 −0 tests/ffi/ffi-fallback-rec.icry
+8 −0 tests/ffi/ffi-fallback-rec.icry.stdout
+8 −0 tests/ffi/ffi-fallback-rec.icry.stdout.darwin
+8 −0 tests/ffi/ffi-fallback-rec.icry.stdout.mingw32
+9 −0 tests/ffi/ffi-fallback.c
+11 −0 tests/ffi/ffi-fallback.cry
+76 −0 tests/ffi/ffi-fallback.icry
+151 −0 tests/ffi/ffi-fallback.icry.stdout
+151 −0 tests/ffi/ffi-fallback.icry.stdout.darwin
+151 −0 tests/ffi/ffi-fallback.icry.stdout.mingw32
+8 −12 tests/ffi/ffi-runtime-errors.icry.stdout
+8 −12 tests/ffi/ffi-runtime-errors.icry.stdout.darwin
+8 −12 tests/ffi/ffi-runtime-errors.icry.stdout.mingw32
2 changes: 2 additions & 0 deletions intTests/test_import_foreign/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Test that SAW is able to import Cryptol `foreign` functions, and uses the
Cryptol definition when available.
4 changes: 4 additions & 0 deletions intTests/test_import_foreign/test.cry
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
foreign add : [8] -> [8] -> [8]
add x y = x + y

foreign f : [8] -> [8]
7 changes: 7 additions & 0 deletions intTests/test_import_foreign/test.saw
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import "test.cry";

// requires definition of add
prove_print z3 {{ \x y -> add x y == x + y }};

// does not require definition of f
prove_print (unint_z3 ["f"]) {{ \x -> f x + 1 == 1 + f x }};
3 changes: 3 additions & 0 deletions intTests/test_import_foreign/test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
set -e

$SAW test.saw
6 changes: 3 additions & 3 deletions src/SAWScript/AutoMatch/Cryptol.hs
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,9 @@ whereBindings _ = Nothing
-- We can't handle primitives currently
declDefExpr :: AST.DeclDef -> Maybe AST.Expr
declDefExpr = \case
AST.DPrim -> Nothing
AST.DForeign {} -> Nothing
AST.DExpr expr -> Just expr
AST.DPrim -> Nothing
AST.DForeign _ mexpr -> mexpr
AST.DExpr expr -> Just expr

-- | If a lambda is of the form @\(a,b,...,z) -> ...)@ then give the list of names bound in the tuple
tupleLambdaBindings :: AST.Expr -> Maybe [AST.Name]
Expand Down
Loading