3
3
import logging
4
4
from abc import ABC
5
5
from dataclasses import dataclass , field
6
- from typing import TYPE_CHECKING , final
6
+ from typing import TYPE_CHECKING , NamedTuple , final
7
7
8
8
from ..cterm import CSubst , CTerm
9
9
from ..kast .inner import KApply , KLabel , KRewrite , KVariable , Subst
47
47
_LOGGER : Final = logging .getLogger (__name__ )
48
48
49
49
50
+ class CTermExecute (NamedTuple ):
51
+ state : CTerm
52
+ unknown_predicate : KInner | None
53
+ next_states : tuple [CTerm , ...]
54
+ depth : int
55
+ vacuous : bool
56
+ logs : tuple [LogEntry , ...]
57
+
58
+
50
59
class KCFGExplore :
51
60
kprint : KPrint
52
61
_kore_client : KoreClient
@@ -77,40 +86,42 @@ def cterm_execute(
77
86
cut_point_rules : Iterable [str ] | None = None ,
78
87
terminal_rules : Iterable [str ] | None = None ,
79
88
module_name : str | None = None ,
80
- ) -> tuple [ KInner | None , bool , int , CTerm , list [ CTerm ], tuple [ LogEntry , ...]] :
89
+ ) -> CTermExecute :
81
90
_LOGGER .debug (f'Executing: { cterm } ' )
82
91
kore = self .kprint .kast_to_kore (cterm .kast , GENERATED_TOP_CELL )
83
- er = self ._kore_client .execute (
92
+ response = self ._kore_client .execute (
84
93
kore ,
85
94
max_depth = depth ,
86
95
cut_point_rules = cut_point_rules ,
87
96
terminal_rules = terminal_rules ,
88
97
module_name = module_name ,
89
- log_successful_rewrites = self ._trace_rewrites if self . _trace_rewrites else None ,
90
- log_failed_rewrites = self ._trace_rewrites if self . _trace_rewrites else None ,
91
- log_successful_simplifications = self ._trace_rewrites if self . _trace_rewrites else None ,
92
- log_failed_simplifications = self ._trace_rewrites if self . _trace_rewrites else None ,
98
+ log_successful_rewrites = self ._trace_rewrites ,
99
+ log_failed_rewrites = self ._trace_rewrites ,
100
+ log_successful_simplifications = self ._trace_rewrites ,
101
+ log_failed_simplifications = self ._trace_rewrites ,
93
102
)
94
103
95
- _is_vacuous = er .reason is StopReason .VACUOUS
96
- depth = er .depth
97
- next_state = CTerm .from_kast (self .kprint .kore_to_kast (er .state .kore ))
98
- _next_states = er .next_states if er .next_states is not None else []
99
- next_states = [CTerm .from_kast (self .kprint .kore_to_kast (ns .kore )) for ns in _next_states ]
100
- next_states = [cterm for cterm in next_states if not cterm .is_bottom ]
101
- if len (next_states ) == 1 and len (next_states ) < len (_next_states ):
102
- return None , _is_vacuous , depth + 1 , next_states [0 ], [], er .logs
103
- elif len (next_states ) == 1 :
104
- if er .reason == StopReason .CUT_POINT_RULE :
105
- return None , _is_vacuous , depth , next_state , next_states , er .logs
106
- else :
107
- next_states = []
108
104
unknown_predicate = None
109
- if isinstance (er , AbortedResult ):
105
+ if isinstance (response , AbortedResult ):
110
106
unknown_predicate = (
111
- self .kprint .kore_to_kast (er .unknown_predicate ) if er .unknown_predicate is not None else None
107
+ self .kprint .kore_to_kast (response .unknown_predicate ) if response .unknown_predicate is not None else None
112
108
)
113
- return unknown_predicate , _is_vacuous , depth , next_state , next_states , er .logs
109
+
110
+ state = CTerm .from_kast (self .kprint .kore_to_kast (response .state .kore ))
111
+ resp_next_states = response .next_states or ()
112
+ next_states = tuple (CTerm .from_kast (self .kprint .kore_to_kast (ns .kore )) for ns in resp_next_states )
113
+
114
+ assert all (not cterm .is_bottom for cterm in next_states )
115
+ assert len (next_states ) != 1 or response .reason is StopReason .CUT_POINT_RULE
116
+
117
+ return CTermExecute (
118
+ state = state ,
119
+ unknown_predicate = unknown_predicate ,
120
+ next_states = next_states ,
121
+ depth = response .depth ,
122
+ vacuous = response .reason is StopReason .VACUOUS ,
123
+ logs = response .logs ,
124
+ )
114
125
115
126
def cterm_simplify (self , cterm : CTerm ) -> tuple [KInner | None , CTerm , tuple [LogEntry , ...]]:
116
127
_LOGGER .debug (f'Simplifying: { cterm } ' )
@@ -319,16 +330,14 @@ def step(
319
330
if len (successors ) != 0 and type (successors [0 ]) is KCFG .Split :
320
331
raise ValueError (f'Cannot take step from split node { self .id } : { shorten_hashes (node .id )} ' )
321
332
_LOGGER .info (f'Taking { depth } steps from node { self .id } : { shorten_hashes (node .id )} ' )
322
- _ , _ , actual_depth , cterm , next_cterms , next_node_logs = self .cterm_execute (
323
- node .cterm , depth = depth , module_name = module_name
324
- )
325
- if actual_depth != depth :
326
- raise ValueError (f'Unable to take { depth } steps from node, got { actual_depth } steps { self .id } : { node .id } ' )
327
- if len (next_cterms ) > 0 :
333
+ exec_res = self .cterm_execute (node .cterm , depth = depth , module_name = module_name )
334
+ if exec_res .depth != depth :
335
+ raise ValueError (f'Unable to take { depth } steps from node, got { exec_res .depth } steps { self .id } : { node .id } ' )
336
+ if len (exec_res .next_states ) > 0 :
328
337
raise ValueError (f'Found branch within { depth } steps { self .id } : { node .id } ' )
329
- new_node = cfg .create_node (cterm )
338
+ new_node = cfg .create_node (exec_res . state )
330
339
_LOGGER .info (f'Found new node at depth { depth } { self .id } : { shorten_hashes ((node .id , new_node .id ))} ' )
331
- logs [new_node .id ] = next_node_logs
340
+ logs [new_node .id ] = exec_res . logs
332
341
out_edges = cfg .edges (source_id = node .id )
333
342
if len (out_edges ) == 0 :
334
343
cfg .create_edge (node .id , new_node .id , depth = depth )
@@ -424,7 +433,7 @@ def extend_cterm(
424
433
if len (branches ) > 1 :
425
434
return Branch (branches , heuristic = True )
426
435
427
- unknown_predicate , _is_vacuous , depth , cterm , next_cterms , next_node_logs = self .cterm_execute (
436
+ cterm , unknown_predicate , next_cterms , depth , vacuous , next_node_logs = self .cterm_execute (
428
437
_cterm ,
429
438
depth = execute_depth ,
430
439
cut_point_rules = cut_point_rules ,
@@ -438,7 +447,7 @@ def extend_cterm(
438
447
439
448
# Stuck, Vacuous or Undecided
440
449
if not next_cterms :
441
- if _is_vacuous :
450
+ if vacuous :
442
451
return Vacuous ()
443
452
if unknown_predicate is not None :
444
453
return Undecided (unknown_predicate )
0 commit comments