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

Add an eval_int command to the remote API and Python interface #1660

Merged
merged 9 commits into from
May 9, 2022
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
4 changes: 2 additions & 2 deletions saw-remote-api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Revision history for saw-remote-api


## 0.9.1 -- YYYY-MM-DD
chameco marked this conversation as resolved.
Show resolved Hide resolved

* `SAW/set option`'s `"option"` parameter is now allowed to be `"What4 eval"`,
Expand All @@ -16,7 +15,8 @@
verification, so JVM specifications must leave these lists empty. Attempting
to provide a non-empty list for either of these fields in a JVM specification
will result in an error.

* Introduced new methods `SAW/eval int` and `SAW/eval bool` that allow the
evaluation of Cryptol expressions into Python values.

## 0.9.0 -- 2021-11-19

Expand Down
48 changes: 48 additions & 0 deletions saw-remote-api/docs/SAW.rst
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,54 @@ Return fields



SAW/eval int (command)
~~~~~~~~~~~~~~~~~~~~~~

Attempt to evaluate the given term to a concrete integer.

Parameter fields
++++++++++++++++


``expr``
The Cryptol expression to evaluate.



Return fields
+++++++++++++


``value``
The integer value of the expresssion.




SAW/eval bool (command)
~~~~~~~~~~~~~~~~~~~~~~~

Attempt to evaluate the given term to a concrete boolean.

Parameter fields
++++++++++++++++


``expr``
The Cryptol expression to evaluate.



Return fields
+++++++++++++


``value``
The boolean value of the expresssion.




SAW/set option (command)
~~~~~~~~~~~~~~~~~~~~~~~~

Expand Down
2 changes: 2 additions & 0 deletions saw-remote-api/python/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
`set_option(LaxLoadsAndStores(), True)` in order for `points_to_bitfield` to
work as expected. `points_to_bitfield` is only supported for LLVM (and not
JVM) verification.
* Added two new commands, `eval_int` and `eval_bool`, that evaluate Cryptol
expressions to Python integers or booleans.


## 0.9.0 -- 2021-11-19
Expand Down
41 changes: 21 additions & 20 deletions saw-remote-api/python/poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 20 additions & 0 deletions saw-remote-api/python/saw_client/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -648,6 +648,26 @@ def prove(goal: cryptoltypes.CryptolJSON,
pr.counterexample = None
return pr

def eval_int(expr: cryptoltypes.CryptolJSON) -> int:
"""Atempts to evaluate the given expression as a concrete integer.
"""
conn = __get_designated_connection()
res = conn.eval_int(expr).result()
v = res['value']
if not isinstance(v, int):
raise ValueError(str(v) + " is not an integer")
return v

def eval_bool(expr: cryptoltypes.CryptolJSON) -> bool:
"""Atempts to evaluate the given expression as a concrete boolean.
"""
conn = __get_designated_connection()
res = conn.eval_bool(expr).result()
v = res['value']
if not isinstance(v, bool):
raise ValueError(str(v) + " is not a boolean")
return v

def set_option(option : option.SAWOption, value : bool) -> None:
"""Set a boolean-valued SAW option."""
global __designated_connection
Expand Down
24 changes: 24 additions & 0 deletions saw-remote-api/python/saw_client/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,30 @@ def __init__(
def process_result(self, res : Any) -> Any:
return res

class EvalInt(SAWCommand):
def __init__(
self,
connection : argo.HasProtocolState,
expr : cryptoltypes.CryptolJSON,
timeout : Optional[float]) -> None:
params = {'expr': cryptoltypes.to_cryptol(expr)}
super(EvalInt, self).__init__('SAW/eval int', params, connection, timeout=timeout)

def process_result(self, res : Any) -> Any:
return res

class EvalBool(SAWCommand):
def __init__(
self,
connection : argo.HasProtocolState,
expr : cryptoltypes.CryptolJSON,
timeout : Optional[float]) -> None:
params = {'expr': cryptoltypes.to_cryptol(expr)}
super(EvalBool, self).__init__('SAW/eval bool', params, connection, timeout=timeout)

def process_result(self, res : Any) -> Any:
return res

class SAWReset(argo.Notification):
def __init__(self, connection : argo.HasProtocolState) -> None:
super(SAWReset, self).__init__(
Expand Down
18 changes: 18 additions & 0 deletions saw-remote-api/python/saw_client/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,6 +239,24 @@ def prove(self,
self.most_recent_result = Prove(self, goal, proof_script, timeout)
return self.most_recent_result

def eval_int(self,
expr: cryptoltypes.CryptolJSON,
timeout : Optional[float] = None) -> Command:
"""Create an instance of the `EvalInt` command. Documentation on the purpose and
use of this command is associated with the top-level `eval_int` function.
"""
self.most_recent_result = EvalInt(self, expr, timeout)
return self.most_recent_result

def eval_bool(self,
expr: cryptoltypes.CryptolJSON,
timeout : Optional[float] = None) -> Command:
"""Create an instance of the `EvalBool` command. Documentation on the purpose and
use of this command is associated with the top-level `eval_bool` function.
"""
self.most_recent_result = EvalBool(self, expr, timeout)
return self.most_recent_result

def set_option(self,
option : SAWOption,
value : bool,
Expand Down
22 changes: 22 additions & 0 deletions saw-remote-api/python/tests/saw/test_eval.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import cryptol
import saw_client as saw

import unittest
from pathlib import Path

class ProverTest(unittest.TestCase):

def test_provers(self):
saw.connect(reset_server=True)

if __name__ == "__main__": saw.view(saw.LogResults())

expr1 = cryptol.cry_f('(6 : [8]) * 7')
self.assertEqual(saw.eval_int(expr1), 42)

expr2 = cryptol.cry_f('(1 < 2) : Bit')
self.assertTrue(saw.eval_bool(expr2))


if __name__ == "__main__":
unittest.main()
1 change: 1 addition & 0 deletions saw-remote-api/saw-remote-api.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ library
SAWServer.Data.JVMType,
SAWServer.Data.LLVMType,
SAWServer.Data.SetupValue,
SAWServer.Eval,
SAWServer.Exceptions,
SAWServer.Ghost,
SAWServer.JVMCrucibleSetup,
Expand Down
13 changes: 13 additions & 0 deletions saw-remote-api/saw-remote-api/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ import SAWServer.CryptolSetup
cryptolLoadFileDescr,
cryptolLoadFile )
import SAWServer.Data.JVMType()
import SAWServer.Eval
( evalIntDescr,
evalInt,
evalBoolDescr,
evalBool )
import SAWServer.Ghost
( createGhostVariableDescr,
createGhostVariable )
Expand Down Expand Up @@ -117,6 +122,14 @@ sawMethods =
"SAW/prove"
proveDescr
prove
, Argo.command
"SAW/eval int"
evalIntDescr
evalInt
, Argo.command
"SAW/eval bool"
evalBoolDescr
evalBool
, Argo.command
"SAW/set option"
setOptionDescr
Expand Down
Loading