Generates random Python functions using Markov chains
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

227 lignes
7.7 KiB

  1. import opcode
  2. import sys
  3. import func_smash
  4. OP_LOAD = {"LOAD_CONST": True, "LOAD_FAST": False, "LOAD_GLOBAL": False}
  5. OP_BINARY = {"BINARY_POWER": "**", "BINARY_MULTIPLY": "*",
  6. "BINARY_DIVIDE": "/", "BINARY_MODULO": "%", "BINARY_ADD": "+",
  7. "BINARY_SUBTRACT": "-", "BINARY_FLOOR_DIVIDE": "//",
  8. "BINARY_TRUE_DIVIDE": "/", "BINARY_LSHIFT": "<<",
  9. "BINARY_RSHIFT": ">>", "BINARY_AND": "&", "BINARY_XOR": "^",
  10. "BINARY_OR": "|"}
  11. OP_INPLACE = {"INPLACE_FLOOR_DIVIDE": "//", "INPLACE_TRUE_DIVIDE": "/",
  12. "INPLACE_ADD": "+", "INPLACE_SUBTRACT": "-",
  13. "INPLACE_MULTIPLY": "*", "INPLACE_DIVIDE": "/",
  14. "INPLACE_MODULO": "%", "INPLACE_POWER": "**",
  15. "INPLACE_LSHIFT": "<<", "INPLACE_RSHIFT": ">>",
  16. "INPLACE_AND": "&", "INPLACE_XOR": "^", "INPLACE_OR": "|"}
  17. OP_SUBSCR = ("BINARY_SUBSCR", "INPLACE_SUBSCR")
  18. OP_BUILD = {"BUILD_TUPLE": ("(", ")"), "BUILD_LIST": ("[", "]"),
  19. "BUILD_SET": ("{", "}")}
  20. TAB = 4
  21. def prettify_function(func, indent=0):
  22. args = _get_func_args(func)
  23. _print(indent, "def {0}({1}):".format(func.func_name, args))
  24. prettify_code(func.__code__, indent=indent+TAB)
  25. def prettify_code(codeobj, indent=0):
  26. codes = []
  27. codestring = codeobj.co_code
  28. length = len(codestring)
  29. i = 0
  30. while i < length:
  31. code = ord(codestring[i])
  32. i += 1
  33. if code >= opcode.HAVE_ARGUMENT:
  34. arg = func_smash._get_argument(codeobj, codestring, i, code)
  35. i += 2
  36. codes.append((code, arg))
  37. else:
  38. codes.append((code, None))
  39. skip_next_line = False
  40. lines = _parse_codestring(codes)
  41. for i, line in enumerate(lines):
  42. if skip_next_line:
  43. skip_next_line = False
  44. continue
  45. added_indent, code = line[0], line[1:]
  46. if code[0] == "else:" and lines[i+2][0] >= added_indent:
  47. # Remove the automatic "pass" after each "if" as it's not needed
  48. skip_next_line = True
  49. _print(indent + added_indent, *code)
  50. def _parse_codestring(codes):
  51. indent = 0
  52. lines = []
  53. stack = []
  54. print_buffer = []
  55. block_dedent_at = []
  56. block_else_at = []
  57. i = 0
  58. for instruction in codes:
  59. code, arg = instruction
  60. opname = opcode.opname[code]
  61. if code >= opcode.HAVE_ARGUMENT:
  62. i += 3
  63. else:
  64. i += 1
  65. for x in block_dedent_at:
  66. if i >= x:
  67. indent -= TAB
  68. block_dedent_at.remove(x)
  69. for x in block_else_at:
  70. if i >= x:
  71. lines.append((indent, "else:"))
  72. indent += TAB
  73. lines.append((indent, "pass"))
  74. block_else_at.remove(x)
  75. _print(indent, i, opname, arg, debug=True)
  76. if opname in OP_LOAD:
  77. _push(stack, arg, literal=OP_LOAD[opname])
  78. elif opname in OP_BINARY:
  79. tos, tos1 = _pop(stack), _pop(stack)
  80. _push(stack, " ".join((tos1, OP_BINARY[opname], tos)))
  81. elif opname in OP_INPLACE: # Works, but doesn't use inplace op magic
  82. tos, tos1 = _pop(stack), _pop(stack)
  83. _push(stack, " ".join((tos1, OP_INPLACE[opname], tos)))
  84. elif opname in OP_SUBSCR:
  85. tos, tos1 = _pop(stack), _pop(stack)
  86. _push(stack, "{0}[{1}]".format(tos1, tos))
  87. elif opname in OP_BUILD:
  88. args = []
  89. for i in xrange(arg):
  90. args.append(_pop(stack))
  91. args.reverse()
  92. start, end = OP_BUILD[opname]
  93. _push(stack, start + ", ".join(args) + end)
  94. elif opname == "BUILD_MAP":
  95. _push(stack, "{}")
  96. elif opname == "STORE_FAST":
  97. lines.append((indent, arg, "=", _pop(stack)))
  98. elif opname == "STORE_MAP":
  99. key, value = _pop(stack), _pop(stack)
  100. pair = ": ".join((key, value))
  101. oldmap = _pop(stack)
  102. if oldmap == "{}":
  103. newmap = "{" + pair + "}"
  104. else:
  105. newmap = oldmap[:-1] + ", " + pair + "}"
  106. _push(stack, newmap)
  107. elif opname == "LOAD_ATTR":
  108. tos = _pop(stack)
  109. new_tos = tos + "." + arg
  110. _push(stack, new_tos)
  111. elif opname == "POP_TOP":
  112. lines.append((indent, _pop(stack)))
  113. elif opname == "CALL_FUNCTION":
  114. numargs, numkwargs = arg
  115. args = []
  116. for i in xrange(numkwargs):
  117. value = _pop(stack)
  118. key = _pop(stack, never_literal=True)
  119. args.append("=".join((key, value)))
  120. for i in xrange(numargs):
  121. args.append(_pop(stack))
  122. args.reverse()
  123. funcname = _pop(stack)
  124. _push(stack, "{0}({1})".format(funcname, ", ".join(args)))
  125. elif opname == "PRINT_ITEM":
  126. print_buffer.append(_pop(stack))
  127. elif opname == "PRINT_NEWLINE":
  128. lines.append((indent, "print", ", ".join(print_buffer)))
  129. print_buffer = []
  130. elif opname == "RETURN_VALUE":
  131. lines.append((indent, "return", _pop(stack)))
  132. elif opname == "COMPARE_OP":
  133. tos, tos1 = _pop(stack), _pop(stack)
  134. compare = " ".join((tos1, arg, tos))
  135. _push(stack, compare)
  136. elif opname == "POP_JUMP_IF_FALSE":
  137. test = _pop(stack)
  138. block_dedent_at.append(arg)
  139. block_else_at.append(arg)
  140. lines.append((indent, "if {0}:".format(test)))
  141. indent += TAB
  142. lines.append((indent, "pass".format(test)))
  143. elif opname == "POP_JUMP_IF_TRUE":
  144. test = _pop(stack)
  145. block_dedent_at.append(arg)
  146. block_else_at.append(arg)
  147. lines.append((indent, "if not ({0}):".format(test)))
  148. indent += TAB
  149. lines.append((indent, "pass".format(test)))
  150. elif opname == "JUMP_ABSOLUTE":
  151. block_dedent_at.append(i)
  152. elif opname == "JUMP_FORWARD":
  153. block_dedent_at.append(i + arg)
  154. else:
  155. raise NotImplementedError(opname, arg, stack)
  156. return lines
  157. def _get_func_args(func):
  158. codeobj = func.__code__
  159. count = codeobj.co_argcount
  160. if count == 0:
  161. return ""
  162. return ", ".join([arg for arg in codeobj.co_varnames[:count]])
  163. def _push(stack, item, literal=False):
  164. stack.append((item, literal))
  165. def _pop(stack, never_literal=False):
  166. item, literal = stack.pop()
  167. return repr(item) if literal and not never_literal else item
  168. def _print(indentation, *args, **kwargs):
  169. argstring = " ".join([str(arg) for arg in args if str(arg)])
  170. if kwargs.get("debug"):
  171. # Ignore debug messages without -d flag
  172. if len(sys.argv) > 1 and sys.argv[1] == "-d":
  173. print " " * 50 + "#", argstring
  174. return
  175. print " " * indentation + argstring
  176. if __name__ == "__main__":
  177. def f1(a):
  178. b = a + 10 / 7.0
  179. d = long_func(a, b+9, c=42, d="43")
  180. print b, d
  181. ex_tuple = ("Hello", "world!", abcdef)
  182. ex_list = [1, 2, 3] * 3 + [4, 5, 6]
  183. ex_set = {99, 98, 97, 96, 95}
  184. ex_dict = {d: e, f: False, "testing": g}
  185. return ex_dict
  186. def f2(a, b, c):
  187. if cmp1:
  188. line1
  189. if cmp2:
  190. line2
  191. elif cmp3:
  192. line3
  193. elif cmp4:
  194. line4
  195. else:
  196. line5
  197. line6
  198. else:
  199. line7
  200. line8
  201. if cmp4:
  202. line9
  203. if cmp5:
  204. if cmp6:
  205. if cmp7:
  206. if cmp8:
  207. if cmp9:
  208. line10
  209. return line11
  210. prettify_function(f1)
  211. print
  212. prettify_function(f2)