Skip to content

Commit eb46ee6

Browse files
authored
Merge pull request #93 from dflook/constants
Add simple constant folding
2 parents 22513c3 + 056ef3d commit eb46ee6

File tree

20 files changed

+454
-62
lines changed

20 files changed

+454
-62
lines changed

.github/workflows/test_corpus.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,13 @@ jobs:
7474
7575
- name: Run tests
7676
run: |
77+
if [[ "${{ matrix.python }}" == "python3.3" || "${{ matrix.python }}" == "python3.4" || "${{ matrix.python }}" == "python3.5" ]]; then
78+
# These versions randomise the hash seed, but don't preserve dict order
79+
# This affects how names are assigned. Disable the hash randomisation for
80+
# deterministic results.
81+
export PYTHONHASHSEED=0
82+
fi
83+
7784
${{matrix.python}} workflow/corpus_test/generate_results.py /corpus /corpus-results $(<sha.txt) ${{ inputs.regenerate-results }}
7885
7986
generate_report:

docker/Dockerfile-fuzz

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
FROM fedora:38 AS fuzz
2+
3+
RUN dnf install -y \
4+
python3 \
5+
python3-pip \
6+
&& dnf clean all && rm -rf /var/cache/dnf/*
7+
8+
RUN pip install hypothesis[cli] hypofuzz
9+
10+
COPY fuzz.sh /fuzz.sh
11+
12+
WORKDIR /tmp/work
13+
ENTRYPOINT ["/fuzz.sh"]
14+
15+
EXPOSE 9999/tcp
16+
VOLUME /tmp/work

docker/build-images.sh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ docker build --tag danielflook/python-minifier-build:python3.10-$DATE -f Dockerf
2626
docker pull fedora:36
2727
docker build --tag danielflook/python-minifier-build:python3.11-$DATE -f Dockerfile-fedora36 --target python3.11 .
2828

29+
docker pull fedora:38
30+
docker build --tag danielflook/python-minifier-build:fuzz-$DATE -f Dockerfile-fuzz --target fuzz .
31+
2932
docker push danielflook/python-minifier-build:python3.3-$DATE
3033
docker push danielflook/python-minifier-build:python2.7-$DATE
3134
docker push danielflook/python-minifier-build:python3.4-$DATE
@@ -38,3 +41,4 @@ docker push danielflook/python-minifier-build:python3.10-$DATE
3841
docker push danielflook/python-minifier-build:python3.11-$DATE
3942
docker push danielflook/python-minifier-build:pypy-$DATE
4043
docker push danielflook/python-minifier-build:pypy3-$DATE
44+
docker push danielflook/python-minifier-build:fuzz-$DATE

docker/fuzz.sh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/usr/bin/env bash
2+
3+
pip install .
4+
5+
exec hypothesis fuzz hypo_test
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
SECONDS_IN_A_DAY = 60 * 60 * 24
2+
SECONDS_IN_A_WEEK = SECONDS_IN_A_DAY * 7
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Constant Folding
2+
================
3+
4+
This transform evaluates constant expressions with literal operands when minifying and replaces the expression with the resulting value, if the value is shorter than the expression.
5+
6+
There are some limitations, notably the division and power operators are not evaluated.
7+
8+
This will be most effective with numeric literals.
9+
10+
This transform is always safe and enabled by default. Disable by passing the ``constant_folding=False`` argument to the :func:`python_minifier.minify` function,
11+
or passing ``--no-constant-folding`` to the pyminify command.
12+
13+
Example
14+
-------
15+
16+
Input
17+
~~~~~
18+
19+
.. literalinclude:: constant_folding.py
20+
21+
Output
22+
~~~~~~
23+
24+
.. literalinclude:: constant_folding.min.py
25+
:language: python

docs/source/transforms/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ They can be enabled or disabled through the minify function, or passing options
1919
convert_posargs_to_args
2020
preserve_shebang
2121
remove_explicit_return_none
22+
constant_folding
2223

2324
.. toctree::
2425
:caption: Disabled by default

hypo_test/expressions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,12 +240,14 @@ def arguments(draw, for_lambda=False) -> ast.arguments:
240240
allow_annotation = False if for_lambda else True
241241

242242
args = draw(lists(arg(allow_annotation), max_size=2))
243+
posonlyargs = draw(lists(arg(allow_annotation), max_size=2))
243244
kwonlyargs = draw(lists(arg(allow_annotation), max_size=2))
244245
vararg = draw(none() | arg(allow_annotation))
245246
kwarg = draw(none() | arg(allow_annotation))
246247
defaults=[]
247248
kw_defaults=draw(lists(none() | expression(), max_size=len(kwonlyargs), min_size=len(kwonlyargs)))
248249
return ast.arguments(
250+
posonlyargs=posonlyargs,
249251
args=args,
250252
vararg=vararg,
251253
kwonlyargs=kwonlyargs,

hypo_test/folding.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
from hypothesis import assume
2+
from hypothesis.strategies import integers, lists, binary, sampled_from, recursive, dictionaries, booleans, SearchStrategy, text, composite, one_of, floats, complex_numbers, characters, none
3+
import ast
4+
5+
from expressions import NameConstant, Num
6+
7+
leaves = NameConstant() | Num()
8+
9+
@composite
10+
def BinOp(draw, expression) -> ast.BinOp:
11+
op = draw(sampled_from([
12+
ast.Add(),
13+
ast.Sub(),
14+
ast.Mult(),
15+
ast.Div(),
16+
ast.FloorDiv(),
17+
ast.Mod(),
18+
ast.Pow(),
19+
ast.LShift(),
20+
ast.RShift(),
21+
ast.BitOr(),
22+
ast.BitXor(),
23+
ast.BitAnd(),
24+
ast.MatMult()
25+
]))
26+
27+
le = draw(lists(expression, min_size=2, max_size=2))
28+
29+
return ast.BinOp(le[0], op, le[1])
30+
31+
32+
def expression() -> SearchStrategy:
33+
return recursive(
34+
leaves,
35+
lambda expression:
36+
BinOp(expression),
37+
max_leaves=150
38+
)
39+
40+
@composite
41+
def FoldableExpression(draw) -> ast.Expression:
42+
""" An eval expression """
43+
e = draw(expression())
44+
return ast.Expression(e)

hypo_test/module.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,4 +269,4 @@ def suite() -> SearchStrategy:
269269
@composite
270270
def Module(draw) -> ast.Module:
271271
b = draw(lists(suite(), min_size=1, max_size=10))
272-
return ast.Module(body=b)
272+
return ast.Module(body=b, type_ignores=[])

0 commit comments

Comments
 (0)