diff --git a/pytest/.gitignore b/pytest/.gitignore index 225fc6f6..c1828ea4 100644 --- a/pytest/.gitignore +++ b/pytest/.gitignore @@ -1 +1,2 @@ +/.hypothesis /__pycache__ diff --git a/test/bytecode_2.5/02_try_else.pyc b/test/bytecode_2.5/02_try_else.pyc new file mode 100644 index 00000000..8b7ac30e Binary files /dev/null and b/test/bytecode_2.5/02_try_else.pyc differ diff --git a/test/simple_source/bug25/02_try_else.py b/test/simple_source/bug25/02_try_else.py new file mode 100644 index 00000000..5c708c31 --- /dev/null +++ b/test/simple_source/bug25/02_try_else.py @@ -0,0 +1,12 @@ +# Python 2.5 bug +# Was turning into tryelse when there in fact is no else. +def options(self, section): + """Return a list of option names for the given section name.""" + try: + opts = self._sections[section].copy() + except KeyError: + raise NoSectionError(section) + opts.update(self._defaults) + if '__name__' in opts: + del opts['__name__'] + return opts.keys() diff --git a/uncompyle6/parsers/parse25.py b/uncompyle6/parsers/parse25.py index 5a162f15..d8307503 100644 --- a/uncompyle6/parsers/parse25.py +++ b/uncompyle6/parsers/parse25.py @@ -13,7 +13,7 @@ class Python25Parser(Python26Parser): self.customized = {} def p_misc25(self, args): - ''' + """ # If "return_if_stmt" is in a loop, a JUMP_BACK can be emitted. In 2.6 the # JUMP_BACK doesn't appear @@ -33,7 +33,31 @@ class Python25Parser(Python26Parser): with_cleanup ::= LOAD_FAST DELETE_FAST WITH_CLEANUP END_FINALLY with_cleanup ::= LOAD_NAME DELETE_NAME WITH_CLEANUP END_FINALLY - ''' + """ + + def add_custom_rules(self, tokens, customize): + super(Python25Parser, self).add_custom_rules(tokens, customize) + if self.version == 2.5: + self.check_reduce['tryelsestmt'] = 'tokens' + + + def reduce_is_invalid(self, rule, ast, tokens, first, last): + super(Python25Parser, self).reduce_is_invalid(rule, ast, tokens, first, last) + + lhs = rule[0] + if lhs in ('tryelsestmt', ): + # The end of the else part of try/else come_from has to come + # from an END_FINALLY statement + if tokens[last-1].type.startswith('COME_FROM'): + end_finally_offset = int(tokens[last-1].pattr) + current = first + while current < last: + offset = tokens[current].offset + if offset == end_finally_offset: + return tokens[current].type != 'END_FINALLY' + current += 1 + return False + class Python25ParserSingle(Python26Parser, PythonParserSingle): pass diff --git a/uncompyle6/parsers/parse26.py b/uncompyle6/parsers/parse26.py index bb6cdffa..79967f46 100644 --- a/uncompyle6/parsers/parse26.py +++ b/uncompyle6/parsers/parse26.py @@ -42,7 +42,7 @@ class Python26Parser(Python2Parser): try_middle come_froms tryelsestmt ::= SETUP_EXCEPT suite_stmts_opt POP_BLOCK - try_middle else_suite come_froms + try_middle else_suite COME_FROM _ifstmts_jump ::= c_stmts_opt JUMP_FORWARD COME_FROM POP_TOP