77from dataclasses import dataclass
88from typing import TYPE_CHECKING
99
10- from pyk .kast .inner import KApply , KSort
10+ from pyk .kast .inner import KApply , KSort , KToken , KVariable
1111from pyk .kast .prelude .kint import intToken
1212from pyk .kast .prelude .string import stringToken
13+ from pyk .kore .syntax import App , EVar , SortApp , String , Symbol , SymbolDecl
1314
1415from .build import HASKELL_DEF_DIR , LLVM_DEF_DIR , LLVM_LIB_DIR
1516from .kmir import KMIR
1617
1718if TYPE_CHECKING :
19+ from collections .abc import Sequence
1820 from pathlib import Path
1921 from typing import Any , Final
2022
2123 from pyk .kast import KInner
24+ from pyk .kore .syntax import Axiom , Sentence
2225
2326 from .smir import SMIRInfo
2427
@@ -117,7 +120,7 @@ def kompile_smir(
117120 target_dir .mkdir (parents = True , exist_ok = True )
118121
119122 kmir = KMIR (HASKELL_DEF_DIR )
120- rules = _make_kore_rules (kmir , smir_info )
123+ rules = make_kore_rules (kmir , smir_info )
121124 _LOGGER .info (f'Generated { len (rules )} function equations to add to `definition.kore' )
122125
123126 if symbolic :
@@ -216,35 +219,142 @@ def kompile_smir(
216219 return KompiledConcrete (llvm_dir = target_llvm_path )
217220
218221
219- def _make_kore_rules (kmir : KMIR , smir_info : SMIRInfo ) -> list [str ]: # generates kore syntax directly as string
222+ def _make_stratified_rules (
223+ kmir : KMIR ,
224+ fun : str ,
225+ arg_sort : str ,
226+ result_sort : str ,
227+ id_cons : str ,
228+ assocs : list [tuple [int , KInner ]],
229+ not_found : KInner ,
230+ strata : int = 10 ,
231+ ) -> Sequence [Sentence ]:
232+ from pyk .kore .prelude import int_dv
233+ from pyk .kore .rule import FunctionRule
234+
235+ int_eqls = "Lbl'UndsEqlsEqls'Int'Unds'"
236+ int_tmod = "Lbl'UndsPerc'Int'Unds'"
237+
238+ arg_sort_kore = SortApp ('Sort' + arg_sort )
239+ int_sort_kore = SortApp ('SortInt' )
240+ result_sort_kore = SortApp ('Sort' + result_sort )
241+ id_cons_kore = 'Lbl' + id_cons
242+
243+ declarations = [
244+ # declare stratified functions
245+ SymbolDecl (
246+ symbol = Symbol ('Lbl' + fun + str (i )),
247+ param_sorts = (int_sort_kore ,),
248+ sort = result_sort_kore ,
249+ attrs = (
250+ App ('function' ),
251+ App ('total' ),
252+ ),
253+ )
254+ for i in range (strata )
255+ ]
256+ dispatch = [
257+ # define dispatch equations to stratified functions
258+ # f'rule {fun}({id_cons}(N) => {fun}{i}(N)) requires N /Int {strata} ==Int {i}'
259+ FunctionRule (
260+ App ('Lbl' + fun , (), (App (id_cons_kore , (), (EVar ('VarN' , int_sort_kore ),)),)),
261+ App ('Lbl' + fun + str (i ), (), (EVar ('VarN' , int_sort_kore ),)),
262+ App (int_eqls , (), [App (int_tmod , (), [EVar ('VarN' , int_sort_kore ), int_dv (strata )]), int_dv (i )]),
263+ None ,
264+ result_sort_kore ,
265+ (arg_sort_kore ,),
266+ None ,
267+ 0 ,
268+ f'{ fun } { i } -dispatch' ,
269+ f'{ fun } { i } -dispatch' ,
270+ )
271+ .to_axiom ()
272+ .let_attrs ((App ("UNIQUE'Unds'ID" , (), (String (f'{ fun } { i } -dispatch' ),)),))
273+ for i in range (strata )
274+ ]
275+ defaults = [
276+ # define dispatch equations to stratified functions
277+ # f'rule {fun}{i}(N) => {default} [owise]'
278+ FunctionRule (
279+ App ('Lbl' + fun + str (i ), (), (EVar ('VarN' , SortApp ('SortInt' )),)),
280+ kmir .kast_to_kore (not_found , KSort (result_sort )),
281+ None ,
282+ None ,
283+ result_sort_kore ,
284+ (int_sort_kore ,),
285+ None ,
286+ 200 ,
287+ f'{ fun } { i } -default' ,
288+ f'{ fun } { i } -default' ,
289+ )
290+ .to_axiom ()
291+ .let_attrs ((App ('owise' ), App ("UNIQUE'Unds'ID" , (), (String (f'{ fun } { i } -default' ),))))
292+ for i in range (strata )
293+ ]
220294 equations = []
295+ for i , result in assocs :
296+ m = i % strata
297+ equations .append (
298+ _mk_equation (kmir , fun + str (m ), intToken (i ), 'Int' , result , result_sort ).let_attrs (
299+ (App ("UNIQUE'Unds'ID" , (), (String (f'{ fun } { m } -{ i } -generated' ),)),)
300+ )
301+ )
302+ return [* declarations , * dispatch , * defaults , * equations ]
303+
221304
305+ def make_kore_rules (kmir : KMIR , smir_info : SMIRInfo ) -> Sequence [Sentence ]:
222306 # kprint tool is too chatty
223307 kprint_logger = logging .getLogger ('pyk.ktool.kprint' )
224308 kprint_logger .setLevel (logging .WARNING )
225309
310+ unknown_function = KApply (
311+ 'MonoItemKind::MonoItemFn' ,
312+ (
313+ KApply ('symbol(_)_LIB_Symbol_String' , (KToken ('"** UNKNOWN FUNCTION **"' , KSort ('String' )),)),
314+ KApply ('defId(_)_BODY_DefId_Int' , (KVariable ('TY' , KSort ('Int' )),)),
315+ KApply ('noBody_BODY_MaybeBody' , ()),
316+ ),
317+ )
318+ default_function = _mk_equation (
319+ kmir , 'lookupFunction' , KApply ('ty' , (KVariable ('TY' ),)), 'Ty' , unknown_function , 'MonoItemKind'
320+ ).let_attrs (((App ('owise' )),))
321+
322+ equations : list [Axiom ] = [default_function ]
323+
226324 for fty , kind in _functions (kmir , smir_info ).items ():
227325 equations .append (
228326 _mk_equation (kmir , 'lookupFunction' , KApply ('ty' , (intToken (fty ),)), 'Ty' , kind , 'MonoItemKind' )
229327 )
230328
231- types : set [KInner ] = set ()
232- for type in smir_info ._smir ['types' ]:
233- parse_result = kmir .parser .parse_mir_json (type , 'TypeMapping' )
234- assert parse_result is not None
235- type_mapping , _ = parse_result
236- assert isinstance (type_mapping , KApply ) and len (type_mapping .args ) == 2
237- ty , tyinfo = type_mapping .args
238- if ty in types :
239- raise ValueError (f'Key collision in type map: { ty } ' )
240- types .add (ty )
241- equations .append (_mk_equation (kmir , 'lookupTy' , ty , 'Ty' , tyinfo , 'TypeInfo' ))
329+ # stratify type and alloc lookups
330+ def get_int_arg (app : KInner ) -> int :
331+ match app :
332+ case KApply (_, args = (KToken (token = int_arg , sort = KSort ('Int' )),)):
333+ return int (int_arg )
334+ case _:
335+ raise Exception (f'Cannot extract int arg from { app } ' )
336+
337+ invalid_type = KApply ('TypeInfo::VoidType' , ())
338+ parsed_types = [kmir .parser .parse_mir_json (type , 'TypeMapping' ) for type in smir_info ._smir ['types' ]]
339+ type_mappings = [type_mapping for type_mapping , _ in (result for result in parsed_types if result is not None )]
340+
341+ type_assocs = [
342+ (get_int_arg (ty ), info )
343+ for ty , info in (type_mapping .args for type_mapping in type_mappings if isinstance (type_mapping , KApply ))
344+ ]
242345
243- for alloc in smir_info ._smir ['allocs' ]:
244- alloc_id , value = _decode_alloc (smir_info = smir_info , raw_alloc = alloc )
245- equations .append (_mk_equation (kmir , 'lookupAlloc' , alloc_id , 'AllocId' , value , 'Evaluation' ))
346+ type_equations = _make_stratified_rules (kmir , 'lookupTy' , 'Ty' , 'TypeInfo' , 'ty' , type_assocs , invalid_type )
246347
247- return equations
348+ invalid_alloc_n = KApply (
349+ 'InvalidAlloc(_)_RT-VALUE-SYNTAX_Evaluation_AllocId' , (KApply ('allocId' , (KVariable ('N' ),)),)
350+ )
351+ decoded_allocs = [_decode_alloc (smir_info = smir_info , raw_alloc = alloc ) for alloc in smir_info ._smir ['allocs' ]]
352+ allocs = [(get_int_arg (alloc_id ), value ) for (alloc_id , value ) in decoded_allocs ]
353+ alloc_equations = _make_stratified_rules (
354+ kmir , 'lookupAlloc' , 'AllocId' , 'Evaluation' , 'allocId' , allocs , invalid_alloc_n
355+ )
356+
357+ return [* equations , * type_equations , * alloc_equations ]
248358
249359
250360def _functions (kmir : KMIR , smir_info : SMIRInfo ) -> dict [int , KInner ]:
@@ -275,7 +385,7 @@ def _functions(kmir: KMIR, smir_info: SMIRInfo) -> dict[int, KInner]:
275385 return functions
276386
277387
278- def _mk_equation (kmir : KMIR , fun : str , arg : KInner , arg_sort : str , result : KInner , result_sort : str ) -> str :
388+ def _mk_equation (kmir : KMIR , fun : str , arg : KInner , arg_sort : str , result : KInner , result_sort : str ) -> Axiom :
279389 from pyk .kore .rule import FunctionRule
280390 from pyk .kore .syntax import App , SortApp
281391
@@ -296,17 +406,7 @@ def _mk_equation(kmir: KMIR, fun: str, arg: KInner, arg_sort: str, result: KInne
296406 uid = 'fubar' ,
297407 label = 'fubaz' ,
298408 )
299- return '\n ' .join (
300- [
301- '' ,
302- '' ,
303- (
304- f'// { fun } ({ kmir .pretty_print (arg )} )'
305- + (f' => { kmir .pretty_print (result )} ' if len (kmir .pretty_print (result )) < 1000 else '' )
306- ),
307- rule .to_axiom ().text ,
308- ]
309- )
409+ return rule .to_axiom ()
310410
311411
312412def _decode_alloc (smir_info : SMIRInfo , raw_alloc : Any ) -> tuple [KInner , KInner ]:
@@ -326,7 +426,7 @@ def _decode_alloc(smir_info: SMIRInfo, raw_alloc: Any) -> tuple[KInner, KInner]:
326426 return alloc_id_term , value .to_kast ()
327427
328428
329- def _insert_rules_and_write (input_file : Path , rules : list [ str ], output_file : Path ) -> None :
429+ def _insert_rules_and_write (input_file : Path , rules : Sequence [ Sentence ], output_file : Path ) -> None :
330430 with open (input_file , 'r' ) as f :
331431 lines = f .readlines ()
332432
@@ -337,7 +437,7 @@ def _insert_rules_and_write(input_file: Path, rules: list[str], output_file: Pat
337437
338438 # Insert rules before the endmodule line
339439 new_lines .append (f'\n // Generated from file { input_file } \n \n ' )
340- new_lines .extend (rules )
440+ new_lines .extend ([ ax . text + ' \n ' for ax in rules ] )
341441 new_lines .append ('\n ' + last_line )
342442
343443 # Write to output file
0 commit comments