Skip to content
This repository was archived by the owner on Apr 25, 2024. It is now read-only.

Commit 67cbf36

Browse files
committed
Merge remote-tracking branch 'origin/master' into georgy/prettier-unknown
2 parents 8d4bb89 + f9a2da5 commit 67cbf36

34 files changed

+982
-186
lines changed

deps/k_release

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
6.1.31
1+
6.1.52

package/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
0.1.519
1+
0.1.543

poetry.lock

Lines changed: 13 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
44

55
[tool.poetry]
66
name = "pyk"
7-
version = "0.1.519"
7+
version = "0.1.543"
88
description = ""
99
authors = [
1010
"Runtime Verification, Inc. <[email protected]>",
@@ -20,6 +20,7 @@ psutil = "5.9.5"
2020
pybind11 = "^2.10.3"
2121
textual = "^0.27.0"
2222
tomli = "^2.0.1"
23+
xdg-base-dirs = "^6.0.1"
2324

2425
[tool.poetry.group.dev.dependencies]
2526
autoflake = "*"
@@ -43,6 +44,7 @@ types-psutil = "^5.9.5.10"
4344
pyk = "pyk.__main__:main"
4445
pyk-covr = "pyk.kcovr:main"
4546
kbuild = "pyk.kbuild.__main__:main"
47+
kdist = "pyk.kdist.__main__:main"
4648
krepl = "pyk.krepl.__main__:main"
4749
kore-exec-covr = "pyk.kore_exec_covr.__main__:main"
4850

src/pyk/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@
66
from typing import Final
77

88

9-
K_VERSION: Final = '6.1.31'
9+
K_VERSION: Final = '6.1.52'

src/pyk/kcfg/explore.py

Lines changed: 42 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44
from abc import ABC
55
from dataclasses import dataclass, field
6-
from typing import TYPE_CHECKING, final
6+
from typing import TYPE_CHECKING, NamedTuple, final
77

88
from ..cterm import CSubst, CTerm
99
from ..kast.inner import KApply, KLabel, KRewrite, KVariable, Subst
@@ -47,6 +47,15 @@
4747
_LOGGER: Final = logging.getLogger(__name__)
4848

4949

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+
5059
class KCFGExplore:
5160
kprint: KPrint
5261
_kore_client: KoreClient
@@ -77,40 +86,42 @@ def cterm_execute(
7786
cut_point_rules: Iterable[str] | None = None,
7887
terminal_rules: Iterable[str] | None = None,
7988
module_name: str | None = None,
80-
) -> tuple[KInner | None, bool, int, CTerm, list[CTerm], tuple[LogEntry, ...]]:
89+
) -> CTermExecute:
8190
_LOGGER.debug(f'Executing: {cterm}')
8291
kore = self.kprint.kast_to_kore(cterm.kast, GENERATED_TOP_CELL)
83-
er = self._kore_client.execute(
92+
response = self._kore_client.execute(
8493
kore,
8594
max_depth=depth,
8695
cut_point_rules=cut_point_rules,
8796
terminal_rules=terminal_rules,
8897
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,
93102
)
94103

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 = []
108104
unknown_predicate = None
109-
if isinstance(er, AbortedResult):
105+
if isinstance(response, AbortedResult):
110106
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
112108
)
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+
)
114125

115126
def cterm_simplify(self, cterm: CTerm) -> tuple[KInner | None, CTerm, tuple[LogEntry, ...]]:
116127
_LOGGER.debug(f'Simplifying: {cterm}')
@@ -319,16 +330,14 @@ def step(
319330
if len(successors) != 0 and type(successors[0]) is KCFG.Split:
320331
raise ValueError(f'Cannot take step from split node {self.id}: {shorten_hashes(node.id)}')
321332
_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:
328337
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)
330339
_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
332341
out_edges = cfg.edges(source_id=node.id)
333342
if len(out_edges) == 0:
334343
cfg.create_edge(node.id, new_node.id, depth=depth)
@@ -424,7 +433,7 @@ def extend_cterm(
424433
if len(branches) > 1:
425434
return Branch(branches, heuristic=True)
426435

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(
428437
_cterm,
429438
depth=execute_depth,
430439
cut_point_rules=cut_point_rules,
@@ -438,7 +447,7 @@ def extend_cterm(
438447

439448
# Stuck, Vacuous or Undecided
440449
if not next_cterms:
441-
if _is_vacuous:
450+
if vacuous:
442451
return Vacuous()
443452
if unknown_predicate is not None:
444453
return Undecided(unknown_predicate)

src/pyk/kdist/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
from ._cache import target_ids
2+
from ._kdist import KDIST_DIR, KDist, kdist

src/pyk/kdist/__main__.py

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from __future__ import annotations
2+
3+
import fnmatch
4+
import logging
5+
from argparse import ArgumentParser
6+
from typing import TYPE_CHECKING
7+
8+
from pyk.cli.args import KCLIArgs
9+
from pyk.cli.utils import loglevel
10+
11+
from ..kdist import kdist, target_ids
12+
13+
if TYPE_CHECKING:
14+
from argparse import Namespace
15+
from typing import Final
16+
17+
18+
_LOGGER: Final = logging.getLogger(__name__)
19+
_LOG_FORMAT: Final = '%(levelname)s %(asctime)s %(name)s - %(message)s'
20+
21+
22+
def main() -> None:
23+
args = _parse_arguments()
24+
25+
logging.basicConfig(level=loglevel(args), format=_LOG_FORMAT)
26+
27+
if args.command == 'build':
28+
_exec_build(**vars(args))
29+
30+
elif args.command == 'clean':
31+
_exec_clean(args.target)
32+
33+
elif args.command == 'which':
34+
_exec_which(args.target)
35+
36+
elif args.command == 'list':
37+
_exec_list()
38+
39+
else:
40+
raise AssertionError()
41+
42+
43+
def _exec_build(
44+
command: str,
45+
targets: list[str],
46+
args: list[str],
47+
jobs: int,
48+
force: bool,
49+
verbose: bool,
50+
debug: bool,
51+
) -> None:
52+
kdist.build(
53+
target_ids=_process_targets(targets),
54+
args=_process_args(args),
55+
jobs=jobs,
56+
force=force,
57+
verbose=verbose or debug,
58+
)
59+
60+
61+
def _process_targets(targets: list[str]) -> list[str]:
62+
all_target_fqns = [target_id.full_name for target_id in target_ids()]
63+
res = []
64+
for pattern in targets:
65+
matches = fnmatch.filter(all_target_fqns, pattern)
66+
if not matches:
67+
raise ValueError(f'No target matches pattern: {pattern!r}')
68+
res += matches
69+
return res
70+
71+
72+
def _process_args(args: list[str]) -> dict[str, str]:
73+
res: dict[str, str] = {}
74+
for arg in args:
75+
segments = arg.split('=')
76+
if len(segments) < 2:
77+
raise ValueError(f"Expected assignment of the form 'arg=value', got: {arg!r}")
78+
key, *values = segments
79+
res[key] = '='.join(values)
80+
return res
81+
82+
83+
def _exec_clean(target: str | None) -> None:
84+
res = kdist.clean(target)
85+
print(res)
86+
87+
88+
def _exec_which(target: str | None) -> None:
89+
res = kdist.which(target)
90+
print(res)
91+
92+
93+
def _exec_list() -> None:
94+
targets_by_plugin: dict[str, list[str]] = {}
95+
for plugin_name, target_name in target_ids():
96+
targets = targets_by_plugin.get(plugin_name, [])
97+
targets.append(target_name)
98+
targets_by_plugin[plugin_name] = targets
99+
100+
for plugin_name in targets_by_plugin:
101+
print(plugin_name)
102+
for target_name in targets_by_plugin[plugin_name]:
103+
print(f'* {target_name}')
104+
105+
106+
def _parse_arguments() -> Namespace:
107+
def add_target_arg(parser: ArgumentParser, help_text: str) -> None:
108+
parser.add_argument(
109+
'target',
110+
metavar='TARGET',
111+
nargs='?',
112+
help=help_text,
113+
)
114+
115+
k_cli_args = KCLIArgs()
116+
117+
parser = ArgumentParser(prog='kdist', parents=[k_cli_args.logging_args])
118+
command_parser = parser.add_subparsers(dest='command', required=True)
119+
120+
build_parser = command_parser.add_parser('build', help='build targets')
121+
build_parser.add_argument('targets', metavar='TARGET', nargs='*', default='*', help='target to build')
122+
build_parser.add_argument(
123+
'-a',
124+
'--arg',
125+
dest='args',
126+
metavar='ARG',
127+
action='append',
128+
default=[],
129+
help='build with argument',
130+
)
131+
build_parser.add_argument('-f', '--force', action='store_true', default=False, help='force build')
132+
build_parser.add_argument('-j', '--jobs', metavar='N', type=int, default=1, help='maximal number of build jobs')
133+
134+
clean_parser = command_parser.add_parser('clean', help='clean targets')
135+
add_target_arg(clean_parser, 'target to clean')
136+
137+
which_parser = command_parser.add_parser('which', help='print target location')
138+
add_target_arg(which_parser, 'target to print directory for')
139+
140+
command_parser.add_parser('list', help='print list of available targets')
141+
142+
return parser.parse_args()
143+
144+
145+
if __name__ == '__main__':
146+
main()

0 commit comments

Comments
 (0)