"""

Compiler Methods
----------------

When adding a new knode to the ktree there are several stages of
processing as we discover whatever we can.

"""

import types

import refine, typeset, codegen

def _copy_edge_list (parameters):

    """ Performs a deep copy of a list of edges; this is used to freeze the
    state of a list of parameters. """
    
    return map (lambda edge: edge.clone(), parameters)


def basic_KNode (self, comp, worklist):

    """ This routine is called by the compiler object when the
    knode is first created.  It allows the knode to add any work
    to the worklist that needs doing.  Most knodes do nothing with
    it, but some, like functions, use it to ensure that they are
    fully compiled. """
    
    return

def refine_KNode (self, comp, worklist):

    """ This routine is called by the compiler object during
    the refinement phase.  """

    for edge in self.get_children (): edge.node.refine (comp, worklist)
    return

def basic_FunctionKNode (self, comp, worklist):

    """ Called by the compiler when this node is first created.
    First, finds any sub-functions defined and adds them to the
    worklist.  Then, prepares an initial build based on no
    assumptions for the types of the parameters. """

    # Find all code objects that the function might reference and
    # create knodes for them.
    for const in self.codeobject.co_consts:
        if type (const) is types.CodeType:
            knode = FunctionKNode (self, const)
            self.subfunctions.append ( (const, knode) )
            worklist += lambda: knode.basic (comp, worklist)
            pass
        pass

    # Add to the worklist the production of a version with no
    # assumptions about parameters...
    plainparams = _copy_edge_list (self.parameters)
    worklist += lambda: self.build (comp, plainparams)

    # If this function is defined within a class, then we also want to
    # add versions of the methods that assume that the type of the
    # first parameter is a linear subtype of the class ptr.
    if self.parent.is_class() and len (self.parameters) >= 1:
        # Don't compile the linear sub-type until we actually *see* a
        # subtype!!
        #lscparams = _copy_edge_list (self.parameters)
        #lscparams[0].node = comp.knodes.InstanceKNode (self)
        #lscparams[0].node.get_types().add_hint (typeset.LINEARSUBCLASS,
        #                                        self.parent)
        #worklist += lambda: self.build (comp, lscparams)

        eparams = _copy_edge_list (self.parameters)
        eparams[0].node = comp.knodes.InstanceKNode (self)
        eparams[0].node.get_types().add_hint (typeset.EXACT,
                                              self.parent)
        worklist += lambda: self.build (comp, eparams)
        pass

    return

def refine_FunctionKNode (self, comp, worklist):
    
    """ This routine is called by the compiler object during
    the refinement phase.  For now, it simply calls the
    refinement routines. """

    for jit in self.jittedversions: refine.refine_ir (comp, self, jit)

    for func in self.subfunctions: func.refine (comp, worklist)
    refine_KNode (self, comp, worklist)
    return

def codegen_KNode (self, comp, md, modobj):

    """ This routine is called by the compiler object during
    the codegen phase.  """

    for edge in self.get_children (): edge.node.codegen (comp, md, modobj)
    return

def codegen_FunctionKNode (self, comp, md, modobj):

    for jittedversion in self.jittedversions:
        codegen.generate_jitted (comp, modobj, md, self, jittedversion)
        pass
    pass
