1212from pyk .kast .prelude .string import stringToken
1313from pyk .kdist import kdist
1414from pyk .kore .syntax import App , EVar , SortApp , String , Symbol , SymbolDecl
15+ from pyk .utils import single
1516
1617from .kmir import KMIR
1718
19+ from pathlib import Path
20+
1821if 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 ,
0 commit comments