Skip to content

Commit 263aff7

Browse files
authored
Adding show-kcfg and view-kcfg (#252)
* Moved CLI stuff to `cli.py` and added `kcfg-show` * Added `view-kcfg` commmand. Output is not 100% yet. * formatting * Removed implied `argparse` destinations. Fixed typos etc.
1 parent 89803be commit 263aff7

File tree

3 files changed

+435
-157
lines changed

3 files changed

+435
-157
lines changed

kmir/src/kmir/__main__.py

Lines changed: 110 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import logging
22
import sys
3-
from argparse import ArgumentParser, Namespace
3+
from argparse import Namespace
4+
from collections.abc import Iterable
45
from pathlib import Path
56
from typing import Any, Final
67

7-
from pyk.cli.utils import dir_path, file_path
88
from pyk.kast.outer import KApply, KClaim, KRewrite
99
from pyk.kcfg import KCFG
1010
from pyk.ktool.kprint import KAstInput, KAstOutput
@@ -13,10 +13,20 @@
1313
from pyk.proof import APRProof
1414
from pyk.proof.equality import EqualityProof
1515
from pyk.proof.proof import Proof
16+
from pyk.proof.show import APRProofShow
17+
from pyk.proof.tui import APRProofViewer
1618
from pyk.utils import BugReport
1719

20+
from .cli import create_argument_parser
1821
from .kmir import KMIR
19-
from .utils import ensure_ksequence_on_k_cell, kmir_prove, legacy_explore, print_failure_info
22+
from .utils import (
23+
NodeIdLike,
24+
ensure_ksequence_on_k_cell,
25+
get_apr_proof_for_spec,
26+
kmir_prove,
27+
legacy_explore,
28+
print_failure_info,
29+
)
2030

2131
_LOGGER: Final = logging.getLogger(__name__)
2232
_LOG_FORMAT: Final = '%(levelname)s %(asctime)s %(name)s - %(message)s'
@@ -103,6 +113,9 @@ def exec_prove(
103113
trace_rewrites: bool = False,
104114
**kwargs: Any,
105115
) -> None:
116+
if spec_file is None:
117+
raise ValueError('A spec file must be provided')
118+
106119
# TODO: workers
107120
# TODO: md_selector doesn't work
108121
spec_file_path = Path(spec_file)
@@ -201,168 +214,110 @@ def _init_and_run_proof(claim: KClaim) -> tuple[bool, list[str] | None]:
201214
sys.exit(failed)
202215

203216

204-
def create_argument_parser() -> ArgumentParser:
205-
logging_args = ArgumentParser(add_help=False)
206-
logging_args.add_argument('--verbose', '-v', default=False, action='store_true', help='Verbose output.')
207-
logging_args.add_argument('--debug', default=False, action='store_true', help='Debug output.')
217+
def exec_show_kcfg(
218+
definition_dir: str,
219+
haskell_dir: str,
220+
spec_file: Path,
221+
save_directory: Path | None = None,
222+
claim_labels: Iterable[str] | None = None,
223+
exclude_claim_labels: Iterable[str] = (),
224+
spec_module: str | None = None,
225+
md_selector: str | None = None,
226+
nodes: Iterable[NodeIdLike] = (),
227+
node_deltas: Iterable[tuple[NodeIdLike, NodeIdLike]] = (),
228+
to_module: bool = False,
229+
minimize: bool = True,
230+
failure_info: bool = False,
231+
sort_collections: bool = False,
232+
pending: bool = False,
233+
failing: bool = False,
234+
**kwargs: Any,
235+
) -> None:
236+
# TODO: include dirs
208237

209-
parser = ArgumentParser(prog='kmir', description='KMIR command line tool')
238+
if spec_file is None:
239+
raise ValueError('A spec file must be provided')
210240

211-
command_parser = parser.add_subparsers(dest='command', required=True, help='Command to execute')
241+
kmir = KMIR(definition_dir, haskell_dir, use_directory=save_directory)
212242

213-
# Init (See flake.nix)
214-
# This command is not needed unless it is for the flake, so we should hide it from users
215-
if 'init' in sys.argv:
216-
init_subparser = command_parser.add_parser('init', parents=[logging_args])
217-
init_subparser.add_argument(
218-
'llvm_dir',
219-
type=dir_path,
220-
help='Path to the llvm definition',
221-
)
243+
kprove: KProve
244+
if kmir.kprove is None:
245+
raise ValueError('Cannot use KProve object when it is None')
246+
else:
247+
kprove = kmir.kprove
222248

223-
# Parse
224-
parse_subparser = command_parser.add_parser('parse', parents=[logging_args], help='Parse a MIR file')
225-
parse_subparser.add_argument(
226-
'input_file',
227-
type=file_path,
228-
help='Path to .mir file',
229-
)
230-
parse_subparser.add_argument(
231-
'--definition-dir',
232-
default=None,
233-
dest='definition_dir',
234-
type=dir_path,
235-
help='Path to LLVM definition to use.',
236-
)
237-
parse_subparser.add_argument(
238-
'--input',
239-
dest='input',
240-
type=str,
241-
default='program',
242-
help='Input mode',
243-
choices=['program', 'binary', 'json', 'kast', 'kore'],
244-
required=False,
245-
)
246-
parse_subparser.add_argument(
247-
'--output',
248-
dest='output',
249-
type=str,
250-
default='kore',
251-
help='Output mode',
252-
choices=['pretty', 'program', 'json', 'kore', 'kast', 'none'],
253-
required=False,
249+
proof = get_apr_proof_for_spec(
250+
kprove,
251+
spec_file,
252+
save_directory=save_directory,
253+
spec_module_name=spec_module,
254+
# include_dirs=include_dirs,
255+
md_selector=md_selector,
256+
claim_labels=claim_labels,
257+
exclude_claim_labels=exclude_claim_labels,
254258
)
255259

256-
# Run
257-
run_subparser = command_parser.add_parser('run', parents=[logging_args], help='Run a MIR program')
258-
run_subparser.add_argument(
259-
'input_file',
260-
type=file_path,
261-
help='Path to .mir file',
262-
)
263-
run_subparser.add_argument(
264-
'--definition-dir',
265-
default=None,
266-
dest='definition_dir',
267-
type=dir_path,
268-
help='Path to LLVM definition to use.',
269-
)
270-
run_subparser.add_argument(
271-
'--output',
272-
dest='output',
273-
type=str,
274-
default='kast',
275-
help='Output mode',
276-
choices=['pretty', 'program', 'json', 'kore', 'kast', 'none'],
277-
required=False,
278-
)
279-
run_subparser.add_argument(
280-
'--ignore-return-code',
281-
action='store_true',
282-
default=False,
283-
help='Ignore return code of krun, alwasys return 0 (use for debugging only)',
284-
)
285-
run_subparser.add_argument(
286-
'--bug-report',
287-
action='store_true',
288-
default=False,
289-
help='Generate a haskell-backend bug report for the execution',
290-
)
291-
run_subparser.add_argument(
292-
'--depth',
293-
default=None,
294-
type=int,
295-
help='Stop execution after `depth` rewrite steps',
260+
if pending:
261+
nodes = list(nodes) + [node.id for node in proof.pending]
262+
if failing:
263+
nodes = list(nodes) + [node.id for node in proof.failing]
264+
265+
# TODO: Create NodePrinter ???
266+
proof_show = APRProofShow(kprove)
267+
268+
res_lines = proof_show.show(
269+
proof,
270+
nodes=nodes,
271+
node_deltas=node_deltas,
272+
to_module=to_module,
273+
minimize=minimize,
274+
sort_collections=sort_collections,
296275
)
297276

298-
# Prove
299-
prove_subparser = command_parser.add_parser(
300-
'prove', parents=[logging_args], help='Prove a MIR specification WARN: EXPERIMENTAL AND WORK IN PROGRESS'
301-
)
302-
prove_subparser.add_argument(
303-
'--definition-dir',
304-
dest='definition_dir',
305-
type=dir_path,
306-
help='Path to LLVM definition to use.',
307-
)
308-
prove_subparser.add_argument(
309-
'--haskell-dir',
310-
dest='haskell_dir',
311-
type=dir_path,
312-
help='Path to Haskell definition to use.',
313-
)
314-
prove_subparser.add_argument(
315-
'--spec-file',
316-
dest='spec_file',
317-
type=file_path,
318-
help='Path to specification file',
319-
)
320-
prove_subparser.add_argument(
321-
'--bug-report',
322-
action='store_true',
323-
default=False,
324-
help='Generate a haskell-backend bug report for the execution',
325-
)
326-
prove_subparser.add_argument(
327-
'--depth',
328-
default=None,
329-
type=int,
330-
help='Stop execution after `depth` rewrite steps',
331-
)
332-
prove_subparser.add_argument(
333-
'--smt-timeout',
334-
dest='smt_timeout',
335-
type=int,
336-
default=125,
337-
help='Timeout in ms to use for SMT queries',
338-
)
339-
prove_subparser.add_argument(
340-
'--smt-retry-limit',
341-
dest='smt_retry_limit',
342-
type=int,
343-
default=4,
344-
help='Number of times to retry SMT queries with scaling timeouts.',
345-
)
346-
prove_subparser.add_argument(
347-
'--trace-rewrites',
348-
default=False,
349-
action='store_true',
350-
help='Log traces of all simplification and rewrite rule applications.',
351-
)
352-
prove_subparser.add_argument(
353-
'--save-directory',
354-
dest='save_directory',
355-
type=dir_path,
356-
help='Path to KCFG proofs directory, directory must already exist.',
357-
)
358-
prove_subparser.add_argument(
359-
'--reinit',
360-
action='store_true',
361-
default=False,
362-
help='Reinit a proof.S',
277+
if failure_info:
278+
with legacy_explore(kprove, id=proof.id) as kcfg_explore:
279+
res_lines += print_failure_info(proof, kcfg_explore)
280+
281+
print('\n'.join(res_lines))
282+
283+
284+
def exec_view_kcfg(
285+
definition_dir: str,
286+
haskell_dir: str,
287+
spec_file: Path,
288+
save_directory: Path | None = None,
289+
claim_labels: Iterable[str] | None = None,
290+
exclude_claim_labels: Iterable[str] = (),
291+
spec_module: str | None = None,
292+
md_selector: str | None = None,
293+
**kwargs: Any,
294+
) -> None:
295+
# TODO: include dirs
296+
297+
if spec_file is None:
298+
raise ValueError('A spec file must be provided')
299+
kmir = KMIR(definition_dir, haskell_dir, use_directory=save_directory)
300+
301+
kprove: KProve
302+
if kmir.kprove is None:
303+
raise ValueError('Cannot use KProve object when it is None')
304+
else:
305+
kprove = kmir.kprove
306+
307+
proof = get_apr_proof_for_spec(
308+
kprove,
309+
spec_file,
310+
save_directory=save_directory,
311+
spec_module_name=spec_module,
312+
md_selector=md_selector,
313+
claim_labels=claim_labels,
314+
exclude_claim_labels=exclude_claim_labels,
363315
)
364316

365-
return parser
317+
# TODO: NodePrinter ???
318+
proof_view = APRProofViewer(proof, kprove)
319+
320+
proof_view.run()
366321

367322

368323
def _loglevel(args: Namespace) -> int:

0 commit comments

Comments
 (0)