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
+ next_states : tuple [CTerm , ...]
53
+ depth : int
54
+ vacuous : bool
55
+ logs : tuple [LogEntry , ...]
56
+
57
+
50
58
class KCFGExplore :
51
59
kprint : KPrint
52
60
_kore_client : KoreClient
@@ -77,39 +85,39 @@ def cterm_execute(
77
85
cut_point_rules : Iterable [str ] | None = None ,
78
86
terminal_rules : Iterable [str ] | None = None ,
79
87
module_name : str | None = None ,
80
- ) -> tuple [ bool , int , CTerm , list [ CTerm ], tuple [ LogEntry , ...]] :
88
+ ) -> CTermExecute :
81
89
_LOGGER .debug (f'Executing: { cterm } ' )
82
90
kore = self .kprint .kast_to_kore (cterm .kast , GENERATED_TOP_CELL )
83
- er = self ._kore_client .execute (
91
+ response = self ._kore_client .execute (
84
92
kore ,
85
93
max_depth = depth ,
86
94
cut_point_rules = cut_point_rules ,
87
95
terminal_rules = terminal_rules ,
88
96
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 ,
97
+ log_successful_rewrites = self ._trace_rewrites ,
98
+ log_failed_rewrites = self ._trace_rewrites ,
99
+ log_successful_simplifications = self ._trace_rewrites ,
100
+ log_failed_simplifications = self ._trace_rewrites ,
93
101
)
94
102
95
- if isinstance (er , AbortedResult ):
96
- unknown_predicate = er .unknown_predicate .text if er .unknown_predicate else None
103
+ if isinstance (response , AbortedResult ):
104
+ unknown_predicate = response .unknown_predicate .text if response .unknown_predicate else None
97
105
raise ValueError (f'Backend responded with aborted state. Unknown predicate: { unknown_predicate } ' )
98
106
99
- _is_vacuous = er . reason is StopReason . VACUOUS
100
- depth = er . depth
101
- next_state = CTerm .from_kast (self .kprint .kore_to_kast (er . state . kore ))
102
- _next_states = er . next_states if er . next_states is not None else []
103
- next_states = [ CTerm . from_kast ( self . kprint . kore_to_kast ( ns . kore )) for ns in _next_states ]
104
- next_states = [ cterm for cterm in next_states if not cterm . is_bottom ]
105
- if len ( next_states ) == 1 and len ( next_states ) < len ( _next_states ):
106
- return _is_vacuous , depth + 1 , next_states [ 0 ], [], er . logs
107
- elif len ( next_states ) == 1 :
108
- if er . reason == StopReason . CUT_POINT_RULE :
109
- return _is_vacuous , depth , next_state , next_states , er . logs
110
- else :
111
- next_states = []
112
- return _is_vacuous , depth , next_state , next_states , er . logs
107
+ state = CTerm . from_kast ( self . kprint . kore_to_kast ( response . state . kore ))
108
+ resp_next_states = response . next_states or ()
109
+ next_states = tuple ( CTerm .from_kast (self .kprint .kore_to_kast (ns . kore )) for ns in resp_next_states )
110
+
111
+ assert all ( not cterm . is_bottom for cterm in next_states )
112
+ assert len ( next_states ) != 1 or response . reason is StopReason . CUT_POINT_RULE
113
+
114
+ return CTermExecute (
115
+ state = state ,
116
+ next_states = next_states ,
117
+ depth = response . depth ,
118
+ vacuous = response . reason is StopReason . VACUOUS ,
119
+ logs = response . logs ,
120
+ )
113
121
114
122
def cterm_simplify (self , cterm : CTerm ) -> tuple [CTerm , tuple [LogEntry , ...]]:
115
123
_LOGGER .debug (f'Simplifying: { cterm } ' )
@@ -302,16 +310,14 @@ def step(
302
310
if len (successors ) != 0 and type (successors [0 ]) is KCFG .Split :
303
311
raise ValueError (f'Cannot take step from split node { self .id } : { shorten_hashes (node .id )} ' )
304
312
_LOGGER .info (f'Taking { depth } steps from node { self .id } : { shorten_hashes (node .id )} ' )
305
- _ , actual_depth , cterm , next_cterms , next_node_logs = self .cterm_execute (
306
- node .cterm , depth = depth , module_name = module_name
307
- )
308
- if actual_depth != depth :
309
- raise ValueError (f'Unable to take { depth } steps from node, got { actual_depth } steps { self .id } : { node .id } ' )
310
- if len (next_cterms ) > 0 :
313
+ exec_res = self .cterm_execute (node .cterm , depth = depth , module_name = module_name )
314
+ if exec_res .depth != depth :
315
+ raise ValueError (f'Unable to take { depth } steps from node, got { exec_res .depth } steps { self .id } : { node .id } ' )
316
+ if len (exec_res .next_states ) > 0 :
311
317
raise ValueError (f'Found branch within { depth } steps { self .id } : { node .id } ' )
312
- new_node = cfg .create_node (cterm )
318
+ new_node = cfg .create_node (exec_res . state )
313
319
_LOGGER .info (f'Found new node at depth { depth } { self .id } : { shorten_hashes ((node .id , new_node .id ))} ' )
314
- logs [new_node .id ] = next_node_logs
320
+ logs [new_node .id ] = exec_res . logs
315
321
out_edges = cfg .edges (source_id = node .id )
316
322
if len (out_edges ) == 0 :
317
323
cfg .create_edge (node .id , new_node .id , depth = depth )
@@ -405,7 +411,7 @@ def extend_cterm(
405
411
if len (branches ) > 1 :
406
412
return Branch (branches , heuristic = True )
407
413
408
- _is_vacuous , depth , cterm , next_cterms , next_node_logs = self .cterm_execute (
414
+ cterm , next_cterms , depth , vacuous , next_node_logs = self .cterm_execute (
409
415
_cterm ,
410
416
depth = execute_depth ,
411
417
cut_point_rules = cut_point_rules ,
@@ -419,7 +425,7 @@ def extend_cterm(
419
425
420
426
# Stuck or vacuous
421
427
if not next_cterms :
422
- if _is_vacuous :
428
+ if vacuous :
423
429
return Vacuous ()
424
430
return Stuck ()
425
431
0 commit comments