#include "ascript/Symbol.h"

namespace AScript {

//-----------------------------------------------------------------------------
// static variables
//-----------------------------------------------------------------------------
SymbolPool *SymbolPool::_pInst = NULL;

const SymbolSet SymbolSet::Null;

//-----------------------------------------------------------------------------
// Symbol
//-----------------------------------------------------------------------------
Symbol::Symbol(UniqNumber uniqNum, const char *name) : _uniqNum(uniqNum)
{
	_name = new char[::strlen(name) + 1];
	::strcpy(_name, name);
}

Symbol::~Symbol()
{
	delete[] _name;
}

const Symbol *Symbol::Add(const char *name)
{
	return SymbolPool::GetInstance()->Add(name);
}

bool Symbol::IsFlowControlSymbol() const
{
	return 
		IsIdentical(AScript_Symbol(if_)) ||
		IsIdentical(AScript_Symbol(elsif)) ||
		IsIdentical(AScript_Symbol(repeat)) ||
		IsIdentical(AScript_Symbol(while_)) ||
		IsIdentical(AScript_Symbol(for_)) ||
		IsIdentical(AScript_Symbol(cross));
}

//-----------------------------------------------------------------------------
// SymbolList
//-----------------------------------------------------------------------------
String SymbolList::Join(const char *sep) const
{
	if (empty()) return String("");
	SymbolList::const_iterator ppSymbol = begin();
	String rtn((*ppSymbol)->GetName());
	ppSymbol++;
	for ( ; ppSymbol != end(); ppSymbol++) {
		rtn += sep;
		rtn += (*ppSymbol)->GetName();
	}
	return rtn;
}

String SymbolList::Join(const char sepChar) const
{
	char sep[2];
	sep[0] = sepChar;
	sep[1] = '\0';
	return Join(sep);
}

//-----------------------------------------------------------------------------
// SymbolSet
//-----------------------------------------------------------------------------
SymbolSet::SymbolSet(const SymbolSet &symbolSet)
{
	foreach_const (SymbolSet, ppSymbol, symbolSet) Insert(*ppSymbol);
}

SymbolSet::~SymbolSet()
{
}

void SymbolSet::operator=(const SymbolSet &symbolSet)
{
	foreach_const (SymbolSet, ppSymbol, symbolSet) Insert(*ppSymbol);
}

//-----------------------------------------------------------------------------
// SymbolPool
//-----------------------------------------------------------------------------
SymbolPool::~SymbolPool()
{
	foreach (Content, ppSymbol, _content) {
		Symbol::Delete(*ppSymbol);
	}
}

void SymbolPool::Initialize()
{
	if (_pInst == NULL) {
		_pInst = new SymbolPool();
		_pInst->_Initialize();
	}
}

void SymbolPool::_Initialize()
{
	AScript_RealizeSymbolEx(Str_Empty,		"");
	AScript_RealizeSymbolEx(Char_Plus,		"+");
	AScript_RealizeSymbolEx(Char_Multiply,	"*");
	AScript_RealizeSymbolEx(Char_Question,	"?");
	AScript_RealizeSymbolEx(Char_Modulo,	"%");
	AScript_RealizeSymbolEx(Char_And,		"&");
	AScript_RealizeSymbol(boolean);
	AScript_RealizeSymbol(number);
	AScript_RealizeSymbol(string);
	AScript_RealizeSymbol(ps1);
	AScript_RealizeSymbol(ps2);
	AScript_RealizeSymbol(stdin);
	AScript_RealizeSymbol(stdout);
	AScript_RealizeSymbol(stderr);
	AScript_RealizeSymbol(e);
	AScript_RealizeSymbol(pi);
	AScript_RealizeSymbol(nil);
	AScript_RealizeSymbol(zero);
	AScript_RealizeSymbol(raise);
	AScript_RealizeSymbolEx(true_,			"true");
	AScript_RealizeSymbolEx(false_,			"false");
	AScript_RealizeSymbol(j);
	AScript_RealizeSymbolEx(if_,			"if");
	AScript_RealizeSymbol(elsif);
	AScript_RealizeSymbolEx(else_,			"else");
	AScript_RealizeSymbol(repeat);
	AScript_RealizeSymbolEx(while_,			"while");
	AScript_RealizeSymbolEx(for_,			"for");
	AScript_RealizeSymbol(cross);
	AScript_RealizeSymbolEx(break_,			"break");
	AScript_RealizeSymbolEx(continue_,		"continue");
	AScript_RealizeSymbolEx(except_,		"except");
	AScript_RealizeSymbol(text);
	AScript_RealizeSymbol(message);
	AScript_RealizeSymbol(value);
	AScript_RealizeSymbol(__init__);
	AScript_RealizeSymbol(__del__);
	AScript_RealizeSymbol(__str__);
	AScript_RealizeSymbol(__setprop__);
	AScript_RealizeSymbol(__getprop__);
	AScript_RealizeSymbol(__setitem__);
	AScript_RealizeSymbol(__getitem__);
	AScript_RealizeSymbol(__name__);
	AScript_RealizeSymbol(__doc__);
	AScript_RealizeSymbol(super);
	AScript_RealizeSymbol(self);
	AScript_RealizeSymbolEx(static_,		"static");
	AScript_RealizeSymbolEx(const_,			"const");
	AScript_RealizeSymbolEx(_anonymous_,	"<>");
	AScript_RealizeSymbolEx(public_,		"public");
	AScript_RealizeSymbolEx(private_,		"private");
	AScript_RealizeSymbolEx(protected_,		"protected");
	AScript_RealizeSymbol(dynamic_scope);
	AScript_RealizeSymbol(inside_scope);
	AScript_RealizeSymbol(symbol_func);
	AScript_RealizeSymbol(force);
	AScript_RealizeSymbol(overwrite);
	AScript_RealizeSymbol(raw);
	AScript_RealizeSymbol(stat);
	AScript_RealizeSymbol(map);
	AScript_RealizeSymbol(nomap);
	AScript_RealizeSymbol(fork);
	AScript_RealizeSymbol(strict);
	AScript_RealizeSymbol(loose);
	AScript_RealizeSymbol(block);
	AScript_RealizeSymbol(list);
	AScript_RealizeSymbol(xlist);
	AScript_RealizeSymbol(set);
	AScript_RealizeSymbol(xset);
	AScript_RealizeSymbol(iter);
	AScript_RealizeSymbol(xiter);
	AScript_RealizeSymbol(iteritem);
	AScript_RealizeSymbol(xiteritem);
	AScript_RealizeSymbol(listitem);
	AScript_RealizeSymbol(xlistitem);
	AScript_RealizeSymbol(rev);
	AScript_RealizeSymbol(and);
	AScript_RealizeSymbol(or);
	AScript_RealizeSymbol(xor);
	AScript_RealizeSymbol(root);
	AScript_RealizeSymbolEx(void_,			"void");
	AScript_RealizeSymbolEx(extern_,		"extern");
	AScript_RealizeSymbol(reduce);
	AScript_RealizeSymbol(xreduce);
	AScript_RealizeSymbol(local);
	AScript_RealizeSymbol(flat);
	AScript_RealizeSymbol(noflat);
	AScript_RealizeSymbol(icase);
	AScript_RealizeSymbol(chop);
	AScript_RealizeSymbol(upper);
	AScript_RealizeSymbol(lower);
	AScript_RealizeSymbol(index);
	AScript_RealizeSymbol(last_index);
	AScript_RealizeSymbol(indices);
	AScript_RealizeSymbol(transpose);
	AScript_RealizeSymbol(ascend);
	AScript_RealizeSymbol(descend);
	AScript_RealizeSymbol(stable);
	AScript_RealizeSymbol(up);
	AScript_RealizeSymbol(down);
	AScript_RealizeSymbol(center);
	AScript_RealizeSymbol(both);
	AScript_RealizeSymbol(left);
	AScript_RealizeSymbol(right);
	AScript_RealizeSymbol(prev);
	AScript_RealizeSymbol(next);
	AScript_RealizeSymbol(stay);
	AScript_RealizeSymbol(forward);
	AScript_RealizeSymbol(backward);
	AScript_RealizeSymbol(help);
	AScript_RealizeSymbol(symbol);
	AScript_RealizeSymbol(name);
	AScript_RealizeSymbol(fullname);
	AScript_RealizeSymbol(readable);
	AScript_RealizeSymbol(writable);
	AScript_RealizeSymbol(argsymbols);
	AScript_RealizeSymbol(expr);
	AScript_RealizeSymbol(parent);
	AScript_RealizeSymbol(parents);
	AScript_RealizeSymbol(sibling);
	AScript_RealizeSymbol(siblings);
	AScript_RealizeSymbol(child);
	AScript_RealizeSymbol(children);
	AScript_RealizeSymbol(path);
	AScript_RealizeSymbol(shrink);
	AScript_RealizeSymbol(shrinkable);
	AScript_RealizeSymbol(x);
	AScript_RealizeSymbol(y);
	AScript_RealizeSymbol(z);
	AScript_RealizeSymbol(box);
	AScript_RealizeSymbol(imgtype);
	AScript_RealizeSymbol(format);
	AScript_RealizeSymbol(stream);
	AScript_RealizeSymbol(color);
	AScript_RealizeSymbol(width);
	AScript_RealizeSymbol(height);
	AScript_RealizeSymbol(palette);
	AScript_RealizeSymbol(gray);
	AScript_RealizeSymbol(rgb);
	AScript_RealizeSymbol(rgba);
	AScript_RealizeSymbol(rgbq);
	AScript_RealizeSymbol(bgr);
	AScript_RealizeSymbol(bgra);
	AScript_RealizeSymbol(bitmap);
	AScript_RealizeSymbol(red);
	AScript_RealizeSymbol(green);
	AScript_RealizeSymbol(blue);
	AScript_RealizeSymbol(alpha);
	AScript_RealizeSymbol(u8);
	AScript_RealizeSymbol(s8);
	AScript_RealizeSymbol(u16le);
	AScript_RealizeSymbol(s16le);
	AScript_RealizeSymbol(u16be);
	AScript_RealizeSymbol(s16be);
	AScript_RealizeSymbol(channels);
	AScript_RealizeSymbol(len);
	AScript_RealizeSymbol(open);
	AScript_RealizeSymbol(open_l);
	AScript_RealizeSymbol(open_r);
	AScript_RealizeSymbol(sticky);
	AScript_RealizeSymbol(sticky_l);
	AScript_RealizeSymbol(sticky_r);
	AScript_RealizeSymbol(horz);
	AScript_RealizeSymbol(vert);
	AScript_RealizeSymbol(mono);
	AScript_RealizeSymbol(basic);
	AScript_RealizeSymbol(win256);
	AScript_RealizeSymbol(websafe);
	AScript_RealizeSymbol(blank2);
	AScript_RealizeSymbol(blank4);
	AScript_RealizeSymbol(blank8);
	AScript_RealizeSymbol(blank16);
	AScript_RealizeSymbol(blank32);
	AScript_RealizeSymbol(blank64);
	AScript_RealizeSymbol(blank128);
	AScript_RealizeSymbol(blank256);
	AScript_RealizeSymbol(http);
	AScript_RealizeSymbol(ftp);
	AScript_RealizeSymbol(year);
	AScript_RealizeSymbol(month);
	AScript_RealizeSymbol(day);
	AScript_RealizeSymbol(hour);
	AScript_RealizeSymbol(min);
	AScript_RealizeSymbol(sec);
	AScript_RealizeSymbol(usec);
	AScript_RealizeSymbol(wday);
	AScript_RealizeSymbol(yday);
	AScript_RealizeSymbol(days);
	AScript_RealizeSymbol(secs);
	AScript_RealizeSymbol(usecs);
	AScript_RealizeSymbol(single);
	AScript_RealizeSymbol(multi);
	AScript_RealizeSymbol(w3c);
	AScript_RealizeSymbol(asctime);
	AScript_RealizeSymbol(unixtime);
	AScript_RealizeSymbol(utf8);
	AScript_RealizeSymbol(utf16);
	AScript_RealizeSymbol(utf32);
	AScript_RealizeSymbol(msc);
	AScript_RealizeSymbol(bcc);
	AScript_RealizeSymbol(gnuc);
	AScript_RealizeSymbol(file);
	AScript_RealizeSymbol(dir);
}

const Symbol *SymbolPool::Add(const char *name)
{
	Symbol *pSymbol = new Symbol(_uniqNum, name);
	std::pair<Content::iterator, bool> rtn = _content.insert(pSymbol);
	if (rtn.second) {
		_uniqNum++;
	} else {
		Symbol::Delete(pSymbol);
	}
	pSymbol = *rtn.first;
	return pSymbol;
}

SymbolPool *SymbolPool::GetInstance()
{
	return _pInst;
}

//-----------------------------------------------------------------------------
// OccurPattern
//-----------------------------------------------------------------------------
const Symbol *GetOccurPatternSymbol(OccurPattern occurPattern)
{
	return
		(occurPattern == OCCUR_ZeroOrOnce)? AScript_Symbol(Char_Question) :
		(occurPattern == OCCUR_ZeroOrMore)? AScript_Symbol(Char_Multiply) :
		(occurPattern == OCCUR_OnceOrMore)? AScript_Symbol(Char_Plus) :
		AScript_Symbol(Str_Empty);
}

}
