|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- import opcode
- import sys
-
- import func_smash
-
- OP_HASLOAD = {"LOAD_CONST": True, "LOAD_FAST": False, "LOAD_GLOBAL": False}
- OP_HASBINARY = {"BINARY_ADD": "+", "BINARY_SUBTRACT": "-",
- "BINARY_MULTIPLY": "*", "BINARY_DIVIDE": "/",
- "BINARY_POWER": "**", "BINARY_MODULO": "%"}
- OP_HASBUILD = {"BUILD_TUPLE": ("(", ")"), "BUILD_LIST": ("[", "]"),
- "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:
- _push(stack, arg, literal=OP_HASLOAD[opname])
- elif opname in OP_HASBINARY:
- tos, tos1 = _pop(stack), _pop(stack)
- _push(stack, " ".join((tos1, OP_HASBINARY[opname], tos)))
- elif opname in OP_HASBUILD:
- args = []
- for i in xrange(arg):
- args.append(_pop(stack))
- args.reverse()
- start, end = OP_HASBUILD[opname]
- _push(stack, start + ", ".join(args) + end)
- elif opname == "BUILD_MAP":
- _push(stack, "{}")
- elif opname == "STORE_FAST":
- _print(indent, arg, "=", _pop(stack))
- elif opname == "STORE_MAP":
- pair = ": ".join((_pop(stack), _pop(stack)))
- oldmap = _pop(stack)
- if oldmap == "{}":
- newmap = "{" + pair + "}"
- else:
- newmap = oldmap[:-1] + ", " + pair + "}"
- _push(stack, newmap)
- elif opname == "POP_TOP":
- _print(indent, _pop(stack))
- elif opname == "CALL_FUNCTION":
- numargs, numkwargs = arg
- args = []
- for i in xrange(numkwargs):
- value = _pop(stack)
- key = _pop(stack, never_literal=True)
- args.append("=".join((key, value)))
- for i in xrange(numargs):
- args.append(_pop(stack))
- args.reverse()
- funcname = _pop(stack)
- _push(stack, "{0}({1})".format(funcname, ", ".join(args)))
- elif opname == "PRINT_ITEM":
- print_buffer.append(_pop(stack))
- elif opname == "PRINT_NEWLINE":
- _print(indent, "print", ", ".join(print_buffer))
- print_buffer = []
- elif opname == "RETURN_VALUE":
- _print(indent, "return", _pop(stack))
- 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 _push(stack, item, literal=False):
- stack.append((item, literal))
-
- def _pop(stack, never_literal=False):
- item, literal = stack.pop()
- return repr(item) if literal and not never_literal else item
-
- 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 " " * 50 + "#", 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
- ex_tuple = ("Hello", "world!", abcdef)
- ex_list = [1, 2, 3] * 3 + [4, 5, 6]
- ex_set = {99, 98, 97, 96, 95}
- ex_dict = {d: e, f: False, "testing": g}
- return ex_dict
-
- def f2():
- pass
-
- prettify_function(f1)
- print
- prettify_function(f2)
|