from pypy.translator.backendopt import graphanalyze
from pypy.rpython.ootypesystem import ootype

top_set = object()
empty_set = frozenset()

class WriteAnalyzer(graphanalyze.GraphAnalyzer):

    @staticmethod
    def join_two_results(result1, result2):
        if result1 is top_set:
            return top_set
        if result2 is top_set:
            return top_set
        return result1.union(result2)

    @staticmethod
    def bottom_result():
        return empty_set

    @staticmethod
    def top_result():
        return top_set

    @staticmethod
    def is_top_result(result):
        return result is top_set

    def analyze_simple_operation(self, op):
        if op.opname in ("setfield", "oosetfield"):
            return frozenset([
                ("struct", op.args[0].concretetype, op.args[1].value)])
        elif op.opname == "setarrayitem":
            return self._array_result(op.args[0].concretetype)
        return empty_set

    def _array_result(self, TYPE):
        return frozenset([("array", TYPE)])

    def analyze_external_method(self, op, TYPE, meth):
        if isinstance(TYPE, ootype.Array):
            methname = op.args[0].value
            if methname == 'll_setitem_fast':
                return self._array_result(op.args[1].concretetype)
            elif methname in ('ll_getitem_fast', 'll_length'):
                return self.bottom_result()
        return graphanalyze.GraphAnalyzer.analyze_external_method(self, op, TYPE, meth)


class ReadWriteAnalyzer(WriteAnalyzer):

    def analyze_simple_operation(self, op):
        if op.opname == "getfield":
            return frozenset([
                ("readstruct", op.args[0].concretetype, op.args[1].value)])
        elif op.opname == "getarrayitem":
            return frozenset([
                ("readarray", op.args[0].concretetype)])
        return WriteAnalyzer.analyze_simple_operation(self, op)

