shrinkray 25.12.27.1__tar.gz → 25.12.27.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {shrinkray-25.12.27.1/src/shrinkray.egg-info → shrinkray-25.12.27.3}/PKG-INFO +1 -28
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/README.md +0 -27
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/pyproject.toml +1 -1
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/__main__.py +25 -11
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/bytes.py +8 -7
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/definitions.py +3 -67
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/genericlanguages.py +14 -10
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/json.py +2 -2
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/sat.py +2 -7
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/problem.py +257 -11
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/reducer.py +9 -2
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/state.py +199 -67
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/client.py +2 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/protocol.py +8 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/worker.py +67 -17
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/tui.py +114 -92
- shrinkray-25.12.27.3/src/shrinkray/validation.py +403 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3/src/shrinkray.egg-info}/PKG-INFO +1 -28
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/SOURCES.txt +3 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_byte_reduction_passes.py +44 -2
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_definitions.py +2 -2
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_dimacs_cnf.py +1 -1
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_generic_language.py +3 -4
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_json_passes.py +1 -2
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_main.py +40 -35
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_misc_reduction_performance.py +1 -1
- shrinkray-25.12.27.3/tests/test_natural_sort_orders.py +547 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_problem.py +10 -17
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_reducer.py +29 -5
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_reduction_passes.py +33 -7
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_sat.py +8 -5
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_state.py +264 -7
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_worker.py +98 -1
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_tui.py +158 -155
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_tui_snapshots.py +108 -0
- shrinkray-25.12.27.3/tests/test_validation.py +1131 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/LICENSE +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/setup.cfg +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/__init__.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/cli.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/display.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/formatting.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/__init__.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/clangdelta.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/patching.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/python.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/passes/sequences.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/process.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/py.typed +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/subprocess/__init__.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/ui.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray/work.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/dependency_links.txt +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/entry_points.txt +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/requires.txt +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/src/shrinkray.egg-info/top_level.txt +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_clang_delta.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_cli.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_display.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_formatting.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_generic_shrinking_properties.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_patching.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_process.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_python_reducers.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_client.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_integration.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_subprocess_protocol.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_ui.py +0 -0
- {shrinkray-25.12.27.1 → shrinkray-25.12.27.3}/tests/test_work.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: shrinkray
|
|
3
|
-
Version: 25.12.27.
|
|
3
|
+
Version: 25.12.27.3
|
|
4
4
|
Summary: Shrink Ray
|
|
5
5
|
Author-email: "David R. MacIver" <david@drmaciver.com>
|
|
6
6
|
License: MIT
|
|
@@ -159,30 +159,3 @@ not to handle well, but it's easy to extend with additional transformations.
|
|
|
159
159
|
It is also fairly easy to add support for new formats as needed.
|
|
160
160
|
|
|
161
161
|
If you run into a test case and interestingness test that you care about that shrink ray handles badly please let me know and I'll likely see about improving its handling of that format.
|
|
162
|
-
|
|
163
|
-
## Parallelism
|
|
164
|
-
|
|
165
|
-
You can control the number of parallel tasks shrinkray will run with the `--parallelism` flag. By default this will be the number of CPU cores you have available
|
|
166
|
-
|
|
167
|
-
Shrink Ray is designed to be able to run heavily in parallel, with a basic heuristic of aiming to be embarrassingly parallel when making no progress, mostly sequential when making progress, and smoothly scaling in between the two. It mostly succeeds at this.
|
|
168
|
-
|
|
169
|
-
Currently the bottleneck on scaling to a very large number of cores is how fast the controlling Python program can generate variant test cases to try and pass them to the interestingness test. This isn't well optimised at present and I don't currently have good benchmarks for it, but I'd expect you to be able to get linear speedups on most workflows while running 10-20 test cases in parallel, and to start to struggle past that.
|
|
170
|
-
|
|
171
|
-
This also depends on the performance of the interestingness test - the slower your test is to run, the more you'll be able to scale linearly with the number of cores available.
|
|
172
|
-
|
|
173
|
-
I'm quite interested in getting this part to scale well, so please let me know if you find examples where it doesn't seem to work.
|
|
174
|
-
|
|
175
|
-
## Bug Reports
|
|
176
|
-
|
|
177
|
-
Shrink Ray is still pretty new and under-tested software, so it definitely has bugs. If you run into any, [please file an issue](https://github.com/DRMacIver/shrinkray/issues).
|
|
178
|
-
|
|
179
|
-
As well as obvious bugs (crashes, etc) I'm also very interested in hearing about usability issues and cases where the reduced test case isn't very good.
|
|
180
|
-
|
|
181
|
-
Requests for new features, new supported formats, etc. also welcome although I'm less likely to jump right on them.
|
|
182
|
-
|
|
183
|
-
## Sponsorship
|
|
184
|
-
|
|
185
|
-
Shrink Ray is something of a labour of love - I wanted to have a tool that actually put into practice many of my ideas about test-case reduction, as I think the previous state of the art was well behind where I'd like it to be.
|
|
186
|
-
|
|
187
|
-
That being said, it is first and foremost designed to be a useful tool for practical engineering problems.
|
|
188
|
-
If you find it useful as such, please [consider sponsoring my development of it](https://github.com/sponsors/DRMacIver).
|
|
@@ -119,30 +119,3 @@ not to handle well, but it's easy to extend with additional transformations.
|
|
|
119
119
|
It is also fairly easy to add support for new formats as needed.
|
|
120
120
|
|
|
121
121
|
If you run into a test case and interestingness test that you care about that shrink ray handles badly please let me know and I'll likely see about improving its handling of that format.
|
|
122
|
-
|
|
123
|
-
## Parallelism
|
|
124
|
-
|
|
125
|
-
You can control the number of parallel tasks shrinkray will run with the `--parallelism` flag. By default this will be the number of CPU cores you have available
|
|
126
|
-
|
|
127
|
-
Shrink Ray is designed to be able to run heavily in parallel, with a basic heuristic of aiming to be embarrassingly parallel when making no progress, mostly sequential when making progress, and smoothly scaling in between the two. It mostly succeeds at this.
|
|
128
|
-
|
|
129
|
-
Currently the bottleneck on scaling to a very large number of cores is how fast the controlling Python program can generate variant test cases to try and pass them to the interestingness test. This isn't well optimised at present and I don't currently have good benchmarks for it, but I'd expect you to be able to get linear speedups on most workflows while running 10-20 test cases in parallel, and to start to struggle past that.
|
|
130
|
-
|
|
131
|
-
This also depends on the performance of the interestingness test - the slower your test is to run, the more you'll be able to scale linearly with the number of cores available.
|
|
132
|
-
|
|
133
|
-
I'm quite interested in getting this part to scale well, so please let me know if you find examples where it doesn't seem to work.
|
|
134
|
-
|
|
135
|
-
## Bug Reports
|
|
136
|
-
|
|
137
|
-
Shrink Ray is still pretty new and under-tested software, so it definitely has bugs. If you run into any, [please file an issue](https://github.com/DRMacIver/shrinkray/issues).
|
|
138
|
-
|
|
139
|
-
As well as obvious bugs (crashes, etc) I'm also very interested in hearing about usability issues and cases where the reduced test case isn't very good.
|
|
140
|
-
|
|
141
|
-
Requests for new features, new supported formats, etc. also welcome although I'm less likely to jump right on them.
|
|
142
|
-
|
|
143
|
-
## Sponsorship
|
|
144
|
-
|
|
145
|
-
Shrink Ray is something of a labour of love - I wanted to have a tool that actually put into practice many of my ideas about test-case reduction, as I think the previous state of the art was well behind where I'd like it to be.
|
|
146
|
-
|
|
147
|
-
That being said, it is first and foremost designed to be a useful tool for practical engineering problems.
|
|
148
|
-
If you find it useful as such, please [consider sponsoring my development of it](https://github.com/sponsors/DRMacIver).
|
|
@@ -17,18 +17,19 @@ from shrinkray.cli import (
|
|
|
17
17
|
validate_command,
|
|
18
18
|
validate_ui,
|
|
19
19
|
)
|
|
20
|
+
from shrinkray.formatting import determine_formatter_command
|
|
20
21
|
from shrinkray.passes.clangdelta import (
|
|
21
22
|
C_FILE_EXTENSIONS,
|
|
22
23
|
ClangDelta,
|
|
23
24
|
find_clang_delta,
|
|
24
25
|
)
|
|
25
|
-
from shrinkray.problem import InvalidInitialExample
|
|
26
26
|
from shrinkray.state import (
|
|
27
27
|
ShrinkRayDirectoryState,
|
|
28
28
|
ShrinkRayState,
|
|
29
29
|
ShrinkRayStateSingleFile,
|
|
30
30
|
)
|
|
31
31
|
from shrinkray.ui import BasicUI, ShrinkRayUI
|
|
32
|
+
from shrinkray.validation import run_validation
|
|
32
33
|
from shrinkray.work import Volume
|
|
33
34
|
|
|
34
35
|
|
|
@@ -39,12 +40,9 @@ async def run_shrink_ray(
|
|
|
39
40
|
"""Run the shrink ray reduction process."""
|
|
40
41
|
async with trio.open_nursery() as nursery:
|
|
41
42
|
problem = state.problem
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
assert len(excs.exceptions) == 1
|
|
46
|
-
(e,) = excs.exceptions
|
|
47
|
-
await state.report_error(e)
|
|
43
|
+
# Validation runs before run_shrink_ray is called, so setup() should
|
|
44
|
+
# always succeed. If it doesn't, there's a bug and we want it to propagate.
|
|
45
|
+
await problem.setup()
|
|
48
46
|
|
|
49
47
|
reducer = state.reducer
|
|
50
48
|
|
|
@@ -273,6 +271,26 @@ def main(
|
|
|
273
271
|
if not backup:
|
|
274
272
|
backup = filename + os.extsep + "bak"
|
|
275
273
|
|
|
274
|
+
# Run initial validation before any state setup
|
|
275
|
+
# This validates the interestingness test and formatter with proper output streaming
|
|
276
|
+
formatter_command = None
|
|
277
|
+
if not os.path.isdir(filename) and formatter.lower() != "none":
|
|
278
|
+
formatter_command = determine_formatter_command(formatter, filename)
|
|
279
|
+
|
|
280
|
+
validation_result = run_validation(
|
|
281
|
+
file_path=filename,
|
|
282
|
+
test=test,
|
|
283
|
+
input_type=input_type,
|
|
284
|
+
in_place=in_place,
|
|
285
|
+
formatter_command=formatter_command,
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
if not validation_result.success:
|
|
289
|
+
print(f"\nError: {validation_result.error_message}", file=sys.stderr)
|
|
290
|
+
sys.exit(1)
|
|
291
|
+
|
|
292
|
+
print("\nStarting reduction...", file=sys.stderr, flush=True)
|
|
293
|
+
|
|
276
294
|
state_kwargs: dict[str, Any] = {
|
|
277
295
|
"input_type": input_type,
|
|
278
296
|
"in_place": in_place,
|
|
@@ -307,8 +325,6 @@ def main(
|
|
|
307
325
|
|
|
308
326
|
state = ShrinkRayDirectoryState(initial=initial, **state_kwargs)
|
|
309
327
|
|
|
310
|
-
trio.run(state.check_formatter)
|
|
311
|
-
|
|
312
328
|
else:
|
|
313
329
|
try:
|
|
314
330
|
os.remove(backup)
|
|
@@ -323,8 +339,6 @@ def main(
|
|
|
323
339
|
|
|
324
340
|
state = ShrinkRayStateSingleFile(initial=initial, **state_kwargs)
|
|
325
341
|
|
|
326
|
-
trio.run(state.check_formatter)
|
|
327
|
-
|
|
328
342
|
if ui_type == UIType.textual:
|
|
329
343
|
from shrinkray.tui import run_textual_ui
|
|
330
344
|
|
|
@@ -24,8 +24,8 @@ from collections.abc import Sequence
|
|
|
24
24
|
|
|
25
25
|
from attrs import define
|
|
26
26
|
|
|
27
|
-
from shrinkray.passes.definitions import Format, ReductionProblem
|
|
28
27
|
from shrinkray.passes.patching import Cuts, Patches, apply_patches
|
|
28
|
+
from shrinkray.problem import Format, ReductionProblem
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
@define(frozen=True)
|
|
@@ -739,12 +739,13 @@ async def line_sorter(problem: ReductionProblem[bytes]):
|
|
|
739
739
|
while i < len(lines):
|
|
740
740
|
j = i
|
|
741
741
|
while j > 0:
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
742
|
+
attempt = list(lines)
|
|
743
|
+
attempt[j - 1], attempt[j] = attempt[j], attempt[j - 1]
|
|
744
|
+
new_test_case = b"\n".join(attempt)
|
|
745
|
+
if problem.sort_key(new_test_case) < problem.sort_key(
|
|
746
|
+
problem.current_test_case
|
|
747
|
+
):
|
|
748
|
+
if not await problem.is_interesting(new_test_case):
|
|
748
749
|
break
|
|
749
750
|
else:
|
|
750
751
|
j -= 1
|
|
@@ -4,20 +4,20 @@ This module defines the core type aliases and abstractions for reduction:
|
|
|
4
4
|
|
|
5
5
|
- ReductionPass[T]: A function that attempts to reduce a test case
|
|
6
6
|
- ReductionPump[T]: A function that may temporarily increase test case size
|
|
7
|
-
- Format[S, T]: A bidirectional transformation between types
|
|
8
7
|
- compose(): Combines a Format with a pass to work on a different type
|
|
9
8
|
|
|
10
9
|
These abstractions enable format-agnostic reduction: the same pass
|
|
11
10
|
(e.g., "delete duplicate elements") can work on bytes, lines, tokens,
|
|
12
11
|
JSON arrays, or any other sequence-like type.
|
|
12
|
+
|
|
13
|
+
Note: Format, ParseError, and DumpError are defined in shrinkray.problem.
|
|
13
14
|
"""
|
|
14
15
|
|
|
15
|
-
from abc import ABC, abstractmethod
|
|
16
16
|
from collections.abc import Awaitable, Callable
|
|
17
17
|
from functools import wraps
|
|
18
18
|
from typing import TypeVar
|
|
19
19
|
|
|
20
|
-
from shrinkray.problem import ReductionProblem
|
|
20
|
+
from shrinkray.problem import Format, ParseError, ReductionProblem
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
S = TypeVar("S")
|
|
@@ -36,70 +36,6 @@ ReductionPass = Callable[[ReductionProblem[T]], Awaitable[None]]
|
|
|
36
36
|
ReductionPump = Callable[[ReductionProblem[T]], Awaitable[T]]
|
|
37
37
|
|
|
38
38
|
|
|
39
|
-
class ParseError(Exception):
|
|
40
|
-
"""Raised when a Format cannot parse its input."""
|
|
41
|
-
|
|
42
|
-
pass
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class DumpError(Exception):
|
|
46
|
-
"""Raised when a Format cannot serialize its output.
|
|
47
|
-
|
|
48
|
-
This occurs because not all internal representations map to valid
|
|
49
|
-
output in the target format. For example, a reduction might create
|
|
50
|
-
an invalid AST structure that cannot be converted back to source code.
|
|
51
|
-
"""
|
|
52
|
-
|
|
53
|
-
pass
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class Format[S, T](ABC):
|
|
57
|
-
"""A bidirectional transformation between two types.
|
|
58
|
-
|
|
59
|
-
Formats enable format-agnostic passes by abstracting the
|
|
60
|
-
parse/serialize cycle. For example:
|
|
61
|
-
|
|
62
|
-
- Split(b"\\n"): bytes <-> list[bytes] (lines)
|
|
63
|
-
- Tokenize(): bytes <-> list[bytes] (tokens)
|
|
64
|
-
- JSON: bytes <-> Any (Python objects)
|
|
65
|
-
- DimacsCNF: bytes <-> list[list[int]] (SAT clauses)
|
|
66
|
-
|
|
67
|
-
A Format must satisfy the round-trip property:
|
|
68
|
-
dumps(parse(x)) should be equivalent to x
|
|
69
|
-
(possibly with normalization)
|
|
70
|
-
|
|
71
|
-
Example usage:
|
|
72
|
-
# Delete duplicate lines
|
|
73
|
-
compose(Split(b"\\n"), delete_duplicates)
|
|
74
|
-
|
|
75
|
-
# Reduce integer literals in source code
|
|
76
|
-
compose(IntegerFormat(), reduce_integer)
|
|
77
|
-
"""
|
|
78
|
-
|
|
79
|
-
@property
|
|
80
|
-
def name(self) -> str:
|
|
81
|
-
"""Human-readable name for this format, used in pass names."""
|
|
82
|
-
return repr(self)
|
|
83
|
-
|
|
84
|
-
@abstractmethod
|
|
85
|
-
def parse(self, input: S) -> T:
|
|
86
|
-
"""Parse input into the target type. Raises ParseError on failure."""
|
|
87
|
-
...
|
|
88
|
-
|
|
89
|
-
def is_valid(self, input: S) -> bool:
|
|
90
|
-
"""Check if input can be parsed by this format."""
|
|
91
|
-
try:
|
|
92
|
-
self.parse(input)
|
|
93
|
-
return True
|
|
94
|
-
except ParseError:
|
|
95
|
-
return False
|
|
96
|
-
|
|
97
|
-
@abstractmethod
|
|
98
|
-
def dumps(self, input: T) -> S:
|
|
99
|
-
"""Serialize the target type back to the source type."""
|
|
100
|
-
...
|
|
101
|
-
|
|
102
|
-
|
|
103
39
|
def compose(format: Format[S, T], reduction_pass: ReductionPass[T]) -> ReductionPass[S]:
|
|
104
40
|
"""Wrap a reduction pass to work through a Format transformation.
|
|
105
41
|
|
|
@@ -3,7 +3,7 @@ Module of reduction passes designed for "things that look like programming langu
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import re
|
|
6
|
-
from collections.abc import Callable
|
|
6
|
+
from collections.abc import Callable
|
|
7
7
|
from functools import wraps
|
|
8
8
|
from string import ascii_lowercase, ascii_uppercase
|
|
9
9
|
from typing import AnyStr
|
|
@@ -12,9 +12,15 @@ import trio
|
|
|
12
12
|
from attr import define
|
|
13
13
|
|
|
14
14
|
from shrinkray.passes.bytes import ByteReplacement, delete_intervals
|
|
15
|
-
from shrinkray.passes.definitions import
|
|
15
|
+
from shrinkray.passes.definitions import ReductionPass
|
|
16
16
|
from shrinkray.passes.patching import PatchApplier, Patches, apply_patches
|
|
17
|
-
from shrinkray.problem import
|
|
17
|
+
from shrinkray.problem import (
|
|
18
|
+
BasicReductionProblem,
|
|
19
|
+
Format,
|
|
20
|
+
ParseError,
|
|
21
|
+
ReductionProblem,
|
|
22
|
+
sort_key_for_initial,
|
|
23
|
+
)
|
|
18
24
|
from shrinkray.work import NotFound
|
|
19
25
|
|
|
20
26
|
|
|
@@ -240,10 +246,6 @@ async def simplify_brackets(problem: ReductionProblem[bytes]) -> None:
|
|
|
240
246
|
IDENTIFIER = re.compile(rb"(\b[A-Za-z][A-Za-z0-9_]*\b)|([0-9]+)")
|
|
241
247
|
|
|
242
248
|
|
|
243
|
-
def shortlex[T: Sized](s: T) -> tuple[int, T]:
|
|
244
|
-
return (len(s), s)
|
|
245
|
-
|
|
246
|
-
|
|
247
249
|
async def normalize_identifiers(problem: ReductionProblem[bytes]) -> None:
|
|
248
250
|
"""Replace identifiers with shorter alternatives.
|
|
249
251
|
|
|
@@ -261,8 +263,10 @@ async def normalize_identifiers(problem: ReductionProblem[bytes]) -> None:
|
|
|
261
263
|
replacements.add(c)
|
|
262
264
|
break
|
|
263
265
|
|
|
264
|
-
|
|
265
|
-
|
|
266
|
+
sort_key = sort_key_for_initial(problem.current_test_case)
|
|
267
|
+
|
|
268
|
+
replacements = sorted(replacements, key=sort_key)
|
|
269
|
+
targets = sorted(identifiers, key=sort_key, reverse=True)
|
|
266
270
|
|
|
267
271
|
# TODO: This could use better parallelisation.
|
|
268
272
|
for t in targets:
|
|
@@ -272,7 +276,7 @@ async def normalize_identifiers(problem: ReductionProblem[bytes]) -> None:
|
|
|
272
276
|
continue
|
|
273
277
|
|
|
274
278
|
async def can_replace(r):
|
|
275
|
-
if
|
|
279
|
+
if sort_key(r) >= sort_key(t):
|
|
276
280
|
return False
|
|
277
281
|
attempt = pattern.sub(r, source)
|
|
278
282
|
assert attempt != source
|
|
@@ -4,9 +4,9 @@ from typing import Any
|
|
|
4
4
|
|
|
5
5
|
from attrs import define
|
|
6
6
|
|
|
7
|
-
from shrinkray.passes.definitions import
|
|
7
|
+
from shrinkray.passes.definitions import ReductionPass
|
|
8
8
|
from shrinkray.passes.patching import Patches, apply_patches
|
|
9
|
-
from shrinkray.problem import ReductionProblem
|
|
9
|
+
from shrinkray.problem import Format, ParseError, ReductionProblem
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def is_json(s: bytes) -> bool:
|
|
@@ -1,15 +1,10 @@
|
|
|
1
1
|
from collections import Counter, defaultdict
|
|
2
2
|
from collections.abc import Callable, Iterable, Iterator
|
|
3
3
|
|
|
4
|
-
from shrinkray.passes.definitions import
|
|
5
|
-
DumpError,
|
|
6
|
-
Format,
|
|
7
|
-
ParseError,
|
|
8
|
-
ReductionPass,
|
|
9
|
-
)
|
|
4
|
+
from shrinkray.passes.definitions import ReductionPass
|
|
10
5
|
from shrinkray.passes.patching import Conflict, SetPatches, apply_patches
|
|
11
6
|
from shrinkray.passes.sequences import delete_elements
|
|
12
|
-
from shrinkray.problem import ReductionProblem
|
|
7
|
+
from shrinkray.problem import DumpError, Format, ParseError, ReductionProblem
|
|
13
8
|
|
|
14
9
|
|
|
15
10
|
Clause = list[int]
|