|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import logging |
| 4 | +from functools import reduce |
| 5 | +from typing import TYPE_CHECKING |
| 6 | + |
| 7 | +from ..cterm import CTerm |
| 8 | +from ..kast.inner import KApply, KSequence, KSort, KToken, KVariable |
| 9 | +from ..kast.manip import bool_to_ml_pred, extract_lhs, extract_rhs |
| 10 | +from ..kast.outer import KRule |
| 11 | +from ..kore.prelude import DOTK, SORT_K |
| 12 | +from ..kore.syntax import DV, And, App, Axiom, EVar, Import, MLPattern, MLQuant, Module, Rewrites, SortApp, String, Top |
| 13 | +from ..prelude.bytes import BYTES, pretty_bytes_str |
| 14 | +from ..prelude.k import K |
| 15 | +from ..prelude.string import STRING, pretty_string |
| 16 | +from ._utils import munge |
| 17 | + |
| 18 | +if TYPE_CHECKING: |
| 19 | + from typing import Final |
| 20 | + |
| 21 | + from ..kast import KInner |
| 22 | + from ..kast.outer import KDefinition, KFlatModule, KImport |
| 23 | + from ..kore.kompiled import KompiledKore |
| 24 | + from ..kore.syntax import Pattern, Sentence, Sort |
| 25 | + |
| 26 | +_LOGGER: Final = logging.getLogger(__name__) |
| 27 | + |
| 28 | + |
| 29 | +ML_CONN_LABELS: Final = { |
| 30 | + '#Top': r'\top', |
| 31 | + '#Bottom': r'\bottom', |
| 32 | + '#Not': r'\not', |
| 33 | + '#And': r'\and', |
| 34 | + '#Or': r'\or', |
| 35 | + '#Implies': r'\implies', |
| 36 | + '#Iff': r'\iff', |
| 37 | +} |
| 38 | + |
| 39 | +ML_QUANT_LABELS: Final = { |
| 40 | + '#Exists': r'\exists', |
| 41 | + '#Forall': r'\forall', |
| 42 | +} |
| 43 | + |
| 44 | +ML_PRED_LABELS: Final = { |
| 45 | + '#Ceil': r'\ceil', |
| 46 | + '#Floor': r'\floor', |
| 47 | + '#Equals': r'\equals', |
| 48 | + '#In': r'\in', |
| 49 | +} |
| 50 | + |
| 51 | +ML_PATTERN_LABELS: Final = dict( |
| 52 | + **ML_CONN_LABELS, |
| 53 | + **ML_QUANT_LABELS, |
| 54 | + **ML_PRED_LABELS, |
| 55 | +) |
| 56 | + |
| 57 | + |
| 58 | +def kast_to_kore( |
| 59 | + kast_defn: KDefinition, |
| 60 | + kompiled_kore: KompiledKore, |
| 61 | + kast: KInner, |
| 62 | + sort: KSort | None = None, |
| 63 | +) -> Pattern: |
| 64 | + if sort is None: |
| 65 | + sort = K |
| 66 | + kast = kast_defn.add_ksequence_under_k_productions(kast) |
| 67 | + kast = kast_defn.sort_vars(kast, sort) |
| 68 | + kast = kast_defn.add_cell_map_items(kast) |
| 69 | + kast = kast_defn.add_sort_params(kast) |
| 70 | + kore = _kast_to_kore(kast) |
| 71 | + kore = kompiled_kore.add_injections(kore, _ksort_to_kore(sort)) |
| 72 | + return kore |
| 73 | + |
| 74 | + |
| 75 | +# 'krule' should have sorts on variables |
| 76 | +def krule_to_kore(kast_defn: KDefinition, kompiled_kore: KompiledKore, krule: KRule) -> Axiom: |
| 77 | + krule_body = krule.body |
| 78 | + krule_lhs = CTerm(extract_lhs(krule_body), [bool_to_ml_pred(krule.requires)]) |
| 79 | + krule_rhs = CTerm(extract_rhs(krule_body), [bool_to_ml_pred(krule.ensures)]) |
| 80 | + |
| 81 | + top_level_kore_sort = SortApp('SortGeneratedTopCell') |
| 82 | + top_level_k_sort = KSort('GeneratedTopCell') |
| 83 | + # The backend does not like rewrite rules without a precondition |
| 84 | + if len(krule_lhs.constraints) > 0: |
| 85 | + kore_lhs0: Pattern = kast_to_kore(kast_defn, kompiled_kore, krule_lhs.kast, sort=top_level_k_sort) |
| 86 | + else: |
| 87 | + kore_lhs0 = And( |
| 88 | + top_level_kore_sort, |
| 89 | + ( |
| 90 | + kast_to_kore(kast_defn, kompiled_kore, krule_lhs.kast, sort=top_level_k_sort), |
| 91 | + Top(top_level_kore_sort), |
| 92 | + ), |
| 93 | + ) |
| 94 | + |
| 95 | + kore_rhs0: Pattern = kast_to_kore(kast_defn, kompiled_kore, krule_rhs.kast, sort=top_level_k_sort) |
| 96 | + |
| 97 | + kore_lhs = kompiled_kore.add_injections(kore_lhs0, sort=top_level_kore_sort) |
| 98 | + kore_rhs = kompiled_kore.add_injections(kore_rhs0, sort=top_level_kore_sort) |
| 99 | + prio = krule.priority |
| 100 | + attrs = [App(symbol='priority', sorts=(), args=(String(str(prio)),))] |
| 101 | + if 'label' in krule.att: |
| 102 | + label = krule.att['label'] |
| 103 | + attrs.append(App(symbol='label', sorts=(), args=(String(label),))) |
| 104 | + axiom = Axiom( |
| 105 | + vars=(), |
| 106 | + pattern=Rewrites( |
| 107 | + sort=top_level_kore_sort, |
| 108 | + left=kore_lhs, |
| 109 | + right=kore_rhs, |
| 110 | + ), |
| 111 | + attrs=attrs, |
| 112 | + ) |
| 113 | + return axiom |
| 114 | + |
| 115 | + |
| 116 | +def kflatmodule_to_kore(kast_defn: KDefinition, kompiled_kore: KompiledKore, kflatmodule: KFlatModule) -> Module: |
| 117 | + kore_axioms: list[Sentence] = [] |
| 118 | + for sent in kflatmodule.sentences: |
| 119 | + if type(sent) is not KRule: |
| 120 | + raise ValueError(f'Cannot convert sentence to Kore: {sent}') |
| 121 | + kore_axioms.append(krule_to_kore(kast_defn, kompiled_kore, sent)) |
| 122 | + imports: list[Sentence] = [_kimport_to_kore(kimport) for kimport in kflatmodule.imports] |
| 123 | + return Module(name=kflatmodule.name, sentences=(imports + kore_axioms)) |
| 124 | + |
| 125 | + |
| 126 | +def _kimport_to_kore(kimport: KImport) -> Import: |
| 127 | + return Import(module_name=kimport.name, attrs=()) |
| 128 | + |
| 129 | + |
| 130 | +def _ksort_to_kore(ksort: KSort) -> SortApp: |
| 131 | + return SortApp('Sort' + ksort.name) |
| 132 | + |
| 133 | + |
| 134 | +def _kast_to_kore(term: KInner) -> Pattern: |
| 135 | + stack: list = [term, []] |
| 136 | + while True: |
| 137 | + patterns = stack[-1] |
| 138 | + term = stack[-2] |
| 139 | + idx = len(patterns) - len(term.terms) |
| 140 | + if not idx: |
| 141 | + stack.pop() |
| 142 | + stack.pop() |
| 143 | + pattern = _kinner_to_kore(term, patterns) |
| 144 | + if not stack: |
| 145 | + return pattern |
| 146 | + stack[-1].append(pattern) |
| 147 | + else: |
| 148 | + stack.append(term.terms[idx]) |
| 149 | + stack.append([]) |
| 150 | + |
| 151 | + |
| 152 | +def _kinner_to_kore(kinner: KInner, patterns: list[Pattern]) -> Pattern: |
| 153 | + match kinner: |
| 154 | + case KToken(): |
| 155 | + assert not patterns |
| 156 | + return _ktoken_to_kore(kinner) |
| 157 | + case KVariable(): |
| 158 | + assert not patterns |
| 159 | + return _kvariable_to_kore(kinner) |
| 160 | + case KSequence(): |
| 161 | + return _ksequence_to_kore(kinner, patterns) |
| 162 | + case KApply(): |
| 163 | + return _kapply_to_kore(kinner, patterns) |
| 164 | + case _: |
| 165 | + raise ValueError(f'Unsupported KInner: {kinner}') |
| 166 | + |
| 167 | + |
| 168 | +def _ktoken_to_kore(ktoken: KToken) -> DV: |
| 169 | + value: String |
| 170 | + if ktoken.sort == STRING: |
| 171 | + value = String(pretty_string(ktoken)) |
| 172 | + elif ktoken.sort == BYTES: |
| 173 | + value = String(pretty_bytes_str(ktoken)) |
| 174 | + else: |
| 175 | + value = String(ktoken.token) |
| 176 | + |
| 177 | + sort = _ksort_to_kore(ktoken.sort) |
| 178 | + |
| 179 | + return DV(sort, value) |
| 180 | + |
| 181 | + |
| 182 | +def _kvariable_to_kore(kvar: KVariable) -> EVar: |
| 183 | + sort: Sort |
| 184 | + if kvar.sort: |
| 185 | + sort = _ksort_to_kore(kvar.sort) |
| 186 | + else: |
| 187 | + sort = SORT_K |
| 188 | + return EVar('Var' + munge(kvar.name), sort) |
| 189 | + |
| 190 | + |
| 191 | +def _ksequence_to_kore(kseq: KSequence, patterns: list[Pattern]) -> Pattern: |
| 192 | + if not patterns: |
| 193 | + return DOTK |
| 194 | + |
| 195 | + unit: Pattern |
| 196 | + args: list[Pattern] |
| 197 | + |
| 198 | + last = patterns[-1] |
| 199 | + if type(last) is EVar and last.sort == SORT_K: |
| 200 | + unit = last |
| 201 | + args = patterns[:-1] |
| 202 | + else: |
| 203 | + unit = DOTK |
| 204 | + args = patterns |
| 205 | + |
| 206 | + args.reverse() |
| 207 | + return reduce(lambda x, y: App('kseq', (), (y, x)), args, unit) |
| 208 | + |
| 209 | + |
| 210 | +def _kapply_to_kore(kapply: KApply, patterns: list[Pattern]) -> Pattern: |
| 211 | + if kapply.label.name in ML_QUANT_LABELS: |
| 212 | + return _kapply_to_ml_quant(kapply, patterns) |
| 213 | + |
| 214 | + return _kapply_to_pattern(kapply, patterns) |
| 215 | + |
| 216 | + |
| 217 | +def _kapply_to_ml_quant(kapply: KApply, patterns: list[Pattern]) -> MLQuant: |
| 218 | + label = kapply.label |
| 219 | + symbol = ML_QUANT_LABELS[label.name] |
| 220 | + sorts = tuple(_ksort_to_kore(ksort) for ksort in label.params) |
| 221 | + return MLQuant.of(symbol, sorts, patterns) |
| 222 | + |
| 223 | + |
| 224 | +def _kapply_to_pattern(kapply: KApply, patterns: list[Pattern]) -> Pattern: |
| 225 | + label = kapply.label |
| 226 | + symbol = _label_to_kore(label.name) |
| 227 | + sorts = tuple(_ksort_to_kore(ksort) for ksort in label.params) |
| 228 | + |
| 229 | + if label.name in ML_PATTERN_LABELS: |
| 230 | + return MLPattern.of(symbol, sorts, patterns) |
| 231 | + |
| 232 | + return App(symbol, sorts, patterns) |
| 233 | + |
| 234 | + |
| 235 | +def _label_to_kore(label: str) -> str: |
| 236 | + if label in ML_PATTERN_LABELS: |
| 237 | + return ML_PATTERN_LABELS[label] |
| 238 | + |
| 239 | + return 'Lbl' + munge(label) |
0 commit comments