Skip to content

Commit 8bf264b

Browse files
committed
Allow conmpilation of a <file>:<module> via --add-module.
1 parent 53e9dab commit 8bf264b

5 files changed

Lines changed: 41 additions & 18 deletions

File tree

kmir/src/kmir/__main__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -555,9 +555,9 @@ def _arg_parser() -> ArgumentParser:
555555
)
556556
prove_parser.add_argument(
557557
'--add-module',
558-
type=Path,
559-
metavar='FILE',
560-
help='K module file to include (.json format from --to-module)',
558+
type=str,
559+
metavar='MODULE',
560+
help='K module to include: file.k:MODULE_NAME or file.md:MODULE_NAME for K source, or file.json (from --to-module) for pre-exported JSON',
561561
)
562562
prove_parser.add_argument(
563563
'--max-workers', metavar='N', type=int, help='Maximum number of workers for parallel exploration'

kmir/src/kmir/kmir.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def from_kompiled_kore(
5757
smir_info: SMIRInfo,
5858
target_dir: Path,
5959
*,
60-
extra_module: Path | None = None,
60+
extra_module: str | None = None,
6161
bug_report: Path | None = None,
6262
symbolic: bool = True,
6363
llvm_target: str | None = None,

kmir/src/kmir/kompile.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
from pyk.kast.prelude.string import stringToken
1313
from pyk.kdist import kdist
1414
from pyk.kore.syntax import App, EVar, SortApp, String, Symbol, SymbolDecl
15+
from pyk.utils import single
1516

1617
from .kmir import KMIR
1718

19+
from pathlib import Path
20+
1821
if TYPE_CHECKING:
1922
from collections.abc import Sequence
20-
from pathlib import Path
2123
from typing import Any, Final
2224

2325
from pyk.kast.inner import KInner
@@ -162,27 +164,48 @@ def _add_exists_quantifiers(axiom: Axiom) -> Axiom:
162164
return Axiom(vars=axiom.vars, pattern=new_pattern, attrs=axiom.attrs)
163165

164166

165-
def _load_extra_module_rules(kmir: KMIR, module_path: Path) -> list[Sentence]:
166-
"""Load a K module from JSON and convert rules to Kore axioms.
167+
def _load_extra_module_rules(kmir: KMIR, module_spec: str) -> list[Sentence]:
168+
"""Load a K module and convert rules to Kore axioms.
169+
170+
Supports two formats:
171+
- JSON file path: ``path/to/module.json`` (from ``--to-module``)
172+
- K source with module name: ``path/to/file.k:MODULE_NAME`` or ``path/to/file.md:MODULE_NAME``
167173
168174
Args:
169175
kmir: KMIR instance with the definition
170-
module_path: Path to JSON module file (from --to-module output.json)
176+
module_spec: Module specification string
171177
172178
Returns:
173179
List of Kore axioms converted from the module rules
174180
"""
175181
from pyk.kast.outer import KFlatModule, KRule
176182
from pyk.konvert import krule_to_kore
177183

178-
_LOGGER.info(f'Loading extra module rules: {module_path}')
184+
_LOGGER.info(f'Loading extra module rules: {module_spec}')
179185

180-
if module_path.suffix != '.json':
181-
_LOGGER.warning(f'Only JSON format is supported for --add-module: {module_path}')
182-
return []
186+
if ':' in module_spec:
187+
# K source format: file.k:MODULE_NAME or file.md:MODULE_NAME
188+
file_str, module_name = module_spec.rsplit(':', 1)
189+
file_path = Path(file_str)
190+
if not file_path.is_file():
191+
raise ValueError(f'Supplied module path is not a file: {file_path}')
192+
if file_path.suffix not in ('.k', '.md'):
193+
raise ValueError(f'K source module must be a .k or .md file, got: {file_path}')
183194

184-
module_dict = json.loads(module_path.read_text())
185-
k_module = KFlatModule.from_dict(module_dict)
195+
include_dirs = (kdist.which('mir-semantics.haskell').parent,)
196+
module_list = kmir.parse_modules(file_path, module_name=module_name, include_dirs=include_dirs)
197+
k_module = single(module for module in module_list.modules if module.name == module_name)
198+
else:
199+
# JSON format: path/to/module.json
200+
file_path = Path(module_spec)
201+
if not file_path.is_file():
202+
raise ValueError(f'Supplied module path is not a file: {file_path}')
203+
if file_path.suffix != '.json':
204+
raise ValueError(
205+
f'Expected .json file or file.k:MODULE_NAME / file.md:MODULE_NAME format, got: {file_path}'
206+
)
207+
module_dict = json.loads(file_path.read_text())
208+
k_module = KFlatModule.from_dict(module_dict)
186209

187210
axioms: list[Sentence] = []
188211
for sentence in k_module.sentences:
@@ -203,7 +226,7 @@ def kompile_smir(
203226
target_dir: Path,
204227
*,
205228
bug_report: Path | None = None,
206-
extra_module: Path | None = None,
229+
extra_module: str | None = None,
207230
symbolic: bool = True,
208231
llvm_target: str | None = None,
209232
llvm_lib_target: str | None = None,

kmir/src/kmir/options.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ class ProveOpts(KMirOpts):
7676
smir: bool
7777
parsed_smir: dict | None
7878
start_symbol: str
79-
add_module: Path | None
79+
add_module: str | None
8080
break_on_calls: bool
8181
break_on_function_calls: bool
8282
break_on_intrinsic_calls: bool
@@ -127,7 +127,7 @@ def __init__(
127127
break_every_terminator: bool = False,
128128
break_every_step: bool = False,
129129
terminate_on_thunk: bool = False,
130-
add_module: Path | None = None,
130+
add_module: str | None = None,
131131
break_on_function: list[str] | None = None,
132132
) -> None:
133133
self.rs_file = rs_file

kmir/src/tests/integration/test_cli.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -293,7 +293,7 @@ def test_cli_prove_add_module(kmir: KMIR, tmp_path: Path) -> None:
293293
smir=False,
294294
start_symbol=start_symbol,
295295
max_depth=1,
296-
add_module=stored_module_json,
296+
add_module=str(stored_module_json),
297297
)
298298
proof_with_module = KMIR.prove_program(opts_with_module)
299299

0 commit comments

Comments
 (0)