You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 16:59:52 +08:00
Compare commits
27 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
b21e8b8b57 | ||
|
4007b8b702 | ||
|
598b58796d | ||
|
f7bad891a4 | ||
|
357f28dd89 | ||
|
5cc572147a | ||
|
11be90758f | ||
|
e3720515ae | ||
|
7dec354a47 | ||
|
2a8daca25d | ||
|
7799819cad | ||
|
c6c50b5dfb | ||
|
d357898bbf | ||
|
c4e7ddf90a | ||
|
02f502c40a | ||
|
de4fbb08f2 | ||
|
e14675c2dc | ||
|
3449be024b | ||
|
8b50b15f0a | ||
|
e2e925679d | ||
|
7deeee8502 | ||
|
acdd025162 | ||
|
9acb3cf068 | ||
|
40a653cd3b | ||
|
3ac3979535 | ||
|
7eba933cfa | ||
|
ad5d3333da |
@@ -36,9 +36,11 @@ jobs:
|
||||
# fallback to using the latest cache if no exact match is found
|
||||
- v2-dependencies-
|
||||
|
||||
- run: pip install --user --upgrade setuptools
|
||||
- run: pip install --user -e .
|
||||
- run: pip install --user -r requirements-dev.txt
|
||||
- run:
|
||||
command: | # Use pip to install dependengcies
|
||||
pip install --user --upgrade setuptools
|
||||
pip install --user -e .
|
||||
pip install --user -r requirements-dev.txt
|
||||
|
||||
# Save dependency cache
|
||||
- save_cache:
|
||||
|
18
NEWS.md
18
NEWS.md
@@ -1,3 +1,21 @@
|
||||
3.7.2: 2020-6-27
|
||||
================
|
||||
|
||||
* Use newer xdis
|
||||
* Docstrings (again) which were broken again on earlier Python
|
||||
* Fix 2.6 and 2.7 decompilation bug in handling "list if" comprehensions
|
||||
|
||||
|
||||
|
||||
3.7.1: 2020-6-12 Fleetwood66
|
||||
====================================================
|
||||
|
||||
Released to pick up new xdis version which has fixes to read bytestings better on 3.x
|
||||
|
||||
* Handle 3.7+ "else" branch removal adAs seen in `_cmp()` of `python3.8/distutils/version.py` with optimization `-O2`
|
||||
* 3.6+ "with" and "with .. as" grammar improvements
|
||||
* ast-check for "for" loop was missing some grammar rules
|
||||
|
||||
3.7.0: 2020-5-19 Primidi 1st Prairial - Alfalfa - HF
|
||||
====================================================
|
||||
|
||||
|
@@ -69,7 +69,7 @@ entry_points = {
|
||||
]}
|
||||
ftp_url = None
|
||||
install_requires = ["spark-parser >= 1.8.9, < 1.9.0",
|
||||
"xdis >= 4.6.0, < 4.7.0"]
|
||||
"xdis >= 4.7.0, <5.1.0"]
|
||||
|
||||
license = "GPL3"
|
||||
mailing_list = "python-debugger@googlegroups.com"
|
||||
|
@@ -2,17 +2,17 @@
|
||||
**Table of Contents**
|
||||
|
||||
- [Get latest sources:](#get-latest-sources)
|
||||
- [Change version in uncompyle6/version.py](#change-version-in-uncompyle6versionpy)
|
||||
- [Change version in uncompyle6/version.py:](#change-version-in-uncompyle6versionpy)
|
||||
- [Update ChangeLog:](#update-changelog)
|
||||
- [Update NEWS from ChangeLog:](#update-news-from-changelog)
|
||||
- [Update NEWS.md from ChangeLog:](#update-newsmd-from-changelog)
|
||||
- [Make sure pyenv is running and check newer versions](#make-sure-pyenv-is-running-and-check-newer-versions)
|
||||
- [Switch to python-2.4, sync that up and build that first since it creates a tarball which we don't want.](#switch-to-python-24-sync-that-up-and-build-that-first-since-it-creates-a-tarball-which-we-dont-want)
|
||||
- [Update NEWS from master branch](#update-news-from-master-branch)
|
||||
- [Check against all versions](#check-against-all-versions)
|
||||
- [Check against older versions](#check-against-older-versions)
|
||||
- [Make packages and tag](#make-packages-and-tag)
|
||||
- [Upload single package and look at Rst Formating](#upload-single-package-and-look-at-rst-formating)
|
||||
- [Upload rest of versions](#upload-rest-of-versions)
|
||||
- [Push tags:](#push-tags)
|
||||
- [Check package on github](#check-package-on-github)
|
||||
- [Release on Github](#release-on-github)
|
||||
- [Get onto PyPI](#get-onto-pypi)
|
||||
- [Update tags:](#update-tags)
|
||||
|
||||
<!-- markdown-toc end -->
|
||||
# Get latest sources:
|
||||
@@ -60,27 +60,36 @@
|
||||
$ . ./admin-tools/make-dist-newer.sh
|
||||
$ twine check dist/uncompyle6-$VERSION*
|
||||
|
||||
# Upload single package and look at Rst Formating
|
||||
# Check package on github
|
||||
|
||||
$ twine check dist/uncompyle6-${VERSION}*
|
||||
$ twine upload dist/uncompyle6-${VERSION}-py3.3.egg
|
||||
$ mkdir /tmp/gittest; pushd /tmp/gittest
|
||||
$ pyenv local 3.7.5
|
||||
$ pip install -e git://github.com/rocky/python-uncompyle6.git#egg=uncompyle6
|
||||
$ uncompyle6 --help
|
||||
$ pip uninstall uncompyle6
|
||||
$ popd
|
||||
|
||||
# Upload rest of versions
|
||||
|
||||
$ twine upload dist/uncompyle6-${VERSION}*
|
||||
# Release on Github
|
||||
|
||||
Goto https://github.com/rocky/python-uncompyle6/releases
|
||||
|
||||
# Push tags:
|
||||
Now check the *tagged* release. (Checking the untagged release was previously done).
|
||||
|
||||
Todo: turn this into a script in `admin-tools`
|
||||
|
||||
$ pushd /tmp/gittest
|
||||
$ pip install -e git://github.com/rocky/python-uncompyle6.git@$VERSION#egg=uncompyle6
|
||||
$ uncompyle6 --help
|
||||
$ pip uninstall uncompyle6
|
||||
$ popd
|
||||
|
||||
|
||||
# Get onto PyPI
|
||||
|
||||
$ twine upload dist/uncompyle6-${VERSION}*
|
||||
|
||||
|
||||
# Update tags:
|
||||
|
||||
$ git push --tags
|
||||
|
||||
# Check on a VM
|
||||
|
||||
$ cd /virtual/vagrant/virtual/vagrant/ubuntu-zesty
|
||||
$ vagrant up
|
||||
$ vagrant ssh
|
||||
$ pyenv local 3.5.2
|
||||
$ pip install --upgrade uncompyle6
|
||||
$ exit
|
||||
$ vagrant halt
|
||||
$ git pull --tags
|
||||
|
@@ -19,6 +19,7 @@ for path in py_source:
|
||||
else:
|
||||
cfile = "bytecode_%s%s/%s" % (version, suffix, short) + "c"
|
||||
print("byte-compiling %s to %s" % (path, cfile))
|
||||
py_compile.compile(path, cfile)
|
||||
optimize = 2
|
||||
py_compile.compile(path, cfile, optimize=optimize)
|
||||
if isinstance(version, str) or version >= (2, 6, 0):
|
||||
os.system("../bin/uncompyle6 -a -T %s" % cfile)
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.7/03_else_removal.pyc
Normal file
BIN
test/bytecode_3.7/03_else_removal.pyc
Normal file
Binary file not shown.
Binary file not shown.
BIN
test/bytecode_3.8/03_else_removal.pyc
Normal file
BIN
test/bytecode_3.8/03_else_removal.pyc
Normal file
Binary file not shown.
@@ -51,7 +51,7 @@ for VERSION in $PYVERSIONS ; do
|
||||
LOGFILE=/tmp/${MAIN}-$VERSION-$$.log
|
||||
|
||||
case "$VERSION" in
|
||||
3.7.7 | 3.8.2 | 3.1.5 | 3.0.1 )
|
||||
3.7.7 | 3.8.3 | 3.1.5 | 3.0.1 )
|
||||
continue
|
||||
;;
|
||||
3.5.9 )
|
||||
|
@@ -2,6 +2,7 @@
|
||||
# Bug was code not knowing which Python versions
|
||||
# have kwargs coming before positional args in code.
|
||||
|
||||
"""This program is self-checking!"""
|
||||
# RUNNABLE!
|
||||
|
||||
def tometadata(self, metadata, schema, Table, args, name=None):
|
||||
|
12
test/simple_source/bug37/03_else_removal.py
Normal file
12
test/simple_source/bug37/03_else_removal.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# From python3.8/distutils/version.py with optimization -O2
|
||||
# The bug was that the other "else" constant propagated removed.
|
||||
|
||||
# NOTE: this program needs to be compile with optimization
|
||||
def _cmp (b, c):
|
||||
if b:
|
||||
if c:
|
||||
return 0
|
||||
else:
|
||||
return 1
|
||||
else:
|
||||
assert False, "never get here"
|
@@ -16,3 +16,25 @@ def withas_bug(self, nested, a, b):
|
||||
with self.assertRaises(ZeroDivisionError):
|
||||
with nested(a(), b()) as (x, y):
|
||||
1 // 0
|
||||
|
||||
# From 3.7.7 test_functools.py
|
||||
# Bug is a unreachable code after "return"
|
||||
def test_invalid_registrations(x):
|
||||
return
|
||||
with x:
|
||||
x = 1
|
||||
|
||||
# From 3.7.7 test_re.py
|
||||
# Bug was hooking in c_with.
|
||||
def test_re_tests(tests):
|
||||
for t in tests:
|
||||
with a:
|
||||
continue
|
||||
|
||||
# Adapted from 3.8 distutils/command/config.py
|
||||
# In 3.8 the problem was in handling "with .. as" code
|
||||
def _gen_temp_sourcefile(x, a, headers, lang):
|
||||
with x as y:
|
||||
if a:
|
||||
y = 2
|
||||
return 5
|
||||
|
@@ -55,7 +55,6 @@ SKIP_TESTS=(
|
||||
[test_ossaudiodev.py]=1 # it fails on its own
|
||||
[test_pdb.py]=1 # Line-number specific
|
||||
[test_pep277.py]=1 # it fails on its own
|
||||
[test_pep352.py]=1 # Investigate
|
||||
[test_plistlib.py]=1 # it fails on its own
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_pyclbr.py]=1 # Investigate
|
||||
|
@@ -60,7 +60,6 @@ SKIP_TESTS=(
|
||||
[test_ossaudiodev.py]=1 # it fails on its own
|
||||
|
||||
[test_pep277.py]=1 # it fails on its own
|
||||
[test_pep352.py]=1 # Investigate
|
||||
[test_pyclbr.py]=1 # Investigate
|
||||
[test_pwd.py]=1 # Long test - might work? Control flow?
|
||||
[test_py3kwarn.py]=1 # it fails on its own
|
||||
|
@@ -17,8 +17,6 @@ SKIP_TESTS=(
|
||||
[test_peepholer.py]=1
|
||||
[test_pep352.py]=1
|
||||
|
||||
[test_quopri.py]=1 # TypeError: Can't convert 'bytes' object to str implicitly
|
||||
|
||||
[test_runpy.py]=1
|
||||
|
||||
[test_ssl.py]=1 # too installation specific
|
||||
@@ -35,5 +33,4 @@ if (( BATCH )) ; then
|
||||
# Fails in crontab environment?
|
||||
# Figure out what's up here
|
||||
SKIP_TESTS[test_exception_variations.py]=1
|
||||
SKIP_TESTS[test_quopri.py]=1
|
||||
fi
|
||||
|
@@ -1,4 +1,15 @@
|
||||
SKIP_TESTS=(
|
||||
# FIXME: Did this work sometime in the past ?
|
||||
# for elem in g(s):
|
||||
# if not tgt and isOdd(elem): continue
|
||||
# is erroneously:
|
||||
# for elem in g(s):
|
||||
# if tgt or isOdd(elem):
|
||||
# pass
|
||||
# else:
|
||||
# tgt.append(elem)
|
||||
[test_itertools.py]=1
|
||||
|
||||
[test_buffer.py]=1 # FIXME: Works on c90ff51
|
||||
[test_cmath.py]=1 # FIXME: Works on c90ff51
|
||||
|
||||
|
@@ -1,4 +1,15 @@
|
||||
SKIP_TESTS=(
|
||||
# FIXME: Did this work sometime in the past ?
|
||||
# for elem in g(s):
|
||||
# if not tgt and isOdd(elem): continue
|
||||
# is erroneously:
|
||||
# for elem in g(s):
|
||||
# if tgt or isOdd(elem):
|
||||
# pass
|
||||
# else:
|
||||
# tgt.append(elem)
|
||||
[test_itertools.py]=1
|
||||
|
||||
[test_buffer.py]=1 # FIXME: Works on c90ff51
|
||||
[test_cmath.py]=1 # FIXME: Works on c90ff51
|
||||
[test_strftime.py]=1 # FIXME: Works on c90ff51
|
||||
@@ -87,5 +98,4 @@ if (( batch )) ; then
|
||||
# Figure out what's up here
|
||||
SKIP_TESTS[test_exception_variations.py]=1
|
||||
SKIP_TESTS[test_mailbox.py]=1 # Takes to long on POWER; over 15 secs
|
||||
SKIP_TESTS[test_quopri.py]=1
|
||||
fi
|
||||
|
@@ -138,7 +138,6 @@ if (( BATCH )) ; then
|
||||
SKIP_TESTS[test_ioctl.py]=1 # it fails on its own
|
||||
SKIP_TESTS[test_poplib.py]=1 # May be a result of POWER installation
|
||||
|
||||
SKIP_TESTS[test_quopri.py]=1
|
||||
SKIP_TESTS[test_sysconfig.py]=1 # POWER extension fails
|
||||
SKIP_TESTS[test_tarfile.py]=1 # too long to run on POWER 15 secs
|
||||
SKIP_TESTS[test_venv.py]=1 # takes too long 11 seconds
|
||||
|
@@ -123,8 +123,6 @@ SKIP_TESTS=(
|
||||
[test_pyclbr.py]=1 # it fails on its own
|
||||
[test_pydoc.py]=1 # it fails on its own
|
||||
|
||||
[test_quopri.py]=1 # AssertionError: b'123=four' != '123=four'
|
||||
|
||||
[test_random.py]=1 # it fails on its own
|
||||
[test_range.py]=1
|
||||
[test_regrtest.py]=1 # test takes too long to run: 12 seconds
|
||||
|
@@ -1,4 +1,19 @@
|
||||
SKIP_TESTS=(
|
||||
# FIXME: Did this work sometime in the past ?
|
||||
# for elem in g(s):
|
||||
# if not tgt and isOdd(elem): continue
|
||||
# is erroneously:
|
||||
# for elem in g(s):
|
||||
# if tgt or isOdd(elem):
|
||||
# pass
|
||||
# else:
|
||||
# tgt.append(elem)
|
||||
[test_itertools.py]=1
|
||||
|
||||
# Fails on decompyle3 as well.
|
||||
# complicated control flow and "and/or" expressions
|
||||
[test_pickle.py]=1
|
||||
|
||||
[test_builtin.py]=1 # FIXME works on decompyle6
|
||||
[test_context.py]=1 # FIXME works on decompyle6
|
||||
[test_doctest2.py]=1 # FIXME works on decompyle6
|
||||
@@ -48,6 +63,7 @@ SKIP_TESTS=(
|
||||
|
||||
[test_faulthandler.py]=1 # test takes too long before decompiling
|
||||
[test_fileinput.py]=1 # Test assertion failures
|
||||
[test_finalization.py]=1 # if/else logic
|
||||
[test_frame.py]=1 # test assertion errors
|
||||
[test_ftplib.py]=1 # parse error
|
||||
[test_fstring.py]=1 # need to disambiguate leading fstrings from docstrings
|
||||
|
@@ -78,7 +78,6 @@ case $PYVERSION in
|
||||
# Fails in crontab environment?
|
||||
# Figure out what's up here
|
||||
SKIP_TESTS[test_exception_variations.py]=1
|
||||
SKIP_TESTS[test_quopri.py]=1
|
||||
fi
|
||||
;;
|
||||
3.1)
|
||||
@@ -91,7 +90,6 @@ case $PYVERSION in
|
||||
# Fails in crontab environment?
|
||||
# Figure out what's up here
|
||||
SKIP_TESTS[test_exception_variations.py]=1
|
||||
SKIP_TESTS[test_quopri.py]=1
|
||||
fi
|
||||
;;
|
||||
3.2)
|
||||
|
@@ -119,12 +119,10 @@ def decompile(
|
||||
mapstream = _get_outstream(mapstream)
|
||||
|
||||
deparsed = deparse_code_with_map(
|
||||
bytecode_version,
|
||||
co,
|
||||
out,
|
||||
showasm,
|
||||
showast,
|
||||
showgrammar,
|
||||
bytecode_version,
|
||||
debug_opts,
|
||||
code_objects=code_objects,
|
||||
is_pypy=is_pypy,
|
||||
)
|
||||
|
@@ -232,7 +232,10 @@ class Python26Parser(Python2Parser):
|
||||
|
||||
comp_for ::= SETUP_LOOP expr for_iter store comp_iter jb_pb_come_from
|
||||
|
||||
comp_body ::= gen_comp_body
|
||||
comp_iter ::= comp_if_not
|
||||
comp_if_not ::= expr jmp_true comp_iter
|
||||
|
||||
comp_body ::= gen_comp_body
|
||||
|
||||
for_block ::= l_stmts_opt _come_froms POP_TOP JUMP_BACK
|
||||
|
||||
|
@@ -8,7 +8,6 @@ from uncompyle6.parser import PythonParserSingle, nop_func
|
||||
from uncompyle6.parsers.parse2 import Python2Parser
|
||||
from uncompyle6.parsers.reducecheck import (
|
||||
or_check,
|
||||
ifelsestmt,
|
||||
tryelsestmt,
|
||||
)
|
||||
|
||||
|
@@ -679,6 +679,7 @@ class Python3Parser(PythonParser):
|
||||
"RAISE",
|
||||
"SETUP",
|
||||
"UNPACK",
|
||||
"WITH",
|
||||
)
|
||||
)
|
||||
|
||||
|
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2016-2019 Rocky Bernstein
|
||||
# Copyright (c) 2016-2020 Rocky Bernstein
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@@ -305,28 +305,25 @@ class Python36Parser(Python35Parser):
|
||||
self.addRule(rule, nop_func)
|
||||
# Check to combine assignment + annotation into one statement
|
||||
self.check_reduce['assign'] = 'token'
|
||||
elif opname == "WITH_CLEANUP_START":
|
||||
rules_str = """
|
||||
stmt ::= with_null
|
||||
with_null ::= with_suffix
|
||||
with_suffix ::= WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
elif opname == 'SETUP_WITH':
|
||||
rules_str = """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||
with_suffix
|
||||
|
||||
# Removes POP_BLOCK LOAD_CONST from 3.6-
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
# Removes POP_BLOCK LOAD_CONST from 3.6-
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
with_suffix
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
BEGIN_FINALLY COME_FROM_WITH
|
||||
with_suffix
|
||||
"""
|
||||
if self.version < 3.8:
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
LOAD_CONST
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
else:
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
BEGIN_FINALLY COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH
|
||||
END_FINALLY
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
pass
|
||||
pass
|
||||
|
@@ -94,6 +94,9 @@ class Python37Parser(Python37BaseParser):
|
||||
else_suitec ::= c_stmts
|
||||
else_suitec ::= returns
|
||||
|
||||
else_suite_opt ::= else_suite
|
||||
else_suite_opt ::= pass
|
||||
|
||||
stmt ::= classdef
|
||||
stmt ::= call_stmt
|
||||
|
||||
@@ -635,6 +638,12 @@ class Python37Parser(Python37BaseParser):
|
||||
if_exp37 ::= expr expr jf_cfs expr COME_FROM
|
||||
jf_cfs ::= JUMP_FORWARD _come_froms
|
||||
ifelsestmt ::= testexpr c_stmts_opt jf_cfs else_suite opt_come_from_except
|
||||
|
||||
# This is probably more realistically an "ifstmt" (with a null else)
|
||||
# see _cmp() of python3.8/distutils/__pycache__/version.cpython-38.opt-1.pyc
|
||||
ifelsestmt ::= testexpr stmts jf_cfs else_suite_opt opt_come_from_except
|
||||
|
||||
|
||||
expr_pjit ::= expr POP_JUMP_IF_TRUE
|
||||
expr_jit ::= expr JUMP_IF_TRUE
|
||||
expr_jt ::= expr jmp_true
|
||||
|
@@ -127,6 +127,7 @@ class Python37BaseParser(PythonParser):
|
||||
"RAISE",
|
||||
"SETUP",
|
||||
"UNPACK",
|
||||
"WITH",
|
||||
)
|
||||
)
|
||||
|
||||
@@ -993,55 +994,70 @@ class Python37BaseParser(PythonParser):
|
||||
)
|
||||
custom_ops_processed.add(opname)
|
||||
|
||||
elif opname == "WITH_CLEANUP_START":
|
||||
rules_str = """
|
||||
stmt ::= with_null
|
||||
with_null ::= with_suffix
|
||||
with_suffix ::= WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
elif opname == "SETUP_WITH":
|
||||
rules_str = """
|
||||
stmt ::= with
|
||||
stmt ::= withasstmt
|
||||
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP
|
||||
suite_stmts_opt
|
||||
COME_FROM_WITH
|
||||
with_suffix
|
||||
withasstmt ::= expr SETUP_WITH store suite_stmts_opt COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP
|
||||
suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
with_suffix
|
||||
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
with_suffix
|
||||
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
"""
|
||||
if self.version < 3.8:
|
||||
rules_str += """
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
LOAD_CONST
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
"""
|
||||
else:
|
||||
rules_str += """
|
||||
with ::= expr
|
||||
with ::= expr
|
||||
SETUP_WITH POP_TOP suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH END_FINALLY
|
||||
with_suffix
|
||||
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts_opt
|
||||
POP_BLOCK LOAD_CONST COME_FROM_WITH
|
||||
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
withasstmt ::= expr
|
||||
SETUP_WITH store suite_stmts
|
||||
POP_BLOCK BEGIN_FINALLY COME_FROM_WITH with_suffix
|
||||
|
||||
with ::= expr SETUP_WITH POP_TOP suite_stmts_opt POP_BLOCK
|
||||
BEGIN_FINALLY COME_FROM_WITH
|
||||
WITH_CLEANUP_START WITH_CLEANUP_FINISH
|
||||
END_FINALLY
|
||||
with_suffix
|
||||
"""
|
||||
self.addRule(rules_str, nop_func)
|
||||
|
||||
|
@@ -45,6 +45,7 @@ class Python38Parser(Python37Parser):
|
||||
stmt ::= try_elsestmtl38
|
||||
stmt ::= try_except_ret38
|
||||
stmt ::= try_except38
|
||||
stmt ::= try_except_as
|
||||
stmt ::= whilestmt38
|
||||
stmt ::= whileTruestmt38
|
||||
stmt ::= call_stmt
|
||||
@@ -133,6 +134,8 @@ class Python38Parser(Python37Parser):
|
||||
except_cond1 ::= DUP_TOP expr COMPARE_OP jmp_false
|
||||
POP_TOP POP_TOP POP_TOP
|
||||
POP_EXCEPT
|
||||
except_cond_as ::= DUP_TOP expr COMPARE_OP POP_JUMP_IF_FALSE
|
||||
POP_TOP STORE_FAST POP_TOP
|
||||
|
||||
try_elsestmtl38 ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
|
||||
except_handler38 COME_FROM
|
||||
@@ -145,6 +148,10 @@ class Python38Parser(Python37Parser):
|
||||
# suite_stmts has a return
|
||||
try_except38 ::= SETUP_FINALLY POP_BLOCK suite_stmts
|
||||
except_handler38b
|
||||
try_except_as ::= SETUP_FINALLY POP_BLOCK suite_stmts
|
||||
except_handler_as END_FINALLY COME_FROM
|
||||
try_except_as ::= SETUP_FINALLY suite_stmts
|
||||
except_handler_as END_FINALLY COME_FROM
|
||||
|
||||
try_except_ret38 ::= SETUP_FINALLY returns except_ret38a
|
||||
try_except_ret38a ::= SETUP_FINALLY returns except_handler38c
|
||||
@@ -165,6 +172,11 @@ class Python38Parser(Python37Parser):
|
||||
except_handler38a ::= COME_FROM_FINALLY POP_TOP POP_TOP POP_TOP
|
||||
POP_EXCEPT POP_TOP stmts END_FINALLY
|
||||
|
||||
except_handler38c ::= COME_FROM_FINALLY except_cond1a except_stmts
|
||||
POP_EXCEPT JUMP_FORWARD COME_FROM
|
||||
except_handler_as ::= COME_FROM_FINALLY except_cond_as tryfinallystmt
|
||||
POP_EXCEPT JUMP_FORWARD COME_FROM
|
||||
|
||||
tryfinallystmt ::= SETUP_FINALLY suite_stmts_opt POP_BLOCK
|
||||
BEGIN_FINALLY COME_FROM_FINALLY suite_stmts_opt
|
||||
END_FINALLY
|
||||
|
@@ -95,6 +95,34 @@ IFELSE_STMT_RULES = frozenset(
|
||||
"else_suite",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ifelsestmt",
|
||||
(
|
||||
"testexpr",
|
||||
"stmts",
|
||||
"jf_cfs",
|
||||
"else_suite_opt",
|
||||
"opt_come_from_except",
|
||||
),
|
||||
),
|
||||
(
|
||||
"ifelsestmt",
|
||||
(
|
||||
"testexpr",
|
||||
"stmts",
|
||||
"jf_cfs",
|
||||
"\\e_else_suite_opt",
|
||||
"\\e_opt_come_from_except")
|
||||
),
|
||||
(
|
||||
"ifelsestmt",
|
||||
(
|
||||
"testexpr",
|
||||
"stmts",
|
||||
"jf_cfs",
|
||||
"\\e_else_suite_opt",
|
||||
"opt_come_from_except")
|
||||
),
|
||||
])
|
||||
|
||||
def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
@@ -103,12 +131,17 @@ def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
# ifelsestmt jumped outside of loop. No good.
|
||||
return True
|
||||
|
||||
# print("XXX", first, last)
|
||||
# for t in range(first, last):
|
||||
# print(tokens[t])
|
||||
# print("=" * 30)
|
||||
|
||||
if rule not in IFELSE_STMT_RULES:
|
||||
# print("XXX", rule)
|
||||
return False
|
||||
|
||||
# Avoid if/else where the "then" is a "raise_stmt1" for an
|
||||
# assert statemetn. Parse this as an "assert" instead.
|
||||
# assert statement. Parse this as an "assert" instead.
|
||||
stmts = ast[1]
|
||||
if stmts in ("c_stmts",) and len(stmts) == 1:
|
||||
raise_stmt1 = stmts[0]
|
||||
@@ -176,9 +209,7 @@ def ifelsestmt(self, lhs, n, rule, ast, tokens, first, last):
|
||||
if jump_else_end == "jf_cf_pop":
|
||||
jump_else_end = jump_else_end[0]
|
||||
|
||||
jump_to_jump = False
|
||||
if jump_else_end == "JUMP_FORWARD":
|
||||
jump_to_jump = True
|
||||
endif_target = int(jump_else_end.pattr)
|
||||
last_offset = tokens[last].off2int()
|
||||
if endif_target != last_offset:
|
||||
|
@@ -8,22 +8,29 @@ FIXME idea: extend parsing system to do same kinds of checks or nonterminal
|
||||
before reduction and don't reduce when there is a problem.
|
||||
"""
|
||||
|
||||
|
||||
def checker(ast, in_loop, errors):
|
||||
if ast is None:
|
||||
return
|
||||
in_loop = (in_loop or (ast.kind in ('while1stmt', 'whileTruestmt',
|
||||
'whilestmt', 'whileelsestmt', 'while1elsestmt',
|
||||
'for_block'))
|
||||
or ast.kind.startswith('async_for'))
|
||||
if ast.kind in ('aug_assign1', 'aug_assign2') and ast[0][0] == 'and':
|
||||
in_loop = (
|
||||
in_loop
|
||||
or ast.kind.startswith("for")
|
||||
or ast.kind.startswith("while")
|
||||
or ast.kind.startswith("async_for")
|
||||
)
|
||||
if ast.kind in ("aug_assign1", "aug_assign2") and ast[0][0] == "and":
|
||||
text = str(ast)
|
||||
error_text = '\n# improper augmented assigment (e.g. +=, *=, ...):\n#\t' + '\n# '.join(text.split("\n")) + '\n'
|
||||
error_text = (
|
||||
"\n# improper augmented assigment (e.g. +=, *=, ...):\n#\t"
|
||||
+ "\n# ".join(text.split("\n"))
|
||||
+ "\n"
|
||||
)
|
||||
errors.append(error_text)
|
||||
|
||||
for node in ast:
|
||||
if not in_loop and node.kind in ('continue', 'break'):
|
||||
if not in_loop and node.kind in ("continue", "break"):
|
||||
text = str(node)
|
||||
error_text = '\n# not in loop:\n#\t' + '\n# '.join(text.split("\n"))
|
||||
error_text = "\n# not in loop:\n#\t" + "\n# ".join(text.split("\n"))
|
||||
errors.append(error_text)
|
||||
if hasattr(node, '__repr1__'):
|
||||
if hasattr(node, "__repr1__"):
|
||||
checker(node, in_loop, errors)
|
||||
|
@@ -50,12 +50,24 @@ def customize_for_version38(self, version):
|
||||
"%|%c\n", 0
|
||||
),
|
||||
|
||||
"except_cond_as": (
|
||||
"%|except %c as %c:\n",
|
||||
(1, "expr"),
|
||||
(-2, "STORE_FAST"),
|
||||
),
|
||||
|
||||
'except_handler38': (
|
||||
'%c', (2, 'except_stmts') ),
|
||||
|
||||
'except_handler38a': (
|
||||
'%c', (-2, 'stmts') ),
|
||||
|
||||
"except_handler_as": (
|
||||
"%c%+\n%+%c%-",
|
||||
(1, "except_cond_as"),
|
||||
(2, "tryfinallystmt"),
|
||||
),
|
||||
|
||||
'except_ret38a': (
|
||||
'return %c', (4, 'expr') ),
|
||||
|
||||
@@ -105,6 +117,13 @@ def customize_for_version38(self, version):
|
||||
'try_except38': (
|
||||
'%|try:\n%+%c\n%-%|except:\n%|%-%c\n\n',
|
||||
(-2, 'suite_stmts_opt'), (-1, 'except_handler38a') ),
|
||||
|
||||
"try_except_as": (
|
||||
"%|try:\n%+%c%-\n%|%-%c\n\n",
|
||||
(-4, "suite_stmts"), # Go from the end because of POP_BLOCK variation
|
||||
(-3, "except_handler_as"),
|
||||
),
|
||||
|
||||
"try_except_ret38": (
|
||||
"%|try:\n%+%c%-\n%|except:\n%+%|%c%-\n\n",
|
||||
(1, "returns"),
|
||||
|
@@ -895,6 +895,12 @@ class SourceWalker(GenericASTTraversal, object):
|
||||
doc_node = node[0]
|
||||
if doc_node.attr:
|
||||
docstring = doc_node.attr
|
||||
if not isinstance(docstring, str):
|
||||
# FIXME: we have mistakenly tagged something as a doc
|
||||
# string in transform when it isn't one.
|
||||
# The rule in n_mkfunc is pretty flaky.
|
||||
self.prune()
|
||||
return
|
||||
else:
|
||||
docstring = node[0].pattr
|
||||
|
||||
|
@@ -95,10 +95,18 @@ class TreeTransform(GenericASTTraversal, object):
|
||||
|
||||
code = find_code_node(node, code_index).attr
|
||||
|
||||
mkfunc_pattr = node[-1].pattr
|
||||
if isinstance(mkfunc_pattr, tuple):
|
||||
assert len(mkfunc_pattr, 4) and isinstance(mkfunc_pattr, int)
|
||||
is_closure = node[-1].pattr[3] != 0
|
||||
else:
|
||||
# FIXME: This is what we had before. It is hoaky and probably wrong.
|
||||
is_closure = mkfunc_pattr == "closure"
|
||||
|
||||
if (
|
||||
node[-1].pattr != "closure"
|
||||
(not is_closure)
|
||||
and len(code.co_consts) > 0
|
||||
and code.co_consts[0] is not None
|
||||
and isinstance(code.co_consts[0], str)
|
||||
):
|
||||
docstring_node = SyntaxTree(
|
||||
"docstring", [Token("LOAD_STR", has_arg=True, pattr=code.co_consts[0])]
|
||||
@@ -433,6 +441,7 @@ class TreeTransform(GenericASTTraversal, object):
|
||||
ast[i] = ast[i][0]
|
||||
|
||||
if is_docstring(self.ast[i]):
|
||||
load_const = self.ast[i].first_child()
|
||||
docstring_ast = SyntaxTree(
|
||||
"docstring",
|
||||
[
|
||||
@@ -440,8 +449,8 @@ class TreeTransform(GenericASTTraversal, object):
|
||||
"LOAD_STR",
|
||||
has_arg=True,
|
||||
offset=0,
|
||||
attr=self.ast[i][0][0].attr,
|
||||
pattr=self.ast[i][0][0].pattr,
|
||||
attr=load_const.attr,
|
||||
pattr=load_const.pattr,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
@@ -12,4 +12,4 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# This file is suitable for sourcing inside POSIX shell as
|
||||
# well as importing into Python
|
||||
VERSION="3.7.0" # noqa
|
||||
VERSION="3.7.2" # noqa
|
||||
|
Reference in New Issue
Block a user