# Copyright (c) 2016-2018 by Rocky Bernstein # Copyright (c) 2000-2002 by hartmut Goebel # Copyright (c) 1999 John Aycock # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . import re, sys from uncompyle6 import PYTHON3 if PYTHON3: intern = sys.intern class Token(): """ Class representing a byte-code instruction. A byte-code token is equivalent to Python 3's dis.instruction or the contents of one line as output by dis.dis(). """ # FIXME: match Python 3.4's terms: # linestart = starts_line # attr = argval # pattr = argrepr def __init__(self, opname, attr=None, pattr=None, offset=-1, linestart=None, op=None, has_arg=None, opc=None): self.kind = intern(opname) self.has_arg = has_arg self.attr = attr self.pattr = pattr self.offset = offset self.linestart = linestart if has_arg is False: self.attr = None self.pattr = None if opc is None: from xdis.std import _std_api self.opc = _std_api.opc else: self.opc = opc if op is None: self.op = self.opc.opmap.get(self.kind, None) else: self.op = op def __eq__(self, o): """ '==' on kind and "pattr" attributes. It is okay if offsets and linestarts are different""" if isinstance(o, Token): return (self.kind == o.kind) and (self.pattr == o.pattr) else: # ?? do we need this? return self.kind == o def __ne__(self, o): """ '!=', but it's okay if offsets and linestarts are different""" return not self.__eq__(o) def __repr__(self): return str(self.kind) # def __str__(self): # pattr = self.pattr if self.pattr is not None else '' # prefix = '\n%3d ' % self.linestart if self.linestart else (' ' * 6) # return (prefix + # ('%9s %-18s %r' % (self.offset, self.kind, pattr))) def __str__(self): return self.format(line_prefix='') def format(self, line_prefix=''): prefix = ('\n%s%4d ' % (line_prefix, self.linestart) if self.linestart else (' ' * (6 + len(line_prefix)))) offset_opname = '%6s %-17s' % (self.offset, self.kind) if not self.has_arg: return "%s%s" % (prefix, offset_opname) argstr = "%6d " % self.attr if isinstance(self.attr, int) else (' '*7) if self.has_arg: pattr = self.pattr if self.opc: if self.op in self.opc.JREL_OPS: if not self.pattr.startswith('to '): pattr = "to " + self.pattr elif self.op in self.opc.JABS_OPS: self.pattr= str(self.pattr) if not self.pattr.startswith('to '): pattr = "to " + str(self.pattr) pass elif self.op in self.opc.CONST_OPS: # Compare with pysource n_LOAD_CONST attr = self.attr if attr is None: pattr = None elif self.op in self.opc.hascompare: if isinstance(self.attr, int): pattr = self.opc.cmp_op[self.attr] # And so on. See xdis/bytecode.py get_instructions_bytes pass elif re.search('_\d+$', self.kind): return "%s%s%s" % (prefix, offset_opname, argstr) else: pattr = '' return "%s%s%s %r" % (prefix, offset_opname, argstr, pattr) def __hash__(self): return hash(self.kind) def __getitem__(self, i): raise IndexError NoneToken = Token('LOAD_CONST', offset=-1, attr=None, pattr=None)