WIP Make function redo

This commit is contained in:
rocky
2016-05-11 09:53:33 -04:00
parent b134d08e91
commit 1e22734b6b
5 changed files with 147 additions and 36 deletions

View File

@@ -201,6 +201,8 @@ class Python3Parser(PythonParser):
del_stmt ::= expr DELETE_ATTR
kwarg ::= LOAD_CONST expr
kwargs ::= kwargs kwarg
kwargs ::=
classdef ::= build_class designator
# Python3 introduced LOAD_BUILD_CLASS
@@ -507,21 +509,17 @@ class Python3Parser(PythonParser):
elif opname_base == 'UNPACK_LIST':
rule = 'unpack_list ::= ' + opname + ' designator' * token.attr
elif opname_base.startswith('MAKE_FUNCTION'):
self.addRule('mklambda ::= %s LOAD_LAMBDA %s' %
('expr ' * token.attr, opname), nop_func)
rule = 'mkfunc ::= %sLOAD_CONST %s' % ('expr ' * token.attr, opname)
self.add_unique_rule(rule, opname, token.attr, customize)
if opname.startswith('MAKE_FUNCTION_N'):
args_pos = token.attr & 0xff
args_kw = (token.attr >> 8) & 0xff
rule = ('mkfunc ::= %s %s %s %s' %
args_pos, args_kw, annotate_args = token.attr
self.addRule('mklambda ::= %sLOAD_LAMBDA %s' %
('pos_arg ' * args_pos, opname), nop_func)
if self.version > 3.2:
rule = ('mkfunc ::= %skwargs %s %s' %
('pos_arg ' * args_pos,
'expr ' * args_kw,
'LOAD_CONST ' * 3,
'LOAD_CONST ' * 2,
opname))
else:
rule = 'mkfunc ::= %sLOAD_CONST LOAD_CONST %s' % ('pos_arg ' * token.attr, opname)
pass
rule = ('mkfunc ::= %sLOAD_CONST %s' %
('pos_arg ' * args_pos, opname))
self.add_unique_rule(rule, opname, token.attr, customize)
elif opname.startswith('MAKE_CLOSURE'):
self.add_unique_rule('mklambda ::= %sload_closure LOAD_LAMBDA %s' %

View File

@@ -306,7 +306,8 @@ def _get_instructions_bytes(code, varnames=None, names=None, constants=None,
elif op in hasfree:
argval, argrepr = _get_name_info(arg, cells)
elif op in hasnargs:
argrepr = "%d positional, %d keyword pair" % (code[i-2], code[i-1])
argrepr = ("%d positional, %d keyword pair, %d annotated" %
(code[i-2], code[i-1], code[i]))
yield Instruction(opname[op_num], op,
arg, argval, argrepr,
offset, starts_line, is_jump_target)

View File

@@ -167,7 +167,29 @@ class Scanner3(scan.Scanner):
elif op in op3.hasfree:
pattr = free[oparg]
if op_name in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
if op_name == 'MAKE_FUNCTION':
argc = oparg
attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
pos_args, name_pair_args, annotate_args = attr
if name_pair_args > 0:
op_name = 'MAKE_FUNCTION_N%d' % name_pair_args
pass
if annotate_args > 0:
op_name = '%s_A_%d' % [op_name, annotate_args]
pass
op_name = '%s_%d' % (op_name, pos_args)
pattr = ("%d positional, %d keyword pair, %d annotated" %
(pos_args, name_pair_args, annotate_args))
tokens.append(
Token(
type_ = op_name,
attr = (pos_args, name_pair_args, annotate_args),
pattr = pattr,
offset = offset,
linestart = linestart)
)
continue
elif op_name in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
'UNPACK_SEQUENCE',
'MAKE_FUNCTION', 'CALL_FUNCTION', 'MAKE_CLOSURE',
'CALL_FUNCTION_VAR', 'CALL_FUNCTION_KW',

View File

@@ -30,6 +30,8 @@ class Scanner35(scan3.Scanner3):
# we do post-processing like we do here.
def disassemble(self, co, classname=None,
code_objects={}):
dis.disassemble(co) # DEBUG
# Container for tokens
tokens = []
customize = {}
@@ -104,28 +106,37 @@ class Scanner35(scan3.Scanner3):
else:
pattr = const
pass
elif opname == 'MAKE_FUNCTION':
argc = inst.argval
attr = ((argc & 0xFF), (argc >> 8) & 0xFF, (argc >> 16) & 0x7FFF)
pos_args, name_pair_args, annotate_args = attr
if name_pair_args > 0:
opname = 'MAKE_FUNCTION_N%d' % name_pair_args
pass
if annotate_args > 0:
opname = '%s_A_%d' % [op_name, annotate_args]
pass
opname = '%s_%d' % (opname, pos_args)
pattr = ("%d positional, %d keyword pair, %d annotated" %
(pos_args, name_pair_args, annotate_args))
tokens.append(
Token(
type_ = opname,
attr = (pos_args, name_pair_args, annotate_args),
pattr = pattr,
offset = inst.offset,
linestart = inst.starts_line)
)
continue
elif opname in ('BUILD_LIST', 'BUILD_TUPLE', 'BUILD_SET', 'BUILD_SLICE',
'BUILD_MAP',
'UNPACK_SEQUENCE',
'MAKE_FUNCTION', 'MAKE_CLOSURE',
'DUP_TOPX', 'RAISE_VARARGS'
'BUILD_MAP', 'UNPACK_SEQUENCE', 'MAKE_CLOSURE',
'RAISE_VARARGS'
):
pos_args = inst.argval
if inst.opname == 'MAKE_FUNCTION':
argc = inst.argval
pos_args = (argc & 0xFF)
name_pair_args = (argc >> 8) & 0xFF
if name_pair_args > 0:
opname = 'MAKE_FUNCTION_N%d' % name_pair_args
pass
annotate_args = (argc >> 16) & 0x7FFF
if annotate_args > 0:
opname = '%s_A_%d' % [op_name, annotate_args]
pass
elif inst.opname != 'BUILD_SLICE':
if inst.opname != 'BUILD_SLICE':
customize[opname] = pos_args
pass
opname = '%s_%d' % (opname, pos_args)
elif opname == 'JUMP_ABSOLUTE':
pattr = inst.argval
target = self.get_target(inst.offset)

View File

@@ -261,6 +261,7 @@ TABLE_DIRECT = {
'classdefdeco': ( '%c', 0),
'classdefdeco1': ( '\n\n%|@%c%c', 0, 1),
'kwarg': ( '%[0]{pattr}=%c', 1),
'kwargs': ( '%C', (0, maxint, ', ') ),
'importlist2': ( '%C', (0, maxint, ', ') ),
'assert': ( '%|assert %c\n' , 0 ),
@@ -951,7 +952,11 @@ class SourceWalker(GenericASTTraversal, object):
self.write(func_name)
self.indentMore()
self.make_function(node, isLambda=False, code_index=code_index)
if self.version > 3.2:
self.make_function33(node, isLambda=False, code_index=code_index)
else:
self.make_function2(node, isLambda=False, code_index=code_index)
if len(self.param_stack) > 1:
self.write('\n\n')
else:
@@ -1521,7 +1526,7 @@ class SourceWalker(GenericASTTraversal, object):
# return self.traverse(node[1])
raise Exception("Can't find tuple parameter " + name)
def make_function(self, node, isLambda, nested=1, code_index=-2):
def make_function2(self, node, isLambda, nested=1, code_index=-2):
"""Dump function defintion, doc string, and function body."""
def build_param(ast, name, default):
@@ -1539,7 +1544,6 @@ class SourceWalker(GenericASTTraversal, object):
if default:
if self.showast:
print()
print('--', name)
print(default)
print('--')
@@ -1549,9 +1553,13 @@ class SourceWalker(GenericASTTraversal, object):
return result
else:
return name
# node[-1] == MAKE_xxx_n
defparams = node[:node[-1].attr]
# node[-1] == MAKE_FUNCTION_n
if isinstance(node[-1].attr, tuple):
defparams = node[:node[-1].attr[0]]
else:
defparams = node[:node[-1].attr]
code = node[code_index].attr
assert iscode(code)
@@ -1575,6 +1583,7 @@ class SourceWalker(GenericASTTraversal, object):
return
# build parameters
params = [build_param(ast, name, default) for
name, default in zip_longest(paramnames, defparams, fillvalue=None)]
# params = [ build_param(ast, name, default) for
@@ -1601,6 +1610,76 @@ class SourceWalker(GenericASTTraversal, object):
self.print_("(", ", ".join(params), "):")
# self.print_(indent, '#flags:\t', int(code.co_flags))
self.make_function_tail(indent, code, ast, isLambda)
def make_function33(self, node, isLambda, nested=1, code_index=-2):
"""Dump function defintion, doc string, and function body."""
def build_param(ast, name, default):
"""build parameters:
- handle defaults
- handle format tuple parameters
"""
if default:
if self.showast:
print()
print('--', name)
print(default)
print('--')
result = '%s = %s' % (name, self.traverse(default, indent='') )
if result[-2:] == '= ': # default was 'LOAD_CONST None'
result += 'None'
return result
else:
return name
# node[-1] == MAKE_FUNCTION_xxx
args_node = node[-1]
if isinstance(args_node.attr, tuple):
pos_args, kw_args, annotate_args = args_node.attr
else:
pos_args = args_node.attr
code = node[code_index].attr
assert iscode(code)
code = Code(code, self.scanner, self.currentclass)
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
# build positional parameters
argc = code.co_argcount
params = list(code.co_varnames[:argc])
params.reverse() # back to correct order
if 4 & code.co_flags: # flag 2 -> variable number of args
params.append('*%s' % code.co_varnames[argc])
argc += 1
if 8 & code.co_flags: # flag 3 -> keyword args
params.append('**%s' % code.co_varnames[argc])
argc += 1
# dump parameter list (with default values)
indent = self.indent
if isLambda:
self.write("lambda ", ", ".join(params), ": ")
else:
self.print_("(", ", ".join(params), "):")
# self.print_(indent, '#flags:\t', int(code.co_flags))
self.make_function_tail(indent, code, ast, isLambda)
def make_function_tail(self, indent, code, ast, isLambda):
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])