xosski

.pyc

Nov 6th, 2024
16
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 117.40 KB | None | 0 0
  1. #!/usr/bin/env python3
  2.  
  3. """
  4. Decompiler for Python3.7.
  5. Decompile a module or a function using the decompile() function
  6.  
  7. >>> from unpyc3 import decompile
  8. >>> def foo(x, y, z=3, *args):
  9. ... global g
  10. ... for i, j in zip(x, y):
  11. ... if z == i + j or args[i] == j:
  12. ... g = i, j
  13. ... return
  14. ...
  15. >>> print(decompile(foo))
  16.  
  17. def foo(x, y, z=3, *args):
  18. global g
  19. for i, j in zip(x, y):
  20. if z == i + j or args[i] == j:
  21. g = i, j
  22. return
  23. >>>
  24. """
  25. from __future__ import annotations
  26.  
  27. __package__ = "unpyc"
  28. import sys
  29. import traceback
  30. from pathlib import Path
  31. from types import ModuleType
  32. nspkg = ModuleType(__package__)
  33. nspkg.__package__ = __package__
  34. nspkg.__name__ = __package__
  35. nspkg.__path__ = [
  36. Path(__file__).parent.absolute().as_posix()
  37. ]
  38. sys.modules[__package__] = nspkg
  39.  
  40. sys.modules[f"[__package__].{__name__}"] = __import__(__name__)
  41. from typing import Union, Iterable, Any, List
  42. from importlib.machinery import SourceFileLoader
  43. from importlib.util import module_from_spec, spec_from_loader
  44. import opcode
  45.  
  46. for name in ("opcodes",):
  47. path = (
  48. Path(__file__).parent / f"{name}.py"
  49. ).absolute().as_posix()
  50. loader = SourceFileLoader(
  51. f"{__package__}.{name}",
  52. path,
  53. )
  54. module = module_from_spec(
  55. spec_from_loader(
  56. f"{__package__}.{name}",
  57. loader=loader,
  58. origin=path,
  59. is_package=False
  60. )
  61. )
  62. loader.exec_module(module)
  63. globals().update({name: module})
  64.  
  65. opnames = {}
  66. opmap = {}
  67.  
  68. for opc, opname in enumerate(opcode.opname):
  69. opmap[opname] = opc
  70. opnames[opc] = opname
  71.  
  72. for opname, code in opmap.items():
  73. if not opname.isidentifier():
  74. continue
  75. # sys.stderr.write(f'Adding opcode {opname=} -> {code=}\x0a')
  76. exec(f'{opname} = {code}')
  77. # sys.stderr.flush()
  78.  
  79. def missing_var(name):
  80. if name not in globals():
  81. globals()[name] = -1
  82.  
  83. missing_var("END_FINALLY")
  84. missing_var("BREAK_LOOP")
  85.  
  86. # __all__ = ['decompile']
  87.  
  88.  
  89.  
  90. def set_trace(trace_function):
  91. global current_trace
  92. current_trace = trace_function if trace_function else _trace
  93.  
  94.  
  95. def get_trace():
  96. global current_trace
  97. return None if current_trace == _trace else current_trace
  98.  
  99.  
  100. def trace(*args):
  101. global current_trace
  102. if current_trace:
  103. current_trace(*args)
  104.  
  105.  
  106. def _trace(*args):
  107. pass
  108.  
  109.  
  110. current_trace = _trace
  111.  
  112. IS_NOT_310 = sys.version_info < (3, 10)
  113.  
  114. # TODO:
  115. # - Support for keyword-only arguments
  116. # - Handle assert statements better
  117. # - (Partly done) Nice spacing between function/class declarations
  118.  
  119. import dis
  120. from array import array
  121. from opcode import opname, opmap, HAVE_ARGUMENT, cmp_op
  122. import inspect
  123.  
  124. import struct
  125. import sys
  126.  
  127. # Masks for code object's co_flag attribute
  128. VARARGS = 4
  129. VARKEYWORDS = 8
  130.  
  131. # Put opcode names in the global namespace
  132. for name, val in opmap.items():
  133. globals()[name] = val
  134.  
  135. # These opcodes will generate a statement. This is used in the first
  136. # pass (in Code.find_else) to find which POP_JUMP_IF_* instructions
  137. # are jumps to the else clause of an if statement
  138. stmt_opcodes = {1, 130, 137, 138, 143, 80, 83, 86, 87, 88, 89, 90, 91, 95, 96, 97, 98, 108, 109, 119, 120, 121, 122, 125, 126}
  139.  
  140. # Conditional branching opcode that make up if statements and and/or
  141. # expressions
  142. pop_jump_if_opcodes = (POP_JUMP_IF_TRUE, POP_JUMP_IF_FALSE)
  143.  
  144. # These opcodes indicate that a pop_jump_if_x to the address just
  145. # after them is an else-jump
  146. else_jump_opcodes = (
  147. JUMP_FORWARD,
  148. RETURN_VALUE,
  149. JUMP_ABSOLUTE,
  150. RAISE_VARARGS,
  151. POP_TOP,
  152. )
  153. if "SETUP_LOOP" in globals():
  154. else_jump_opcodes += (
  155. SETUP_LOOP,
  156. )
  157. # These opcodes indicate for loop rather than while loop
  158. for_jump_opcodes = (GET_ITER, FOR_ITER, GET_ANEXT)
  159.  
  160.  
  161. def read_code(stream):
  162. # This helper is needed in order for the PEP 302 emulation to
  163. # correctly handle compiled files
  164. # Note: stream must be opened in "rb" mode
  165. import marshal
  166.  
  167. if sys.version_info < (3, 4):
  168. import imp
  169.  
  170. runtime_magic = imp.get_magic()
  171. else:
  172. import importlib.util
  173.  
  174. runtime_magic = importlib.util.MAGIC_NUMBER
  175.  
  176. magic = stream.read(4)
  177. if magic != runtime_magic:
  178. print("*** Warning: file has wrong magic number ***")
  179.  
  180. flags = 0
  181. if sys.version_info >= (3, 7):
  182. flags = struct.unpack('i', stream.read(4))[0]
  183.  
  184. if flags & 1:
  185. stream.read(4)
  186. stream.read(4)
  187. else:
  188. stream.read(4) # Skip timestamp
  189. if sys.version_info >= (3, 3):
  190. stream.read(4) # Skip rawsize
  191. return marshal.load(stream)
  192.  
  193.  
  194. def dec_module(path) -> Suite:
  195. if path.endswith(".py"):
  196. if sys.version_info < (3, 6):
  197. import imp
  198.  
  199. path = imp.cache_from_source(path)
  200. else:
  201. import importlib.util
  202.  
  203. path = importlib.util.cache_from_source(path)
  204. elif not path.endswith(".pyc") and not path.endswith(".pyo"):
  205. raise ValueError("path must point to a .py or .pyc file")
  206. with open(path, "rb") as stream:
  207. code_obj = read_code(stream)
  208. code = Code(code_obj)
  209. return code.get_suite(
  210. include_declarations=False, look_for_docstring=True
  211. )
  212.  
  213.  
  214. def decompile(obj) -> Union[Suite, PyStatement]:
  215. """
  216. Decompile obj if it is a module object, a function or a
  217. code object. If obj is a string, it is assumed to be the path
  218. to a python module.
  219. """
  220. if isinstance(obj, str):
  221. return dec_module(obj)
  222. if inspect.iscode(obj):
  223. code = Code(obj)
  224. return code.get_suite()
  225. if inspect.isfunction(obj):
  226. code = Code(obj.__code__)
  227. defaults = obj.__defaults__
  228. kwdefaults = obj.__kwdefaults__
  229. return DefStatement(
  230. code, defaults, kwdefaults, obj.__closure__
  231. )
  232. elif inspect.ismodule(obj):
  233. return dec_module(obj.__file__)
  234. else:
  235. msg = "Object must be string, module, function or code object"
  236. raise TypeError(msg)
  237.  
  238.  
  239. class Indent:
  240. def __init__(self, indent_level=0, indent_step=4):
  241. self.level = indent_level
  242. self.step = indent_step
  243.  
  244. def write(self, pattern, *args, **kwargs):
  245. if args or kwargs:
  246. pattern = pattern.format(*args, **kwargs)
  247. return self.indent(pattern)
  248.  
  249. def __add__(self, indent_increase):
  250. return type(self)(self.level + indent_increase, self.step)
  251.  
  252.  
  253. class IndentPrint(Indent):
  254. def indent(self, string):
  255. print(" " * self.step * self.level + string)
  256.  
  257.  
  258. class IndentString(Indent):
  259. def __init__(self, indent_level=0, indent_step=4, lines=None):
  260. Indent.__init__(self, indent_level, indent_step)
  261. if lines is None:
  262. self.lines = []
  263. else:
  264. self.lines = lines
  265.  
  266. def __add__(self, indent_increase):
  267. return type(self)(
  268. self.level + indent_increase, self.step, self.lines
  269. )
  270.  
  271. def sep(self):
  272. if not self.lines or self.lines[-1]:
  273. self.lines.append("")
  274.  
  275. def indent(self, string):
  276. self.lines.append(" " * self.step * self.level + string)
  277.  
  278. def __str__(self):
  279. return "\n".join(self.lines)
  280.  
  281.  
  282. class Stack:
  283. def __init__(self):
  284. self._stack = []
  285. self._counts = {}
  286.  
  287. def __bool__(self):
  288. return bool(self._stack)
  289.  
  290. def __len__(self):
  291. return len(self._stack)
  292.  
  293. def __contains__(self, val):
  294. return self.get_count(val) > 0
  295.  
  296. def get_count(self, obj):
  297. return self._counts.get(id(obj), 0)
  298.  
  299. def set_count(self, obj, val):
  300. if val:
  301. self._counts[id(obj)] = val
  302. else:
  303. del self._counts[id(obj)]
  304.  
  305. def pop1(self):
  306. val = None
  307. if self._stack:
  308. val = self._stack.pop()
  309. else:
  310. raise Exception('Empty stack popped!')
  311. self.set_count(val, self.get_count(val) - 1)
  312. return val
  313.  
  314. def pop(self, count=None):
  315. if count is None:
  316. val = self.pop1()
  317. return val
  318. else:
  319. vals = [self.pop1() for i in range(count)]
  320. vals.reverse()
  321. return vals
  322.  
  323. def push(self, *args):
  324. for val in args:
  325. self.set_count(val, self.get_count(val) + 1)
  326. self._stack.append(val)
  327.  
  328. def peek(self, count=None):
  329. if count is None:
  330. return self._stack[-1]
  331. else:
  332. return self._stack[-count:]
  333.  
  334. def __getitem__(self, x):
  335. res = Stack()
  336. res._stack = self._stack[x]
  337. _counts = {}
  338. for val in res._stack:
  339. _counts[id(val)] = _counts.get(id(val), 0) + 1
  340. res._counts = _counts
  341. return res
  342.  
  343.  
  344. def code_walker(code):
  345. l = len(code)
  346. code = array('B', code)
  347. oparg = 0
  348. i = 0
  349. extended_arg = 0
  350.  
  351. while i < l:
  352. op = code[i]
  353. offset = 1
  354. if sys.version_info >= (3, 6):
  355. oparg = code[i + offset]
  356. offset += 1
  357. elif op >= HAVE_ARGUMENT:
  358. oparg = (
  359. code[i + offset]
  360. + code[i + offset + 1] * 256
  361. + extended_arg
  362. )
  363. extended_arg = 0
  364. offset += 2
  365. if op == EXTENDED_ARG:
  366. if sys.version_info >= (3, 6):
  367. op = code[i + offset]
  368. offset += 1
  369. oparg <<= 8
  370. oparg |= code[i + offset]
  371. offset += 1
  372. else:
  373. extended_arg = oparg * 65536
  374. yield i, (op, oparg)
  375. i += offset
  376.  
  377.  
  378. class CodeFlags(object):
  379. def __init__(self, cf):
  380. self.flags = cf
  381.  
  382. @property
  383. def optimized(self):
  384. return self.flags & 0x1
  385.  
  386. @property
  387. def new_local(self):
  388. return self.flags & 0x2
  389.  
  390. @property
  391. def varargs(self):
  392. return self.flags & 0x4
  393.  
  394. @property
  395. def varkwargs(self):
  396. return self.flags & 0x8
  397.  
  398. @property
  399. def nested(self):
  400. return self.flags & 0x10
  401.  
  402. @property
  403. def generator(self):
  404. return self.flags & 0x20
  405.  
  406. @property
  407. def no_free(self):
  408. return self.flags & 0x40
  409.  
  410. @property
  411. def coroutine(self):
  412. return self.flags & 0x80
  413.  
  414. @property
  415. def iterable_coroutine(self):
  416. return self.flags & 0x100
  417.  
  418. @property
  419. def async_generator(self):
  420. return self.flags & 0x200
  421.  
  422.  
  423. class Code:
  424. def __init__(self, code_obj, parent=None):
  425. self.code_obj = code_obj
  426. self.parent = parent
  427. self.derefnames = [
  428. PyName(v)
  429. for v in code_obj.co_cellvars + code_obj.co_freevars
  430. ]
  431. self.consts = list(map(PyConst, code_obj.co_consts))
  432. self.names = list(map(PyName, code_obj.co_names))
  433. self.varnames = list(map(PyName, code_obj.co_varnames))
  434. self.instr_seq = list(code_walker(code_obj.co_code))
  435. self.instr_list = self.instr_seq
  436. self.instr_map = {
  437. addr: i for i, (addr, _) in enumerate(self.instr_seq)
  438. }
  439. self.name = code_obj.co_name
  440. self.globals = []
  441. self.nonlocals = []
  442. self.jump_targets = []
  443. self.find_else()
  444. self.find_jumps()
  445. trace('================================================')
  446. trace(self.code_obj)
  447. trace('================================================')
  448. for addr in self:
  449. trace(str(addr))
  450. if (
  451. addr.opcode in stmt_opcodes
  452. or addr.opcode in pop_jump_if_opcodes
  453. ):
  454. trace(' ')
  455. trace('================================================')
  456. self.flags: CodeFlags = CodeFlags(code_obj.co_flags)
  457.  
  458. def __getitem__(self, instr_index):
  459. if 0 <= instr_index < len(self.instr_seq):
  460. return Address(self, instr_index)
  461.  
  462. def __iter__(self):
  463. for i in range(len(self.instr_seq)):
  464. yield Address(self, i)
  465.  
  466. def show(self):
  467. for addr in self:
  468. print(addr)
  469.  
  470. def address(self, addr):
  471. if addr in self.instr_map:
  472. tgt_addr = self.instr_map[addr]
  473. ret = self[tgt_addr]
  474. return ret
  475. if addr in self.instr_list:
  476. tgt_addr = self.instr_list[addr]
  477. ret = self[tgt_addr]
  478. return ret
  479. return self[addr]
  480.  
  481. def iscellvar(self, i):
  482. return i < len(self.code_obj.co_cellvars)
  483.  
  484. def find_jumps(self):
  485. for addr in self:
  486. opcode, arg = addr
  487. jt = addr.jump()
  488. if jt:
  489. self.jump_targets.append(jt)
  490.  
  491. def find_else(self):
  492. jumps = {}
  493. last_jump = None
  494. for addr in self:
  495. opcode, arg = addr
  496. if opcode in pop_jump_if_opcodes:
  497. # 3.10 needs a doubled arg (e.g. 14) but any
  498. # version lower does not (e.g. 28)
  499. jump_addr = self.address(arg * (2 - IS_NOT_310) - 2)
  500. if (
  501. jump_addr.opcode in else_jump_opcodes
  502. or jump_addr.opcode is FOR_ITER
  503. ):
  504. last_jump = addr
  505. jumps[jump_addr] = addr
  506. elif opcode == JUMP_ABSOLUTE:
  507. # This case is to deal with some nested ifs such as:
  508. # if a:
  509. # if b:
  510. # f()
  511. # elif c:
  512. # g()
  513. jump_addr = self.address(arg)
  514. if jump_addr in jumps:
  515. jumps[addr] = jumps[jump_addr]
  516. elif opcode == JUMP_FORWARD:
  517. jump_addr = addr[1] + arg
  518. if jump_addr in jumps:
  519. jumps[addr] = jumps[jump_addr]
  520. elif opcode in stmt_opcodes and last_jump is not None:
  521. # This opcode will generate a statement, so it means
  522. # that the last POP_JUMP_IF_x was an else-jump
  523. jumps[addr] = last_jump
  524. self.else_jumps = set(jumps.values())
  525.  
  526. def get_suite(
  527. self, include_declarations=True, look_for_docstring=False
  528. ) -> Suite:
  529. dec = SuiteDecompiler(self[0])
  530. dec.run()
  531. first_stmt = dec.suite and dec.suite[0]
  532. # Change __doc__ = "docstring" to "docstring"
  533. if look_for_docstring and isinstance(
  534. first_stmt, AssignStatement
  535. ):
  536. chain = first_stmt.chain
  537. if len(chain) == 2 and str(chain[0]) == "__doc__":
  538. dec.suite[0] = DocString(first_stmt.chain[1].val)
  539. if include_declarations and (self.globals or self.nonlocals):
  540. suite = Suite()
  541. if self.globals:
  542. stmt = "global " + ", ".join(map(str, self.globals))
  543. suite.add_statement(SimpleStatement(stmt))
  544. if self.nonlocals:
  545. stmt = "nonlocal " + ", ".join(
  546. map(str, self.nonlocals)
  547. )
  548. suite.add_statement(SimpleStatement(stmt))
  549. for stmt in dec.suite:
  550. suite.add_statement(stmt)
  551. return suite
  552. else:
  553. return dec.suite
  554.  
  555. def declare_global(self, name):
  556. """
  557. Declare name as a global. Called by STORE_GLOBAL and
  558. DELETE_GLOBAL
  559. """
  560. if name not in self.globals:
  561. self.globals.append(name)
  562.  
  563. def ensure_global(self, name):
  564. """
  565. Declare name as global only if it is also a local variable
  566. name in one of the surrounding code objects. This is called
  567. by LOAD_GLOBAL
  568. """
  569. parent = self.parent
  570. while parent:
  571. if name in parent.varnames:
  572. return self.declare_global(name)
  573. parent = parent.parent
  574.  
  575. def declare_nonlocal(self, name):
  576. """
  577. Declare name as nonlocal. Called by STORE_DEREF and
  578. DELETE_DEREF (but only when the name denotes a free variable,
  579. not a cell one).
  580. """
  581. if name not in self.nonlocals:
  582. self.nonlocals.append(name)
  583.  
  584.  
  585. class Address:
  586. def __init__(self, code, instr_index):
  587. self.code = code
  588. self.index = instr_index
  589. self.addr, (self.opcode, self.arg) = code.instr_seq[
  590. instr_index
  591. ]
  592.  
  593. def __eq__(self, other):
  594. return (
  595. isinstance(other, type(self))
  596. and self.code == other.code
  597. and self.index == other.index
  598. )
  599.  
  600. def __lt__(self, other):
  601. return other is None or (
  602. isinstance(other, type(self))
  603. and self.code == other.code
  604. and self.index < other.index
  605. )
  606.  
  607. def __str__(self):
  608. mark = "* " if self in self.code.else_jumps else " "
  609. jump = self.jump()
  610. jt = '>>' if self.is_jump_target else ' '
  611. arg = self.arg or " "
  612. jdest = (
  613. '\t(to {})'.format(jump.addr)
  614. if jump and jump.addr != self.arg
  615. else ''
  616. )
  617. val = ''
  618. op = opname[self.opcode].ljust(18, ' ')
  619. try:
  620.  
  621. val = (
  622. self.code.globals[self.arg]
  623. and self.arg + 1 < len(self.code.globals)
  624. if 'GLOBAL' in op
  625. else self.code.names[self.arg]
  626. if 'ATTR' in op
  627. else self.code.names[self.arg]
  628. if 'NAME' in op
  629. else self.code.names[self.arg]
  630. if 'LOAD_METHOD' in op
  631. else self.code.consts[self.arg]
  632. if 'CONST' in op
  633. else self.code.varnames[self.arg]
  634. if 'FAST' in op
  635. else self.code.derefnames[self.arg]
  636. if 'DEREF' in op
  637. else cmp_op[self.arg]
  638. if 'COMPARE' in op
  639. else ''
  640. )
  641. if val != '':
  642. val = '\t({})'.format(val)
  643. except:
  644. pass
  645.  
  646. return "{}{}\t{}\t{}\t{}{}{}".format(
  647. jt, mark, self.addr, op, arg, jdest, val
  648. )
  649.  
  650. def __add__(self, delta):
  651. return self.code.address(self.addr + delta)
  652.  
  653. def __getitem__(self, index) -> Address:
  654. return self.code[self.index + index]
  655.  
  656. def __iter__(self):
  657. yield self.opcode
  658. yield self.arg
  659.  
  660. def __hash__(self):
  661. return hash((self.code, self.index))
  662.  
  663. @property
  664. def is_else_jump(self):
  665. return self in self.code.else_jumps
  666.  
  667. @property
  668. def is_jump_target(self):
  669. return self in self.code.jump_targets
  670.  
  671. def change_instr(self, opcode, arg=None):
  672. self.code.instr_seq[self.index] = (self.addr, (opcode, arg))
  673.  
  674. def jump(self) -> Address:
  675. opcode = self.opcode
  676. if opcode in dis.hasjrel:
  677. return self[self.arg // (1 + IS_NOT_310) + 1]
  678. elif opcode in dis.hasjabs:
  679. return self.code.address(self.arg * (2 - IS_NOT_310))
  680.  
  681. def seek(
  682. self, opcode: Iterable, increment: int, end: Address = None
  683. ) -> Address:
  684. if not isinstance(opcode, Iterable):
  685. opcode = (opcode,)
  686. a = self[increment]
  687. while a and a != end:
  688. if a.opcode in opcode:
  689. return a
  690. a = a[increment]
  691.  
  692. def seek_back(
  693. self, opcode: Union[Iterable, int], end: Address = None
  694. ) -> Address:
  695. return self.seek(opcode, -1, end)
  696.  
  697. def seek_forward(
  698. self, opcode: Union[Iterable, int], end: Address = None
  699. ) -> Address:
  700. return self.seek(opcode, 1, end)
  701.  
  702. def seek_back_statement(
  703. self, opcode: Union[Iterable, int]
  704. ) -> Address:
  705. last_statement = self.seek_back(stmt_opcodes)
  706. return self.seek(opcode, -1, last_statement)
  707.  
  708. def seek_forward_statement(
  709. self, opcode: Union[Iterable, int]
  710. ) -> Address:
  711. next_statement = self.seek_forward(stmt_opcodes)
  712. return self.seek(opcode, 1, next_statement)
  713.  
  714.  
  715. class AsyncMixin:
  716. def __init__(self):
  717. self.is_async = False
  718.  
  719. @property
  720. def async_prefix(self):
  721. return 'async ' if self.is_async else ''
  722.  
  723.  
  724. class AwaitableMixin:
  725. def __init__(self):
  726. self.is_awaited = False
  727.  
  728. @property
  729. def await_prefix(self):
  730. return 'await ' if self.is_awaited else ''
  731.  
  732.  
  733. class PyExpr:
  734. def wrap(self, condition=True):
  735. if condition:
  736. return "({})".format(self)
  737. else:
  738. return str(self)
  739.  
  740. def store(self, dec, dest):
  741. chain = dec.assignment_chain
  742. chain.append(dest)
  743. if self not in dec.stack:
  744. chain.append(self)
  745. dec.suite.add_statement(AssignStatement(chain))
  746. dec.assignment_chain = []
  747.  
  748. def on_pop(self, dec: SuiteDecompiler):
  749. dec.write(str(self))
  750.  
  751.  
  752. class PyConst(PyExpr):
  753. def __init__(self, val):
  754. self.val = val
  755. if isinstance(val, int):
  756. self.precedence = 14
  757. else:
  758. self.precedence = 100
  759.  
  760. def __str__(self):
  761. return repr(self.val)
  762.  
  763. def __iter__(self):
  764. return iter(self.val)
  765.  
  766. def __eq__(self, other):
  767. return isinstance(other, PyConst) and self.val == other.val
  768.  
  769.  
  770. class PyFormatValue(PyConst):
  771. def __init__(self, val):
  772. super().__init__(val)
  773. self.formatter = ''
  774.  
  775. @staticmethod
  776. def fmt(string):
  777. return f'f\'{string}\''
  778.  
  779. def base(self):
  780. return f'{{{self.val}{self.formatter}}}'
  781.  
  782. def __str__(self):
  783. return self.fmt(self.base())
  784.  
  785.  
  786. class PyFormatString(PyExpr):
  787. precedence = 100
  788.  
  789. def __init__(self, params):
  790. super().__init__()
  791. self.params = params
  792.  
  793. def __str__(self):
  794. return "f'{}'".format(
  795. ''.join(
  796. [
  797. p.base().replace('\'', '\"')
  798. if isinstance(p, PyFormatValue)
  799. else p.name
  800. if isinstance(p, PyName)
  801. else str(p.val.encode('utf-8'))[1:]
  802. .replace('\'', '')
  803. .replace('{', '{{')
  804. .replace('}', '}}')
  805. for p in self.params
  806. ]
  807. )
  808. )
  809.  
  810.  
  811. class PyTuple(PyExpr):
  812. precedence = 0
  813.  
  814. def __init__(self, values):
  815. self.values = values
  816.  
  817. def __str__(self):
  818. if not self.values:
  819. return "()"
  820. valstr = [
  821. val.wrap(val.precedence <= self.precedence)
  822. for val in self.values
  823. ]
  824. if len(valstr) == 1:
  825. return '(' + valstr[0] + "," + ')'
  826. else:
  827. return '(' + ", ".join(valstr) + ')'
  828.  
  829. def __iter__(self):
  830. return iter(self.values)
  831.  
  832. def wrap(self, condition=True):
  833. return str(self)
  834.  
  835.  
  836. class PyList(PyExpr):
  837. precedence = 16
  838.  
  839. def __init__(self, values):
  840. self.values = values
  841.  
  842. def __str__(self):
  843. valstr = ", ".join(
  844. val.wrap(val.precedence <= 0) for val in self.values
  845. )
  846. return "[{}]".format(valstr)
  847.  
  848. def __iter__(self):
  849. return iter(self.values)
  850.  
  851.  
  852. class PySet(PyExpr):
  853. precedence = 16
  854.  
  855. def __init__(self, values):
  856. self.values = values
  857.  
  858. def __str__(self):
  859. valstr = ", ".join(
  860. val.wrap(val.precedence <= 0) for val in self.values
  861. )
  862. return "{{{}}}".format(valstr)
  863.  
  864. def __iter__(self):
  865. return iter(self.values)
  866.  
  867.  
  868. class PyDict(PyExpr):
  869. precedence = 16
  870.  
  871. def __init__(self):
  872. self.items = []
  873.  
  874. def set_item(self, key, val):
  875. self.items.append((key, val))
  876.  
  877. def __str__(self):
  878. itemstr = ", ".join(
  879. f"{kv[0]}: {kv[1]}" if len(kv) == 2 else str(kv[0])
  880. for kv in self.items
  881. )
  882. return f"{{{itemstr}}}"
  883.  
  884.  
  885. class PyName(PyExpr, AwaitableMixin):
  886. precedence = 100
  887.  
  888. def __init__(self, name):
  889. AwaitableMixin.__init__(self)
  890. self.name = name
  891.  
  892. def __str__(self):
  893. return f'{self.await_prefix}{self.name}'
  894.  
  895. def __eq__(self, other):
  896. return (
  897. isinstance(other, type(self)) and self.name == other.name
  898. )
  899.  
  900.  
  901. class PyUnaryOp(PyExpr):
  902. def __init__(self, operand):
  903. self.operand = operand
  904.  
  905. def __str__(self):
  906. opstr = self.operand.wrap(
  907. self.operand.precedence < self.precedence
  908. )
  909. return self.pattern.format(opstr)
  910.  
  911. @classmethod
  912. def instr(cls, stack):
  913. stack.push(cls(stack.pop()))
  914.  
  915.  
  916. class PyBinaryOp(PyExpr):
  917. def __init__(self, left, right):
  918. self.left = left
  919. self.right = right
  920.  
  921. def wrap_left(self):
  922. return self.left.wrap(self.left.precedence < self.precedence)
  923.  
  924. def wrap_right(self):
  925. return self.right.wrap(
  926. self.right.precedence <= self.precedence
  927. )
  928.  
  929. def __str__(self):
  930. return self.pattern.format(
  931. self.wrap_left(), self.wrap_right()
  932. )
  933.  
  934. @classmethod
  935. def instr(cls, stack):
  936. right = stack.pop()
  937. left = stack.pop()
  938. stack.push(cls(left, right))
  939.  
  940.  
  941. class PySubscript(PyBinaryOp):
  942. precedence = 15
  943. pattern = "{}[{}]"
  944.  
  945. def wrap_right(self):
  946. return str(self.right)
  947.  
  948.  
  949. class PyInOp(PyBinaryOp, PyExpr):
  950. precedence = 15
  951. pattern = "{item}{_not} in {seq}"
  952.  
  953. def __init__(self, left, right, negate):
  954. super(PyInOp, self).__init__(left, right)
  955. self.negate = negate
  956.  
  957. def wrap_left(self):
  958. return self.left.wrap(self.left.precedence < self.precedence)
  959.  
  960. def wrap_right(self):
  961. return self.right.wrap(
  962. self.right.precedence <= self.precedence
  963. )
  964.  
  965. def __str__(self):
  966. return self.pattern.format(
  967. item=self.wrap_left(),
  968. seq=self.wrap_right(),
  969. _not="not " if self.negate else "",
  970. )
  971.  
  972.  
  973. class PyIsOp(PyBinaryOp, PyExpr):
  974. precedence = 15
  975. pattern = "{} is {}{}"
  976.  
  977. def __init__(self, left, right, negate):
  978. super(PyIsOp, self).__init__(left, right)
  979. self.negate = negate
  980.  
  981. def wrap_left(self):
  982. return self.left.wrap(self.left.precedence < self.precedence)
  983.  
  984. def wrap_right(self):
  985. return self.right.wrap(
  986. self.right.precedence <= self.precedence
  987. )
  988.  
  989. def __str__(self):
  990. return self.pattern.format(
  991. self.wrap_left(),
  992. "not " if self.negate else "",
  993. self.wrap_right(),
  994. )
  995.  
  996.  
  997. class PySlice(PyExpr):
  998. precedence = 1
  999.  
  1000. def __init__(self, args):
  1001. assert len(args) in (2, 3)
  1002. if len(args) == 2:
  1003. self.start, self.stop = args
  1004. self.step = None
  1005. else:
  1006. self.start, self.stop, self.step = args
  1007. if self.start == PyConst(None):
  1008. self.start = ""
  1009. if self.stop == PyConst(None):
  1010. self.stop = ""
  1011.  
  1012. def __str__(self):
  1013. if self.step is None:
  1014. return "{}:{}".format(self.start, self.stop)
  1015. else:
  1016. return "{}:{}:{}".format(self.start, self.stop, self.step)
  1017.  
  1018.  
  1019. class PyCompare(PyExpr):
  1020. precedence = 6
  1021.  
  1022. def __init__(self, complist):
  1023. self.complist = complist
  1024.  
  1025. def __str__(self):
  1026. return " ".join(
  1027. x if i % 2 else x.wrap(x.precedence <= 6)
  1028. for i, x in enumerate(self.complist)
  1029. )
  1030.  
  1031. def extends(self, other):
  1032. if not isinstance(other, PyCompare):
  1033. return False
  1034. else:
  1035. return self.complist[0] == other.complist[-1]
  1036.  
  1037. def chain(self, other):
  1038. return PyCompare(self.complist + other.complist[1:])
  1039.  
  1040.  
  1041. class PyBooleanAnd(PyBinaryOp):
  1042. precedence = 4
  1043. pattern = "{} and {}"
  1044.  
  1045.  
  1046. class PyBooleanOr(PyBinaryOp):
  1047. precedence = 3
  1048. pattern = "{} or {}"
  1049.  
  1050.  
  1051. class PyIfElse(PyExpr):
  1052. precedence = 2
  1053.  
  1054. def __init__(self, cond, true_expr, false_expr):
  1055. self.cond = cond
  1056. self.true_expr = true_expr
  1057. self.false_expr = false_expr
  1058.  
  1059. def __str__(self):
  1060. p = self.precedence
  1061. cond_str = self.cond.wrap(self.cond.precedence <= p)
  1062. true_str = self.true_expr.wrap(self.cond.precedence <= p)
  1063. false_str = self.false_expr.wrap(self.cond.precedence < p)
  1064. return "{} if {} else {}".format(
  1065. true_str, cond_str, false_str
  1066. )
  1067.  
  1068.  
  1069. class PyAttribute(PyExpr):
  1070. precedence = 15
  1071.  
  1072. def __init__(self, expr, attrname):
  1073. self.expr = expr
  1074. self.attrname = attrname
  1075.  
  1076. def __str__(self):
  1077. expr_str = self.expr.wrap(
  1078. self.expr.precedence < self.precedence
  1079. )
  1080. attrname = self.attrname
  1081.  
  1082. if isinstance(self.expr, PyName) and self.expr.name == 'self':
  1083. __ = attrname.name.find('__')
  1084. if __ > 0:
  1085. attrname = PyName(self.attrname.name[__:])
  1086. return "{}.{}".format(expr_str, attrname)
  1087.  
  1088.  
  1089. class PyCallFunction(PyExpr, AwaitableMixin):
  1090. precedence = 15
  1091.  
  1092. def __init__(
  1093. self,
  1094. func: PyAttribute,
  1095. args: list,
  1096. kwargs: list,
  1097. varargs=None,
  1098. varkw=None,
  1099. ):
  1100. AwaitableMixin.__init__(self)
  1101. self.func = func
  1102. self.args = args
  1103. self.kwargs = kwargs
  1104. self.varargs = (
  1105. varargs
  1106. if not varargs or isinstance(varargs, Iterable)
  1107. else {varargs}
  1108. )
  1109. self.varkw = (
  1110. varkw
  1111. if not varkw or isinstance(varkw, Iterable)
  1112. else {varkw}
  1113. )
  1114.  
  1115. def __str__(self):
  1116. funcstr = self.func.wrap(
  1117. self.func.precedence < self.precedence
  1118. )
  1119. if (
  1120. hasattr(self.args, '__iter__')
  1121. and len(self.args) == 1
  1122. and not (self.kwargs or self.varargs or self.varkw)
  1123. ):
  1124. arg = self.args[0]
  1125. if isinstance(arg, PyGenExpr):
  1126. # Only one pair of brackets arount a single arg genexpr
  1127. return "{}{}".format(funcstr, arg)
  1128. args = [x.wrap(x.precedence <= 0) for x in self.args]
  1129. if self.varargs is not None:
  1130. for varargs in self.varargs:
  1131. args.append("*{}".format(varargs))
  1132. args.extend(
  1133. "{}={}".format(
  1134. str(k).replace('\'', ''), v.wrap(v.precedence <= 0)
  1135. )
  1136. for k, v in self.kwargs
  1137. )
  1138. if self.varkw is not None:
  1139. for varkw in self.varkw:
  1140. args.append("**{}".format(varkw))
  1141. return "{}{}({})".format(
  1142. self.await_prefix, funcstr, ", ".join(args)
  1143. )
  1144.  
  1145.  
  1146. class FunctionDefinition:
  1147. def __init__(
  1148. self,
  1149. code: Code,
  1150. defaults,
  1151. kwdefaults,
  1152. closure,
  1153. paramobjs=None,
  1154. annotations=None,
  1155. ):
  1156. self.code = code
  1157. self.defaults = defaults
  1158. self.kwdefaults = kwdefaults
  1159. self.closure = closure
  1160. self.paramobjs = paramobjs if paramobjs else {}
  1161. self.annotations = annotations if annotations else []
  1162.  
  1163. def is_coroutine(self):
  1164. return self.code.code_obj.co_flags & 0x100
  1165.  
  1166. def getparams(self):
  1167. code_obj = self.code.code_obj
  1168. l = code_obj.co_argcount
  1169. params = []
  1170. for name in code_obj.co_varnames[:l]:
  1171. if name in self.paramobjs:
  1172. params.append(
  1173. '{}:{}'.format(name, str(self.paramobjs[name]))
  1174. )
  1175. else:
  1176. params.append(name)
  1177. if self.defaults:
  1178. for i, arg in enumerate(reversed(self.defaults)):
  1179. name = params[-i - 1]
  1180. if name in self.paramobjs:
  1181. params[-i - 1] = "{}:{}={}".format(
  1182. name, str(self.paramobjs[name]), arg
  1183. )
  1184. else:
  1185. params[-i - 1] = "{}={}".format(name, arg)
  1186. kwcount = code_obj.co_kwonlyargcount
  1187. kwparams = []
  1188. if kwcount:
  1189. for i in range(kwcount):
  1190. name = code_obj.co_varnames[l + i]
  1191. if name in self.kwdefaults and name in self.paramobjs:
  1192. kwparams.append(
  1193. "{}:{}={}".format(
  1194. name,
  1195. self.paramobjs[name],
  1196. self.kwdefaults[name],
  1197. )
  1198. )
  1199. elif name in self.kwdefaults:
  1200. kwparams.append(
  1201. "{}={}".format(name, self.kwdefaults[name])
  1202. )
  1203. else:
  1204. kwparams.append(name)
  1205. l += kwcount
  1206. if code_obj.co_flags & VARARGS:
  1207. name = code_obj.co_varnames[l]
  1208. if name in self.paramobjs:
  1209. params.append(f'*{name}:{str(self.paramobjs[name])}')
  1210. else:
  1211. params.append(f'*{name}')
  1212. l += 1
  1213. elif kwparams:
  1214. params.append("*")
  1215. params.extend(kwparams)
  1216. if code_obj.co_flags & VARKEYWORDS:
  1217. name = code_obj.co_varnames[l]
  1218. if name in self.paramobjs:
  1219. params.append(f'**{name}:{str(self.paramobjs[name])}')
  1220. else:
  1221. params.append(f'**{name}')
  1222.  
  1223. return params
  1224.  
  1225. def getreturn(self):
  1226. if self.paramobjs and 'return' in self.paramobjs:
  1227. return self.paramobjs['return']
  1228. return None
  1229.  
  1230.  
  1231. class PyLambda(PyExpr, FunctionDefinition):
  1232. precedence = 1
  1233.  
  1234. def __str__(self):
  1235. suite = self.code.get_suite()
  1236. params = ", ".join(self.getparams())
  1237. if len(suite.statements) > 0:
  1238.  
  1239. def strip_return(val):
  1240. return (
  1241. val[len("return ") :]
  1242. if val.startswith('return')
  1243. else val
  1244. )
  1245.  
  1246. def strip_yield_none(val):
  1247. return '(yield)' if val == 'yield None' else val
  1248.  
  1249. if isinstance(suite[0], IfStatement):
  1250. end = suite[1] if len(suite) > 1 else PyConst(None)
  1251. expr = "{} if {} else {}".format(
  1252. strip_return(str(suite[0].true_suite)),
  1253. str(suite[0].cond),
  1254. strip_return(str(end)),
  1255. )
  1256. else:
  1257. expr = strip_return(str(suite[0]))
  1258. expr = strip_yield_none(expr)
  1259. else:
  1260. expr = "None"
  1261. return "lambda {}: {}".format(params, expr)
  1262.  
  1263.  
  1264. class PyComp(PyExpr):
  1265. """
  1266. Abstraction for list, set, dict comprehensions and generator expressions
  1267. """
  1268.  
  1269. precedence = 16
  1270.  
  1271. def __init__(
  1272. self,
  1273. code,
  1274. defaults,
  1275. kwdefaults,
  1276. closure,
  1277. paramobjs={},
  1278. annotations=[],
  1279. ):
  1280. assert not defaults and not kwdefaults
  1281. self.code = code
  1282. code[0].change_instr(NOP)
  1283. last_i = len(code.instr_seq) - 1
  1284. code[last_i].change_instr(NOP)
  1285. self.annotations = annotations
  1286.  
  1287. def set_iterable(self, iterable):
  1288. self.code.varnames[0] = iterable
  1289.  
  1290. def __str__(self):
  1291. suite = self.code.get_suite()
  1292. return self.pattern.format(suite.gen_display())
  1293.  
  1294.  
  1295. class PyListComp(PyComp):
  1296. pattern = "[{}]"
  1297.  
  1298.  
  1299. class PySetComp(PyComp):
  1300. pattern = "{{{}}}"
  1301.  
  1302.  
  1303. class PyKeyValue(PyBinaryOp):
  1304. """This is only to create dict comprehensions"""
  1305.  
  1306. precedence = 1
  1307. pattern = "{}: {}"
  1308.  
  1309.  
  1310. class PyDictComp(PyComp):
  1311. pattern = "{{{}}}"
  1312.  
  1313.  
  1314. class PyGenExpr(PyComp):
  1315. precedence = 16
  1316. pattern = "({})"
  1317.  
  1318. def __init__(
  1319. self,
  1320. code,
  1321. defaults,
  1322. kwdefaults,
  1323. closure,
  1324. paramobjs={},
  1325. annotations=[],
  1326. ):
  1327. self.code = code
  1328.  
  1329.  
  1330. class PyYield(PyExpr):
  1331. precedence = 1
  1332.  
  1333. def __init__(self, value):
  1334. self.value = value
  1335.  
  1336. def __str__(self):
  1337. return "yield {}".format(self.value)
  1338.  
  1339.  
  1340. class PyYieldFrom(PyExpr):
  1341. precedence = 1
  1342.  
  1343. def __init__(self, value):
  1344. self.value = value
  1345.  
  1346. def __str__(self):
  1347. return "yield from {}".format(self.value)
  1348.  
  1349.  
  1350. class PyStarred(PyExpr):
  1351. """Used in unpacking assigments"""
  1352.  
  1353. precedence = 15
  1354.  
  1355. def __init__(self, expr):
  1356. self.expr = expr
  1357.  
  1358. def __str__(self):
  1359. es = self.expr.wrap(self.expr.precedence < self.precedence)
  1360. return "*{}".format(es)
  1361.  
  1362.  
  1363. class PyListExtend(PyBinaryOp):
  1364. precedence = 15
  1365. pattern = "({}+{})"
  1366.  
  1367. def wrap_right(self):
  1368. return str(self.right)
  1369.  
  1370.  
  1371. class PySetUpdate(PyBinaryOp):
  1372. precedence = 15
  1373. pattern = "{}.update({})"
  1374.  
  1375. def wrap_right(self):
  1376. return str(self.right)
  1377.  
  1378.  
  1379. class PyDictMerge(PyBinaryOp):
  1380. precedence = 15
  1381. pattern = "dict(**{},**{})"
  1382.  
  1383. def wrap_right(self):
  1384. return str(self.right)
  1385.  
  1386.  
  1387. class PyDictUpdate(PyBinaryOp):
  1388. precedence = 15
  1389. pattern = "{}.update({})"
  1390.  
  1391. def wrap_right(self):
  1392. return str(self.right)
  1393.  
  1394.  
  1395. code_map = {
  1396. '<lambda>': PyLambda,
  1397. '<listcomp>': PyListComp,
  1398. '<setcomp>': PySetComp,
  1399. '<dictcomp>': PyDictComp,
  1400. '<genexpr>': PyGenExpr,
  1401. }
  1402.  
  1403. unary_ops = [
  1404. ('UNARY_POSITIVE', 'Positive', '+{}', 13),
  1405. ('UNARY_NEGATIVE', 'Negative', '-{}', 13),
  1406. ('UNARY_NOT', 'Not', 'not {}', 5),
  1407. ('UNARY_INVERT', 'Invert', '~{}', 13),
  1408. ]
  1409.  
  1410. binary_ops = [
  1411. ('POWER', 'Power', '{}**{}', 14, '{} **= {}'),
  1412. ('MULTIPLY', 'Multiply', '{}*{}', 12, '{} *= {}'),
  1413. ('FLOOR_DIVIDE', 'FloorDivide', '{}//{}', 12, '{} //= {}'),
  1414. ('TRUE_DIVIDE', 'TrueDivide', '{}/{}', 12, '{} /= {}'),
  1415. ('MODULO', 'Modulo', '{} % {}', 12, '{} %= {}'),
  1416. ('ADD', 'Add', '{} + {}', 11, '{} += {}'),
  1417. ('SUBTRACT', 'Subtract', '{} - {}', 11, '{} -= {}'),
  1418. ('SUBSCR', 'Subscript', '{}[{}]', 15, None),
  1419. ('LSHIFT', 'LeftShift', '{} << {}', 10, '{} <<= {}'),
  1420. ('RSHIFT', 'RightShift', '{} >> {}', 10, '{} >>= {}'),
  1421. ('AND', 'And', '{} & {}', 9, '{} &= {}'),
  1422. ('XOR', 'Xor', '{} ^ {}', 8, '{} ^= {}'),
  1423. ('OR', 'Or', '{} | {}', 7, '{} |= {}'),
  1424. ('MATRIX_MULTIPLY', 'MatrixMultiply', '{} @ {}', 12, '{} @= {}'),
  1425. ]
  1426.  
  1427.  
  1428. class PyStatement(object):
  1429. def __str__(self):
  1430. istr = IndentString()
  1431. self.display(istr)
  1432. return str(istr)
  1433.  
  1434. def wrap(self, condition=True):
  1435. if condition:
  1436. assert not condition
  1437. return "({})".format(self)
  1438. else:
  1439. return str(self)
  1440.  
  1441. def on_pop(self, dec):
  1442. # dec.write("#ERROR: Unexpected context 'on_pop': pop on statement: ")
  1443. pass
  1444.  
  1445.  
  1446. class DocString(PyStatement):
  1447. def __init__(self, string):
  1448. self.string = string
  1449.  
  1450. def display(self, indent):
  1451. if '\n' not in self.string:
  1452. indent.write(repr(self.string))
  1453. else:
  1454. if "'''" not in self.string:
  1455. fence = "'''"
  1456. else:
  1457. fence = '"""'
  1458. lines = self.string.split('\n')
  1459. text = '\n'.join(
  1460. l.encode('unicode_escape')
  1461. .decode()
  1462. .replace(fence, '\\' + fence)
  1463. for l in lines
  1464. )
  1465. docstring = "{0}{1}{0}".format(fence, text)
  1466. indent.write(docstring)
  1467.  
  1468.  
  1469. class AssignStatement(PyStatement):
  1470. def __init__(self, chain):
  1471. self.chain = chain
  1472.  
  1473. def display(self, indent):
  1474. indent.write(" = ".join(map(str, self.chain)))
  1475.  
  1476.  
  1477. class InPlaceOp(PyStatement):
  1478. def __init__(self, left, right):
  1479. self.right = right
  1480. self.left = left
  1481.  
  1482. def store(self, dec, dest):
  1483. # assert dest is self.left
  1484. dec.suite.add_statement(self)
  1485.  
  1486. def display(self, indent):
  1487. indent.write(self.pattern, self.left, self.right)
  1488.  
  1489. @classmethod
  1490. def instr(cls, stack):
  1491. right = stack.pop()
  1492. left = stack.pop()
  1493. stack.push(cls(left, right))
  1494.  
  1495.  
  1496. class Unpack:
  1497. precedence = 50
  1498.  
  1499. def __init__(self, val, length, star_index=None):
  1500. self.val = val
  1501. self.length = length
  1502. self.star_index = star_index
  1503. self.dests = []
  1504.  
  1505. def store(self, dec, dest):
  1506. if len(self.dests) == self.star_index:
  1507. dest = PyStarred(dest)
  1508. self.dests.append(dest)
  1509. if len(self.dests) == self.length:
  1510. dec.stack.push(self.val)
  1511. dec.store(PyTuple(self.dests))
  1512.  
  1513.  
  1514. class ImportStatement(PyStatement):
  1515. alias = ""
  1516. precedence = 100
  1517.  
  1518. def __init__(self, name, level, fromlist):
  1519. self.name = name
  1520. self.alias = name
  1521. self.level = level
  1522. self.fromlist = fromlist
  1523. self.aslist = []
  1524.  
  1525. def store(self, dec: SuiteDecompiler, dest):
  1526. self.alias = dest
  1527. dec.suite.add_statement(self)
  1528.  
  1529. def on_pop(self, dec):
  1530. dec.suite.add_statement(self)
  1531.  
  1532. def display(self, indent):
  1533. if self.fromlist == PyConst(None):
  1534. name = self.name.name
  1535. alias = self.alias.name
  1536. if name == alias or name.startswith(alias + "."):
  1537. indent.write("import {}", name)
  1538. else:
  1539. indent.write("import {} as {}", name, alias)
  1540. elif self.fromlist == PyConst(('*',)):
  1541. indent.write("from {} import *", self.name.name)
  1542. else:
  1543. names = []
  1544. for name, alias in zip(self.fromlist, self.aslist):
  1545. if name == alias:
  1546. names.append(name)
  1547. else:
  1548. names.append("{} as {}".format(name, alias))
  1549. indent.write(
  1550. "from {}{} import {}",
  1551. ''.join(['.' for i in range(self.level.val)]),
  1552. self.name,
  1553. ", ".join(names),
  1554. )
  1555.  
  1556.  
  1557. class ImportFrom:
  1558. def __init__(self, name):
  1559. self.name = name
  1560.  
  1561. def store(self, dec, dest):
  1562. imp = dec.stack.peek()
  1563. assert isinstance(imp, ImportStatement)
  1564.  
  1565. if imp.fromlist != PyConst(None):
  1566.  
  1567. imp.aslist.append(dest.name)
  1568. else:
  1569. imp.alias = dest
  1570.  
  1571.  
  1572. class SimpleStatement(PyStatement):
  1573. def __init__(self, val):
  1574. assert val is not None
  1575. self.val = val
  1576.  
  1577. def display(self, indent):
  1578. indent.write(self.val)
  1579.  
  1580. def gen_display(self, seq=()):
  1581. return " ".join((self.val,) + seq)
  1582.  
  1583.  
  1584. class IfStatement(PyStatement):
  1585. def __init__(self, cond, true_suite, false_suite):
  1586. self.cond = cond
  1587. self.true_suite = true_suite
  1588. self.false_suite = false_suite
  1589.  
  1590. def display(self, indent, is_elif=False):
  1591. ptn = "elif {}:" if is_elif else "if {}:"
  1592. indent.write(ptn, self.cond)
  1593. self.true_suite.display(indent + 1)
  1594. if not self.false_suite:
  1595. return
  1596. if len(self.false_suite) == 1:
  1597. stmt = self.false_suite[0]
  1598. if isinstance(stmt, IfStatement):
  1599. stmt.display(indent, is_elif=True)
  1600. return
  1601. indent.write("else:")
  1602. self.false_suite.display(indent + 1)
  1603.  
  1604. def gen_display(self, seq=()):
  1605. assert not self.false_suite
  1606. s = "if {}".format(self.cond)
  1607. return self.true_suite.gen_display(seq + (s,))
  1608.  
  1609.  
  1610. class ForStatement(PyStatement, AsyncMixin):
  1611. def __init__(self, iterable):
  1612. AsyncMixin.__init__(self)
  1613. self.iterable = iterable
  1614. self.else_body: Suite = None
  1615.  
  1616. def store(self, dec, dest):
  1617. self.dest = dest
  1618.  
  1619. def display(self, indent):
  1620. indent.write(
  1621. "{}for {} in {}:",
  1622. self.async_prefix,
  1623. self.dest,
  1624. self.iterable,
  1625. )
  1626. if self.body:
  1627. self.body.display(indent + 1)
  1628. if self.else_body:
  1629. indent.write('else:')
  1630. self.else_body.display(indent + 1)
  1631.  
  1632. def gen_display(self, seq=()):
  1633. s = "{}for {} in {}".format(
  1634. self.async_prefix,
  1635. self.dest,
  1636. self.iterable.wrap()
  1637. if isinstance(self.iterable, PyIfElse)
  1638. else self.iterable,
  1639. )
  1640. return self.body.gen_display(seq + (s,))
  1641.  
  1642.  
  1643. class WhileStatement(PyStatement):
  1644. def __init__(self, cond, body):
  1645. self.cond = cond
  1646. self.body = body
  1647.  
  1648. def display(self, indent):
  1649. indent.write("while {}:", self.cond)
  1650. self.body.display(indent + 1)
  1651.  
  1652.  
  1653. class DecorableStatement(PyStatement):
  1654. def __init__(self):
  1655. self.decorators = []
  1656.  
  1657. def display(self, indent):
  1658. indent.sep()
  1659. for f in reversed(self.decorators):
  1660. indent.write("@{}", f)
  1661. self.display_undecorated(indent)
  1662. indent.sep()
  1663.  
  1664. def decorate(self, f):
  1665. self.decorators.append(f)
  1666.  
  1667.  
  1668. class DefStatement(
  1669. FunctionDefinition, DecorableStatement, AsyncMixin
  1670. ):
  1671. def __init__(
  1672. self,
  1673. code: Code,
  1674. defaults,
  1675. kwdefaults,
  1676. closure,
  1677. paramobjs=None,
  1678. annotations=None,
  1679. ):
  1680. FunctionDefinition.__init__(
  1681. self,
  1682. code,
  1683. defaults,
  1684. kwdefaults,
  1685. closure,
  1686. paramobjs,
  1687. annotations,
  1688. )
  1689. DecorableStatement.__init__(self)
  1690. AsyncMixin.__init__(self)
  1691. self.is_async = (
  1692. code.flags.coroutine or code.flags.async_generator
  1693. )
  1694.  
  1695. def display_undecorated(self, indent):
  1696. paramlist = ", ".join(self.getparams())
  1697. result = self.getreturn()
  1698. if result:
  1699. indent.write(
  1700. "{}def {}({}) -> {}:",
  1701. self.async_prefix,
  1702. self.code.name,
  1703. paramlist,
  1704. result,
  1705. )
  1706. else:
  1707. indent.write(
  1708. "{}def {}({}):",
  1709. self.async_prefix,
  1710. self.code.name,
  1711. paramlist,
  1712. )
  1713. # Assume that co_consts starts with None unless the function
  1714. # has a docstring, in which case it starts with the docstring
  1715. if self.code.consts[0] != PyConst(None):
  1716. docstring = self.code.consts[0].val
  1717. DocString(docstring).display(indent + 1)
  1718. self.code.get_suite().display(indent + 1)
  1719.  
  1720. def store(self, dec, dest):
  1721. self.name = dest
  1722. dec.suite.add_statement(self)
  1723.  
  1724.  
  1725. class TryStatement(PyStatement):
  1726. def __init__(self, try_suite):
  1727. self.try_suite: Suite = try_suite
  1728. self.except_clauses: List[Any, str, Suite] = []
  1729. self.else_suite: Suite = None
  1730.  
  1731. def add_except_clause(self, exception_type, suite):
  1732. self.except_clauses.append([exception_type, None, suite])
  1733.  
  1734. def store(self, dec, dest):
  1735. self.except_clauses[-1][1] = dest
  1736.  
  1737. def display(self, indent):
  1738. indent.write("try:")
  1739. self.try_suite.display(indent + 1)
  1740. for type, name, suite in self.except_clauses:
  1741. if type is None:
  1742. indent.write("except:")
  1743. elif name is None:
  1744. indent.write("except {}:", type)
  1745. else:
  1746. indent.write("except {} as {}:", type, name)
  1747. suite.display(indent + 1)
  1748. if self.else_suite:
  1749. indent.write('else:')
  1750. self.else_suite.display(indent + 1)
  1751.  
  1752.  
  1753. class FinallyStatement(PyStatement):
  1754. def __init__(self, try_suite, finally_suite):
  1755. self.try_suite = try_suite
  1756. self.finally_suite = finally_suite
  1757.  
  1758. def display(self, indent):
  1759. # Wrap the try suite in a TryStatement if necessary
  1760. try_stmt = None
  1761. if len(self.try_suite) == 1:
  1762. try_stmt = self.try_suite[0]
  1763. if not isinstance(try_stmt, TryStatement):
  1764. try_stmt = None
  1765. if try_stmt is None:
  1766. try_stmt = TryStatement(self.try_suite)
  1767. try_stmt.display(indent)
  1768. indent.write("finally:")
  1769. self.finally_suite.display(indent + 1)
  1770.  
  1771.  
  1772. class WithStatement(PyStatement):
  1773. def __init__(self, with_expr):
  1774. self.with_expr = with_expr
  1775. self.with_name = None
  1776. self.is_async = False
  1777.  
  1778. @property
  1779. def async_prefix(self):
  1780. return 'async ' if self.is_async else ''
  1781.  
  1782. def store(self, dec, dest):
  1783. self.with_name = dest
  1784.  
  1785. def display(self, indent, args=None):
  1786. # args to take care of nested withs:
  1787. # with x as t:
  1788. # with y as u:
  1789. # <suite>
  1790. # --->
  1791. # with x as t, y as u:
  1792. # <suite>
  1793. if args is None:
  1794. args = []
  1795. if self.with_name is None:
  1796. args.append(str(self.with_expr))
  1797. else:
  1798. args.append(
  1799. "{} as {}".format(self.with_expr, self.with_name)
  1800. )
  1801. if len(self.suite) == 1 and isinstance(
  1802. self.suite[0], WithStatement
  1803. ):
  1804. self.suite[0].display(indent, args)
  1805. else:
  1806. indent.write(
  1807. self.async_prefix + "with {}:", ", ".join(args)
  1808. )
  1809. self.suite.display(indent + 1)
  1810.  
  1811.  
  1812. class ClassStatement(DecorableStatement):
  1813. def __init__(self, func, name, parents, kwargs):
  1814. DecorableStatement.__init__(self)
  1815. self.func = func
  1816. self.parents = parents
  1817. self.kwargs = kwargs
  1818.  
  1819. def store(self, dec, dest):
  1820. self.name = dest
  1821. dec.suite.add_statement(self)
  1822.  
  1823. def display_undecorated(self, indent):
  1824. if self.parents or self.kwargs:
  1825. args = [str(x) for x in self.parents]
  1826. kwargs = [
  1827. "{}={}".format(str(k).replace('\'', ''), v)
  1828. for k, v in self.kwargs
  1829. ]
  1830. all_args = ", ".join(args + kwargs)
  1831. indent.write("class {}({}):", self.name, all_args)
  1832. else:
  1833. indent.write("class {}:", self.name)
  1834. suite = self.func.code.get_suite(look_for_docstring=True)
  1835. if suite:
  1836. # TODO: find out why sometimes the class suite ends with
  1837. # "return __class__"
  1838. last_stmt = suite[-1]
  1839. if isinstance(last_stmt, SimpleStatement):
  1840. if last_stmt.val.startswith("return "):
  1841. suite.statements.pop()
  1842. clean_vars = ['__module__', '__qualname__']
  1843. for clean_var in clean_vars:
  1844. for i in range(len(suite.statements)):
  1845. stmt = suite.statements[i]
  1846. if isinstance(stmt, AssignStatement) and str(
  1847. stmt
  1848. ).startswith(clean_var):
  1849. suite.statements.pop(i)
  1850. break
  1851.  
  1852. suite.display(indent + 1)
  1853.  
  1854.  
  1855. class Suite:
  1856. def __init__(self):
  1857. self.statements = []
  1858.  
  1859. def __bool__(self) -> bool:
  1860. return bool(self.statements)
  1861.  
  1862. def __len__(self) -> int:
  1863. return len(self.statements)
  1864.  
  1865. def __getitem__(self, i) -> PyStatement:
  1866. return self.statements[i]
  1867.  
  1868. def __setitem__(self, i, val: PyStatement):
  1869. self.statements[i] = val
  1870.  
  1871. def __str__(self):
  1872. istr = IndentString()
  1873. self.display(istr)
  1874. return str(istr)
  1875.  
  1876. def display(self, indent):
  1877. if self.statements:
  1878. for stmt in self.statements:
  1879. stmt.display(indent)
  1880. else:
  1881. indent.write("pass")
  1882.  
  1883. def gen_display(self, seq=()):
  1884. if len(self) != 1:
  1885. raise Exception(
  1886. 'There should only be one statement in a generator.'
  1887. )
  1888. return self[0].gen_display(seq)
  1889.  
  1890. def add_statement(self, stmt):
  1891. self.statements.append(stmt)
  1892.  
  1893.  
  1894. class SuiteDecompiler:
  1895. # An instruction handler can return this to indicate to the run()
  1896. # function that it should return immediately
  1897. END_NOW = object()
  1898.  
  1899. # This is put on the stack by LOAD_BUILD_CLASS
  1900. BUILD_CLASS = object()
  1901.  
  1902. def __init__(self, start_addr, end_addr=None, stack=None):
  1903. self.start_addr = start_addr
  1904. self.end_addr = end_addr
  1905. self.code: Code = start_addr.code
  1906. self.stack = Stack() if stack is None else stack
  1907. self.suite: Suite = Suite()
  1908. self.assignment_chain = []
  1909. self.popjump_stack = []
  1910. self.is_loop = False
  1911. self.convert_return_break = False
  1912. other_self = sys._getframe(1).f_locals.get("self")
  1913. if other_self and hasattr(other_self, "is_loop"):
  1914. self.is_loop = other_self.is_loop
  1915.  
  1916. def IS_OP(self, addr, oparg):
  1917. # case TARGET(IS_OP):
  1918. right = self.stack.pop()
  1919. left = self.stack.peek() # was TOP()
  1920. # res: int = (1 if left == right else 0) ^ oparg;
  1921. # b : bool = True if res else False;
  1922. self.stack.push(PyIsOp(left, right, oparg))
  1923. # self.stack.push(b);
  1924.  
  1925. def CONTAINS_OP(self, addr, oparg):
  1926. right = self.stack.pop()
  1927. left = self.stack.pop()
  1928. pyseq = right
  1929. item = left
  1930. # res: int = 1 if (left in pyseq) else 0;
  1931. # if res < 0: raise AssertionError("res < 0: %d" % res)
  1932. # b: bool = true if (res ^ oparg) else false
  1933. # self.stack.push(b)
  1934. self.stack.push(PyInOp(left, right, oparg))
  1935.  
  1936. def push_popjump(self, jtruthiness, jaddr, jcond, original_jaddr):
  1937. stack = self.popjump_stack
  1938. if jaddr and jaddr[-1].is_else_jump:
  1939. # Increase jaddr to the 'else' address if it jumps to the 'then'
  1940. jaddr = jaddr[-1].jump()
  1941. while stack:
  1942. truthiness, addr, cond, original_addr = stack[-1]
  1943. # if jaddr == None:
  1944. # raise Exception("#ERROR: jaddr is None")
  1945. # jaddr == None \
  1946. if jaddr and jaddr < addr or jaddr == addr:
  1947. break
  1948. stack.pop()
  1949. obj_maker = PyBooleanOr if truthiness else PyBooleanAnd
  1950. if truthiness and jtruthiness:
  1951. if original_jaddr.arg == original_addr.arg:
  1952. obj_maker = PyBooleanAnd
  1953. cond = PyNot(cond)
  1954. jcond = PyNot(jcond)
  1955. elif original_jaddr.arg > original_addr.arg:
  1956. obj_maker = PyBooleanOr
  1957. jcond = PyNot(jcond)
  1958. if not truthiness and not jtruthiness:
  1959. if original_jaddr.arg < original_addr.arg:
  1960. obj_maker = PyBooleanOr
  1961. cond = PyNot(cond)
  1962. elif original_jaddr.arg > original_addr.arg:
  1963. obj_maker = PyBooleanOr
  1964. cond = PyNot(cond)
  1965. if truthiness and not jtruthiness:
  1966. if original_jaddr.arg == original_addr.arg:
  1967. obj_maker = PyBooleanAnd
  1968. cond = PyNot(cond)
  1969. if isinstance(jcond, obj_maker):
  1970. # Use associativity of 'and' and 'or' to minimise the
  1971. # number of parentheses
  1972. jcond = obj_maker(
  1973. obj_maker(cond, jcond.left), jcond.right
  1974. )
  1975. else:
  1976. jcond = obj_maker(cond, jcond)
  1977. stack.append((jtruthiness, jaddr, jcond, original_jaddr))
  1978.  
  1979. def pop_popjump(self):
  1980. if not self.popjump_stack:
  1981. raise Exception(
  1982. 'Attempted to pop an empty popjump stack.'
  1983. )
  1984. (
  1985. truthiness,
  1986. addr,
  1987. cond,
  1988. original_addr,
  1989. ) = self.popjump_stack.pop()
  1990. return cond
  1991.  
  1992. def run(self):
  1993. addr, end_addr = self.start_addr, self.end_addr
  1994. while addr and addr < end_addr:
  1995. opcode, arg = addr
  1996. args = (addr,) if opcode < HAVE_ARGUMENT else (addr, arg)
  1997. try:
  1998. method = getattr(self, opname[opcode])
  1999. new_addr = method(*args)
  2000. if new_addr is self.END_NOW:
  2001. break
  2002. elif new_addr is None:
  2003. new_addr = addr[1]
  2004. addr = new_addr
  2005. except BaseException as e:
  2006. traceback.print_exception(BaseException, e, e.__traceback__)
  2007. addr = None
  2008. return addr
  2009.  
  2010. def write(self, template, *args):
  2011. def fmt(x):
  2012. if isinstance(x, int):
  2013. return self.stack.getval(x)
  2014. else:
  2015. return x
  2016.  
  2017. if args:
  2018. line = template.format(*map(fmt, args))
  2019. else:
  2020. line = template
  2021. self.suite.add_statement(SimpleStatement(line))
  2022.  
  2023. def store(self, dest):
  2024. val = self.stack.pop()
  2025. val.store(self, dest)
  2026.  
  2027. def is_for_loop(self, addr, end_addr):
  2028. i = 0
  2029. while 1:
  2030. cur_addr = addr[i]
  2031. if cur_addr == end_addr:
  2032. break
  2033. elif cur_addr.opcode in else_jump_opcodes:
  2034. cur_addr = cur_addr.jump()
  2035. if cur_addr and cur_addr.opcode in for_jump_opcodes:
  2036. return True
  2037. break
  2038. elif cur_addr.opcode in for_jump_opcodes:
  2039. return True
  2040. i = i + 1
  2041. return False
  2042.  
  2043. def scan_to_first_jump_if(
  2044. self, addr: Address, end_addr: Address
  2045. ) -> Union[Address, None]:
  2046. i = 0
  2047. while 1:
  2048. cur_addr = addr[i]
  2049. if cur_addr == end_addr:
  2050. break
  2051. elif cur_addr.opcode in pop_jump_if_opcodes:
  2052. return cur_addr
  2053. elif cur_addr.opcode in else_jump_opcodes:
  2054. break
  2055. elif cur_addr.opcode in for_jump_opcodes:
  2056. break
  2057. i = i + 1
  2058. return None
  2059.  
  2060. def scan_for_final_jump(self, start_addr, end_addr):
  2061. i = 0
  2062. end = None
  2063. while 1:
  2064. cur_addr = end_addr[i]
  2065. if cur_addr == start_addr:
  2066. break
  2067. elif cur_addr.opcode is JUMP_ABSOLUTE:
  2068. end = cur_addr
  2069. return end
  2070. elif cur_addr.opcode in else_jump_opcodes:
  2071. break
  2072. elif cur_addr.opcode in pop_jump_if_opcodes:
  2073. break
  2074. i = i - 1
  2075. return end
  2076.  
  2077. #
  2078. # All opcode methods in CAPS below.
  2079. #
  2080.  
  2081. def SETUP_LOOP(self, addr: Address, delta):
  2082. jump_addr = addr.jump()
  2083. end_addr = jump_addr[-1]
  2084.  
  2085. end_cond = self.scan_to_first_jump_if(addr[1], end_addr)
  2086. if (
  2087. end_addr.opcode in (POP_BLOCK, POP_TOP)
  2088. or not end_cond
  2089. or end_addr.seek_back(
  2090. else_jump_opcodes, end_addr.seek_back(stmt_opcodes)
  2091. )
  2092. ): # assume conditional
  2093. # scan to first jump
  2094. end_jump = None if not end_cond else end_cond.jump()
  2095. if end_jump and end_jump.opcode is POP_BLOCK:
  2096. end_jump = end_jump[1]
  2097.  
  2098. if end_cond and end_cond[1].opcode is BREAK_LOOP:
  2099. end_cond = None
  2100. if end_cond and end_jump == jump_addr:
  2101. # scan for conditional
  2102. d_cond = SuiteDecompiler(addr[1], end_cond)
  2103. #
  2104. d_cond.run()
  2105. cond = d_cond.stack.pop()
  2106. if end_cond.opcode is POP_JUMP_IF_TRUE:
  2107. cond = PyNot(cond)
  2108. d_body = SuiteDecompiler(end_cond[1], end_addr)
  2109. while_stmt = WhileStatement(cond, d_body.suite)
  2110. d_body.stack.push(while_stmt)
  2111. d_body.run()
  2112. while_stmt.body = d_body.suite
  2113. self.suite.add_statement(while_stmt)
  2114. return jump_addr
  2115. elif (
  2116. not end_cond or not end_cond.jump()[1] == addr.jump()
  2117. ) and not self.is_for_loop(addr[1], end_addr):
  2118. d_body = SuiteDecompiler(addr[1], end_addr)
  2119. while_stmt = WhileStatement(
  2120. PyConst(True), d_body.suite
  2121. )
  2122. d_body.stack.push(while_stmt)
  2123. d_body.run()
  2124. while_stmt.body = d_body.suite
  2125. self.suite.add_statement(while_stmt)
  2126. return jump_addr
  2127. return None
  2128.  
  2129. def BREAK_LOOP(self, addr):
  2130. self.write("break")
  2131.  
  2132. def CONTINUE_LOOP(self, addr, *argv):
  2133. self.write("continue")
  2134.  
  2135. def SETUP_FINALLY(self, addr, delta):
  2136. start_finally: Address = addr.jump()
  2137. d_try = SuiteDecompiler(addr[1], start_finally)
  2138. d_try.run()
  2139. d_finally = SuiteDecompiler(start_finally)
  2140. end_finally = d_finally.run()
  2141. self.suite.add_statement(
  2142. FinallyStatement(d_try.suite, d_finally.suite)
  2143. )
  2144. if end_finally:
  2145. return end_finally[1]
  2146. else:
  2147. return self.END_NOW
  2148.  
  2149. def END_FINALLY(self, addr):
  2150. return self.END_NOW
  2151.  
  2152. def SETUP_EXCEPT(self, addr, delta):
  2153. end_addr = addr
  2154. start_except = addr.jump()
  2155. start_try = addr[1]
  2156. end_try = start_except
  2157. if sys.version_info < (3, 7):
  2158. if end_try.opcode is JUMP_FORWARD:
  2159. end_try = end_try[1] + end_try.arg
  2160. elif end_try.opcode is JUMP_ABSOLUTE:
  2161. end_try = end_try[-1]
  2162. else:
  2163. end_try = end_try[1]
  2164. d_try = SuiteDecompiler(start_try, end_try)
  2165. d_try.run()
  2166.  
  2167. stmt = TryStatement(d_try.suite)
  2168. j_except: Address = None
  2169. while start_except.opcode is not END_FINALLY:
  2170. if start_except.opcode is DUP_TOP:
  2171. # There's a new except clause
  2172. d_except = SuiteDecompiler(start_except[1])
  2173. d_except.stack.push(stmt)
  2174. d_except.run()
  2175. start_except = stmt.next_start_except
  2176. j_except = start_except[-1]
  2177. end_addr = start_except[1]
  2178. elif start_except.opcode is POP_TOP:
  2179. # It's a bare except clause - it starts:
  2180. # POP_TOP
  2181. # POP_TOP
  2182. # POP_TOP
  2183. # <except stuff>
  2184. # POP_EXCEPT
  2185. start_except = start_except[3]
  2186. end_except = start_except
  2187.  
  2188. nested_try: int = 0
  2189. while (
  2190. end_except
  2191. and end_except[-1].opcode is not RETURN_VALUE
  2192. ):
  2193. if end_except.opcode is SETUP_EXCEPT:
  2194. nested_try += 1
  2195. if end_except.opcode is POP_EXCEPT:
  2196. if nested_try == 0:
  2197. break
  2198. nested_try -= 1
  2199. end_except = end_except[1]
  2200. # Handle edge case where there is a return in the except
  2201. if end_except[-1].opcode is RETURN_VALUE:
  2202. d_except = SuiteDecompiler(
  2203. start_except, end_except
  2204. )
  2205. end_except = d_except.run()
  2206. stmt.add_except_clause(None, d_except.suite)
  2207. self.suite.add_statement(stmt)
  2208. return end_except
  2209.  
  2210. d_except = SuiteDecompiler(start_except, end_except)
  2211. end_except = d_except.run()
  2212. stmt.add_except_clause(None, d_except.suite)
  2213. start_except = end_except[2]
  2214. assert start_except.opcode is END_FINALLY
  2215.  
  2216. end_addr = start_except[1]
  2217. j_except: Address = end_except[1]
  2218. self.suite.add_statement(stmt)
  2219. if j_except and j_except.opcode in (
  2220. JUMP_FORWARD,
  2221. JUMP_ABSOLUTE,
  2222. RETURN_VALUE,
  2223. ):
  2224. j_next = j_except.jump()
  2225. start_else = end_addr
  2226. if j_next:
  2227. if j_next < start_else:
  2228. if j_next < start_else and "SETUP_LOOP" in globals():
  2229. j_next = j_next.seek_back(SETUP_LOOP)
  2230. if j_next:
  2231. j_next = j_next.jump()
  2232. else:
  2233. return_count = 0
  2234. next_return = start_else
  2235. while next_return:
  2236. if next_return.opcode in pop_jump_if_opcodes:
  2237. j_next_return = next_return.jump()
  2238. if j_next_return > next_return:
  2239. next_return = j_next_return
  2240. if next_return.opcode is RETURN_VALUE:
  2241. return_count += 1
  2242. next_return = next_return[1]
  2243. if return_count == 1:
  2244. return end_addr
  2245.  
  2246. end_else = j_next
  2247. d_else = SuiteDecompiler(start_else, end_else)
  2248. end_addr = d_else.run()
  2249. if not end_addr:
  2250. end_addr = self.END_NOW
  2251. stmt.else_suite = d_else.suite
  2252. return end_addr
  2253.  
  2254. def SETUP_WITH(self, addr, delta):
  2255. end_with = addr.jump()
  2256. with_stmt = WithStatement(self.stack.pop())
  2257. d_with = SuiteDecompiler(addr[1], end_with)
  2258. d_with.stack.push(with_stmt)
  2259. d_with.run()
  2260. with_stmt.suite = d_with.suite
  2261. self.suite.add_statement(with_stmt)
  2262. if sys.version_info <= (3, 4):
  2263. assert end_with.opcode is WITH_CLEANUP
  2264. assert end_with[1].opcode is END_FINALLY
  2265. return end_with[2]
  2266. elif end_with.opcode is WITH_CLEANUP_START:
  2267. assert end_with.opcode is WITH_CLEANUP_START
  2268. assert end_with[1].opcode is WITH_CLEANUP_FINISH
  2269. return end_with[3]
  2270. elif end_with.opcode is WITH_EXCEPT_START:
  2271. """
  2272. TARGET(WITH_EXCEPT_START) {
  2273. /* At the top of the stack are 4 values:
  2274. - TOP = exc_info()
  2275. - SECOND = previous exception
  2276. - THIRD: lasti of exception in exc_info()
  2277. - FOURTH: the context.__exit__ bound method
  2278. We call FOURTH(type(TOP), TOP, GetTraceback(TOP)).
  2279. Then we push the __exit__ return value.
  2280. */
  2281. PyObject *exit_func;
  2282. PyObject *exc, *val, *tb, *res;
  2283. val = TOP();
  2284. assert(val && PyExceptionInstance_Check(val));
  2285. exc = PyExceptionInstance_Class(val);
  2286. tb = PyException_GetTraceback(val);
  2287. Py_XDECREF(tb);
  2288. assert(PyLong_Check(PEEK(3)));
  2289. exit_func = PEEK(4);
  2290. PyObject *stack[4] = {NULL, exc, val, tb};
  2291. res = PyObject_Vectorcall(exit_func, stack + 1,
  2292. 3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
  2293. }
  2294. """
  2295. start_index = [
  2296. idx
  2297. for idx, (a, (k, v)) in enumerate(
  2298. end_with.code.instr_seq
  2299. )
  2300. if a == end_with[0].addr
  2301. ][0]
  2302. end_index = [
  2303. idx
  2304. for idx, (a, (k, v)) in enumerate(
  2305. end_with.code.instr_seq
  2306. )
  2307. if idx > start_index and k == POP_EXCEPT
  2308. ][0]
  2309. """
  2310. >> 182 WITH_EXCEPT_START
  2311. 184 POP_JUMP_IF_TRUE 188
  2312. 186 RERAISE
  2313. >> 188 POP_TOP
  2314. 190 POP_TOP
  2315. 192 POP_TOP
  2316. 194 POP_EXCEPT
  2317. """
  2318. assert end_with.opcode is WITH_EXCEPT_START
  2319. assert (
  2320. end_with[end_index - start_index].opcode is POP_EXCEPT
  2321. )
  2322. return end_with[end_index - start_index]
  2323. else:
  2324. raise AssertionError(
  2325. "Unexpectee opcode at start of BEGIN_WITH:"
  2326. " end_with.opcode = {}".format(end_with.opcode)
  2327. )
  2328.  
  2329. def POP_BLOCK(self, addr):
  2330. pass
  2331.  
  2332. def POP_EXCEPT(self, addr):
  2333. return self.END_NOW
  2334.  
  2335. def NOP(self, addr):
  2336. return
  2337.  
  2338. def SETUP_ANNOTATIONS(self, addr):
  2339. return
  2340.  
  2341. def COMPARE_OP(self, addr, compare_opname):
  2342. left, right = self.stack.pop(2)
  2343. if compare_opname != 10: # 10 is exception match
  2344. self.stack.push(
  2345. PyCompare([left, cmp_op[compare_opname], right])
  2346. )
  2347. else:
  2348. # It's an exception match
  2349. # left is a TryStatement
  2350. # right is the exception type to be matched
  2351. # It goes:
  2352. # COMPARE_OP 10
  2353. # POP_JUMP_IF_FALSE <next except>
  2354. # POP_TOP
  2355. # POP_TOP or STORE_FAST (if the match is named)
  2356. # POP_TOP
  2357. # SETUP_FINALLY if the match was named
  2358. assert addr[1].opcode is POP_JUMP_IF_FALSE
  2359. left.next_start_except = addr[1].jump()
  2360. assert addr[2].opcode is POP_TOP
  2361. assert addr[4].opcode is POP_TOP
  2362. if addr[5].opcode is SETUP_FINALLY:
  2363. except_start = addr[6]
  2364. except_end = addr[5].jump()
  2365. else:
  2366. except_start = addr[5]
  2367. except_end = left.next_start_except
  2368. d_body = SuiteDecompiler(except_start, except_end)
  2369. d_body.run()
  2370. left.add_except_clause(right, d_body.suite)
  2371. if addr[3].opcode is not POP_TOP:
  2372. # The exception is named
  2373. d_exc_name = SuiteDecompiler(addr[3], addr[4])
  2374. d_exc_name.stack.push(left)
  2375. # This will store the name in left:
  2376. d_exc_name.run()
  2377. # We're done with this except clause
  2378. return self.END_NOW
  2379.  
  2380. #
  2381. # Stack manipulation
  2382. #
  2383.  
  2384. def POP_TOP(self, addr):
  2385. val = self.stack.pop()
  2386. if (sys.version_info > (3, 7)
  2387. and isinstance(val, (ForStatement, WhileStatement))
  2388. and addr[1].opcode is JUMP_ABSOLUTE):
  2389. self.write("break")
  2390. return addr[2]
  2391. val.on_pop(self)
  2392.  
  2393. calls = []
  2394.  
  2395. def PRINT_EXPR(self, addr):
  2396.  
  2397. expr = self.stack.pop()
  2398. self.calls += [(self, addr, expr)]
  2399.  
  2400. self.write("{}", expr)
  2401. # expr.on_pop(self)
  2402.  
  2403. def ROT_TWO(self, addr):
  2404. # special case: x, y = z, t
  2405. if (
  2406. addr[2]
  2407. and addr[1].opcode is STORE_NAME
  2408. and addr[2].opcode is STORE_NAME
  2409. ):
  2410. val = PyTuple(self.stack.pop(2))
  2411. unpack = Unpack(val, 2)
  2412. self.stack.push(unpack)
  2413. self.stack.push(unpack)
  2414. else:
  2415. tos1, tos = self.stack.pop(2)
  2416. self.stack.push(tos, tos1)
  2417.  
  2418. def ROT_THREE(self, addr):
  2419. # special case: x, y, z = a, b, c
  2420. if (
  2421. addr[4]
  2422. and addr[1].opcode is ROT_TWO
  2423. and addr[2].opcode is STORE_NAME
  2424. and addr[3].opcode is STORE_NAME
  2425. and addr[4].opcode is STORE_NAME
  2426. ):
  2427. val = PyTuple(self.stack.pop(3))
  2428. unpack = Unpack(val, 3)
  2429. self.stack.push(unpack)
  2430. self.stack.push(unpack)
  2431. self.stack.push(unpack)
  2432. return addr[2]
  2433. else:
  2434. tos2, tos1, tos = self.stack.pop(3)
  2435. self.stack.push(tos, tos2, tos1)
  2436.  
  2437. def DUP_TOP(self, addr):
  2438. self.stack.push(self.stack.peek())
  2439.  
  2440. def DUP_TOP_TWO(self, addr):
  2441. self.stack.push(*self.stack.peek(2))
  2442.  
  2443. #
  2444. # LOAD / STORE / DELETE
  2445. #
  2446.  
  2447. # FAST
  2448.  
  2449. def LOAD_FAST(self, addr, var_num):
  2450. name = self.code.varnames[var_num]
  2451. self.stack.push(name)
  2452.  
  2453. def STORE_FAST(self, addr, var_num):
  2454. name = self.code.varnames[var_num]
  2455. self.store(name)
  2456.  
  2457. def DELETE_FAST(self, addr, var_num):
  2458. name = self.code.varnames[var_num]
  2459. self.write("del {}", name)
  2460.  
  2461. # DEREF
  2462.  
  2463. def LOAD_DEREF(self, addr, i):
  2464. name = self.code.derefnames[i]
  2465. self.stack.push(name)
  2466.  
  2467. def LOAD_CLASSDEREF(self, addr, i):
  2468. name = self.code.derefnames[i]
  2469. self.stack.push(name)
  2470.  
  2471. def STORE_DEREF(self, addr, i):
  2472. name = self.code.derefnames[i]
  2473. if not self.code.iscellvar(i):
  2474. self.code.declare_nonlocal(name)
  2475. self.store(name)
  2476.  
  2477. def DELETE_DEREF(self, addr, i):
  2478. name = self.code.derefnames[i]
  2479. if not self.code.iscellvar(i):
  2480. self.code.declare_nonlocal(name)
  2481. self.write("del {}", name)
  2482.  
  2483. # GLOBAL
  2484.  
  2485. def LOAD_GLOBAL(self, addr, namei):
  2486. name = self.code.names[namei]
  2487. self.code.ensure_global(name)
  2488. self.stack.push(name)
  2489.  
  2490. def STORE_GLOBAL(self, addr, namei):
  2491. name = self.code.names[namei]
  2492. self.code.declare_global(name)
  2493. self.store(name)
  2494.  
  2495. def DELETE_GLOBAL(self, addr, namei):
  2496. name = self.code.names[namei]
  2497. self.declare_global(name)
  2498. self.write("del {}", name)
  2499.  
  2500. # NAME
  2501.  
  2502. def LOAD_NAME(self, addr, namei):
  2503. name = self.code.names[namei]
  2504. self.stack.push(name)
  2505.  
  2506. def STORE_NAME(self, addr, namei):
  2507. name = self.code.names[namei]
  2508. self.store(name)
  2509.  
  2510. def DELETE_NAME(self, addr, namei):
  2511. name = self.code.names[namei]
  2512. self.write("del {}", name)
  2513.  
  2514. # METHOD
  2515. def LOAD_METHOD(self, addr, namei):
  2516. expr = self.stack.pop()
  2517. attrname = self.code.names[namei]
  2518. self.stack.push(PyAttribute(expr, attrname))
  2519.  
  2520. def CALL_METHOD(self, addr, argc, have_var=False, have_kw=False):
  2521. kw_argc = argc >> 8
  2522. pos_argc = argc
  2523. varkw = self.stack.pop() if have_kw else None
  2524. varargs = self.stack.pop() if have_var else None
  2525. kwargs_iter = iter(self.stack.pop(2 * kw_argc))
  2526. kwargs = list(zip(kwargs_iter, kwargs_iter))
  2527. posargs = self.stack.pop(pos_argc)
  2528. func = self.stack.pop()
  2529. if func is self.BUILD_CLASS:
  2530. # It's a class construction
  2531. # TODO: check the assert statement below is correct
  2532. assert not (have_var or have_kw)
  2533. func, name, *parents = posargs
  2534. self.stack.push(
  2535. ClassStatement(func, name, parents, kwargs)
  2536. )
  2537. elif isinstance(func, PyComp):
  2538. # It's a list/set/dict comprehension or generator expression
  2539. assert not (have_var or have_kw)
  2540. assert len(posargs) == 1 and not kwargs
  2541. func.set_iterable(posargs[0])
  2542. self.stack.push(func)
  2543. elif posargs and isinstance(posargs[0], DecorableStatement):
  2544. # It's a decorator for a def/class statement
  2545. assert len(posargs) == 1 and not kwargs
  2546. defn = posargs[0]
  2547. defn.decorate(func)
  2548. self.stack.push(defn)
  2549. else:
  2550. # It's none of the above, so it must be a normal function call
  2551. func_call = PyCallFunction(
  2552. func, posargs, kwargs, varargs, varkw
  2553. )
  2554. self.stack.push(func_call)
  2555.  
  2556. # ATTR
  2557.  
  2558. def LOAD_ATTR(self, addr, namei):
  2559. expr = self.stack.pop()
  2560. attrname = self.code.names[namei]
  2561. self.stack.push(PyAttribute(expr, attrname))
  2562.  
  2563. def STORE_ATTR(self, addr, namei):
  2564. expr = self.stack.pop1()
  2565. attrname = self.code.names[namei]
  2566. self.store(PyAttribute(expr, attrname))
  2567.  
  2568. def DELETE_ATTR(self, addr, namei):
  2569. expr = self.stack.pop()
  2570. attrname = self.code.names[namei]
  2571. self.write("del {}.{}", expr, attrname)
  2572.  
  2573. # SUBSCR
  2574.  
  2575. def STORE_SUBSCR(self, addr):
  2576. expr, sub = self.stack.pop(2)
  2577. self.store(PySubscript(expr, sub))
  2578.  
  2579. def DELETE_SUBSCR(self, addr):
  2580. expr, sub = self.stack.pop(2)
  2581. self.write("del {}[{}]", expr, sub)
  2582.  
  2583. # CONST
  2584. CONST_LITERALS = {Ellipsis: PyName('...')}
  2585.  
  2586. def LOAD_CONST(self, addr, consti):
  2587. const = self.code.consts[consti]
  2588. if const.val in self.CONST_LITERALS:
  2589. const = self.CONST_LITERALS[const.val]
  2590. self.stack.push(const)
  2591.  
  2592. #
  2593. # Import statements
  2594. #
  2595.  
  2596. def IMPORT_NAME(self, addr, namei):
  2597. name = self.code.names[namei]
  2598.  
  2599. if len(self.stack._stack) > 1:
  2600. level, fromlist = self.stack.pop(2)
  2601. else:
  2602. return addr[0]
  2603. self.stack.push(ImportStatement(name, level, fromlist))
  2604. # special case check for import x.y.z as w
  2605. # syntax which uses attributes and assignments
  2606. # and is difficult to workaround
  2607. i = 1
  2608. while addr[i].opcode is LOAD_ATTR:
  2609. i = i + 1
  2610. if i > 1 and addr[i].opcode in (STORE_FAST, STORE_NAME, STORE_ATTR):
  2611. return addr[i]
  2612. return None
  2613.  
  2614. def IMPORT_FROM(self, addr: Address, namei):
  2615. name = self.code.names[namei]
  2616. self.stack.push(ImportFrom(name))
  2617. if addr[1].opcode is ROT_TWO:
  2618. return addr.seek_forward(STORE_NAME)
  2619.  
  2620. def IMPORT_STAR(self, addr):
  2621. self.POP_TOP(addr)
  2622.  
  2623. #
  2624. # Function call
  2625. #
  2626.  
  2627. def STORE_LOCALS(self, addr):
  2628. self.stack.pop()
  2629. return addr[3]
  2630.  
  2631. def LOAD_BUILD_CLASS(self, addr):
  2632. self.stack.push(self.BUILD_CLASS)
  2633.  
  2634. def RETURN_VALUE(self, addr):
  2635. value = self.stack.pop()
  2636. if isinstance(value, PyConst) and value.val is None:
  2637. if addr[1] is not None:
  2638. if (
  2639. self.code.flags.generator
  2640. and addr[3]
  2641. and not self.code[0].seek_forward(
  2642. {YIELD_FROM, YIELD_VALUE}
  2643. )
  2644. ):
  2645. self.write('yield')
  2646. else:
  2647. self.write("return")
  2648. return
  2649. if self.code.flags.iterable_coroutine:
  2650. self.write("yield {}", value)
  2651. else:
  2652. self.write("return {}", value)
  2653. if self.code.flags.generator:
  2654. self.write('yield')
  2655.  
  2656. def GET_YIELD_FROM_ITER(self, addr):
  2657. pass
  2658.  
  2659. def YIELD_VALUE(self, addr):
  2660. if self.code.name == '<genexpr>':
  2661. return
  2662. value = self.stack.pop()
  2663. self.stack.push(PyYield(value))
  2664.  
  2665. def YIELD_FROM(self, addr):
  2666. value = self.stack.pop() # TODO: from statement ?
  2667. value = self.stack.pop()
  2668. self.stack.push(PyYieldFrom(value))
  2669.  
  2670. def CALL_FUNCTION_CORE(
  2671. self, func, posargs, kwargs, varargs, varkw
  2672. ):
  2673. if func is self.BUILD_CLASS:
  2674. # It's a class construction
  2675. # TODO: check the assert statement below is correct
  2676. # assert not (have_var or have_kw)
  2677. func, name, *parents = posargs
  2678. self.stack.push(
  2679. ClassStatement(func, name, parents, kwargs)
  2680. )
  2681. elif isinstance(func, PyComp):
  2682. # It's a list/set/dict comprehension or generator expression
  2683. # assert not (have_var or have_kw)
  2684. assert len(posargs) == 1 and not kwargs
  2685. func.set_iterable(posargs[0])
  2686. self.stack.push(func)
  2687. elif (
  2688. posargs
  2689. and isinstance(posargs, list)
  2690. and isinstance(posargs[0], DecorableStatement)
  2691. ):
  2692. # It's a decorator for a def/class statement
  2693. assert len(posargs) == 1 and not kwargs
  2694. defn = posargs[0]
  2695. defn.decorate(func)
  2696. self.stack.push(defn)
  2697. else:
  2698. # It's none of the above, so it must be a normal function call
  2699. func_call = PyCallFunction(
  2700. func, posargs, kwargs, varargs, varkw
  2701. )
  2702. self.stack.push(func_call)
  2703.  
  2704. def CALL_FUNCTION(
  2705. self, addr, argc, have_var=False, have_kw=False
  2706. ):
  2707. if sys.version_info >= (3, 6):
  2708. pos_argc = argc
  2709. posargs = self.stack.pop(pos_argc)
  2710. func = self.stack.pop()
  2711. self.CALL_FUNCTION_CORE(func, posargs, [], None, None)
  2712. else:
  2713. kw_argc = argc >> 8
  2714. pos_argc = argc & 0xFF
  2715. varkw = self.stack.pop() if have_kw else None
  2716. varargs = self.stack.pop() if have_var else None
  2717. kwargs_iter = iter(self.stack.pop(2 * kw_argc))
  2718. kwargs = list(zip(kwargs_iter, kwargs_iter))
  2719. posargs = self.stack.pop(pos_argc)
  2720. func = self.stack.pop()
  2721. self.CALL_FUNCTION_CORE(
  2722. func, posargs, kwargs, varargs, varkw
  2723. )
  2724.  
  2725. def CALL_FUNCTION_VAR(self, addr, argc):
  2726. self.CALL_FUNCTION(addr, argc, have_var=True)
  2727.  
  2728. def CALL_FUNCTION_KW(self, addr, argc):
  2729. if sys.version_info >= (3, 6):
  2730. keys = self.stack.pop()
  2731. kwargc = len(keys.val)
  2732. kwarg_values = self.stack.pop(kwargc)
  2733. posargs = self.stack.pop(argc - kwargc)
  2734. func = self.stack.pop()
  2735. kwarg_dict = list(
  2736. zip([PyName(k) for k in keys], kwarg_values)
  2737. )
  2738. self.CALL_FUNCTION_CORE(
  2739. func, posargs, kwarg_dict, None, None
  2740. )
  2741. else:
  2742. self.CALL_FUNCTION(addr, argc, have_kw=True)
  2743.  
  2744. def CALL_FUNCTION_EX(self, addr, flags):
  2745. kwarg_unpacks = []
  2746. if flags & 1:
  2747. kwarg_unpacks = self.stack.pop()
  2748.  
  2749. kwarg_dict = PyDict()
  2750. if isinstance(kwarg_unpacks, PyDict):
  2751. kwarg_dict = kwarg_unpacks
  2752. kwarg_unpacks = []
  2753. elif isinstance(kwarg_unpacks, list):
  2754. if len(kwarg_unpacks):
  2755. if isinstance(kwarg_unpacks[0], PyDict):
  2756. kwarg_dict = kwarg_unpacks[0]
  2757. kwarg_unpacks = kwarg_unpacks[1:]
  2758. else:
  2759. kwarg_unpacks = [kwarg_unpacks]
  2760.  
  2761. if any(
  2762. filter(lambda kv: '.' in str(kv[0]), kwarg_dict.items)
  2763. ):
  2764. kwarg_unpacks.append(kwarg_dict)
  2765. kwarg_dict = PyDict()
  2766.  
  2767. posargs_unpacks = self.stack.pop()
  2768. posargs = PyTuple([])
  2769. if isinstance(posargs_unpacks, PyTuple):
  2770. posargs = posargs_unpacks
  2771. posargs_unpacks = []
  2772. elif isinstance(posargs_unpacks, list):
  2773. if len(posargs_unpacks) > 0:
  2774. posargs = posargs_unpacks[0]
  2775. if isinstance(posargs, PyConst):
  2776. posargs = PyTuple(
  2777. [PyConst(a) for a in posargs.val]
  2778. )
  2779. elif isinstance(posargs, PyAttribute):
  2780. posargs = PyTuple([posargs])
  2781. posargs_unpacks = posargs_unpacks[1:]
  2782. else:
  2783. posargs_unpacks = [posargs_unpacks]
  2784.  
  2785. func = self.stack.pop()
  2786. self.CALL_FUNCTION_CORE(
  2787. func,
  2788. list(posargs.values),
  2789. list(kwarg_dict.items),
  2790. posargs_unpacks,
  2791. kwarg_unpacks,
  2792. )
  2793.  
  2794. def CALL_FUNCTION_VAR_KW(self, addr, argc):
  2795. self.CALL_FUNCTION(addr, argc, have_var=True, have_kw=True)
  2796.  
  2797. # a, b, ... = ...
  2798.  
  2799. def UNPACK_SEQUENCE(self, addr, count):
  2800. unpack = Unpack(self.stack.pop(), count)
  2801. for i in range(count):
  2802. self.stack.push(unpack)
  2803.  
  2804. def UNPACK_EX(self, addr, counts):
  2805. rcount = counts >> 8
  2806. lcount = counts & 0xFF
  2807. count = lcount + rcount + 1
  2808. unpack = Unpack(self.stack.pop(), count, lcount)
  2809. for i in range(count):
  2810. self.stack.push(unpack)
  2811.  
  2812. # Build operations
  2813.  
  2814. def BUILD_SLICE(self, addr, argc):
  2815. assert argc in (2, 3)
  2816. self.stack.push(PySlice(self.stack.pop(argc)))
  2817.  
  2818. def BUILD_TUPLE(self, addr, count):
  2819. values = [self.stack.pop() for i in range(count)]
  2820. values.reverse()
  2821. self.stack.push(PyTuple(values))
  2822.  
  2823. def DICT_MERGE(self, addr, count):
  2824. values = []
  2825. for o in self.stack.pop(count):
  2826. if isinstance(o, PyTuple):
  2827. values.extend(o.values)
  2828. else:
  2829. values.append(PyStarred(o))
  2830. self.stack.push(PyList(values))
  2831.  
  2832. def BUILD_TUPLE_UNPACK(self, addr, count):
  2833. values = []
  2834. for o in self.stack.pop(count):
  2835. if isinstance(o, PyTuple):
  2836. values.extend(o.values)
  2837. else:
  2838. values.append(PyStarred(o))
  2839.  
  2840. self.stack.push(PyTuple(values))
  2841.  
  2842. def BUILD_TUPLE_UNPACK_WITH_CALL(self, addr, count):
  2843. self.stack.push(self.stack.pop(count))
  2844.  
  2845. def BUILD_LIST(self, addr, count):
  2846. values = [self.stack.pop() for i in range(count)]
  2847. values.reverse()
  2848. self.stack.push(PyList(values))
  2849.  
  2850. def BUILD_LIST_UNPACK(self, addr, count):
  2851. values = []
  2852. for o in self.stack.pop(count):
  2853. if isinstance(o, PyTuple):
  2854. values.extend(o.values)
  2855. else:
  2856. values.append(PyStarred(o))
  2857.  
  2858. self.stack.push(PyList(values))
  2859.  
  2860. def BUILD_SET(self, addr, count):
  2861. values = [self.stack.pop() for i in range(count)]
  2862. values.reverse()
  2863. self.stack.push(PySet(values))
  2864.  
  2865. def BUILD_SET_UNPACK(self, addr, count):
  2866. values = []
  2867. for o in self.stack.pop(count):
  2868. if isinstance(o, PySet):
  2869. values.extend(o.values)
  2870. else:
  2871. values.append(PyStarred(o))
  2872.  
  2873. self.stack.push(PySet(values))
  2874.  
  2875. def BUILD_MAP(self, addr, count):
  2876. d = PyDict()
  2877. if sys.version_info >= (3, 5):
  2878. for i in range(count):
  2879. d.items.append(tuple(self.stack.pop(2)))
  2880. d.items = list(reversed(d.items))
  2881. self.stack.push(d)
  2882.  
  2883. def BUILD_MAP_UNPACK(self, addr, count):
  2884. d = PyDict()
  2885. for i in range(count):
  2886. o = self.stack.pop()
  2887. if isinstance(o, PyDict):
  2888. for item in reversed(o.items):
  2889. k, v = item
  2890. d.set_item(
  2891. PyConst(
  2892. k.val
  2893. if isinstance(k, PyConst)
  2894. else k.name
  2895. ),
  2896. v,
  2897. )
  2898. else:
  2899. d.items.append((PyStarred(PyStarred(o)),))
  2900. d.items = list(reversed(d.items))
  2901. self.stack.push(d)
  2902.  
  2903. def BUILD_MAP_UNPACK_WITH_CALL(self, addr, count):
  2904. self.stack.push(self.stack.pop(count))
  2905.  
  2906. def BUILD_CONST_KEY_MAP(self, addr, count):
  2907. keys = self.stack.pop()
  2908. vals = self.stack.pop(count)
  2909. dict = PyDict()
  2910. for i in range(count):
  2911. dict.set_item(PyConst(keys.val[i]), vals[i])
  2912. self.stack.push(dict)
  2913.  
  2914. def STORE_MAP(self, addr):
  2915. v, k = self.stack.pop(2)
  2916. d = self.stack.peek()
  2917. d.set_item(k, v)
  2918.  
  2919. # Comprehension operations - just create an expression statement
  2920.  
  2921. def LIST_APPEND(self, addr, i):
  2922. self.POP_TOP(addr)
  2923.  
  2924. def SET_ADD(self, addr, i):
  2925. self.POP_TOP(addr)
  2926.  
  2927. def MAP_ADD(self, addr, i):
  2928. value, key = self.stack.pop(2)
  2929. self.stack.push(PyKeyValue(key, value))
  2930. self.POP_TOP(addr)
  2931.  
  2932. """
  2933. def LIST_TO_TUPLE(self, addr):
  2934. list_obj = self.stack.pop()
  2935. tuple_obj = PyTuple(list_obj)
  2936. #self.POP_TOP(addr)
  2937. self.stack.push(tuple_obj)
  2938.  
  2939. def LIST_EXTEND(self, addr, oparg):
  2940. iterable = self.stack.pop()
  2941. list_obj = self.stack.peek(oparg)
  2942. none_val = None
  2943. try:
  2944. list_obj += [iterable]
  2945. #self.stack.push(PyList(list_obj))
  2946. except TypeError as _te:
  2947. if not hasattr(iterable, "__iter__") and \
  2948. not hasattr(iterable, "__getitem__"):
  2949. raise TypeError(
  2950. "Value after * must be an iterable, not {!s}".format(
  2951. type(iterable).__name__))
  2952. list_obj[0].values + [PyStarred(iterable)]
  2953. self.stack.push(PyList(list_obj[0].values))
  2954. #self.POP_TOP(addr)
  2955.  
  2956. def SET_UPDATE(self, addr, i, oparg):
  2957. iterable = self.stack.pop()
  2958. set_obj = self.stack.peek(oparg)[0]
  2959. for item in iterable:
  2960. set_obj.values.add(item)
  2961. self.stack.push(set_obj)
  2962. #self.POP_TOP(addr)
  2963.  
  2964. def DICT_UPDATE(self, addr, i, oparg):
  2965. update = self.stack.pop()
  2966. dict_obj = self.stack.peek(oparg)[0]
  2967. if (PyDict_Update(dict_obj, update) < 0):
  2968. if (_PyErr_ExceptionMatches(AttributeError)):
  2969. raise TypeError("'{!s}' object_obj is not a mapping".format(
  2970. type(update).__name__))
  2971. #self.POP_TOP(addr)
  2972. self.stack.push(dict_obj)
  2973.  
  2974. def DICT_MERGE(self, addr, oparg):
  2975. other = self.stack.pop()
  2976. dict_obj = self.stack.peek()
  2977. if isinstance(other, PyDict):
  2978. self.print("{}.update({})".format(dict_obj, other))
  2979. self.stack.push(dict_obj)
  2980. else:
  2981. for key, value in dict_obj.items:
  2982. self.stack.push(PyKeyValue(key, value))
  2983. self.stack.push(dict_obj)
  2984. #self.POP_TOP(addr)
  2985.  
  2986. # and operator
  2987. """
  2988.  
  2989. def LIST_TO_TUPLE(self, addr):
  2990. list_value = self.stack.pop()
  2991. values = list_value.values
  2992. self.stack.push(PyTuple(values))
  2993.  
  2994. def LIST_EXTEND(self, addr, i):
  2995. items = self.stack.pop(1)
  2996. item2 = self.stack.pop(1)
  2997. if hasattr(item2[0], "expr"):
  2998. exprs = [item2[0].expr]
  2999. else:
  3000. exprs = item2[0].values
  3001. new_list = PyList([*exprs, PyStarred(items[0])])
  3002. self.stack.push(new_list)
  3003.  
  3004. def SET_UPDATE(self, addr, i):
  3005. self.POP_TOP(addr)
  3006. pass # self.POP_TOP(addr)
  3007.  
  3008. def DICT_UPDATE(self, addr, i):
  3009. items = self.stack.pop(1)
  3010. self.stack.push(items[0])
  3011. self.POP_TOP(addr)
  3012.  
  3013. def DICT_MERGE(self, addr, i):
  3014. items = self.stack.pop(1)
  3015. item2 = self.stack.pop(1)
  3016. new_list = [*item2[0].items] + [items[0]]
  3017. item = None
  3018. if len(new_list) == 1:
  3019. item = new_list[0]
  3020. else:
  3021. item = PyList(new_list)
  3022. self.stack.push(item)
  3023.  
  3024. def JUMP_IF_FALSE_OR_POP(self, addr: Address, target):
  3025. end_addr = addr.jump()
  3026. truthiness = not addr.seek_back_statement(POP_JUMP_IF_TRUE)
  3027. self.push_popjump(
  3028. truthiness, end_addr, self.stack.pop(), addr
  3029. )
  3030. left = self.pop_popjump()
  3031. if end_addr.opcode is ROT_TWO:
  3032. opc, arg = end_addr[-1]
  3033. if opc == JUMP_FORWARD and arg == 2:
  3034. end_addr = end_addr[2]
  3035. elif opc == RETURN_VALUE or opc == JUMP_FORWARD:
  3036. end_addr = end_addr[-1]
  3037. d = SuiteDecompiler(addr[1], end_addr, self.stack)
  3038. d.run()
  3039. right = self.stack.pop()
  3040. if isinstance(right, PyCompare) and right.extends(
  3041. left
  3042. ):
  3043. py_and = left.chain(right)
  3044. else:
  3045. py_and = PyBooleanAnd(left, right)
  3046. self.stack.push(py_and)
  3047. return end_addr[3]
  3048.  
  3049. d = SuiteDecompiler(addr[1], end_addr, self.stack)
  3050. if end_addr[-1].opcode is RETURN_VALUE:
  3051. d = SuiteDecompiler(addr[1], end_addr[-1], self.stack)
  3052. else:
  3053. d = SuiteDecompiler(addr[1], end_addr, self.stack)
  3054.  
  3055. d.run()
  3056. # if end_addr.opcode is RETURN_VALUE:
  3057. # return end_addr[2]
  3058. right = self.stack.pop()
  3059. if isinstance(right, PyCompare) and right.extends(left):
  3060. py_and = left.chain(right)
  3061. else:
  3062. py_and = PyBooleanAnd(left, right)
  3063. self.stack.push(py_and)
  3064. return end_addr
  3065.  
  3066. # This appears when there are chained comparisons, e.g. 1 <= x < 10
  3067.  
  3068. def JUMP_FORWARD(self, addr, delta):
  3069. ## if delta == 2 and addr[1].opcode is ROT_TWO and addr[2].opcode is POP_TOP:
  3070. ## # We're in the special case of chained comparisons
  3071. ## return addr[3]
  3072. ## else:
  3073. ## # I'm hoping its an unused JUMP in an if-else statement
  3074. ## return addr[1]
  3075. return addr.jump()
  3076.  
  3077. # or operator
  3078.  
  3079. def JUMP_IF_TRUE_OR_POP(self, addr, target):
  3080. end_addr = addr.jump()
  3081. self.push_popjump(True, end_addr, self.stack.pop(), addr)
  3082. left = self.pop_popjump()
  3083. d = SuiteDecompiler(addr[1], end_addr, self.stack)
  3084. d.run()
  3085. right = self.stack.pop()
  3086. self.stack.push(PyBooleanOr(left, right))
  3087. return end_addr
  3088.  
  3089. #
  3090. # If-else statements/expressions and related structures
  3091. #
  3092.  
  3093. def POP_JUMP_IF(
  3094. self, addr: Address, target: int, truthiness: bool
  3095. ) -> Union[Address, None]:
  3096. jump_addr = addr.jump()
  3097.  
  3098. last_loop = None
  3099. if "SETUP_LOOP" in globals():
  3100. last_loop = addr.seek_back(SETUP_LOOP)
  3101.  
  3102. last_loop = last_loop or addr
  3103. in_loop = last_loop and last_loop.jump() > addr
  3104. end_of_loop = (
  3105. jump_addr.opcode is FOR_ITER
  3106. or (
  3107. "SETUP_LOOP" in globals()
  3108. and jump_addr[-1].opcode is SETUP_LOOP
  3109. )
  3110. )
  3111. if jump_addr.opcode is FOR_ITER:
  3112. # We are in a for-loop with nothing after the if-suite
  3113. # But take care: for-loops in generator expression do
  3114. # not end in POP_BLOCK, hence the test below.
  3115. jump_addr = jump_addr.jump()
  3116. else:
  3117. if end_of_loop:
  3118. # We are in a while-loop with nothing after the if-suite
  3119. jump_addr = jump_addr[-1].jump()[-1]
  3120. #else:
  3121. #jump_addr = addr[1]
  3122. # raise Exception("unhandled")
  3123. if self.stack._stack:
  3124. cond = self.stack.pop()
  3125. else:
  3126. cond = not truthiness
  3127. # chained compare
  3128. # ex:
  3129. # if x <= y <= z:
  3130. if (
  3131. addr[-3]
  3132. and addr[-1].opcode is COMPARE_OP
  3133. and addr[-2].opcode is ROT_THREE
  3134. and addr[-3].opcode is DUP_TOP
  3135. ):
  3136. if self.popjump_stack:
  3137. c = self.pop_popjump()
  3138. c = c.chain(cond)
  3139. self.push_popjump(not truthiness, jump_addr, c, addr)
  3140. else:
  3141. self.push_popjump(
  3142. not truthiness, jump_addr, cond, addr
  3143. )
  3144. return
  3145.  
  3146. is_chained = isinstance(cond, PyCompare) and addr.seek_back(
  3147. ROT_THREE, addr.seek_back(stmt_opcodes)
  3148. )
  3149. if is_chained and self.popjump_stack:
  3150. pj = self.pop_popjump()
  3151. if isinstance(pj, PyCompare):
  3152. cond = pj.chain(cond)
  3153.  
  3154. if not addr.is_else_jump:
  3155. # Handle generator expressions with or clause
  3156. for_iter = addr.seek_back(FOR_ITER)
  3157. if for_iter:
  3158. end_of_for = for_iter.jump()
  3159. if end_of_for.addr > addr.addr:
  3160. gen = jump_addr.seek_forward(
  3161. (YIELD_VALUE, LIST_APPEND), end_of_for
  3162. )
  3163. if gen:
  3164. if not truthiness:
  3165. truthiness = not truthiness
  3166. if truthiness:
  3167. cond = PyNot(cond)
  3168. self.push_popjump(
  3169. truthiness, jump_addr, cond, addr
  3170. )
  3171. return None
  3172.  
  3173. self.push_popjump(truthiness, jump_addr, cond, addr)
  3174. # Dictionary comprehension
  3175. if jump_addr.seek_forward(MAP_ADD):
  3176. return None
  3177.  
  3178. if addr.code.name == '<lambda>':
  3179. return None
  3180. # Generator
  3181. if jump_addr.seek_forward(YIELD_VALUE):
  3182. return None
  3183.  
  3184. if jump_addr.seek_back(
  3185. JUMP_IF_TRUE_OR_POP, jump_addr[-2]
  3186. ):
  3187. return None
  3188. # Generator
  3189. if (
  3190. jump_addr.opcode is not END_FINALLY
  3191. and jump_addr[1]
  3192. and jump_addr[1].opcode is JUMP_ABSOLUTE
  3193. ):
  3194. return None
  3195.  
  3196. next_addr = addr[1]
  3197. while next_addr and next_addr < jump_addr:
  3198. if next_addr.opcode in stmt_opcodes:
  3199. break
  3200. if next_addr.opcode in pop_jump_if_opcodes:
  3201. next_jump_addr = next_addr.jump()
  3202. if next_jump_addr > jump_addr or (
  3203. next_jump_addr == jump_addr
  3204. and jump_addr[-1].opcode in else_jump_opcodes
  3205. ):
  3206. return None
  3207.  
  3208. if next_addr.opcode in (
  3209. JUMP_IF_FALSE_OR_POP,
  3210. JUMP_IF_TRUE_OR_POP,
  3211. ):
  3212. next_jump_addr = next_addr.jump()
  3213. if next_jump_addr > jump_addr or (
  3214. next_jump_addr == jump_addr
  3215. and jump_addr[-1].opcode in else_jump_opcodes
  3216. ):
  3217. return None
  3218. next_addr = next_addr[1]
  3219. # if there are no nested conditionals and no else clause, write the true portion and jump ahead to the end of the conditional
  3220. cond = self.pop_popjump()
  3221. end_true = jump_addr
  3222. if truthiness:
  3223. cond = PyNot(cond)
  3224. d_true = SuiteDecompiler(addr[1], end_true, self.stack[:])
  3225. d_true.run()
  3226. stmt = IfStatement(cond, d_true.suite, None)
  3227. self.suite.add_statement(stmt)
  3228. return end_true
  3229. # Increase jump_addr to pop all previous jumps
  3230. self.push_popjump(truthiness, jump_addr[1], cond, addr)
  3231. cond = self.pop_popjump()
  3232. end_true = jump_addr[-1]
  3233. if truthiness:
  3234. last_pj = addr.seek_back(pop_jump_if_opcodes)
  3235. if (
  3236. last_pj
  3237. and last_pj.arg == addr.arg
  3238. and isinstance(cond, PyBooleanAnd)
  3239. or isinstance(cond, PyBooleanOr)
  3240. ):
  3241. if last_pj.opcode is not addr.opcode:
  3242. cond.right = PyNot(cond.right)
  3243. else:
  3244. cond = PyNot(cond)
  3245.  
  3246. if end_true.opcode is RETURN_VALUE:
  3247. end_false = jump_addr.seek_forward(RETURN_VALUE)
  3248. if (
  3249. end_false
  3250. and end_false[2]
  3251. and end_false[2].opcode is RETURN_VALUE
  3252. ):
  3253. d_true = SuiteDecompiler(addr[1], jump_addr, self.stack[:])
  3254. d_true.run()
  3255. d_false = SuiteDecompiler(jump_addr, end_false[1], self.stack[:])
  3256. d_false.run()
  3257. self.suite.add_statement(
  3258. IfStatement(cond, d_true.suite, d_false.suite)
  3259. )
  3260.  
  3261. return end_false[1]
  3262.  
  3263. if (
  3264. end_true.opcode is RAISE_VARARGS
  3265. and addr[1].opcode is LOAD_GLOBAL
  3266. ):
  3267. assert_addr = addr[1]
  3268. if (
  3269. assert_addr.code.names[assert_addr.arg].name
  3270. == 'AssertionError'
  3271. ):
  3272. cond = (
  3273. cond.operand
  3274. if isinstance(cond, PyNot)
  3275. else PyNot(cond)
  3276. )
  3277. d_true = SuiteDecompiler(addr[1], end_true, self.stack[:])
  3278. d_true.run()
  3279. assert_pop = d_true.stack.pop()
  3280. assert_args = (
  3281. assert_pop.args
  3282. if isinstance(assert_pop, PyCallFunction)
  3283. else []
  3284. )
  3285. assert_arg_str = ', '.join(
  3286. map(str, [cond, *assert_args])
  3287. )
  3288. self.suite.add_statement(
  3289. SimpleStatement(f'assert {assert_arg_str}')
  3290. )
  3291. return jump_addr
  3292. if self.is_loop:
  3293. # - If the true clause ends in return and we're not in
  3294. # another loop, break instead
  3295. # - If the true clause jumps forward and it's past loop
  3296. # boundaries, break instead
  3297. if self.convert_return_break and end_true.opcode is RETURN_VALUE:
  3298. d_true = SuiteDecompiler(addr[1], end_true, self.stack[:])
  3299. d_true.run()
  3300. d_true.suite.add_statement(SimpleStatement("break"))
  3301. self.suite.add_statement(
  3302. IfStatement(cond, d_true.suite, Suite())
  3303. )
  3304. return jump_addr
  3305. elif end_true.opcode is JUMP_FORWARD:
  3306. end_false = end_true.jump()
  3307. instr = self.wrap_addr(end_false)[-1]
  3308. if instr.opcode is JUMP_ABSOLUTE:
  3309. d_true = SuiteDecompiler(addr[1], end_true, self.stack[:])
  3310. d_true.run()
  3311. d_true.suite.add_statement(SimpleStatement("break"))
  3312. self.suite.add_statement(
  3313. IfStatement(cond, d_true.suite, Suite())
  3314. )
  3315. return jump_addr
  3316. # - If the true clause ends in return, make sure it's included
  3317. # - If the true clause ends in RAISE_VARARGS, then it's an
  3318. # assert statement. For now I just write it as a raise within
  3319. # an if (see below)
  3320. if end_true.opcode in (RETURN_VALUE, RAISE_VARARGS, POP_TOP):
  3321. d_true = SuiteDecompiler(addr[1], jump_addr, self.stack[:])
  3322. d_true.run()
  3323. self.suite.add_statement(
  3324. IfStatement(cond, d_true.suite, Suite())
  3325. )
  3326. return jump_addr
  3327. if is_chained and addr[1].opcode is JUMP_ABSOLUTE:
  3328. end_true = end_true[-2]
  3329. d_true = SuiteDecompiler(addr[1], end_true, self.stack[:])
  3330. d_true.run()
  3331. l = None
  3332. if addr[1].opcode is JUMP_ABSOLUTE:
  3333. j = addr[1].jump()
  3334. if last_loop != None and len(last_loop) > 1:
  3335. l = last_loop[1]
  3336. while l != None and l.opcode not in stmt_opcodes:
  3337. if l == j:
  3338. d_true.suite.add_statement(
  3339. SimpleStatement('continue')
  3340. )
  3341.  
  3342. self.suite.add_statement(
  3343. IfStatement(cond, d_true.suite, None)
  3344. )
  3345. return addr[2]
  3346. l = l[1]
  3347.  
  3348. if jump_addr.opcode is POP_BLOCK and not end_of_loop:
  3349. # It's a while loop
  3350. stmt = WhileStatement(cond, d_true.suite)
  3351. self.suite.add_statement(stmt)
  3352. return jump_addr[1]
  3353. # It's an if-else (expression or statement)
  3354. if end_true.opcode is JUMP_FORWARD:
  3355. end_false = end_true.jump()
  3356. elif end_true.opcode is JUMP_ABSOLUTE:
  3357. end_false = end_true.jump()
  3358. if end_false.opcode is FOR_ITER:
  3359. # We are in a for-loop with nothing after the else-suite
  3360. end_false = end_false.jump()[-1]
  3361. elif "SETUP_LOOP" in globals() and self.wrap_addr(end_false)[-1].opcode is SETUP_LOOP:
  3362. # We are in a while-loop with nothing after the else-suite
  3363. end_false = self.wrap_addr(end_false)[-1].jump()[-1]
  3364. elif self.is_loop:
  3365. end_false = jump_addr
  3366. if end_false.opcode is RETURN_VALUE:
  3367. end_false = self.wrap_addr(end_false)[1]
  3368. elif end_true.opcode is RETURN_VALUE:
  3369. # find the next RETURN_VALUE
  3370. end_false = jump_addr
  3371. while end_false.opcode is not RETURN_VALUE:
  3372. end_false = end_false[1]
  3373. end_false = end_false[1]
  3374. elif end_true.opcode is BREAK_LOOP:
  3375. # likely in a loop in a try/except
  3376. end_false = jump_addr
  3377. else:
  3378. end_false = jump_addr
  3379. # # normal statement
  3380. # raise Exception("#ERROR: Unexpected statement: {} | {}\n".format(end_true, jump_addr, jump_addr[-1]))
  3381. # # raise Unknown
  3382. # jump_addr = end_true[-2]
  3383. # stmt = IfStatement(cond, d_true.suite, None)
  3384. # self.suite.add_statement(stmt)
  3385. # return jump_addr or self.END_NOW
  3386. d_false = SuiteDecompiler(jump_addr, end_false, self.stack[:])
  3387. d_false.run()
  3388. stack_level = len(self.stack)
  3389. if len(d_true.stack) == len(d_false.stack) > stack_level:
  3390. assert not (d_true.suite or d_false.suite)
  3391. # this happens in specific if else conditions with assigments
  3392. true_expr = d_true.stack.pop()
  3393. false_expr = d_false.stack.pop()
  3394. self.stack.push(PyIfElse(cond, true_expr, false_expr))
  3395. else:
  3396. stmt = IfStatement(cond, d_true.suite, d_false.suite)
  3397. self.suite.add_statement(stmt)
  3398. return end_false or self.END_NOW
  3399.  
  3400. def POP_JUMP_IF_FALSE(self, addr, target):
  3401. return self.POP_JUMP_IF(addr, target, truthiness=False)
  3402.  
  3403. def POP_JUMP_IF_TRUE(self, addr, target):
  3404. return self.POP_JUMP_IF(addr, target, truthiness=True)
  3405.  
  3406. def addr2list(self, addr):
  3407. import attrdict, inspect
  3408.  
  3409. if not (addr[-1] is None):
  3410. return addr
  3411.  
  3412. a = dict(
  3413. (idx, addr.code[addr.index + idx])
  3414. for idx in range(-5, len(list(addr.code)) - addr.index)
  3415. )
  3416. [a.__setitem__(*pair) for pair in inspect.getmembers(addr)]
  3417. wa = attrdict()
  3418. wa.update(a)
  3419. if a[-1] is None:
  3420. wa.update({-1: Address(addr.code, addr.index - 1)})
  3421. return wa
  3422.  
  3423. def wrap_addr(self, addr):
  3424. if not isinstance(addr, Address):
  3425. return addr
  3426. if addr[-1] is None:
  3427. return self.addr2list(addr)
  3428. return addr
  3429.  
  3430. def JUMP_ABSOLUTE(self, addr, target):
  3431. import operator, sys
  3432.  
  3433. if 'debug' in globals():
  3434. print("*** JUMP ABSOLUTE ***", addr)
  3435. globals()['debug'] += [
  3436. (
  3437. self.JUMP_ABSOLUTE,
  3438. (addr, target),
  3439. sys._current_frames(),
  3440. )
  3441. ]
  3442.  
  3443. # return addr.jump()
  3444.  
  3445. # TODO: print out continue if not final jump
  3446. jump_addr = addr.jump()
  3447.  
  3448. if "SETUP_LOOP" in globals() and self.wrap_addr(jump_addr)[-1].opcode is SETUP_LOOP:
  3449. end_addr = jump_addr + self.wrap_addr(jump_addr)[-1].arg
  3450.  
  3451. last_jump = self.scan_for_final_jump(
  3452. jump_addr, self.wrap_addr(end_addr)[-1]
  3453. )
  3454. if last_jump != addr:
  3455. self.suite.add_statement(SimpleStatement('continue'))
  3456. pass
  3457.  
  3458. #
  3459. # For loops
  3460. #
  3461.  
  3462. def GET_ITER(self, addr):
  3463. pass
  3464.  
  3465. def FOR_ITER(self, addr: Address, delta):
  3466. if addr[-1] and addr[-1].opcode is RETURN_VALUE:
  3467. # Dead code
  3468. return self.END_NOW
  3469. iterable = self.stack.pop()
  3470. jump_addr = addr.jump()
  3471. end_body = jump_addr
  3472. if end_body.opcode is not POP_BLOCK:
  3473. end_body = end_body[-1]
  3474. d_body = SuiteDecompiler(addr[1], end_body)
  3475. d_body.is_loop = sys.version_info > (3, 7)
  3476. d_body.convert_return_break = not self.is_loop
  3477. for_stmt = ForStatement(iterable)
  3478. d_body.stack.push(*self.stack._stack, for_stmt, for_stmt)
  3479. d_body.run()
  3480. for_stmt.body = d_body.suite
  3481. loop = None
  3482. outer_loop = None
  3483. if "SETUP_LOOP" in globals():
  3484. loop = addr.seek_back(SETUP_LOOP)
  3485. while loop:
  3486. if "SETUP_LOOP" in globals():
  3487. outer_loop = loop.seek_back(SETUP_LOOP)
  3488. if outer_loop:
  3489. if outer_loop.jump().addr < loop.addr:
  3490. break
  3491. else:
  3492. loop = outer_loop
  3493. else:
  3494. break
  3495. end_addr = jump_addr
  3496. if loop:
  3497. end_of_loop = loop.jump()[-1]
  3498. if end_of_loop.opcode is not POP_BLOCK:
  3499. else_start = end_of_loop.seek_back(POP_BLOCK)
  3500. d_else = SuiteDecompiler(else_start, loop.jump())
  3501. d_else.run()
  3502. for_stmt.else_body = d_else.suite
  3503. end_addr = loop.jump()
  3504. self.suite.add_statement(for_stmt)
  3505. return end_addr
  3506.  
  3507. # Function creation
  3508.  
  3509. def MAKE_FUNCTION_OLD(self, addr, argc, is_closure=False):
  3510. testType = self.stack.pop().val
  3511. if isinstance(testType, str):
  3512. code = Code(self.stack.pop().val, self.code)
  3513. else:
  3514. code = Code(testType, self.code)
  3515. closure = self.stack.pop() if is_closure else None
  3516. # parameter annotation objects
  3517. paramobjs = {}
  3518. paramcount = (argc >> 16) & 0x7FFF
  3519. if paramcount:
  3520. paramobjs = dict(
  3521. zip(
  3522. self.stack.pop().val,
  3523. self.stack.pop(paramcount - 1),
  3524. )
  3525. )
  3526. # default argument objects in positional order
  3527. defaults = self.stack.pop(argc & 0xFF)
  3528. # pairs of name and default argument, with the name just below the object on the stack, for keyword-only parameters
  3529. kwdefaults = {}
  3530. for i in range((argc >> 8) & 0xFF):
  3531. k, v = self.stack.pop(2)
  3532. if hasattr(k, 'name'):
  3533. kwdefaults[k.name] = v
  3534. elif hasattr(k, 'val'):
  3535. kwdefaults[k.val] = v
  3536. else:
  3537. kwdefaults[str(k)] = v
  3538. func_maker = code_map.get(code.name, DefStatement)
  3539. self.stack.push(
  3540. func_maker(code, defaults, kwdefaults, closure, paramobjs)
  3541. )
  3542.  
  3543. def MAKE_FUNCTION_NEW(self, addr, argc, is_closure=False):
  3544. testType = self.stack.pop().val
  3545. if isinstance(testType, str):
  3546. code = Code(self.stack.pop().val, self.code)
  3547. else:
  3548. code = Code(testType, self.code)
  3549. closure = self.stack.pop() if is_closure else None
  3550. annotations = {}
  3551. kwdefaults = {}
  3552. defaults = {}
  3553. if argc & 8:
  3554. annotations = list(self.stack.pop())
  3555. if argc & 4:
  3556. annotations = self.stack.pop()
  3557. if isinstance(annotations, PyDict):
  3558. annotations = {
  3559. str(k[0].val).replace('\'', ''): str(k[1])
  3560. for k in annotations.items
  3561. }
  3562. if argc & 2:
  3563. kwdefaults = self.stack.pop()
  3564. if isinstance(kwdefaults, PyDict):
  3565. kwdefaults = {
  3566. str(k[0].val): str(
  3567. k[1]
  3568. if isinstance(k[1], PyExpr)
  3569. else PyConst(k[1])
  3570. )
  3571. for k in kwdefaults.items
  3572. }
  3573. if not kwdefaults:
  3574. kwdefaults = {}
  3575. if argc & 1:
  3576. defaults = list(
  3577. map(
  3578. lambda x: str(
  3579. x if isinstance(x, PyExpr) else PyConst(x)
  3580. ),
  3581. self.stack.pop(),
  3582. )
  3583. )
  3584. func_maker = code_map.get(code.name, DefStatement)
  3585. self.stack.push(
  3586. func_maker(
  3587. code,
  3588. defaults,
  3589. kwdefaults,
  3590. closure,
  3591. annotations,
  3592. annotations,
  3593. )
  3594. )
  3595.  
  3596. def MAKE_FUNCTION(self, addr, argc, is_closure=False):
  3597. if sys.version_info < (3, 6):
  3598. self.MAKE_FUNCTION_OLD(addr, argc, is_closure)
  3599. else:
  3600. self.MAKE_FUNCTION_NEW(addr, argc, is_closure)
  3601.  
  3602. def LOAD_CLOSURE(self, addr, i):
  3603. # Push the varname. It doesn't matter as it is not used for now.
  3604. self.stack.push(self.code.derefnames[i])
  3605.  
  3606. def MAKE_CLOSURE(self, addr, argc):
  3607. self.MAKE_FUNCTION(addr, argc, is_closure=True)
  3608.  
  3609. #
  3610. # Raising exceptions
  3611. #
  3612.  
  3613. def RAISE_VARARGS(self, addr, argc):
  3614. # TODO: find out when argc is 2 or 3
  3615. # Answer: In Python 3, only 0, 1, or 2 argument (see PEP 3109)
  3616. if argc == 0:
  3617. self.write("raise")
  3618. elif argc == 1:
  3619. exception = self.stack.pop()
  3620. self.write("raise {}", exception)
  3621. elif argc == 2:
  3622. from_exc, exc = self.stack.pop(), self.stack.pop()
  3623. self.write("raise {} from {}".format(exc, from_exc))
  3624. else:
  3625. raise Unknown
  3626.  
  3627. def EXTENDED_ARG(self, addr, ext):
  3628. # self.write("# ERROR: {} : {}".format(addr, ext) )
  3629. pass
  3630.  
  3631. def WITH_CLEANUP(self, addr, *args, **kwargs):
  3632. # self.write("# ERROR: {} : {}".format(addr, args))
  3633. pass
  3634.  
  3635. def WITH_CLEANUP_START(self, addr, *args, **kwargs):
  3636. pass
  3637.  
  3638. def WITH_CLEANUP_FINISH(self, addr, *args, **kwargs):
  3639. jaddr = addr.jump()
  3640. return jaddr
  3641.  
  3642. # Formatted string literals
  3643. def FORMAT_VALUE(self, addr, flags):
  3644. formatter = ''
  3645. if flags == 1:
  3646. formatter = '!s'
  3647. elif flags == 2:
  3648. formatter = '!r'
  3649. elif flags == 3:
  3650. formatter = '!a'
  3651. elif flags == 4:
  3652. formatter = f':{self.stack.pop().val}'
  3653. val = self.stack.pop()
  3654. f = PyFormatValue(val)
  3655. f.formatter = formatter
  3656. self.stack.push(f)
  3657.  
  3658. def BUILD_STRING(self, addr, c):
  3659. params = self.stack.pop(c)
  3660. self.stack.push(PyFormatString(params))
  3661.  
  3662. # Coroutines
  3663. def GET_AWAITABLE(self, addr: Address):
  3664. func: AwaitableMixin = self.stack.pop()
  3665. func.is_awaited = True
  3666. self.stack.push(func)
  3667. yield_op = addr.seek_forward(YIELD_FROM)
  3668. return yield_op[1]
  3669.  
  3670. def BEFORE_ASYNC_WITH(self, addr: Address):
  3671. with_addr = addr.seek_forward(SETUP_ASYNC_WITH)
  3672. end_with = with_addr.jump()
  3673. with_stmt = WithStatement(self.stack.pop())
  3674. with_stmt.is_async = True
  3675. d_with = SuiteDecompiler(addr[1], end_with)
  3676. d_with.stack.push(with_stmt)
  3677. d_with.run()
  3678. with_stmt.suite = d_with.suite
  3679. self.suite.add_statement(with_stmt)
  3680. if sys.version_info <= (3, 4):
  3681. assert end_with.opcode is WITH_CLEANUP
  3682. assert end_with[1].opcode is END_FINALLY
  3683. return end_with[2]
  3684. else:
  3685. assert end_with.opcode is WITH_CLEANUP_START
  3686. assert end_with[1].opcode is GET_AWAITABLE
  3687. assert end_with[4].opcode is WITH_CLEANUP_FINISH
  3688. return end_with[5]
  3689.  
  3690. def SETUP_ASYNC_WITH(self, addr: Address, arg):
  3691. pass
  3692.  
  3693. def GET_AITER(self, addr: Address):
  3694. return addr[2]
  3695.  
  3696. def GET_ANEXT(self, addr: Address):
  3697. iterable = self.stack.pop()
  3698. for_stmt = ForStatement(iterable)
  3699. for_stmt.is_async = True
  3700. jump_addr = addr[-1].jump()
  3701. d_body = SuiteDecompiler(addr[3], jump_addr[-1])
  3702. d_body.stack.push(for_stmt)
  3703. d_body.run()
  3704. jump_addr = jump_addr[-1].jump()
  3705. new_start = jump_addr
  3706. new_end = jump_addr[-2].jump()[-1]
  3707. d_body.start_addr = new_start
  3708.  
  3709. d_body.end_addr = new_end
  3710.  
  3711. d_body.run()
  3712.  
  3713. for_stmt.body = d_body.suite
  3714. self.suite.add_statement(for_stmt)
  3715. new_end = new_end.seek_forward(POP_BLOCK)
  3716. return new_end
  3717.  
  3718.  
  3719. SuiteDecompiler.RESUME = SuiteDecompiler.__dict__["CONTINUE_LOOP"]
  3720. SuiteDecompiler.CALL_NO_KW = SuiteDecompiler.__dict__[
  3721. "CALL_FUNCTION_VAR"
  3722. ]
  3723.  
  3724.  
  3725. def make_dynamic_instr(cls):
  3726. def method(self, addr):
  3727. cls.instr(self.stack)
  3728.  
  3729. return method
  3730.  
  3731.  
  3732. # Create unary operators types and opcode handlers
  3733. for op, name, ptn, prec in unary_ops:
  3734. name = 'Py' + name
  3735. tp = type(name, (PyUnaryOp,), dict(pattern=ptn, precedence=prec))
  3736. globals()[name] = tp
  3737. setattr(SuiteDecompiler, op, make_dynamic_instr(tp))
  3738.  
  3739. # Create binary operators types and opcode handlers
  3740. for op, name, ptn, prec, inplace_ptn in binary_ops:
  3741. # Create the binary operator
  3742. tp_name = 'Py' + name
  3743. tp = globals().get(tp_name, None)
  3744. if tp is None:
  3745. tp = type(
  3746. tp_name, (PyBinaryOp,), dict(pattern=ptn, precedence=prec)
  3747. )
  3748. globals()[tp_name] = tp
  3749.  
  3750. setattr(SuiteDecompiler, 'BINARY_' + op, make_dynamic_instr(tp))
  3751. # Create the in-place operation
  3752. if inplace_ptn is not None:
  3753. inplace_op = "INPLACE_" + op
  3754. tp_name = 'InPlace' + name
  3755. tp = type(tp_name, (InPlaceOp,), dict(pattern=inplace_ptn))
  3756. globals()[tp_name] = tp
  3757. setattr(SuiteDecompiler, inplace_op, make_dynamic_instr(tp))
  3758.  
  3759. if __name__ == "__main__":
  3760. import sys
  3761.  
  3762. if len(sys.argv) < 2:
  3763. print(
  3764. 'USAGE: {} <filename.pyc> [START [END=-1]]'.format(
  3765. sys.argv[0]
  3766. )
  3767. )
  3768. sys.exit(1)
  3769.  
  3770. start = 0
  3771. end = -1
  3772. if len(sys.argv) > 2:
  3773. start = int(sys.argv[2])
  3774. if len(sys.argv) > 3:
  3775. end = int(sys.argv[3])
  3776. with open(sys.argv[1], "rb") as stream:
  3777. code_obj = read_code(stream)
  3778. code = Code(code_obj)
  3779. dc = SuiteDecompiler(
  3780. code.address(code.instr_list[start][0]),
  3781. code.address(code.instr_list[end][0]),
  3782. )
  3783. try:
  3784. dc.run()
  3785. except Exception as e:
  3786. print("Exception during dc.run():", e, file=sys.stderr)
  3787.  
  3788. s = IndentString()
  3789. dc.suite.display(s)
  3790.  
  3791. print("\x0a".join(s.lines))
  3792.  
Add Comment
Please, Sign In to add comment