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.

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