Generates random Python functions using Markov chains
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

187 lines
5.9 KiB

  1. import opcode
  2. import sys
  3. import func_smash
  4. OP_HASLOAD = {"LOAD_CONST": True, "LOAD_FAST": False, "LOAD_GLOBAL": False}
  5. OP_HASBINARY = {"BINARY_ADD": "+", "BINARY_SUBTRACT": "-",
  6. "BINARY_MULTIPLY": "*", "BINARY_DIVIDE": "/",
  7. "BINARY_POWER": "**", "BINARY_MODULO": "%"}
  8. OP_HASBUILD = {"BUILD_TUPLE": ("(", ")"), "BUILD_LIST": ("[", "]"),
  9. "BUILD_SET": ("{", "}")}
  10. def prettify_function(func, indent=0):
  11. args = _get_func_args(func)
  12. _print(indent, "def {0}({1}):".format(func.func_name, args))
  13. prettify_code(func.__code__, indent=indent+4)
  14. def prettify_code(codeobj, indent=0):
  15. codes = []
  16. codestring = codeobj.co_code
  17. length = len(codestring)
  18. i = 0
  19. while i < length:
  20. code = ord(codestring[i])
  21. i += 1
  22. if code >= opcode.HAVE_ARGUMENT:
  23. arg = func_smash._get_argument(codeobj, codestring, i, code)
  24. i += 2
  25. codes.append((code, arg))
  26. else:
  27. codes.append((code, None))
  28. _print_codestring(codes, indent)
  29. def _print_codestring(codes, indent):
  30. stack = []
  31. print_buffer = []
  32. block_dedent_at = []
  33. block_else_at = []
  34. i = 0
  35. for instruction in codes:
  36. code, arg = instruction
  37. opname = opcode.opname[code]
  38. if code >= opcode.HAVE_ARGUMENT:
  39. i += 3
  40. else:
  41. i += 1
  42. for x in block_dedent_at:
  43. if i >= x:
  44. indent -= 4
  45. block_dedent_at.remove(x)
  46. for x in block_else_at:
  47. if i >= x:
  48. _print(indent, "else:")
  49. indent += 4
  50. _print(indent, "pass")
  51. block_else_at.remove(x)
  52. _print(indent, i, opname, arg, debug=True)
  53. if opname in OP_HASLOAD:
  54. _push(stack, arg, literal=OP_HASLOAD[opname])
  55. elif opname in OP_HASBINARY:
  56. tos, tos1 = _pop(stack), _pop(stack)
  57. _push(stack, " ".join((tos1, OP_HASBINARY[opname], tos)))
  58. elif opname in OP_HASBUILD:
  59. args = []
  60. for i in xrange(arg):
  61. args.append(_pop(stack))
  62. args.reverse()
  63. start, end = OP_HASBUILD[opname]
  64. _push(stack, start + ", ".join(args) + end)
  65. elif opname == "BUILD_MAP":
  66. _push(stack, "{}")
  67. elif opname == "STORE_FAST":
  68. _print(indent, arg, "=", _pop(stack))
  69. elif opname == "STORE_MAP":
  70. key, value = _pop(stack), _pop(stack)
  71. pair = ": ".join((key, value))
  72. oldmap = _pop(stack)
  73. if oldmap == "{}":
  74. newmap = "{" + pair + "}"
  75. else:
  76. newmap = oldmap[:-1] + ", " + pair + "}"
  77. _push(stack, newmap)
  78. elif opname == "LOAD_ATTR":
  79. tos = _pop(stack)
  80. new_tos = tos + "." + arg
  81. _push(stack, new_tos)
  82. elif opname == "POP_TOP":
  83. _print(indent, _pop(stack))
  84. elif opname == "CALL_FUNCTION":
  85. numargs, numkwargs = arg
  86. args = []
  87. for i in xrange(numkwargs):
  88. value = _pop(stack)
  89. key = _pop(stack, never_literal=True)
  90. args.append("=".join((key, value)))
  91. for i in xrange(numargs):
  92. args.append(_pop(stack))
  93. args.reverse()
  94. funcname = _pop(stack)
  95. _push(stack, "{0}({1})".format(funcname, ", ".join(args)))
  96. elif opname == "PRINT_ITEM":
  97. print_buffer.append(_pop(stack))
  98. elif opname == "PRINT_NEWLINE":
  99. _print(indent, "print", ", ".join(print_buffer))
  100. print_buffer = []
  101. elif opname == "RETURN_VALUE":
  102. _print(indent, "return", _pop(stack))
  103. elif opname == "COMPARE_OP":
  104. tos, tos1 = _pop(stack), _pop(stack)
  105. compare = " ".join((tos1, arg, tos))
  106. _push(stack, compare)
  107. elif opname == "POP_JUMP_IF_FALSE":
  108. test = _pop(stack)
  109. _print(indent, "if {0}:".format(test))
  110. block_dedent_at.append(arg)
  111. block_else_at.append(arg)
  112. indent += 4
  113. elif opname == "JUMP_ABSOLUTE":
  114. block_dedent_at.append(i)
  115. elif opname == "JUMP_FORWARD":
  116. block_dedent_at.append(i + arg)
  117. else:
  118. raise NotImplementedError(opname, arg, stack)
  119. def _get_func_args(func):
  120. codeobj = func.__code__
  121. count = codeobj.co_argcount
  122. if count == 0:
  123. return ""
  124. return ", ".join([arg for arg in codeobj.co_varnames[:count]])
  125. def _push(stack, item, literal=False):
  126. stack.append((item, literal))
  127. def _pop(stack, never_literal=False):
  128. item, literal = stack.pop()
  129. return repr(item) if literal and not never_literal else item
  130. def _print(indentation, *args, **kwargs):
  131. argstring = " ".join([str(arg) for arg in args if str(arg)])
  132. if kwargs.get("debug"):
  133. # Ignore debug messages without -d flag
  134. if len(sys.argv) > 1 and sys.argv[1] == "-d":
  135. print " " * 50 + "#", argstring
  136. return
  137. print " " * indentation + argstring
  138. if __name__ == "__main__":
  139. def f1(a):
  140. b = a + 10 / 7.0
  141. d = long_func(a, b+9, c=42, d="43")
  142. print b, d
  143. ex_tuple = ("Hello", "world!", abcdef)
  144. ex_list = [1, 2, 3] * 3 + [4, 5, 6]
  145. ex_set = {99, 98, 97, 96, 95}
  146. ex_dict = {d: e, f: False, "testing": g}
  147. return ex_dict
  148. def f2(a, b, c):
  149. if cmp1:
  150. line1
  151. if cmp2:
  152. line2
  153. elif cmp3:
  154. line3
  155. elif cmp4:
  156. line4
  157. else:
  158. line5
  159. line6
  160. else:
  161. line7
  162. line8
  163. if cmp4:
  164. line9
  165. if cmp5:
  166. if cmp6:
  167. if cmp7:
  168. if cmp8:
  169. if cmp9:
  170. line10
  171. return line11
  172. prettify_function(f1)
  173. print
  174. prettify_function(f2)