You've already forked python-uncompyle6
mirror of
https://github.com/rocky/python-uncompyle6.git
synced 2025-08-03 16:59:52 +08:00
further work on supporting single and multiple fstring decompilation
This commit is contained in:
@@ -21,9 +21,13 @@ def expressions(draw):
|
|||||||
'container',
|
'container',
|
||||||
'self.attribute',
|
'self.attribute',
|
||||||
'self.method()',
|
'self.method()',
|
||||||
|
# These expressions are failing, I think these are control
|
||||||
|
# flow problems rather than problems with FORMAT_VALUE,
|
||||||
|
# however I need to confirm this...
|
||||||
#'sorted(items, key=lambda x: x.name)',
|
#'sorted(items, key=lambda x: x.name)',
|
||||||
#'func(*args, **kwargs)',
|
#'func(*args, **kwargs)',
|
||||||
#'text or default',
|
#'text or default',
|
||||||
|
#'43 if life_the_universe and everything else None'
|
||||||
)))
|
)))
|
||||||
|
|
||||||
|
|
||||||
@@ -119,6 +123,8 @@ def test_format_specifiers(format_specifier):
|
|||||||
|
|
||||||
|
|
||||||
def run_test(text):
|
def run_test(text):
|
||||||
|
hypothesis.assume(len(text))
|
||||||
|
hypothesis.assume("f'{" in text)
|
||||||
expr = text + '\n'
|
expr = text + '\n'
|
||||||
code = compile(expr, '<string>', 'single')
|
code = compile(expr, '<string>', 'single')
|
||||||
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
|
deparsed = deparse_code(PYTHON_VERSION, code, compile_mode='single')
|
||||||
|
@@ -516,19 +516,21 @@ class Python3Parser(PythonParser):
|
|||||||
elif opname == 'FORMAT_VALUE':
|
elif opname == 'FORMAT_VALUE':
|
||||||
# Python 3.6+
|
# Python 3.6+
|
||||||
self.addRule("""
|
self.addRule("""
|
||||||
expr ::= fstring_expr
|
expr ::= fstring_single
|
||||||
fstring_expr ::= expr FORMAT_VALUE
|
fstring_single ::= expr FORMAT_VALUE
|
||||||
str ::= LOAD_CONST
|
|
||||||
fstring_expr_or_str ::= fstring_expr
|
|
||||||
fstring_expr_or_str ::= str
|
|
||||||
""", nop_func)
|
""", nop_func)
|
||||||
elif opname == 'BUILD_STRING':
|
elif opname == 'BUILD_STRING':
|
||||||
# Python 3.6+
|
# Python 3.6+
|
||||||
v = token.attr
|
v = token.attr
|
||||||
fstring_expr_or_str_n = "fstring_expr_or_str_%s" % v
|
fstring_expr_or_str_n = "fstring_expr_or_str_%s" % v
|
||||||
rule = """
|
rule = """
|
||||||
expr ::= fstring
|
expr ::= fstring_expr
|
||||||
fstring ::= %s BUILD_STRING
|
fstring_expr ::= expr FORMAT_VALUE
|
||||||
|
str ::= LOAD_CONST
|
||||||
|
fstring_expr_or_str ::= fstring_expr
|
||||||
|
fstring_expr_or_str ::= str
|
||||||
|
expr ::= fstring_multi
|
||||||
|
fstring_multi ::= %s BUILD_STRING
|
||||||
%s ::= %sBUILD_STRING
|
%s ::= %sBUILD_STRING
|
||||||
""" % (fstring_expr_or_str_n, fstring_expr_or_str_n, "fstring_expr_or_str " * v)
|
""" % (fstring_expr_or_str_n, fstring_expr_or_str_n, "fstring_expr_or_str " * v)
|
||||||
self.addRule(rule, nop_func)
|
self.addRule(rule, nop_func)
|
||||||
|
@@ -16,9 +16,10 @@ class Python36Parser(Python35Parser):
|
|||||||
|
|
||||||
def p_36misc(self, args):
|
def p_36misc(self, args):
|
||||||
"""
|
"""
|
||||||
|
fstring_single ::= expr FORMAT_VALUE
|
||||||
fstring_expr ::= expr FORMAT_VALUE
|
fstring_expr ::= expr FORMAT_VALUE
|
||||||
str ::= LOAD_CONST
|
str ::= LOAD_CONST
|
||||||
fstring ::= fstring_expr_or_strs BUILD_STRING
|
fstring_multi ::= fstring_expr_or_strs BUILD_STRING
|
||||||
fstring_expr_or_strs ::= fstring_expr_or_strs fstring_expr_or_str
|
fstring_expr_or_strs ::= fstring_expr_or_strs fstring_expr_or_str
|
||||||
fstring_expr_or_strs ::= fstring_expr_or_str
|
fstring_expr_or_strs ::= fstring_expr_or_str
|
||||||
fstring_expr_or_str ::= fstring_expr
|
fstring_expr_or_str ::= fstring_expr
|
||||||
|
@@ -633,7 +633,8 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
#######################
|
#######################
|
||||||
TABLE_DIRECT.update({
|
TABLE_DIRECT.update({
|
||||||
'fstring_expr': ( "{%c%{conversion}}", 0),
|
'fstring_expr': ( "{%c%{conversion}}", 0),
|
||||||
'fstring': ( "f'%c'", 0),
|
'fstring_single': ( "f'{%c%{conversion}}'", 0),
|
||||||
|
'fstring_multi': ( "f'%c'", 0),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -1893,6 +1894,9 @@ class SourceWalker(GenericASTTraversal, object):
|
|||||||
node.conversion = self.FSTRING_CONVERSION_MAP.get(node.data[1].attr, '')
|
node.conversion = self.FSTRING_CONVERSION_MAP.get(node.data[1].attr, '')
|
||||||
self.default(node)
|
self.default(node)
|
||||||
|
|
||||||
|
def n_fstring_single(self, node):
|
||||||
|
return self.n_fstring_expr(node)
|
||||||
|
|
||||||
def engine(self, entry, startnode):
|
def engine(self, entry, startnode):
|
||||||
"""The format template interpetation engine. See the comment at the
|
"""The format template interpetation engine. See the comment at the
|
||||||
beginning of this module for the how we interpret format specifications such as
|
beginning of this module for the how we interpret format specifications such as
|
||||||
|
Reference in New Issue
Block a user