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.

220 lignes
7.4 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 == "JUMP_ABSOLUTE":
  144. block_dedent_at.append(i)
  145. elif opname == "JUMP_FORWARD":
  146. block_dedent_at.append(i + arg)
  147. else:
  148. raise NotImplementedError(opname, arg, stack)
  149. return lines
  150. def _get_func_args(func):
  151. codeobj = func.__code__
  152. count = codeobj.co_argcount
  153. if count == 0:
  154. return ""
  155. return ", ".join([arg for arg in codeobj.co_varnames[:count]])
  156. def _push(stack, item, literal=False):
  157. stack.append((item, literal))
  158. def _pop(stack, never_literal=False):
  159. item, literal = stack.pop()
  160. return repr(item) if literal and not never_literal else item
  161. def _print(indentation, *args, **kwargs):
  162. argstring = " ".join([str(arg) for arg in args if str(arg)])
  163. if kwargs.get("debug"):
  164. # Ignore debug messages without -d flag
  165. if len(sys.argv) > 1 and sys.argv[1] == "-d":
  166. print " " * 50 + "#", argstring
  167. return
  168. print " " * indentation + argstring
  169. if __name__ == "__main__":
  170. def f1(a):
  171. b = a + 10 / 7.0
  172. d = long_func(a, b+9, c=42, d="43")
  173. print b, d
  174. ex_tuple = ("Hello", "world!", abcdef)
  175. ex_list = [1, 2, 3] * 3 + [4, 5, 6]
  176. ex_set = {99, 98, 97, 96, 95}
  177. ex_dict = {d: e, f: False, "testing": g}
  178. return ex_dict
  179. def f2(a, b, c):
  180. if cmp1:
  181. line1
  182. if cmp2:
  183. line2
  184. elif cmp3:
  185. line3
  186. elif cmp4:
  187. line4
  188. else:
  189. line5
  190. line6
  191. else:
  192. line7
  193. line8
  194. if cmp4:
  195. line9
  196. if cmp5:
  197. if cmp6:
  198. if cmp7:
  199. if cmp8:
  200. if cmp9:
  201. line10
  202. return line11
  203. prettify_function(f1)
  204. print
  205. prettify_function(f2)