Start to attack Python 3.1 def() -> xx construct

Start to localize make_function routines by Python version
This commit is contained in:
rocky
2016-10-26 08:20:19 -04:00
parent 8feb472d51
commit 7daec3352c
5 changed files with 187 additions and 6 deletions

Binary file not shown.

View File

@@ -0,0 +1,6 @@
# Bug in 3.1 _pyio.py. The -> "IOBase" is problematic
def open(file, mode = "r", buffering = None,
encoding = None, errors = None,
newline = None, closefd = True) -> "IOBase":
return text

View File

@@ -33,8 +33,22 @@ class Python31Parser(Python32Parser):
load ::= LOAD_FAST
load ::= LOAD_NAME
funcdef ::= mkfunc designator
stmt ::= funcdeftest
funcdeftest ::= mkfunctest designator
"""
def add_custom_rules(self, tokens, customize):
super(Python31Parser, self).add_custom_rules(tokens, customize)
for i, token in enumerate(tokens):
opname = token.type
if opname.startswith('MAKE_FUNCTION_A'):
args_pos, args_kw, annotate_args = token.attr
# Check that there are 2 annotated params?
# rule = ('mkfunc2 ::= %s%sEXTENDED_ARG %s' %
# ('pos_arg ' * (args_pos), 'kwargs ' * (annotate_args-1), opname))
rule = ('mkfunctest ::= %s%sLOAD_CONST EXTENDED_ARG %s' %
(('pos_arg ' * (args_pos)), 'kwargs ', opname))
self.add_unique_rule(rule, opname, token.attr, customize)
class Python31ParserSingle(Python31Parser, PythonParserSingle):
pass

View File

@@ -20,7 +20,7 @@ from uncompyle6.scanners.tok import Token
# The byte code versions we support
PYTHON_VERSIONS = (1.5,
2.1, 2.2, 2.3, 2.4, 2.5, 2.6, 2.7,
3.1, 3.2, 3.3, 3.4, 3.5, 3.6)
3.0, 3.1, 3.2, 3.3, 3.4, 3.5, 3.6)
# FIXME: DRY
if PYTHON3:

View File

@@ -612,10 +612,171 @@ class SourceWalker(GenericASTTraversal, object):
})
##########################
# Python 3.2 and 3.3 only
##########################
if 3.2 <= version <= 3.3:
if 3.1 == version:
##########################
# Python 3.1
##########################
TABLE_DIRECT.update({
'funcdeftest': ( '\n\n%|def %c%c\n', -1, 0),
})
def make_function31(node, isLambda, nested=1,
codeNode=None, annotate=None):
"""Dump function defintion, doc string, and function
body. This code is specialzed for Python 3.1"""
def build_param(ast, name, default):
"""build parameters:
- handle defaults
- handle format tuple parameters
"""
if default:
value = self.traverse(default, indent='')
maybe_show_ast_param_default(self.showast, name, value)
result = '%s=%s' % (name, value)
if result[-2:] == '= ': # default was 'LOAD_CONST None'
result += 'None'
return result
else:
return name
# MAKE_FUNCTION_... or MAKE_CLOSURE_...
assert node[-1].type.startswith('MAKE_')
args_node = node[-1]
if isinstance(args_node.attr, tuple):
defparams = node[1:args_node.attr[0]+1]
pos_args, kw_args, annotate_args = args_node.attr
else:
defparams = node[:args_node.attr]
kw_args = 0
pass
lambda_index = -2
if lambda_index and isLambda and iscode(node[lambda_index].attr):
assert node[lambda_index].type == 'LOAD_LAMBDA'
code = node[lambda_index].attr
else:
code = codeNode.attr
assert iscode(code)
code = Code(code, self.scanner, self.currentclass)
# add defaults values to parameter names
argc = code.co_argcount
paramnames = list(code.co_varnames[:argc])
try:
ast = self.build_ast(code._tokens,
code._customize,
isLambda = isLambda,
noneInNames = ('None' in code.co_names))
except ParserError as p:
self.write(str(p))
self.ERROR = p
return
kw_pairs = args_node.attr[1] if self.version >= 3.0 else 0
indent = self.indent
params = [build_param(ast, name, default) for
name, default in zip_longest(paramnames, defparams, fillvalue=None)]
params.reverse() # back to correct order
if 4 & code.co_flags: # flag 2 -> variable number of args
if self.version > 3.0:
params.append('*%s' % code.co_varnames[argc + kw_pairs])
else:
params.append('*%s' % code.co_varnames[argc])
argc += 1
# dump parameter list (with default values)
if isLambda:
self.write("lambda ", ", ".join(params))
else:
self.write("(", ", ".join(params))
# self.println(indent, '#flags:\t', int(code.co_flags))
if kw_args > 0:
if not (4 & code.co_flags):
if argc > 0:
self.write(", *, ")
else:
self.write("*, ")
pass
else:
self.write(", ")
kwargs = node[0]
last = len(kwargs)-1
i = 0
for n in node[0]:
if n == 'kwarg':
self.write('%s=' % n[0].pattr)
self.preorder(n[1])
if i < last:
self.write(', ')
i += 1
pass
pass
pass
if 8 & code.co_flags: # flag 3 -> keyword args
if argc > 0:
self.write(', ')
self.write('**%s' % code.co_varnames[argc + kw_pairs])
if isLambda:
self.write(": ")
else:
self.write(')')
if annotate:
self.write(' -> %s' % annotate)
self.println(":")
if (len(code.co_consts) > 0 and
code.co_consts[0] is not None and not isLambda): # ugly
# docstring exists, dump it
self.print_docstring(indent, code.co_consts[0])
code._tokens = None # save memory
assert ast == 'stmts'
all_globals = find_all_globals(ast, set())
for g in ((all_globals & self.mod_globs) | find_globals(ast, set())):
self.println(self.indent, 'global ', g)
self.mod_globs -= all_globals
has_none = 'None' in code.co_names
rn = has_none and not find_none(ast)
self.gen_source(ast, code.co_name, code._customize, isLambda=isLambda,
returnNone=rn)
code._tokens = code._customize = None # save memory
self.make_function31 = make_function31
def n_mkfunctest(node):
self.indentMore()
code = node[-3]
annotate = None
if node[-4][0][0] == 'LOAD_CONST':
annotate = node[-4][0][0].attr
self.make_function31(node, isLambda=False,
codeNode=code, annotate=annotate)
if len(self.param_stack) > 1:
self.write('\n\n')
else:
self.write('\n\n\n')
self.indentLess()
self.prune() # stop recursing
self.n_mkfunctest = n_mkfunctest
elif 3.2 <= version <= 3.3:
##########################
# Python 3.2 and 3.3
##########################
TABLE_DIRECT.update({
'store_locals': ( '%|# inspect.currentframe().f_locals = __locals__\n', ),
})