#ifndef __SYMBOL_H__
#define __SYMBOL_H__

#include "Common.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Symbol
//-----------------------------------------------------------------------------
class Symbol {
public:
	typedef unsigned int UniqNumber;
	struct KeyCompare_UniqNumber {
		inline bool operator()(const Symbol *pSymbol1, const Symbol *pSymbol2) const {
			return pSymbol1->GetUniqNum() < pSymbol2->GetUniqNum();
		}
	};
	struct KeyCompare_Name {
		inline bool operator()(const Symbol *pSymbol1, const Symbol *pSymbol2) const {
			return ::_tcscmp(pSymbol1->GetName(), pSymbol2->GetName()) < 0;
		}
	};
private:
	UniqNumber _uniqNum;
	TCHAR *_name;
public:
	Symbol(UniqNumber uniqNum, const TCHAR *name);
	~Symbol();
	bool IsFlowControlSymbol() const;
	inline static void Delete(Symbol *pSymbol) { delete pSymbol; }
	inline UniqNumber GetUniqNum() const { return _uniqNum; }
	inline const TCHAR *GetName() const { return _name; }
	inline bool IsIdentical(const Symbol *pSymbol) const {
		return GetUniqNum() == pSymbol->GetUniqNum();
	}
	inline bool IsNone() const { return _name[0] = _T('\0'); }
	static const Symbol *Add(const TCHAR *name);
};

//-----------------------------------------------------------------------------
// SymbolSet
//-----------------------------------------------------------------------------
class SymbolSet : public std::set<const Symbol *, Symbol::KeyCompare_UniqNumber> {
public:
	static const SymbolSet Null;
public:
	inline SymbolSet() {}
	SymbolSet(const SymbolSet &symbolSet);
	void operator=(const SymbolSet &symbolSet);
	inline bool IsSet(const Symbol *pSymbol) const {
		return find(pSymbol) != const_cast<SymbolSet *>(this)->end();
	}
	inline void Insert(const Symbol *pSymbol) {
		insert(pSymbol);
	}
};

//-----------------------------------------------------------------------------
// SymbolPool
//-----------------------------------------------------------------------------
class SymbolPool {
public:
	AScript_DeclareSymbol(Str_Empty);
	AScript_DeclareSymbol(Char_Plus);
	AScript_DeclareSymbol(Char_Multiply);
	AScript_DeclareSymbol(Char_Question);
	AScript_DeclareSymbol(Char_Modulo);
	AScript_DeclareSymbol(Char_And);
	AScript_DeclareSymbol(unknown);
	AScript_DeclareSymbol(number);
	AScript_DeclareSymbol(boolean);
	AScript_DeclareSymbol(symbol);
	AScript_DeclareSymbol(string);
	AScript_DeclareSymbol(complex);
	AScript_DeclareSymbol(Module);
	AScript_DeclareSymbol(Class);
	AScript_DeclareSymbol(Object);
	AScript_DeclareSymbol(Function);
	AScript_DeclareSymbol(List);
	AScript_DeclareSymbol(Dict);
	AScript_DeclareSymbol(File);
	AScript_DeclareSymbol(FileStat);
	AScript_DeclareSymbol(DateTime);
	AScript_DeclareSymbol(Expr);
	AScript_DeclareSymbol(Environment);
	AScript_DeclareSymbol(Error);
	AScript_DeclareSymbol(Struct);
	AScript_DeclareSymbol(e);
	AScript_DeclareSymbol(pi);
	AScript_DeclareSymbol(nil);
	AScript_DeclareSymbol(zero);
	AScript_DeclareSymbol(raise);
	AScript_DeclareSymbol(true_);
	AScript_DeclareSymbol(false_);
	AScript_DeclareSymbol(rem);			// dummy for MS-DOS batch
	AScript_DeclareSymbol(j);
	AScript_DeclareSymbol(if_);
	AScript_DeclareSymbol(elsif);
	AScript_DeclareSymbol(else_);
	AScript_DeclareSymbol(repeat);
	AScript_DeclareSymbol(while_);
	AScript_DeclareSymbol(for_);
	AScript_DeclareSymbol(break_);
	AScript_DeclareSymbol(continue_);
	AScript_DeclareSymbol(except_);
	AScript_DeclareSymbol(__init__);
	AScript_DeclareSymbol(__del__);
	AScript_DeclareSymbol(__str__);
	AScript_DeclareSymbol(super);
	AScript_DeclareSymbol(self);
	AScript_DeclareSymbol(static_);
	AScript_DeclareSymbol(const_);
	AScript_DeclareSymbol(_anonymous_);
	AScript_DeclareSymbol(public_);
	AScript_DeclareSymbol(private_);
	AScript_DeclareSymbol(protected_);
	AScript_DeclareSymbol(dynamic_scope);
	AScript_DeclareSymbol(inside_scope);
	AScript_DeclareSymbol(map);
	AScript_DeclareSymbol(nomap);
	AScript_DeclareSymbol(strict);
	AScript_DeclareSymbol(loose);
	AScript_DeclareSymbol(block);
	AScript_DeclareSymbol(list);
	AScript_DeclareSymbol(xlist);
	AScript_DeclareSymbol(set);
	AScript_DeclareSymbol(xset);
	AScript_DeclareSymbol(rev);
	AScript_DeclareSymbol(and);
	AScript_DeclareSymbol(or);
	AScript_DeclareSymbol(xor);
	AScript_DeclareSymbol(void_);
	AScript_DeclareSymbol(index);
	AScript_DeclareSymbol(icase);
	AScript_DeclareSymbol(last_index);
	AScript_DeclareSymbol(indices);
	AScript_DeclareSymbol(ascend);
	AScript_DeclareSymbol(descend);
	AScript_DeclareSymbol(stable);
	AScript_DeclareSymbol(up);
	AScript_DeclareSymbol(down);
	AScript_DeclareSymbol(left);
	AScript_DeclareSymbol(right);
	AScript_DeclareSymbol(prev);
	AScript_DeclareSymbol(next);
	AScript_DeclareSymbol(name);
	AScript_DeclareSymbol(parent);
	AScript_DeclareSymbol(parents);
	AScript_DeclareSymbol(sibling);
	AScript_DeclareSymbol(siblings);
	AScript_DeclareSymbol(child);
	AScript_DeclareSymbol(children);
	AScript_DeclareSymbol(path);
	AScript_DeclareSymbol(x);
	AScript_DeclareSymbol(y);
	AScript_DeclareSymbol(z);
private:
	typedef std::set<Symbol *, Symbol::KeyCompare_Name> Content;
private:
	static SymbolPool *_pInst;
	Symbol::UniqNumber _uniqNum;
	Content _content;
private:
	inline SymbolPool() {}
public:
	~SymbolPool();
	static void Initialize();
	inline static void SetInstance(SymbolPool *pInst) { _pInst = pInst; }
	inline static SymbolPool *GetInstance() { return _pInst; }
	const Symbol *Add(const TCHAR *name);
private:
	void _Initialize();
private:
	inline SymbolPool(const SymbolPool &symbolPool) {}
	inline void operator=(const SymbolPool &symbolPool) {}
};

}

#endif
