8
8
9
9
from pyk .cli_utils import dir_path , file_path
10
10
from pyk .kast import KApply , KDefinition , KFlatModule , KImport , KRequire , KSort
11
+ from pyk .kcfg import KCFG
11
12
from pyk .ktool .krun import _krun
13
+ from pyk .prelude import mlTop
12
14
13
15
from .gst_to_kore import gst_to_kore
14
16
from .kevm import KEVM
15
17
from .solc_to_k import Contract , contract_to_k , solc_compile
16
- from .utils import KPrint_make_unparsing , add_include_arg
18
+ from .utils import KCFG_from_claim , KPrint_make_unparsing , add_include_arg , read_kast_flatmodulelist
17
19
18
20
_LOGGER : Final = logging .getLogger (__name__ )
19
21
_LOG_FORMAT : Final = '%(levelname)s %(asctime)s %(name)s - %(message)s'
@@ -177,6 +179,8 @@ def exec_foundry_kompile(
177
179
md_selector : Optional [str ],
178
180
regen : bool = False ,
179
181
rekompile : bool = False ,
182
+ reparse : bool = False ,
183
+ reinit : bool = False ,
180
184
requires : Iterable [str ] = (),
181
185
imports : Iterable [str ] = (),
182
186
** kwargs ,
@@ -189,6 +193,9 @@ def exec_foundry_kompile(
189
193
spec_module = 'FOUNDRY-SPEC'
190
194
foundry_definition_dir = foundry_out / 'kompiled'
191
195
foundry_main_file = foundry_definition_dir / 'foundry.k'
196
+ kompiled_timestamp = foundry_definition_dir / 'timestamp'
197
+ parsed_spec = foundry_definition_dir / 'spec.json'
198
+ kcfgs_file = foundry_definition_dir / 'kcfgs.json'
192
199
requires = ['lemmas/lemmas.k' , 'lemmas/int-simplification.k' ] + list (requires )
193
200
imports = ['LEMMAS' , 'INT-SIMPLIFICATION' ] + list (imports )
194
201
if not foundry_definition_dir .exists ():
@@ -205,7 +212,7 @@ def exec_foundry_kompile(
205
212
imports = list (imports ),
206
213
output = fmf ,
207
214
)
208
- if regen or rekompile or not ( foundry_definition_dir / 'timestamp' ) .exists ():
215
+ if regen or rekompile or not kompiled_timestamp .exists ():
209
216
KEVM .kompile (
210
217
foundry_definition_dir ,
211
218
foundry_main_file ,
@@ -216,6 +223,26 @@ def exec_foundry_kompile(
216
223
md_selector = md_selector ,
217
224
profile = profile ,
218
225
)
226
+ kevm = KEVM (foundry_definition_dir , main_file = foundry_main_file , profile = profile )
227
+ if regen or rekompile or reparse or not parsed_spec .exists ():
228
+ prove_args = add_include_arg (includes )
229
+ kevm .prove (
230
+ foundry_main_file ,
231
+ spec_module_name = spec_module ,
232
+ dry_run = True ,
233
+ args = (['--emit-json-spec' , str (parsed_spec )] + prove_args ),
234
+ )
235
+ if regen or rekompile or reparse or reinit or not kcfgs_file .exists ():
236
+ cfgs : Dict [str , Dict ] = {}
237
+ for module in read_kast_flatmodulelist (parsed_spec ).modules :
238
+ for claim in module .claims :
239
+ cfg_label = claim .att ["label" ]
240
+ _LOGGER .info (f'Producing KCFG: { cfg_label } ' )
241
+ cfgs [cfg_label ] = KCFG_from_claim (kevm .definition , claim ).to_dict ()
242
+ with open (kcfgs_file , 'w' ) as kf :
243
+ kf .write (json .dumps (cfgs ))
244
+ kf .close ()
245
+ _LOGGER .info (f'Wrote file: { kcfgs_file } ' )
219
246
220
247
221
248
def exec_prove (
@@ -267,23 +294,45 @@ def exec_foundry_prove(
267
294
_ignore_arg (kwargs , 'definition_dir' , f'--definition: { kwargs ["definition_dir" ]} ' )
268
295
_ignore_arg (kwargs , 'spec_module' , f'--spec-module: { kwargs ["spec_module" ]} ' )
269
296
definition_dir = foundry_out / 'kompiled'
270
- spec_file = definition_dir / 'foundry.k'
271
- spec_module = 'FOUNDRY-SPEC'
272
- claims = [Contract .contract_test_to_claim_id (_t ) for _t in tests ]
273
- exclude_claims = [Contract .contract_test_to_claim_id (_t ) for _t in exclude_tests ]
274
- exec_prove (
275
- definition_dir ,
276
- profile ,
277
- spec_file ,
278
- includes = includes ,
279
- debug_equations = debug_equations ,
280
- bug_report = bug_report ,
281
- depth = depth ,
282
- claims = claims ,
283
- exclude_claims = exclude_claims ,
284
- spec_module = spec_module ,
285
- ** kwargs ,
286
- )
297
+ use_directory = foundry_out / 'specs'
298
+ use_directory .mkdir (parents = True , exist_ok = True )
299
+ kevm = KEVM (definition_dir , profile = profile , use_directory = use_directory )
300
+ kcfgs_file = definition_dir / 'kcfgs.json'
301
+ kcfgs : Dict [str , KCFG ] = {}
302
+ _LOGGER .info (f'Reading file: { kcfgs_file } ' )
303
+ with open (kcfgs_file , 'r' ) as kf :
304
+ kcfgs = {k : KCFG .from_dict (v ) for k , v in json .loads (kf .read ()).items ()}
305
+ tests = [Contract .contract_test_to_claim_id (_t ) for _t in tests ]
306
+ exclude_tests = [Contract .contract_test_to_claim_id (_t ) for _t in exclude_tests ]
307
+ claims = list (kcfgs .keys ())
308
+ _unfound_kcfgs : List [str ] = []
309
+ if len (tests ) > 0 :
310
+ kcfgs = {k : kcfg for k , kcfg in kcfgs .items () if k in tests }
311
+ for _t in tests :
312
+ if _t not in claims :
313
+ _unfound_kcfgs .append (_t )
314
+ for _t in exclude_tests :
315
+ if _t not in claims :
316
+ _unfound_kcfgs .append (_t )
317
+ if _t in kcfgs :
318
+ kcfgs .pop (_t )
319
+ if _unfound_kcfgs :
320
+ _LOGGER .error (f'Missing KCFGs for tests: { _unfound_kcfgs } ' )
321
+ sys .exit (1 )
322
+ _failed_claims : List [str ] = []
323
+ for kcfg_name , kcfg in kcfgs .items ():
324
+ _LOGGER .info (f'Proving KCFG: { kcfg_name } ' )
325
+ edge = kcfg .create_edge (kcfg .get_unique_init ().id , kcfg .get_unique_target ().id , mlTop (), depth = - 1 )
326
+ claim = edge .to_claim ()
327
+ result = kevm .prove_claim (claim , kcfg_name .replace ('.' , '-' ))
328
+ if type (result ) is KApply and result .label .name == '#Top' :
329
+ _LOGGER .info (f'Proved KCFG: { kcfg_name } ' )
330
+ else :
331
+ _LOGGER .error (f'Failed to prove KCFG: { kcfg_name } ' )
332
+ _failed_claims .append (kcfg_name )
333
+ if _failed_claims :
334
+ _LOGGER .error (f'Failed to prove KCFGs: { _failed_claims } ' )
335
+ sys .exit (1 )
287
336
288
337
289
338
def exec_run (
@@ -482,6 +531,20 @@ def parse(s):
482
531
action = 'store_true' ,
483
532
help = 'Rekompile foundry.k even if kompiled definition already exists.' ,
484
533
)
534
+ foundry_kompile .add_argument (
535
+ '--reparse' ,
536
+ dest = 'reparse' ,
537
+ default = False ,
538
+ action = 'store_true' ,
539
+ help = 'Reparse K specifications even if the parsed spec already exists.' ,
540
+ )
541
+ foundry_kompile .add_argument (
542
+ '--reinit' ,
543
+ dest = 'reinit' ,
544
+ default = False ,
545
+ action = 'store_true' ,
546
+ help = 'Reinitialize kcfgs even if they already exist.' ,
547
+ )
485
548
486
549
foundry_prove_args = command_parser .add_parser (
487
550
'foundry-prove' ,
0 commit comments