# Path: pykit/error.py
# class CompileError(Exception):
# class PositioningError(CompileError):
# class IRError(CompileError):
# 
# Path: pykit/types.py
# class Type(object):
# class Typedef(typetuple('Typedef',  ['name', 'type'])):
#     def __init__(self, *values, **kwds):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __nonzero__(self):
#     def __hash__(self):
# def typetuple(name, elems):
#     def __init__(self, name, ty):
# def parse_type(s):
# def typeof(value):
# def convert(value, dst_type):
# def resolve_typedef(type):
# 
# Path: pykit/ir/ops.py
# def op(name, *args):
# def oplist(pattern):
# 
# Path: pykit/ir/pretty.py
# def pretty(value):
#     formatter = formatters[type(value).__name__]
#     return formatter(value)
# 
# Path: pykit/utils/traits.py
# def traits(cls):
#     "@traits class decorator"
#     for name, py_func in vars(cls).items():
#         if isinstance(py_func, TraitBase):
#             py_func.set_attr_name(name)
# 
#     return cls
# 
# class Delegate(TraitBase):
#     """
#     Delegate to some other object.
#     """
# 
#     def __init__(self, value, delegate_attr_name=None, doc=None):
#         super(Delegate, self).__init__(value, doc=doc)
#         self.delegate_attr_name = delegate_attr_name
# 
#     def obj(self, instance):
#         return getattr(instance, self.value)
# 
#     @property
#     def attr(self):
#         return self.delegate_attr_name or self.attr_name
# 
#     def __get__(self, instance, owner):
#         return getattr(self.obj(instance), self.attr)
# 
#     def __set__(self, instance, value):
#         return setattr(self.obj(instance), self.attr, value)
# 
#     def __delete__(self, instance):
#         delattr(self.obj(instance), self.attr)
# 
# Path: pykit/utils/pattern.py
# class match(object):
#     '''Dispatch a function by pattern matching.
#     Start with the most generic case; Add more specialized cases afterwards.
#     Pattern value of type `type` is matched using the builtin `isinstance`.
#     Pattern value of type `Matcher` is used directly.
#     Pattern value of other types is matched using `==`.
#     '''
#     def __init__(self, func):
#         self._generic = func
#         self._cases = []
#         self._argspec = inspect.getargspec(func)
# 
#         assert not self._argspec.varargs, 'Thou shall not use *args'
#         assert not self._argspec.keywords, 'Thou shall not use **kws'
# 
#     def case(self, *patargs, **patkws):
#         def wrap(fn):
#             argspec = inspect.getargspec(fn)
#             assert len(argspec.args) == len(self._argspec.args), "mismatch signature"
#             for pat, arg in zip(patargs, argspec.args):
#                 assert arg not in patkws
#                 patkws[arg] = pat
#             case = Case(_prepare_pattern(patkws.items()), fn, argspec)
#             self._cases.append(case)
#             return self
#         return wrap
# 
#     def __get__(self, inst, type=None):
#         return partial(self, inst)
# 
#     def __call__(self, *args, **kwds):
#         for case in reversed(self._cases):
#             kws = dict(kwds)
#             _pack_args(case.argspec, args, kws)
#             for k, matcher in case.pattern:
#                 if not matcher(kws[k]):
#                     break
#             else:
#                 return case.function(*args, **kwds)
#         else:
#             return self._generic(*args, **kwds)
# 
# Path: pykit/utils/convenience.py
# def nestedmap(f, args):
#     """
#     Map `f` over `args`, which contains elements or nested lists
#     """
#     result = []
#     for arg in args:
#         if isinstance(arg, list):
#             result.append(list(map(f, arg)))
#         else:
#             result.append(f(arg))
# 
#     return result
# 
# def flatten(args):
#     """Flatten nested lists (return as iterator)"""
#     for arg in args:
#         if isinstance(arg, list):
#             for x in arg:
#                 yield x
#         else:
#             yield arg
# 
# def listify(f):
#     """Decorator to turn generator results into lists"""
#     @functools.wraps(f)
#     def wrapper(*args, **kwargs):
#         return list(f(*args, **kwargs))
#     return wrapper
# 
# def make_temper():
#     """Return a function that returns temporary names"""
#     temps = collections.defaultdict(int)
# 
#     def temper(name=""):
#         varname = name.rstrip(string.digits)
#         count = temps[varname]
#         temps[varname] += 1
#         if varname and count == 0:
#             return varname
#         return varname + str(count)
# 
#     return temper


from itertools import chain
from collections import defaultdict
from pykit import error, types
from pykit.adt import LinkedList
from pykit.ir import ops
from pykit.ir.pretty import pretty
from pykit.utils import (flatten, nestedmap, match, Delegate, traits, listify,
                         make_temper)
        from pykit.analysis import defuse
        """Insert self before op"""
        assert self.parent is None, op
        self.parent = op.parent
        self.parent.ops.insert_before(self, op)
        self.function.add_op(self)

    def insert_after(self, op):
        """Insert self after op"""
        assert self.parent is None, self
        self.parent = op.parent
        self.parent.ops.insert_after(self, op)
        self.function.add_op(self)

    # ______________________________________________________________________
    # Replace

    def replace_op(self, opcode, args, type=None):
        """Replace this operation's opcode, args and optionally type"""
        # Replace ourselves inplace
        self.opcode = opcode
        self.set_args(args)
        if type is not None:
            self.type = type

    def replace_args(self, replacements):
        """
        Replace arguments listed in the `replacements` dict. The replacement
        instructions must dominate this instruction.
        """
        if replacements:

# Path: pykit/error.py
# class CompileError(Exception):
# class PositioningError(CompileError):
# class IRError(CompileError):
# 
# Path: pykit/types.py
# class Type(object):
# class Typedef(typetuple('Typedef',  ['name', 'type'])):
#     def __init__(self, *values, **kwds):
#     def __eq__(self, other):
#     def __ne__(self, other):
#     def __nonzero__(self):
#     def __hash__(self):
# def typetuple(name, elems):
#     def __init__(self, name, ty):
# def parse_type(s):
# def typeof(value):
# def convert(value, dst_type):
# def resolve_typedef(type):
# 
# Path: pykit/ir/ops.py
# def op(name, *args):
# def oplist(pattern):
# 
# Path: pykit/ir/pretty.py
# def pretty(value):
#     formatter = formatters[type(value).__name__]
#     return formatter(value)
# 
# Path: pykit/utils/traits.py
# def traits(cls):
#     "@traits class decorator"
#     for name, py_func in vars(cls).items():
#         if isinstance(py_func, TraitBase):
#             py_func.set_attr_name(name)
# 
#     return cls
# 
# class Delegate(TraitBase):
#     """
#     Delegate to some other object.
#     """
# 
#     def __init__(self, value, delegate_attr_name=None, doc=None):
#         super(Delegate, self).__init__(value, doc=doc)
#         self.delegate_attr_name = delegate_attr_name
# 
#     def obj(self, instance):
#         return getattr(instance, self.value)
# 
#     @property
#     def attr(self):
#         return self.delegate_attr_name or self.attr_name
# 
#     def __get__(self, instance, owner):
#         return getattr(self.obj(instance), self.attr)
# 
#     def __set__(self, instance, value):
#         return setattr(self.obj(instance), self.attr, value)
# 
#     def __delete__(self, instance):
#         delattr(self.obj(instance), self.attr)
# 
# Path: pykit/utils/pattern.py
# class match(object):
#     '''Dispatch a function by pattern matching.
#     Start with the most generic case; Add more specialized cases afterwards.
#     Pattern value of type `type` is matched using the builtin `isinstance`.
#     Pattern value of type `Matcher` is used directly.
#     Pattern value of other types is matched using `==`.
#     '''
#     def __init__(self, func):
#         self._generic = func
#         self._cases = []
#         self._argspec = inspect.getargspec(func)
# 
#         assert not self._argspec.varargs, 'Thou shall not use *args'
#         assert not self._argspec.keywords, 'Thou shall not use **kws'
# 
#     def case(self, *patargs, **patkws):
#         def wrap(fn):
#             argspec = inspect.getargspec(fn)
#             assert len(argspec.args) == len(self._argspec.args), "mismatch signature"
#             for pat, arg in zip(patargs, argspec.args):
#                 assert arg not in patkws
#                 patkws[arg] = pat
#             case = Case(_prepare_pattern(patkws.items()), fn, argspec)
#             self._cases.append(case)
#             return self
#         return wrap
# 
#     def __get__(self, inst, type=None):
#         return partial(self, inst)
# 
#     def __call__(self, *args, **kwds):
#         for case in reversed(self._cases):
#             kws = dict(kwds)
#             _pack_args(case.argspec, args, kws)
#             for k, matcher in case.pattern:
#                 if not matcher(kws[k]):
#                     break
#             else:
#                 return case.function(*args, **kwds)
#         else:
#             return self._generic(*args, **kwds)
# 
# Path: pykit/utils/convenience.py
# def nestedmap(f, args):
#     """
#     Map `f` over `args`, which contains elements or nested lists
#     """
#     result = []
#     for arg in args:
#         if isinstance(arg, list):
#             result.append(list(map(f, arg)))
#         else:
#             result.append(f(arg))
# 
#     return result
# 
# def flatten(args):
#     """Flatten nested lists (return as iterator)"""
#     for arg in args:
#         if isinstance(arg, list):
#             for x in arg:
#                 yield x
#         else:
#             yield arg
# 
# def listify(f):
#     """Decorator to turn generator results into lists"""
#     @functools.wraps(f)
#     def wrapper(*args, **kwargs):
#         return list(f(*args, **kwargs))
#     return wrapper
# 
# def make_temper():
#     """Return a function that returns temporary names"""
#     temps = collections.defaultdict(int)
# 
#     def temper(name=""):
#         varname = name.rstrip(string.digits)
#         count = temps[varname]
#         temps[varname] += 1
#         if varname and count == 0:
#             return varname
#         return varname + str(count)
# 
#     return temper


# Path: pykit/ir/value.py
from itertools import chain
from collections import defaultdict
from pykit import error, types
from pykit.adt import LinkedList
from pykit.ir import ops
from pykit.ir.pretty import pretty
from pykit.utils import (flatten, nestedmap, match, Delegate, traits, listify,
                         make_temper)
        from pykit.analysis import defuse

        """Insert self before op"""
        assert self.parent is None, op
        self.parent = op.parent
        self.parent.ops.insert_before(self, op)
        self.function.add_op(self)

    def insert_after(self, op):
        """Insert self after op"""
        assert self.parent is None, self
        self.parent = op.parent
        self.parent.ops.insert_after(self, op)
        self.function.add_op(self)

    # ______________________________________________________________________
    # Replace

    def replace_op(self, opcode, args, type=None):
        """Replace this operation's opcode, args and optionally type"""
        # Replace ourselves inplace
        self.opcode = opcode
        self.set_args(args)
        if type is not None:
            self.type = type

    def replace_args(self, replacements):
        """
        Replace arguments listed in the `replacements` dict. The replacement
        instructions must dominate this instruction.
        """
        if replacements:

            newargs = nestedmap(lambda arg: replacements.get(arg, arg), self.args)