|
1 | 1 | import logging
|
2 | 2 | import sys
|
3 |
| -from argparse import ArgumentParser, Namespace |
| 3 | +from argparse import Namespace |
| 4 | +from collections.abc import Iterable |
4 | 5 | from pathlib import Path
|
5 | 6 | from typing import Any, Final
|
6 | 7 |
|
7 |
| -from pyk.cli.utils import dir_path, file_path |
8 | 8 | from pyk.kast.outer import KApply, KClaim, KRewrite
|
9 | 9 | from pyk.kcfg import KCFG
|
10 | 10 | from pyk.ktool.kprint import KAstInput, KAstOutput
|
|
13 | 13 | from pyk.proof import APRProof
|
14 | 14 | from pyk.proof.equality import EqualityProof
|
15 | 15 | from pyk.proof.proof import Proof
|
| 16 | +from pyk.proof.show import APRProofShow |
| 17 | +from pyk.proof.tui import APRProofViewer |
16 | 18 | from pyk.utils import BugReport
|
17 | 19 |
|
| 20 | +from .cli import create_argument_parser |
18 | 21 | 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 | +) |
20 | 30 |
|
21 | 31 | _LOGGER: Final = logging.getLogger(__name__)
|
22 | 32 | _LOG_FORMAT: Final = '%(levelname)s %(asctime)s %(name)s - %(message)s'
|
@@ -103,6 +113,9 @@ def exec_prove(
|
103 | 113 | trace_rewrites: bool = False,
|
104 | 114 | **kwargs: Any,
|
105 | 115 | ) -> None:
|
| 116 | + if spec_file is None: |
| 117 | + raise ValueError('A spec file must be provided') |
| 118 | + |
106 | 119 | # TODO: workers
|
107 | 120 | # TODO: md_selector doesn't work
|
108 | 121 | spec_file_path = Path(spec_file)
|
@@ -201,168 +214,110 @@ def _init_and_run_proof(claim: KClaim) -> tuple[bool, list[str] | None]:
|
201 | 214 | sys.exit(failed)
|
202 | 215 |
|
203 | 216 |
|
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 |
208 | 237 |
|
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') |
210 | 240 |
|
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) |
212 | 242 |
|
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 |
222 | 248 |
|
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, |
254 | 258 | )
|
255 | 259 |
|
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, |
296 | 275 | )
|
297 | 276 |
|
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, |
363 | 315 | )
|
364 | 316 |
|
365 |
| - return parser |
| 317 | + # TODO: NodePrinter ??? |
| 318 | + proof_view = APRProofViewer(proof, kprove) |
| 319 | + |
| 320 | + proof_view.run() |
366 | 321 |
|
367 | 322 |
|
368 | 323 | def _loglevel(args: Namespace) -> int:
|
|
0 commit comments