def reaching_definitions():
    crud.delete('ins')
    crud.delete('outs')
    crud.delete('kills')

    # Kills is just the starting gens table:
    crud.Db_cur.execute("""
        insert into kills (block_id, symbol_id)
        select distinct block_id, symbol_id from gens
    """)

    # Add gens for global variables in fn calls to calling blocks:
    #
    # E.g. if block B calls FOO, add all gens of global variables inside FOO to
    #      the gens of B.
    #
    # These aren't included in kills, because there may be paths in FOO that
    # don't kill a variable set along another path.
    #
    # FIX: This should exclude declarations in FOO that are killed by later
    #      code in B.
    crud.Db_cur.execute("""
        insert into gens (block_id, symbol_id, triple_id)
        select t.block_id, g.symbol_id, g.triple_id
          from triple t
               inner join block b on t.int_1 = b.word_symbol_id
               inner join gens g on g.block_id = b.id
               inner join symbol_table st
                 on g.symbol_id = st.id and st.context is null
         where t.operator = 'call_direct'
    """)

    # Starting outs simply taken from gens:
    crud.Db_cur.execute("""insert into outs (block_id, symbol_id, triple_id)
                           select block_id, symbol_id, triple_id
                             from gens
    """)

    # Iterate as long as changes are made:
    for depth in itertools.count(0):
        crud.Db_cur.execute("""
          insert or ignore into ins (block_id, symbol_id, triple_id)
          select bs.successor, outs.symbol_id, outs.triple_id
            from outs inner join block_successors bs
              on outs.block_id = bs.predecessor
        """)
        if not crud.Db_cur.rowcount:
            print "reaching_definitions: did", 2 * depth + 1, "database calls"
            break
        crud.Db_cur.execute("""
          insert or ignore into outs (block_id, symbol_id, triple_id)
          select block_id, symbol_id, triple_id
            from ins
           where symbol_id not in (select symbol_id from kills
                                    where kills.block_id = ins.block_id)
        """)
        if not crud.Db_cur.rowcount:
            print "reaching_definitions: did", 2 * depth + 2, "database calls"
            break
def delete_word_by_id(id):
    r'''Delete all ast nodes associated with word_symbol_id 'id'.
    '''
    crud.delete('ast', word_symbol_id=id)
def delete(symbol):
    r'''Deletes all of the blocks associated with 'symbol' from the database.

    This also deletes all associated information in the database for the
    deleted blocks.

    This is used to delete the results from a prior compile run.
    '''
    block_ids = crud.read_column('blocks', 'id', word_symbol_id=symbol)
    if block_ids:
        crud.delete('gens', block_id=block_ids)
        crud.delete('kills', block_id=block_ids)
        crud.delete('ins', block_id=block_ids)
        crud.delete('outs', block_id=block_ids)
        triple.delete(block_ids)
        crud.delete('block_successors', predecessor=block_ids)
        crud.delete('block_successors', successor=block_ids)
        crud.delete('blocks', id=block_ids)