|
- import opcode
- import sys
-
- import func_smash
-
- OP_HASLOAD = ("LOAD_FAST", "LOAD_CONST", "LOAD_GLOBAL")
- OP_HASBINARY = {"BINARY_ADD": "+", "BINARY_SUBTRACT": "-",
- "BINARY_MULTIPLY": "*", "BINARY_DIVIDE": "/",
- "BINARY_POWER": "**", "BINARY_MODULO": "%"}
- OP_HASBUILD = ("BUILD_TUPLE", "BUILD_LIST", "BUILD_MAP", "BUILD_SET")
-
- def prettify_function(func, indent=0):
- args = _get_func_args(func)
- _print(indent, "def {0}({1}):".format(func.func_name, args))
- prettify_code(func.__code__, indent=indent+4)
-
- def prettify_code(codeobj, indent=0):
- codes = []
- codestring = codeobj.co_code
- length = len(codestring)
- i = 0
- while i < length:
- code = ord(codestring[i])
- i += 1
- if code >= opcode.HAVE_ARGUMENT:
- arg = func_smash._get_argument(codeobj, codestring, i, code)
- i += 2
- codes.append((code, arg))
- else:
- codes.append((code, None))
- _print_codestring(codes, indent)
-
- def _print_codestring(codes, indent):
- stack = []
- print_buffer = []
- for instruction in codes:
- code, arg = instruction
- opname = opcode.opname[code]
- _print(indent, opname, arg, "; stack ==", stack, debug=True)
- if opname in OP_HASLOAD:
- stack.append(arg)
- elif opname in OP_HASBINARY:
- tos, tos1 = str(stack.pop()), str(stack.pop())
- stack.append(" ".join((tos1, OP_HASBINARY[opname], tos)))
- elif opname in OP_HASBUILD:
- args = []
- for i in xrange(arg):
- args.append(str(stack.pop()))
- if opname == "BUILD_TUPLE":
- stack.append("(" + ", ".join(args) + ")")
- elif opname == "STORE_FAST":
- _print(indent, arg, "=", stack.pop())
- elif opname == "POP_TOP":
- _print(indent, stack.pop())
- elif opname == "CALL_FUNCTION":
- numargs, numkwargs = arg
- args = []
- for i in xrange(numkwargs):
- value = str(stack.pop())
- key = str(stack.pop())
- args.append("=".join((key, value)))
- for i in xrange(numargs):
- args.append(str(stack.pop()))
- args.reverse()
- funcname = stack.pop()
- stack.append("{0}({1})".format(funcname, ", ".join(args)))
- elif opname == "PRINT_ITEM":
- print_buffer.append(stack.pop())
- elif opname == "PRINT_NEWLINE":
- _print(indent, "print", ", ".join(print_buffer))
- print_buffer = []
- elif opname == "RETURN_VALUE":
- _print(indent, "return", stack.pop())
- else:
- raise NotImplementedError(opname, arg, stack)
-
- def _get_func_args(func):
- codeobj = func.__code__
- count = codeobj.co_argcount
- if count == 0:
- return ""
- return ", ".join([arg for arg in codeobj.co_varnames[:count]])
-
- def _print(indentation, *args, **kwargs):
- argstring = " ".join([str(arg) for arg in args if str(arg)])
- if kwargs.get("debug"):
- # Ignore debug messages without -d flag
- if len(sys.argv) > 1 and sys.argv[1] == "-d":
- print " " * 40 + "#", argstring
- return
- print " " * indentation + argstring
-
- if __name__ == "__main__":
- def f1(a):
- b = a + 10 / 7.0
- d = long_func(a, b+9, c=42, d=43)
- print b, d
- v, z
- return d % 10
-
- def f2():
- pass
-
- prettify_function(f1)
- print
- prettify_function(f2)
|