Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 deletions pyk/src/pyk/kast/outer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
top_down,
)
from .kast import kast_term
from .prelude.k import K_ITEM, K
from .rewrite import indexed_rewrite

if TYPE_CHECKING:
Expand Down Expand Up @@ -1460,13 +1461,15 @@ def transform(
for t, a in zip(prod.argument_sorts, term.args, strict=True):
if type(a) is KVariable:
occurrences[a.name].append(a.let_sort(t))
elif isinstance(term, KSequence) and term.arity > 0:
for a in term.items[0:-1]:
if type(a) is KVariable:
occurrences[a.name].append(a.let_sort(KSort('KItem')))
last_a = term.items[-1]
if type(last_a) is KVariable:
occurrences[last_a.name].append(last_a.let_sort(KSort('K')))
elif isinstance(term, KSequence):
for i, item in enumerate(term.items):
if isinstance(item, KVariable):
if item.sort is not None:
occurrences[item.name].append(item)
elif i == term.arity - 1:
occurrences[item.name].append(item.let_sort(K))
else:
occurrences[item.name].append(item.let_sort(K_ITEM))
return (term, occurrences)

(new_term, var_occurrences) = bottom_up_with_summary(transform, kast)
Expand Down
32 changes: 18 additions & 14 deletions pyk/src/pyk/konvert/_kast_to_kore.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,41 +82,43 @@ def kast_to_kore(definition: KDefinition, kast: KInner, sort: KSort | None = Non
kast = definition.sort_vars(kast, sort)
kast = definition.add_cell_map_items(kast)
kast = definition.add_sort_params(kast)
kast = _replace_ksequence_by_kapply(kast)
kast = _replace_ksequence_by_kapply(definition, kast)
kast = _add_sort_injections(definition, kast, sort)
kore = _kast_to_kore(kast)
return kore


def _replace_ksequence_by_kapply(term: KInner) -> KInner:
def _replace_ksequence_by_kapply(definition: KDefinition, term: KInner) -> KInner:
dotk = KApply('dotk')
kseq = KLabel('kseq')
append = KLabel('append')

def transform(term: KInner) -> KInner:
match term:
case KSequence(items):
return transform_items(items)
case _:
return term
def kapply(x: KInner, y: KInner) -> KApply:
return append(x, y) if definition.sort_strict(x) == K else kseq(x, y)

def ksequence_to_kapply(term: KInner) -> KInner:
if not isinstance(term, KSequence):
return term

items = term.items

def transform_items(items: tuple[KInner, ...]) -> KInner:
if not items:
return dotk

unit: KInner
args: tuple[KInner, ...]

last = items[-1]
if isinstance(last, KVariable) and last.sort == K:
if definition.sort_strict(last) == K:
unit = last
args = items[:-1]
else:
unit = dotk
args = items

return reduce(lambda x, y: kseq(y, x), reversed(args), unit)
return reduce(lambda x, y: kapply(y, x), reversed(args), unit)

return top_down(transform, term)
return top_down(ksequence_to_kapply, term)


def _add_sort_injections(definition: KDefinition, term: KInner, sort: KSort) -> KInner:
Expand Down Expand Up @@ -179,6 +181,8 @@ def _argument_sorts(definition: KDefinition, term: KInner) -> tuple[KSort, ...]:
return (K_ITEM, K)
case 'dotk':
return ()
case 'append':
return (K, K)
case '#Forall' | '#Exists':
_, argument_sorts = definition.resolve_sorts(term.label)
_, argument_sort = argument_sorts
Expand All @@ -202,7 +206,7 @@ def _let_arguments(term: KInner, args: list[KInner]) -> KInner:
def _inject(definition: KDefinition, term: KInner, sort: KSort) -> KInner:
actual_sort: KSort
match term:
case KApply(KLabel('kseq' | 'dotk')): # Special case: pseudo-labels
case KApply(KLabel('kseq' | 'dotk' | 'append')): # Special case: pseudo-labels
actual_sort = K
case _:
actual_sort = definition.sort_strict(term)
Expand Down Expand Up @@ -437,7 +441,7 @@ def _kapply_to_pattern(kapply: KApply, patterns: list[Pattern]) -> Pattern:


def _label_to_kore(label: str) -> str:
if label in ['inj', 'kseq', 'dotk']: # pseudo-labels introduced during KAST-to-KORE tranformation
if label in ['inj', 'kseq', 'dotk', 'append']: # pseudo-labels introduced during KAST-to-KORE tranformation
return label

if label in ML_PATTERN_LABELS:
Expand Down
4 changes: 4 additions & 0 deletions pyk/src/pyk/konvert/_kore_to_kast.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,10 @@ def _pattern_to_kast(pattern: Pattern, terms: list[KInner]) -> KInner:
_, _ = terms
return KSequence(terms)

elif symbol == 'append':
_, _ = terms
return KSequence(terms)

else:
klabel = KLabel(unmunge(symbol[3:]))
return KApply(klabel, terms)
Expand Down
65 changes: 59 additions & 6 deletions pyk/src/tests/integration/konvert/test_simple_proofs.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,59 @@
""",
KSequence([KApply('foo_SIMPLE-PROOFS_KItem'), KApply('foo-bar_SIMPLE-PROOFS_Baz')]),
),
(
'kseq-with-k-head',
KSort('K'),
r'append{}(VarX : SortK{}, kseq{}(inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("1")), dotk{}()))',
KSequence(KVariable('X', 'K'), intToken(1)),
),
(
'kseq-with-k-middle',
KSort('K'),
r"""
kseq{}(
inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("1")),
append{}(
VarX : SortK{},
kseq{}(
inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("2")),
dotk{}()
)
)
)
""",
KSequence(intToken(1), KVariable('X', 'K'), intToken(2)),
),
(
'kseq-with-multiple-ks',
KSort('K'),
r"""
kseq{}(
inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("1")),
append{}(
VarX1 : SortK{},
append{}(
VarX2 : SortK{},
append{}(
VarX3 : SortK{},
kseq{}(
inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("2")),
VarX4 : SortK{}
)
)
)
)
)
""",
KSequence(
intToken(1),
KVariable('X1', 'K'),
KVariable('X2', 'K'),
KVariable('X3', 'K'),
intToken(2),
KVariable('X4', 'K'),
),
),
(
'if-then-else',
KSort('K'),
Expand Down Expand Up @@ -699,20 +752,20 @@ def test_kast_to_kore(
kast: KInner,
) -> None:
# Given
kore = KoreParser(kore_text).pattern()
expected_kore = KoreParser(kore_text).pattern()

# When
actual_kore = kast_to_kore(definition, kast, sort=sort)

# Then
assert actual_kore == kore
assert actual_kore == expected_kore

@pytest.mark.parametrize(
'test_id,sort,kore_text,kast',
KAST_TO_KORE_TEST_DATA,
ids=[test_id for test_id, *_ in KAST_TO_KORE_TEST_DATA],
)
def test_kast_to_kore_frontend_comp(
def test_kast_to_kore_frontend(
self,
definition: KDefinition,
test_id: str,
Expand All @@ -725,13 +778,13 @@ def test_kast_to_kore_frontend_comp(
pytest.skip()

# Given
frontend_kore = kprint.kast_to_kore(kast=kast, sort=sort, force_kast=True)
expected_kore = KoreParser(kore_text).pattern()

# When
actual_kore = kast_to_kore(definition, kast, sort=sort)
actual_kore = kprint.kast_to_kore(kast=kast, sort=sort, force_kast=True)

# Then
assert actual_kore == frontend_kore
assert actual_kore == expected_kore

@pytest.mark.parametrize(
'test_id,_sort,kore_text,kast',
Expand Down
3 changes: 3 additions & 0 deletions pyk/src/tests/integration/test-data/frontend-comp-skip
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ if-then-else-no-sort-param-k
kseq-empty
kseq-singleton
kseq-two-element
kseq-with-k-head
kseq-with-k-middle
kseq-with-multiple-ks
Comment on lines +7 to +9
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, these need to be excluded from kast tests (similarly to other KSequence tests), because for some reason when converting from json to kore, the result is wrapped in an inj into SortKItem:

% kast --definition /tmp/pytest-of-ttoth/pytest-current/kompiled0/simple-proofs-llvm-0 --input json --output kore --expression '{"format": "KAST", "version": 3, "term": {"node": "KSequence", "items": [{"node": "KToken", "token": "1", "sort": {"node": "KSort", "name": "Int"}}, {"node": "KVariable", "name": "X1", "sort": {"node": "KSort", "name": "K"}}, {"node": "KVariable", "name": "X2", "sort": {"node": "KSort", "name": "K"}}, {"node": "KVariable", "name": "X3", "sort": {"node": "KSort", "name": "K"}}, {"node": "KToken", "token": "2", "sort": {"node": "KSort", "name": "Int"}}, {"node": "KVariable", "name": "X4", "sort": {"node": "KSort", "name": "K"}}], "arity": 6}}' --sort K
inj{SortK{}, SortKItem{}}(kseq{}(inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("1")),append{}(VarX1:SortK{},append{}(VarX2:SortK{},append{}(VarX3:SortK{},kseq{}(inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("2")),VarX4:SortK{}))))))

Funnily enough, kast is happy to inject the result into any sort (including undefined ones), except for K:

% kast --definition /tmp/pytest-of-ttoth/pytest-current/kompiled0/simple-proofs-llvm-0 --input json --output kore --expression '{"format": "KAST", "version": 3, "term": "..."}' --sort Whatever
inj{SortK{}, SortWhatever{}}(...)

For conversion from rule syntax, kast works as expected:

$ kast --definition /tmp/pytest-of-ttoth/pytest-current/kompiled0/simple-proofs-llvm-0 --input rule --output kore --expression '1 ~> X1:K ~> X2:K ~> X3:K ~> 2 ~> X4:K' --sort K
kseq{}(inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("1")),append{}(VarX1:SortK{},append{}(VarX2:SortK{},append{}(VarX3:SortK{},kseq{}(inj{SortInt{}, SortKItem{}}(\dv{SortInt{}}("2")),VarX4:SortK{})))))%

ksequence-duo-var-1
ksequence-duo-var-2
ksequence-empty
Expand Down
Loading