/******************************************************************
 * Symtable.h
 * Definitions to handle symbol tables.
 ******************************************************************/
#ifndef __SYMTABLE
#define __SYMTABLE

/******************************************************************
 * INCLUDES
 ******************************************************************/
#include "atom.h"

/******************************************************************
 * CLASSES
 ******************************************************************/

uTask EVALUATE;
uMonitor SYMTABLE;
struct ATOM;
class SYMENTRY;

struct PARAM_LIST
{
    char       *name;
    int         hash;           // Reduces calls to hash...
    PARAM_LIST *next;
};

uMonitor SYMTABLE
{
private:
    int m_refcnt;               // Reference count
protected:
    SYMTABLE *m_parent;         // Next higher table, NULL if global.
    ATOM_MNGR *m_atommngr;	// Who manages our atoms?

    virtual ~SYMTABLE();
public:
    SYMTABLE(SYMTABLE *parent, ATOM_MNGR *atommngr);

    void addRef();
    void removeRef();

    virtual void AddEntry(SYMENTRY *entry) = 0;	// Steals entry
    virtual uNoMutex SYMENTRY *LookupEntry(char *name, int useGlobal=1,
                                    int hashval = -1) const = 0;
				    
    uNoMutex ATOM_MNGR *getAtomMngr() const { return m_atommngr; }

    virtual void print(uOStream &output) = 0;
};

uMonitor SYMTABLE_LIST : public SYMTABLE
{
    SYMENTRY *m_list;		// Single linked list of symbols

    virtual ~SYMTABLE_LIST();

public:
    SYMTABLE_LIST(SYMTABLE *parent, ATOM_MNGR *atommngr);

    virtual void AddEntry(SYMENTRY *entry);     // Steals entry!  Mutexed!
                                        // Update must be atomic!
    virtual uNoMutex SYMENTRY *LookupEntry(char *name, int useGlobal=1,
                                    int hashval = -1) const;

    virtual void print(uOStream &output);
};

uMonitor SYMTABLE_HASH : public SYMTABLE
{
    SYMENTRY *m_hash[256];      // Hash table

    virtual ~SYMTABLE_HASH();        // All deletes through ref counts.

    int      hash(char *name) const;    // Hashes name to 0..255
public:
    SYMTABLE_HASH(SYMTABLE *parent, ATOM_MNGR *atommngr);

    virtual void AddEntry(SYMENTRY *entry);     // Steals entry!  Mutexed!
                                        // Update must be atomic!
    virtual uNoMutex SYMENTRY *LookupEntry(char *name, int useGlobal=1,
                                    int hashval = -1) const;

    virtual void print(uOStream &output);
};

class SYMENTRY      // Entry in symbol table.
{
public:
    SYMENTRY()
    {
        name = NULL;
        hash = -1;
        param = NULL;
        body = NULL;
        next = NULL;
        type = INVALID;
	parent = NULL;
    }
    ~SYMENTRY()
    {
        PARAM_LIST *curp, *nextp;

        if (name)
            FreeMem(name);

        for (curp = param; curp; curp = nextp)
        {
            nextp = curp->next;
            FreeMem(curp->name);
            delete curp;
        }
        if (body)
            parent->getAtomMngr()->Destroy(body);
        delete next;
    }

    char     *name;
    int       hash;         // Hash value of name, -1 if not set
    PARAM_LIST *param;
    int       type;
    ATOM     *body;         // THIS MUST BE GLOBAL!!
    ATOM     *(*fnc)(ATOM *, SYMTABLE *, SYMTABLE *, EVALUATE *);
    SYMTABLE *parent;
    SYMENTRY *next;
};

#endif

