Open Baltoli opened 1 year ago
Let's jsut get the first version of k-repl
implemented and merged which allows single K steps for now, then we can figure otu the rest.
More features it should have:
We should also store the nodes (or allow storing the nodes) in a pyk.kcfg.KCFG
.
Maybe we add a command store NODE_NAME
which allows storing the current node in the KCFG, and defines an alias NODE_NAME
for it?
Then the user can use show-cfg
to display a textual CFG, and can select another node to jump to with select NODE_NAME
.
Some questions I want to answer. Some are probably very easy, others will take more time.
I would feel better about getting started on implementing this if we had answers to these questions written down somewhere in a structured manner, whether on Google or in a single issue body
The kit REPL that we used for the summarizer had these commands: https://github.com/runtimeverification/ksummarize/blob/master/kit-shell
We also have the commands the kore-repl uses. We should probably pick (roughly) a subset of the intersection of the commands of both.
I would propose:
show-cfg
: Display an ascii rendering of the current exploration.step [n] [NODE_ID]
: single K step (symbolic or concrete, depending if there are variables in the configuration).show|print [NODE_ID]
: Display the current configuration, by default as pretty K, and as minimized as possible (with ...
wherever possible). Add options for showing specific cells.case-split CONDITION [NODE_ID]
: From a given node, add the supplied constraint, and also add the node with the negation of the supplied constraint, to the graph.check-implication NODE_ID_1 NODE_ID_2
: Check if NODE_ID_1
is subsumed in NODE_ID_2
, and give back a substitution and contraint that witnesses the subsumption if so.I recommend these commands because they are what has been useful for the kit-shell for exploring proofs. From the kore-repl, the various things people have used are (i) stepping, (ii) selecting nodes, and (iii) displaying the current explored graph structure, (iv) displaying nodes. All of these functionalities are covered by the above commands.
I recommend pyk for implementation, because it already implements all of these functionalities, and speaks both KAST and Kore, and has direct and fast communication with the backends. It also already has the KCFG datastructure for storing execution graphs and manipulating them, and it has the CTerm abstraction, which defines the operations that must be done quickly over states in order to not cause delay on the Python side. We can make sure that the various manipulations exposed by CTerm
(such as CTerm.add_constraint
) have fast and direct operations in the backends, so that we can do our executions and manipulations as much as possible purely in the backends.
@ehildenb's answer seems to be focused on symbolic execution; concrete debuggers typically have different priorities and I think it is worth highlighting those.
- If the idea is to interactively enter commands, what commands should we target to start with?
I think the most important commands are (in order of most important to least important):
show [id]
- pretty-print configuration of state id
(defaults to current configuration)step [step-count]
- executes step-count
stepsbreak <location>
- execute semantic steps until location
is reached (could be either an input program location or a K rule location --- depending on which one is being debugged)
- How can we engineer the code for handling commands so that it's extensible to new commands, both user supplied and developer written?
- How can we support scripting and composition of commands?
I think that this requires developing the correct primitive operations that can be easily composed to produce higher level operations. There are couple of primitives that would be really useful to have:
show
n
steps of semantics evaluation and return a new configuration - needed for step
#location
K term corresponding to a particular line appears in a particular cell - needed for break
on input program AST locationbreak
on K rule
- How does potentially executing multiple branches in parallel interact with the interactivity of entering commands?
It seems like you either:
show
command that displays all currently executed branches or possibly a snapshot of the state of currently executing branchesWhile all of these commands are potentially valuable, I want to remind everyone that what I'm trying to get us to agree on is a basic initial version of the tool. Please moderate your expectations because it's inevitable not everything from these lists will make it into the first version prototype.
To try and make priority for a concrete debugger more clear, I have added click-to-expand sections to hide non-essential commands and their implementation details to my previous comment. I also added two other primitives to my previous comment that are needed for break
.
We would like to implement a REPL (or a toolkit for building a REPL) for languages implemented in K.
I think the focus should be on the second option. So the backends would expose a common debugging interface (with additional custom features that the particular backend supports) for which we can implement a client in Python. The simplest K REPL is then a small script that starts and initializes a Python interpreter.
In this setting, the following questions by @dwightguth would (to some extent) be addressed:
Are we set on python as the language to build this in?
For the client code, yes. The server interface has to be implemented by the backends.
Do we want a command language and if so, what should its features be? How can we support scripting and composition of commands? How can we engineer the code for handling commands so that it's extensible to new commands, both user supplied and developer written?
The scripting language is Python, with all the power (and complexity) it comes with.
Do we want auto complete and other line editing support?
The Python interpreter provides this out of the box.
Do the tools already exist to implement each command? If not, what is missing?
For the client, most of what we need for an MVP is already implemented in pyk
.
How does potentially executing multiple branches in parallel interact with the interactivity of entering commands?
We can use asyncio or some other Python library to handle async
calls in the client.
The following questions regarding interface design would still be open:
If the idea is to interactively enter commands, what commands should we target to start with? For each command we are planning initially, what should the parameters and output of the command be?
Commands:
load PROGRAM
(parse and load a program, initialize it as the first term)step [N]
(take K steps)show [ID]
(display a given configuration)
kit
aliases, uses hashes to identify configurationsadd-alias [alias-name|ID]
etc. if we do this; default aliases for things like case splitting...
smartly by collapsing _Unused
show-diff ID1 ID2
- state delta w/ sensible default arguments (current, last printed)show-cell [...cells]
select ID
step-to-branch
case-split ID Bool
check-implication
run
on top of this core abstraction kprove
, search
etc. are just strategies / scripts of the above commands.command > file
show-cfg
- visual, dot etc implemented by Pyk alreadybreak
step-to-branch
#location
show
Notes:
kprove
cyclehttps://github.com/runtimeverification/llvm-backend/blob/pybind/bin/k-repl
Note that the API as installed is slightly different to this demo as well.
Steps to take:
Notes:
Remember our users of k-repl:
step
, step
, etc...)Some example use-cases:
C
, and verifying the correctness there. Meanwhile, Bob begins on contract D
, which calls contract C
. Once Bob reaches the point in symbolic execution that C
is being called, he wants to use the basic blocks already discovered by Alice (or the full verification results) to do the execution, instead of re-executing that code. They both should be able to store their progress/partial results in the same kserver instance, behind authentication, so they can both incrementally make progress on the proofs, and the server should eventually take care of recognizing when some cached proofs are reusable. For now, let Alice and Bob specific that relationship to the server as "proof D
uses proof C
, so keep the learned lemmas and axioms of C
in context when working on D
".E
which has not been started, and suddenly has a realization about a lemma that will immediately go through! She supplies the lemma in browser, and pushes a button, then walks away to get dinner. The next day, she wants to visualize the results of the proof, and when she pushes the button again to run it again, she doesn't want to have to re-enter the same lemma.
Current Situation
The debugging tools available for K projects are limited. Currently, the following options are available to developers of K-based projects:
Proposal
We would like to implement a REPL (or a toolkit for building a REPL) for languages implemented in K. Doing so would allow for developers to step through their code at the language (or semantics) level.
Requirements / Features
Initial dump of requirements per @sskeirik: