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.

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