#include <cassert>

#include "StackTable.h"

namespace SymTab {
    template< typename Element, typename ConflictFunction >
    StackTable< Element, ConflictFunction >::StackTable() : scopeLevel( 0 )
    {}

    template< typename Element, typename ConflictFunction >
    void StackTable< Element, ConflictFunction >::enterScope() {
	scopeLevel++;
    }

    template< typename Element, typename ConflictFunction >
    void StackTable< Element, ConflictFunction >::leaveScope() {
	for ( typename TableType::iterator it = table.begin(); it != table.end(); ++it ) {
	    std::stack< Entry >& entry = it->second;
	    if ( !entry.empty() && entry.top().second == scopeLevel ) {
		entry.pop();
	    }
	}
	scopeLevel--;
	assert( scopeLevel >= 0 );
    }

    template< typename Element, typename ConflictFunction >
    void StackTable< Element, ConflictFunction >::add( Element *type ) {
	std::stack< Entry >& entry = table[ type->get_name() ];
	if ( !entry.empty() && entry.top().second == scopeLevel ) {
	    entry.top().first = conflictFunction( entry.top().first, type );
	} else {
	    entry.push( Entry( type, scopeLevel ) );
	}
    }

    template< typename Element, typename ConflictFunction >
    void StackTable< Element, ConflictFunction >::add( std::string fwdDeclName ) {
	add( new Element( fwdDeclName ) );
    }

    template< typename Element, typename ConflictFunction >
    Element *StackTable< Element, ConflictFunction >::lookup( std::string id ) const {
	typename TableType::const_iterator it = table.find( id );
	if ( it == table.end() ) {
	    return 0;
	} else if ( !it->second.empty() ) {
	    return it->second.top().first;
	} else {
	    return 0;
	}
    }

    template< typename Element, typename ConflictFunction >
    void StackTable< Element, ConflictFunction >::dump( std::ostream &os ) const {
	for ( typename TableType::const_iterator it = table.begin(); it != table.end(); ++it ) {
	    const std::stack< Entry >& entry = it->second;
	    if ( !entry.empty() && entry.top().second == scopeLevel ) {
		os << it->first << std::endl;
	    }
	}
    }
} // SymTab
