<reponame>justinnoah/typhon
import py

from rpython.rlib.unroll import unrolling_iterable

def freezeField(field, ty):
    if ty and ty.endswith("*"):
        # List.
        return field + "[*]"
    return field

def increment(x=[0]):
    x[0] += 1
    return x[0]

def makeIR(name, terminals, nonterms):
    irAttrs = {
        "_immutable_": True,
        "_immutable_fields_": ("terminals[*]", "nonterms"),
        "terminals": terminals,
        "nonterms": nonterms,
    }

    # The parent class of all nonterminals. Important for manipulating
    # ASTs in RPython.
    class NonTerminal(object):
        _immutable_ = True
    # Please do *not* access this class outside of this implementation; it
    # won't end well. ~ C.
    irAttrs["_NonTerminal"] = NonTerminal

    for nonterm, constructors in nonterms.iteritems():
        # Construct a superclass which every constructor will inherit
        # from.
        class NT(NonTerminal):
            _immutable_ = True
        NT.__name__ = nonterm + str(increment())
        irAttrs[nonterm] = NT

        def build(constructor, pieces):
            ipieces = unrolling_iterable(enumerate(pieces))
            class Constructor(NT):
                _immutable_ = True
                _immutable_fields_ = [freezeField(field, ty)
                                      for field, ty in pieces]

                def __init__(self, *args):
                    for i, (piece, _) in ipieces:
                        setattr(self, piece, args[i])

            Constructor.__name__ = constructor + str(increment())
            irAttrs[constructor] = Constructor

        for constructor, pieces in constructors.iteritems():
            build(constructor, pieces)

    def makePassTo(self, ir):
        """
        Construct a class for a visitor-pattern pass between this IR and the
        next IR.
        """

        attrs = { "src": self, "dest": ir }
        for terminal in self.terminals:
            def visitor(self, x):
                return x
            name = "visit" + terminal
            visitor.__name__ = name
            attrs[name] = visitor

        for nonterm, constructors in self.nonterms.iteritems():
            conClasses = []
            for constructor, pieces in constructors.iteritems():
                visitName = "visit%s" % constructor
                # Recurse on non-terminals by type. Untyped elements are
                # assumed to not be recursive.
                mods = []
                for piece, ty in pieces:
                    if ty:
                        if ty.endswith('*'):
                            # List of elements.
                            ty = ty[:-1]
                            s = "%s = [self.visit%s(x) for x in %s]" % (piece,
                                    ty, piece)
                        else:
                            s = "%s = self.visit%s(%s)" % (piece, ty, piece)
                        mods.append(s)
                params = {
                    "args": ",".join(p[0] for p in pieces),
                    "name": visitName,
                    "constructor": constructor,
                    "mods": ";".join(mods)
                }
                if ir is None:
                    # This pass extracts some sort of summary but does not
                    # create more IR. Force the caller to override every
                    # non-terminal.
                    def mustImplement(self, *args):
                        "NOT_RPYTHON"
                        import pdb; pdb.set_trace()
                        raise NotImplementedError("rutabaga")
                    attrs[visitName] = mustImplement
                else:
                    d = {}
                    exec py.code.Source("""
                        def %(name)s(self, %(args)s):
                            %(mods)s
                            return self.dest.%(constructor)s(%(args)s)
                    """ % params).compile() in d
                    attrs[visitName] = d[visitName]
                    attrs[visitName].__name__ += str(increment())
                specimenPieces = ",".join("specimen.%s" % p[0] for p in pieces)
                callVisit = "self.%s(%s)" % (visitName, specimenPieces)
                conClasses.append((constructor, callVisit))
            # Construct subordinate clauses for the visitor on this
            # non-terminal.
            d = {}
            clauses = []
            for constructor, callVisit in conClasses:
                clauses.append("if isinstance(specimen, self.src.%s): return %s" %
                        (constructor, callVisit))
            params = {
                "name": nonterm,
                "clauses": "\n    ".join(clauses),
            }
            exec py.code.Source("""
def visit%(name)s(self, specimen):
    assert isinstance(specimen, self.src._NonTerminal), "cabbage"
    %(clauses)s
    assert False, "radish"
            """ % params).compile() in d
            attrs.update(d)

        Pass = type("Pass", (object,), attrs)
        # This isn't really a knot so much as a quick and easy way to access
        # the original implementations of the pass's methods. ~ C.
        Pass.super = Pass
        return Pass
    irAttrs["makePassTo"] = makePassTo

    def extend(self, name, terminals, nonterms):
        ts = self.terminals[:]
        for t in terminals:
            if t.startswith("-"):
                # Removal.
                t = t[1:]
                # I wanted to put an assert here, but list.remove() raises
                # ValueError already, so it's not a problem. ~ C.
                ts.remove(t)
            else:
                # Addition.
                ts.append(t)
        # Dammit Python.
        nts = self.nonterms.copy()
        for nt, constructors in nonterms.iteritems():
            # Recurse into every constructor, if we already have the
            # non-terminal. Otherwise, just copy the new thing wholesale.
            if nt in nts:
                # Dammit Python!
                nts[nt] = nts[nt].copy()
                for constructor, pieces in constructors.iteritems():
                    if constructor.startswith("-"):
                        # Removal.
                        constructor = constructor[1:]
                        # As before, raise if not found.
                        del nts[nt][constructor]
                    else:
                        # Addition to a possibly-already-extant constructor.
                        # We'll overwrite the old constructor with the new.
                        nts[nt][constructor] = pieces
            else:
                nts[nt] = constructors
        return makeIR(name, ts, nts)
    irAttrs["extend"] = extend


    def selfPass(self):
        return self.makePassTo(self)
    irAttrs["selfPass"] = selfPass

    return type(name + "IR", (object,), irAttrs)()

import py

from rpython.rlib.unroll import unrolling_iterable

def freezeField(field, ty):
    if ty and ty.endswith("*"):
        # List.
        return field + "[*]"
    return field

def increment(x=[0]):
    x[0] += 1
    return x[0]

def makeIR(name, terminals, nonterms):
    irAttrs = {
        "_immutable_": True,
        "_immutable_fields_": ("terminals[*]", "nonterms"),
        "terminals": terminals,
        "nonterms": nonterms,
    }

    # The parent class of all nonterminals. Important for manipulating
    # ASTs in RPython.
    class NonTerminal(object):
        _immutable_ = True
    # Please do *not* access this class outside of this implementation; it
    # won't end well. ~ C.
    irAttrs["_NonTerminal"] = NonTerminal

    for nonterm, constructors in nonterms.iteritems():
        # Construct a superclass which every constructor will inherit
        # from.
        class NT(NonTerminal):
            _immutable_ = True
        NT.__name__ = nonterm + str(increment())
        irAttrs[nonterm] = NT

        def build(constructor, pieces):
            ipieces = unrolling_iterable(enumerate(pieces))
            class Constructor(NT):
                _immutable_ = True
                _immutable_fields_ = [freezeField(field, ty)
                                      for field, ty in pieces]

                def __init__(self, *args):
                    for i, (piece, _) in ipieces:
                        setattr(self, piece, args[i])

            Constructor.__name__ = constructor + str(increment())
            irAttrs[constructor] = Constructor

        for constructor, pieces in constructors.iteritems():
            build(constructor, pieces)

    def makePassTo(self, ir):
        """
        Construct a class for a visitor-pattern pass between this IR and the
        next IR.
        """

        attrs = { "src": self, "dest": ir }
        for terminal in self.terminals:
            def visitor(self, x):
                return x
            name = "visit" + terminal
            visitor.__name__ = name
            attrs[name] = visitor

        for nonterm, constructors in self.nonterms.iteritems():
            conClasses = []
            for constructor, pieces in constructors.iteritems():
                visitName = "visit%s" % constructor
                # Recurse on non-terminals by type. Untyped elements are
                # assumed to not be recursive.
                mods = []
                for piece, ty in pieces:
                    if ty:
                        if ty.endswith('*'):
                            # List of elements.
                            ty = ty[:-1]
                            s = "%s = [self.visit%s(x) for x in %s]" % (piece,
                                    ty, piece)
                        else:
                            s = "%s = self.visit%s(%s)" % (piece, ty, piece)
                        mods.append(s)
                params = {
                    "args": ",".join(p[0] for p in pieces),
                    "name": visitName,
                    "constructor": constructor,
                    "mods": ";".join(mods)
                }
                if ir is None:
                    # This pass extracts some sort of summary but does not
                    # create more IR. Force the caller to override every
                    # non-terminal.
                    def mustImplement(self, *args):
                        "NOT_RPYTHON"
                        import pdb; pdb.set_trace()
                        raise NotImplementedError("rutabaga")
                    attrs[visitName] = mustImplement
                else:
                    d = {}
                    exec py.code.Source("""
                        def %(name)s(self, %(args)s):
                            %(mods)s
                            return self.dest.%(constructor)s(%(args)s)
                    """ % params).compile() in d
                    attrs[visitName] = d[visitName]
                    attrs[visitName].__name__ += str(increment())
                specimenPieces = ",".join("specimen.%s" % p[0] for p in pieces)
                callVisit = "self.%s(%s)" % (visitName, specimenPieces)
                conClasses.append((constructor, callVisit))
            # Construct subordinate clauses for the visitor on this
            # non-terminal.
            d = {}
            clauses = []
            for constructor, callVisit in conClasses:
                clauses.append("if isinstance(specimen, self.src.%s): return %s" %
                        (constructor, callVisit))
            params = {
                "name": nonterm,
                "clauses": "\n    ".join(clauses),
            }
            exec py.code.Source("""
def visit%(name)s(self, specimen):
    assert isinstance(specimen, self.src._NonTerminal), "cabbage"
    %(clauses)s
    assert False, "radish"
            """ % params).compile() in d
            attrs.update(d)

        Pass = type("Pass", (object,), attrs)
        # This isn't really a knot so much as a quick and easy way to access
        # the original implementations of the pass's methods. ~ C.
        Pass.super = Pass
        return Pass
    irAttrs["makePassTo"] = makePassTo

    def extend(self, name, terminals, nonterms):
        ts = self.terminals[:]
        for t in terminals:
            if t.startswith("-"):
                # Removal.
                t = t[1:]
                # I wanted to put an assert here, but list.remove() raises
                # ValueError already, so it's not a problem. ~ C.
                ts.remove(t)
            else:
                # Addition.
                ts.append(t)
        # Dammit Python.
        nts = self.nonterms.copy()
        for nt, constructors in nonterms.iteritems():
            # Recurse into every constructor, if we already have the
            # non-terminal. Otherwise, just copy the new thing wholesale.
            if nt in nts:
                # Dammit Python!
                nts[nt] = nts[nt].copy()
                for constructor, pieces in constructors.iteritems():
                    if constructor.startswith("-"):
                        # Removal.
                        constructor = constructor[1:]
                        # As before, raise if not found.
                        del nts[nt][constructor]
                    else:
                        # Addition to a possibly-already-extant constructor.
                        # We'll overwrite the old constructor with the new.
                        nts[nt][constructor] = pieces
            else:
                nts[nt] = constructors
        return makeIR(name, ts, nts)
    irAttrs["extend"] = extend


    def selfPass(self):
        return self.makePassTo(self)
    irAttrs["selfPass"] = selfPass

    return type(name + "IR", (object,), irAttrs)()
# List. # The parent class of all nonterminals. Important for manipulating # ASTs in RPython. # Please do *not* access this class outside of this implementation; it # won't end well. ~ C. # Construct a superclass which every constructor will inherit # from. Construct a class for a visitor-pattern pass between this IR and the         next IR. # Recurse on non-terminals by type. Untyped elements are # assumed to not be recursive. # List of elements. # This pass extracts some sort of summary but does not # create more IR. Force the caller to override every # non-terminal. def %(name)s(self, %(args)s):                             %(mods)s                             return self.dest.%(constructor)s(%(args)s) # Construct subordinate clauses for the visitor on this # non-terminal. def visit%(name)s(self, specimen):     assert isinstance(specimen, self.src._NonTerminal), "cabbage"     %(clauses)s     assert False, "radish" # This isn't really a knot so much as a quick and easy way to access # the original implementations of the pass's methods. ~ C. # Removal. # I wanted to put an assert here, but list.remove() raises # ValueError already, so it's not a problem. ~ C. # Addition. # Dammit Python. # Recurse into every constructor, if we already have the # non-terminal. Otherwise, just copy the new thing wholesale. # Dammit Python! # Removal. # As before, raise if not found. # Addition to a possibly-already-extant constructor. # We'll overwrite the old constructor with the new.