#include "AScript.h"
#include "Expr.h"

namespace AScript {

//-----------------------------------------------------------------------------
// Expr
//-----------------------------------------------------------------------------
Expr::~Expr()
{
}

Expr *Expr::IncRef() const
{
	Expr *pExpr = const_cast<Expr *>(this);
	pExpr->_cntRef++;
	return pExpr;
}

Expr *Expr::CloneSubstituted(Environment &env, Signal sig) const
{
	return Clone();
}

Expr *Expr::CloneOptimized(Environment &env, Signal sig) const
{
	return Clone();
}

ValueType Expr::GetStaticValueType() const
{
	return VTYPE_AnyType;
}

Value Expr::DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const
{
	sig.SetError(ERR_SyntaxError, _T("l-value is required"));
	return Value::Null;
}

Expr *Expr::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	sig.SetError(ERR_ArithmeticError, _T("can't generate differential expression"));
	return NULL;
}

bool Expr::FindSymbol(const Symbol *pSymbol) const
{
	ExprVisitor_FindSymbol visitor(pSymbol);
	Accept(visitor);
	return visitor.GetFlag();
}

bool Expr::ExprVisitor_FindSymbol::Visit(const Expr *pExpr)
{
	if (_flag) return false;
	if (pExpr->IsSymbol()) {
		const Expr_Symbol *pExprSym = dynamic_cast<const Expr_Symbol *>(pExpr);
		if (pExprSym->GetSymbol()->IsIdentical(_pSymbol)) {
			_flag = true;
			return false;
		}
	}
	return true;
}

void Expr::GatherSymbol(SymbolSet &symbolSet) const
{
	ExprVisitor_GatherSymbol visitor(symbolSet);
	Accept(visitor);
}

bool Expr::ExprVisitor_GatherSymbol::Visit(const Expr *pExpr)
{
	if (pExpr->IsSymbol()) {
		const Expr_Symbol *pExprSym = dynamic_cast<const Expr_Symbol *>(pExpr);
		_symbolSet.insert(pExprSym->GetSymbol());
	}
	return true;
}

const Expr *Expr::Unquote() const
{
	return this;
}

bool Expr::IsValue() const			{ return false; }
bool Expr::IsSymbol() const			{ return false; }
bool Expr::IsConstructor() const	{ return false; }
bool Expr::IsFunction() const		{ return false; }
bool Expr::IsIndexer() const		{ return false; }
bool Expr::IsContainer() const		{ return false; }
bool Expr::IsBlock() const			{ return false; }
bool Expr::IsBlockParam() const		{ return false; }
bool Expr::IsLister() const			{ return false; }

bool Expr::IsUnary() const			{ return false; }
bool Expr::IsQuote() const			{ return false; }
bool Expr::IsForce() const			{ return false; }
bool Expr::IsPrefix() const			{ return false; }
bool Expr::IsSuffix() const			{ return false; }
bool Expr::IsField() const			{ return false; }
bool Expr::IsUnaryOp() const		{ return false; }

bool Expr::IsBinary() const			{ return false; }
bool Expr::IsAssign() const			{ return false; }
bool Expr::IsDictAssign() const		{ return false; }
bool Expr::IsContainCheck() const	{ return false; }
bool Expr::IsBinaryOp() const		{ return false; }
bool Expr::IsNeg() const			{ return false; }
bool Expr::IsPlus() const			{ return false; }
bool Expr::IsMinus() const			{ return false; }
bool Expr::IsMultiply() const		{ return false; }
bool Expr::IsDivide() const			{ return false; }
bool Expr::IsPower() const			{ return false; }


bool Expr::IsConstZero() const		{ return false; }
bool Expr::IsConstOne() const		{ return false; }
bool Expr::IsConstMinusOne() const	{ return false; }
bool Expr::IsConstMinus() const		{ return false; }

void Expr::SetError_NotAssignableSymbol(Signal sig, const Symbol *pSymbol) const
{
	sig.SetError(ERR_ValueError,
		_T("symbol '%s' cannot be assigned in this object"), pSymbol->GetName());
}

//-----------------------------------------------------------------------------
// ExprList
//-----------------------------------------------------------------------------
const ExprList ExprList::Null;

void ExprList::IncRef() const
{
	foreach (ExprList, ppExpr, *const_cast<ExprList *>(this)) {
		(*ppExpr)->IncRef();
	}
}

Value ExprList::Exec(Environment &env, Signal sig) const
{
	Value result;
	foreach_const (ExprList, ppExpr, *this) {
		result = (*ppExpr)->Exec(env, sig);
		if (sig.IsSignalled()) break;
	}
	return result;
}

Value ExprList::ExecForList(Environment &env, Signal sig, bool flattenFlag) const
{
	Value result;
	ValueList &valList = result.InitAsList(env);
	foreach_const (ExprList, ppExpr, *this) {
		Value value = (*ppExpr)->Exec(env, sig);
		if (sig.IsSignalled()) return Value::Null;
		if (flattenFlag && value.IsList()) {
			value.Accept(sig, ValueVisitorEx(valList));
		} else {
			valList.push_back(value);
		}
	}
	return result;
}

void ExprList::DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const
{
	if (value.IsList()) {
		ValueList &valList = value.GetList();
		ExprList::const_iterator ppExpr = begin();
		ValueList::iterator pValue = valList.begin();
		for ( ; ppExpr != end() && pValue != valList.end(); ppExpr++, pValue++) {
			const Expr *pExpr = *ppExpr;
			pExpr->DoAssign(env, sig, *pValue, pSymbolsAssignable);
			if (sig.IsSignalled()) break;
		}
	} else if (!empty()) {
		const Expr *pExpr = front();
		pExpr->DoAssign(env, sig, value, pSymbolsAssignable);
	}
}

void ExprList::Accept(ExprVisitor &visitor) const
{
	foreach_const (ExprList, ppExpr, *this) {
		(*ppExpr)->Accept(visitor);
	}
}

String ExprList::ToString(Signal sig, const TCHAR *sep) const
{
	String str;
	foreach_const (ExprList, ppExpr, *this) {
		if (ppExpr != begin()) str += sep;
		str += (*ppExpr)->ToString(sig);
	}
	return str;
}

void ExprList::ValueVisitorEx::Visit(Signal sig, const Value &value)
{
	_valList.push_back(value);
}

//-----------------------------------------------------------------------------
// ExprOwner
//-----------------------------------------------------------------------------
ExprOwner::ExprOwner(const ExprList &exprList)
{
	foreach_const (ExprList, ppExpr, exprList) {
		push_back((*ppExpr)->Clone());
	}
}

ExprOwner::ExprOwner(const ExprOwner &exprOwner)
{
	foreach_const (ExprOwner, ppExpr, exprOwner) {
		push_back((*ppExpr)->Clone());
	}
}

ExprOwner::~ExprOwner()
{
	foreach (ExprOwner, ppExpr, *this) {
		Expr::Delete(const_cast<Expr *>(*ppExpr));
	}
}

//-----------------------------------------------------------------------------
// Expr_Unary
//-----------------------------------------------------------------------------
bool Expr_Unary::IsUnary() const { return true; }

Expr_Unary::~Expr_Unary()
{
}

Expr *Expr_Unary::IncRef() const
{
	GetExprChild()->IncRef();
	return Expr::IncRef();
}

void Expr_Unary::Accept(ExprVisitor &visitor) const
{
	if (visitor.Visit(this)) {
		GetExprChild()->Accept(visitor);
	}
}

//-----------------------------------------------------------------------------
// Expr_Binary
//-----------------------------------------------------------------------------
bool Expr_Binary::IsBinary() const { return true; }

Expr_Binary::~Expr_Binary()
{
}

Expr *Expr_Binary::IncRef() const
{
	GetExprLeft()->IncRef();
	GetExprRight()->IncRef();
	return Expr::IncRef();
}

void Expr_Binary::Accept(ExprVisitor &visitor) const
{
	if (visitor.Visit(this)) {
		GetExprLeft()->Accept(visitor);
		GetExprRight()->Accept(visitor);
	}
}

//-----------------------------------------------------------------------------
// Expr_Value
//-----------------------------------------------------------------------------
bool Expr_Value::IsValue() const { return true; }

Expr_Value::~Expr_Value()
{
}

Expr *Expr_Value::IncRef() const
{
	return Expr::IncRef();
}

Expr *Expr_Value::Clone() const
{
	return new Expr_Value(*this);
}

Value Expr_Value::Exec(Environment &env, Signal sig) const
{
	if (_value.IsExpr()) return _value.GetExpr()->Exec(env, sig);
	return _value;
}

ValueType Expr_Value::GetStaticValueType() const
{
	return _value.GetType();
}

Expr *Expr_Value::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	if (!_value.IsNumber()) {
		sig.SetError(ERR_TypeError, _T("non-number value is contained"));
		return NULL;
	}
	return new Expr_Value(0.);
}

void Expr_Value::Accept(ExprVisitor &visitor) const
{
	visitor.Visit(this);
}

bool Expr_Value::IsConstZero() const
{
	return _value.IsNumber() && _value.GetNumber() == 0.;
}

bool Expr_Value::IsConstOne() const
{
	return _value.IsNumber() && _value.GetNumber() == 1.;
}

bool Expr_Value::IsConstMinusOne() const
{
	return _value.IsNumber() && _value.GetNumber() == -1.;
}

bool Expr_Value::IsConstMinus() const
{
	return _value.IsNumber() && _value.GetNumber() < 0.;
}

String Expr_Value::ToString(Signal sig) const
{
	return _value.ToString(sig);
}

//-----------------------------------------------------------------------------
// Expr_Symbol
//-----------------------------------------------------------------------------
bool Expr_Symbol::IsSymbol() const { return true; }

Expr_Symbol::~Expr_Symbol()
{
}

Expr *Expr_Symbol::IncRef() const
{
	return Expr::IncRef();
}

Expr *Expr_Symbol::Clone() const
{
	return new Expr_Symbol(*this);
}

Expr *Expr_Symbol::CloneSubstituted(Environment &env, Signal sig) const
{
	const Value *pValue = env.LookupValue(GetSymbol(), false);
	if (pValue != NULL && pValue->IsExpr()) {
		// substitute with argument's expression
		return pValue->GetExpr()->Clone();
	}
	return Clone();
}

Expr *Expr_Symbol::CloneOptimized(Environment &env, Signal sig) const
{
	return CloneSubstituted(env, sig);
}

Value Expr_Symbol::Exec(Environment &env, Signal sig) const
{
	const Value *pValue = env.LookupValue(GetSymbol(), true);
	if (pValue != NULL) return *pValue;
	sig.SetError(ERR_ValueError, _T("undefined symbol '%s'"), GetSymbol()->GetName());
	return Value::Null;
}

Value Expr_Symbol::DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const
{
	if (pSymbolsAssignable != NULL && !pSymbolsAssignable->IsSet(GetSymbol())) {
		SetError_NotAssignableSymbol(sig, GetSymbol());
		return Value::Null;
	}
	if (value.IsModule()) {
		Module *pModule = value.GetModule();
		if (pModule->IsAnonymous()) {
			pModule->SetSymbol(GetSymbol());
		}
	} else if (value.IsFunction()) {
		Function *pFunc = value.GetFunction();
		if (pFunc->IsAnonymous()) {
			pFunc->SetSymbol(GetSymbol());
		}
		Class *pClassToConstruct = pFunc->GetClassToConstruct();
		if (pClassToConstruct != NULL && pClassToConstruct->IsAnonymous()) {
			pClassToConstruct->SetSymbol(_pSymbol);
		}
	}
	env.AssignValue(GetSymbol(), value, true);
	return value;
}

Expr *Expr_Symbol::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	return (GetSymbol()->IsIdentical(pSymbolVar))?
								new Expr_Value(1.) : new Expr_Value(0.);
}

void Expr_Symbol::Accept(ExprVisitor &visitor) const
{
	visitor.Visit(this);
}

String Expr_Symbol::ToString(Signal sig) const
{
	return GetSymbol()->GetName();
}

//-----------------------------------------------------------------------------
// Expr_Container
//-----------------------------------------------------------------------------
bool Expr_Container::IsContainer() const { return true; }

Expr_Container::~Expr_Container()
{
}

Expr *Expr_Container::IncRef() const
{
	_exprOwner.IncRef();
	return Expr::IncRef();
}

void Expr_Container::Accept(ExprVisitor &visitor) const
{
	if (visitor.Visit(this)) {
		_exprOwner.Accept(visitor);
	}
}

//-----------------------------------------------------------------------------
// Expr_Block
//-----------------------------------------------------------------------------
bool Expr_Block::IsBlock() const { return true; }

Expr_Block::~Expr_Block()
{
	Expr::Delete(_pExprBlockParam);
}

Expr *Expr_Block::Clone() const
{
	return new Expr_Block(*this);
}

Value Expr_Block::Exec(Environment &env, Signal sig) const
{
	if (_pExprBlockParam != NULL) {} // needs to do something here?
	if (env.IsEnvType(ENVTYPE_Lister)) {
		return _exprOwner.ExecForList(env, sig, false);
	}
	return _exprOwner.Exec(env, sig);
}

void Expr_Block::Accept(ExprVisitor &visitor) const
{
	if (_pExprBlockParam != NULL) _pExprBlockParam->Accept(visitor);
	Expr_Container::Accept(visitor);
}

String Expr_Block::ToString(Signal sig) const
{
	String str;
	str += _T("{");
	if (_pExprBlockParam != NULL) {
		str += _pExprBlockParam->ToString(sig);
	}
	str += _T(" ");
	str += GetExprList().ToString(sig);
	if (!GetExprList().empty()) str += _T(" ");
	str += _T("}");
	return str;
}

//-----------------------------------------------------------------------------
// Expr_BlockParam
//-----------------------------------------------------------------------------
bool Expr_BlockParam::IsBlockParam() const { return true; }

Expr_BlockParam::~Expr_BlockParam()
{
}

Expr *Expr_BlockParam::Clone() const
{
	return new Expr_BlockParam(*this);
}

Value Expr_BlockParam::Exec(Environment &env, Signal sig) const
{
	return _exprOwner.Exec(env, sig);
}

String Expr_BlockParam::ToString(Signal sig) const
{
	String str;
	str += _T("|");
	str += GetExprList().ToString(sig);
	str += _T("|");
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Lister
//-----------------------------------------------------------------------------
bool Expr_Lister::IsLister() const { return true; }

Expr_Lister::~Expr_Lister()
{
}

Expr *Expr_Lister::Clone() const
{
	return new Expr_Lister(*this);
}

Expr *Expr_Lister::CloneOptimized(Environment &env, Signal sig) const
{
	Expr_Lister *pExprLister = new Expr_Lister();
	foreach_const (ExprList, ppExpr, _exprOwner) {
		pExprLister->_exprOwner.push_back((*ppExpr)->CloneOptimized(env, sig));
		if (sig.IsSignalled()) break;
	}
	return pExprLister;
}

Value Expr_Lister::Exec(Environment &env, Signal sig) const
{
	Value result;
	ValueList &valList = result.InitAsList(env);
	foreach_const (ExprOwner, ppExpr, _exprOwner) {
		Value value = (*ppExpr)->Exec(env, sig);
		if (sig.IsSignalled()) break;
		valList.push_back(value);
	}
	return result;
}

Value Expr_Lister::DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const
{
	GetExprList().DoAssign(env, sig, value, pSymbolsAssignable);
	return value;
}

Expr *Expr_Lister::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	Expr_Lister *pExprLister = new Expr_Lister();
	foreach_const (ExprOwner, ppExpr, _exprOwner) {
		Expr *pExprGen = (*ppExpr)->Diff(env, sig, pSymbolVar);
		if (pExprGen == NULL) {
			Expr::Delete(pExprLister);
			return NULL;
		}
		pExprLister->AddExpr(pExprGen);
	}
	return pExprLister;
}

String Expr_Lister::ToString(Signal sig) const
{
	String str;
	str += _T("[");
	str += GetExprList().ToString(sig);
	str += _T("]");
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Indexer
//-----------------------------------------------------------------------------
bool Expr_Indexer::IsIndexer() const { return true; }

Expr_Indexer::~Expr_Indexer()
{
	Expr::Delete(_pExprCar);
	Expr::Delete(_pExprLister);
}

Expr *Expr_Indexer::IncRef() const
{
	_pExprCar->IncRef();
	_pExprLister->IncRef();
	return Expr::IncRef();
}

Expr *Expr_Indexer::Clone() const
{
	return new Expr_Indexer(*this);
}

Value Expr_Indexer::Exec(Environment &env, Signal sig) const
{
	Value result;
	Value valueCar = GetExprCar()->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	const ExprList &exprList = GetExprLister()->GetExprList();
	const Object &objCar = *valueCar.GetObject();
	Value valueIdx = exprList.ExecForList(env, sig, true);
	if (sig.IsSignalled() || !valueIdx.IsList()) return Value::Null;
	ValueList &valIdxList = valueIdx.GetList();
	if (valIdxList.size() == 0) return Value::Null;
	if (valueCar.IsString()) {
		const TCHAR *str = valueCar.GetString();
		size_t len = ::_tcslen(str);
		TCHAR strDst[2];
		strDst[1] = _T('\0');
		if (valIdxList.size() == 1) {
			strDst[0] = GetStringChar(sig, str, len, valIdxList.front());
			if (sig.IsSignalled()) return Value::Null;
			result = Value(env, strDst);
		} else {
			ValueList &valListDst = result.InitAsList(env);
			foreach_const (ValueList, pValueIdx, valIdxList) {
				strDst[0] = GetStringChar(sig, str, len, *pValueIdx);
				if (sig.IsSignalled()) return Value::Null;
				valListDst.push_back(Value(env, strDst));
			}
		}
	} else if (valueCar.IsObject()) {
		if (valIdxList.size() == 1) {
			result = objCar.GetByIndex(sig, valIdxList.front());
		} else {
			ValueList &valListDst = result.InitAsList(env);
			foreach_const (ValueList, pValueIdx, valIdxList) {
				Value value = objCar.GetByIndex(sig, *pValueIdx);
				if (sig.IsSignalled()) return Value::Null;
				valListDst.push_back(value);
			}
		}
	} else {
		sig.SetError(ERR_ValueError, _T("string or object should be specified as l-value of indexer"));
		return Value::Null;
	}
	return result;
}

Value Expr_Indexer::DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const
{
	Value valueDst = GetExprCar()->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	if (!valueDst.IsObject()) {
		sig.SetError(ERR_ValueError, _T("object is expected as l-value of indexer"));
		return Value::Null;
	}
	const ExprList &exprList = GetExprLister()->GetExprList();
	Object &objDst = *valueDst.GetObject();
	if (!value.IsList()) {
		// obj[idx] = v  /  obj[idx, idx, ..] = v
		ValueVisitor_AssignValue visitor(objDst, value);
		foreach_const (ExprList, ppExprCdr, exprList) {
			Value valueIdx = (*ppExprCdr)->Exec(env, sig);
			if (sig.IsSignalled()) return Value::Null;
			valueIdx.Accept(sig, visitor);
		}
	} else if (exprList.size() == 1) {
		// obj[idx] = (v, v, v, ..)
		Value valueIdx = exprList.front()->Exec(env, sig);
		if (sig.IsSignalled()) return Value::Null;
		if (valueIdx.IsList()) {
			ValueVisitor_AssignList visitor(objDst, value.GetList());
			valueIdx.Accept(sig, visitor);
		} else {
			objDst.SetByIndex(sig, valueIdx, value);
		}
	} else {
		// obj[idx, idx, ..] = (v, v, v, ..)
		const ValueList &valListCar = value.GetList();
		ValueVisitor_AssignList visitor(objDst, valListCar);
		foreach_const (ExprList, ppExprCdr, exprList) {
			Value valueIdx = (*ppExprCdr)->Exec(env, sig);
			if (sig.IsSignalled()) return Value::Null;
			valueIdx.Accept(sig, visitor);
		}
	}
	return value;
}

TCHAR Expr_Indexer::GetStringChar(Signal sig,
					const TCHAR *str, size_t len, const Value &valueIdx)
{
	if (!valueIdx.IsNumber()) {
		sig.SetError(ERR_IndexError, _T("index must be a number"));
		return _T('\0');
	}
	int idx = static_cast<int>(valueIdx.GetNumber());
	if (idx >= 0) {
		if (idx >= static_cast<int>(len)) {
			sig.SetError(ERR_IndexError, _T("index is out of range"));
			return _T('\0');
		}
		return str[idx];
	} else {
		if (-idx > static_cast<int>(len)) {
			sig.SetError(ERR_IndexError, _T("index is out of range"));
			return _T('\0');
		}
		return str[len + idx];
	}
}

void Expr_Indexer::Accept(ExprVisitor &visitor) const
{
	if (visitor.Visit(this)) {
		GetExprCar()->Accept(visitor);
		GetExprLister()->Accept(visitor);
	}
}

void Expr_Indexer::ValueVisitor_AssignList::Visit(Signal sig, const Value &valueIdx)
{
	if (_pValueSrc != _valListSrc.end()) {
		_objDst.SetByIndex(sig, valueIdx, *_pValueSrc);
		_pValueSrc++;
	}
}

void Expr_Indexer::ValueVisitor_AssignValue::Visit(Signal sig, const Value &valueIdx)
{
	_objDst.SetByIndex(sig, valueIdx, _value);
}

String Expr_Indexer::ToString(Signal sig) const
{
	String str;
	str += GetExprCar()->ToString(sig);
	str += _T("[");
	str += GetExprLister()->GetExprList().ToString(sig);
	str += _T("]");
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Function
//-----------------------------------------------------------------------------
bool Expr_Function::IsFunction() const { return true; }

Expr_Function::Expr_Function(Expr *pExprCar, Expr_Lister *pExprLister, Expr_Block *pExprBlock) :
		_pFunc(NULL), _pExprCar(pExprCar),
		_pExprLister((pExprLister == NULL)? new Expr_Lister() : pExprLister),
		_pExprBlock(pExprBlock), _pExprFuncSucc(NULL)
{
}

Expr_Function::Expr_Function(const Function *pFunc, Expr *pExprArg) :
		_pFunc(pFunc), _pExprCar(new Expr_Symbol(pFunc->GetSymbol())),
		_pExprLister(new Expr_Lister()), _pExprBlock(NULL), _pExprFuncSucc(NULL)
{
	_pExprLister->AddExpr(pExprArg);
}

Expr_Function::Expr_Function(const Function *pFunc, Expr *pExprArg1, Expr *pExprArg2) :
		_pFunc(pFunc), _pExprCar(new Expr_Symbol(pFunc->GetSymbol())),
		_pExprLister(new Expr_Lister()), _pExprBlock(NULL), _pExprFuncSucc(NULL)
{
	_pExprLister->AddExpr(pExprArg1);
	_pExprLister->AddExpr(pExprArg2);
}

Expr_Function::Expr_Function(const Expr_Function &expr) :
		_pFunc(expr._pFunc), _attrs(expr._attrs),
		_pExprCar(expr.GetExprCar()->Clone()),
		_pExprLister(dynamic_cast<Expr_Lister *>(expr._pExprLister->Clone())),
		_pExprBlock((expr._pExprBlock == NULL)? NULL :
					dynamic_cast<Expr_Block *>(expr._pExprBlock->Clone())),
		_pExprFuncSucc((expr._pExprFuncSucc == NULL)? NULL :
					dynamic_cast<Expr_Function *>(expr._pExprFuncSucc->Clone()))
{
}

Expr_Function::~Expr_Function()
{
	Expr::Delete(_pExprCar);
	Expr::Delete(_pExprLister);
	Expr::Delete(_pExprBlock);
	Expr::Delete(_pExprFuncSucc);
}

Expr *Expr_Function::IncRef() const
{
	_pExprCar->IncRef();
	_pExprLister->IncRef();
	if (_pExprBlock != NULL) _pExprBlock->IncRef();
	if (_pExprFuncSucc != NULL) _pExprFuncSucc->IncRef();
	return Expr::IncRef();
}

Expr *Expr_Function::Clone() const
{
	return new Expr_Function(*this);
}

Expr *Expr_Function::CloneOptimized(Environment &env, Signal sig) const
{
	return Clone();
}

Value Expr_Function::Exec(Environment &env, Signal sig) const
{
	const Function *pFuncSuccRequester = NULL;
	for (const Expr_Function *pExprFunc = this; pExprFunc != NULL;
									pExprFunc = pExprFunc->GetSucceeding()) {
		Value result = pExprFunc->ExecEach(env, sig, &pFuncSuccRequester);
		if (pFuncSuccRequester == NULL) return result;
	}
	return Value::Null;
}

Value Expr_Function::ExecEach(Environment &env, Signal sig,
									const Function **ppFuncSuccRequester) const
{
	Value valueSelf;
	if (!_pExprCar->IsField()) {
		Value valueCar = _pExprCar->Exec(env, sig);
		if (sig.IsSignalled()) return Value::Null;
		return EvalFunction(env, sig, valueSelf, valueCar, ppFuncSuccRequester);
	}
	const Expr_Field *pExprField = dynamic_cast<Expr_Field *>(_pExprCar);
	valueSelf = pExprField->GetExprLeft()->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	ObjectBase *pObj = valueSelf.ExtractObject(sig);
	if (sig.IsSignalled()) return Value::Null;
	// see Expr_Field::Exec() as well
	if (pExprField->GetFieldDepthLevel() == 0) {
		Value valueCar = pExprField->GetExprRight()->Exec(*pObj, sig);
		if (sig.IsSignalled()) return Value::Null;
		return EvalFunction(env, sig, valueSelf, valueCar, ppFuncSuccRequester);
	} else if (pObj->IsList()) {
		Value result;
		Object_List *pObjList = dynamic_cast<Object_List *>(pObj);
		if (pObjList->GetList().empty()) {
			result.InitAsList(env);		// create an empty list
			return result;
		}
		ValueList *pValList = NULL;
		size_t n = 0;
		foreach_const (ValueList, pValue, pObjList->GetList()) {
			Value valueSelfEach = *pValue;
			ObjectBase *pObjEach = valueSelfEach.ExtractObject(sig);
			if (sig.IsSignalled()) return Value::Null;
			Value valueCar = pExprField->GetExprRight()->Exec(*pObjEach, sig);
			if (sig.IsSignalled()) return Value::Null;
			Value valueEach = EvalFunction(env, sig,
								valueSelfEach, valueCar, ppFuncSuccRequester);
			if (sig.IsSignalled()) return Value::Null;
			if (valueEach.IsValid()) {
				if (pValList == NULL) {
					pValList = &result.InitAsList(env, n, Value::Null);
				}
				pValList->push_back(valueEach);
			} else if (pValList != NULL) {
				pValList->push_back(valueEach);
			}
			n++;
		}
		return result;
	} else {
		Value valueCar = pExprField->GetExprRight()->Exec(*pObj, sig);
		if (sig.IsSignalled()) return Value::Null;
		return EvalFunction(env, sig, valueSelf, valueCar, ppFuncSuccRequester);
	}
}

Value Expr_Function::EvalFunction(Environment &env, Signal sig,
		Value &valueSelf, Value &value, const Function **ppFuncSuccRequester) const
{
	Object *pObj = value.GetObject();
	if (pObj == NULL) {
		sig.SetError(ERR_TypeError,
			_T("'%s' is not a callable object"), value.ToString(sig, false).c_str());
		return Value::Null;
	}
	if (ppFuncSuccRequester != NULL) {
		const Function *pFuncSuccRequester = *ppFuncSuccRequester;
		*ppFuncSuccRequester = NULL;
		if (pFuncSuccRequester != NULL) {
			if (!pFuncSuccRequester->IsSucceedable(pObj)) {
				sig.SetError(ERR_SyntaxError, _T("invalid succeeding process"));
				return Value::Null;
			}
		}
	}
	ContextExpr contextExpr(GetAttrs(), GetAttrsOpt(),
					GetBlock(), ppFuncSuccRequester, valueSelf, GetExprList());
	return pObj->Call(env, sig, value, contextExpr);
}

Value Expr_Function::DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const
{
	if (!value.IsExpr()) {
		sig.SetError(ERR_SyntaxError, _T("invalid function expression"));
		return Value::Null;
	}
	Expr *pExprBody = value.GetExpr()->IncRef();
	// get symbol part of function's declaration
	const Symbol *pSymbol;
	if (GetExprCar()->IsField()) {
		const Expr_Field *pExprField =
						dynamic_cast<const Expr_Field *>(GetExprCar());
		if (pExprField->GetExprRight()->IsSymbol()) {
			const Expr_Symbol *pExprSym =
						dynamic_cast<const Expr_Symbol *>(pExprField->GetExprRight());
			pSymbol = pExprSym->GetSymbol();
		}
	} else if (GetExprCar()->IsSymbol()) {
		const Expr_Symbol *pExprSym =
						dynamic_cast<const Expr_Symbol *>(GetExprCar());
		pSymbol = pExprSym->GetSymbol();
	} else {
		sig.SetError(ERR_SyntaxError, _T("invalid function expression"));
		return Value::Null;
	}
	if (pSymbolsAssignable != NULL && !pSymbolsAssignable->IsSet(pSymbol)) {
		SetError_NotAssignableSymbol(sig, pSymbol);
		return Value::Null;
	}
	FunctionCustom *pFunc =
			new FunctionCustom(env, pSymbol, pExprBody, NULL, FUNCTYPE_Function);
	if (!pFunc->CustomDeclare(env, sig, SymbolSet::Null,
			ContextExpr(GetAttrs(), GetAttrsOpt(), _pExprBlock, NULL,
												Value::Null, GetExprList()))) {
		Function::Delete(pFunc);
		return Value::Null;
	}
	Value valueFunc;
	valueFunc.InitAsFunction(env, pFunc);
	GetExprCar()->DoAssign(env, sig, valueFunc, pSymbolsAssignable);
	return valueFunc;
}

Expr *Expr_Function::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	Expr *pExprGen = NULL;
	Value value = _pExprCar->Exec(env, sig);
	if (sig.IsSignalled()) return NULL;
	if (!value.IsFunction()) {
		sig.SetError(ERR_SyntaxError, _T("invalid function call"));
		return NULL;
	}
	const Function *pFunc = value.GetFunction();
	return pFunc->Diff(env, sig, GetExprList(), pSymbolVar);
}

void Expr_Function::Accept(ExprVisitor &visitor) const
{
	if (visitor.Visit(this)) {
		GetExprCar()->Accept(visitor);
		GetExprList().Accept(visitor);
	}
}

String Expr_Function::ToString(Signal sig) const
{
	String str;
	str += _pExprCar->ToString(sig);
	bool argListFlag = !GetExprList().empty() ||
									!_attrs.empty() || _pExprBlock == NULL;
	if (_pExprCar->IsSymbol()) {
		const Symbol *pSymbol = dynamic_cast<Expr_Symbol *>(_pExprCar)->GetSymbol();
		if (pSymbol->IsFlowControlSymbol() && argListFlag) {
			str += _T(" ");
		}
	}
	if (argListFlag) {
		str += _T("(");
		str += GetExprList().ToString(sig);
		str += _T(")");
	}
	foreach_const (SymbolSet, ppSymbol, _attrs) {
		const Symbol *pSymbol = *ppSymbol;
		str += _T(":");
		str += pSymbol->GetName();
	}
	if (_pExprBlock != NULL) {
		str += _T(" ");
		str += _pExprBlock->ToString(sig);
	}
	if (_pExprFuncSucc != NULL) {
		str += _T(" ");
		str += _pExprFuncSucc->ToString(sig);
	}
	return str;
}

//-----------------------------------------------------------------------------
// Expr_UnaryOp
//-----------------------------------------------------------------------------
bool Expr_UnaryOp::IsUnaryOp() const { return true; }
bool Expr_UnaryOp::IsNeg() const { return _func.IsNeg(); }

Expr_UnaryOp::Expr_UnaryOp(const Function &func, Expr *pExprChild) :
										Expr_Unary(pExprChild), _func(func)
{
}

Expr_UnaryOp::~Expr_UnaryOp()
{
}

Value Expr_UnaryOp::Exec(Environment &env, Signal sig) const
{
	return _func.EvalExpr(env, sig, ContextExpr(GetExprList()));
}

Expr *Expr_UnaryOp::Clone() const
{
	return new Expr_UnaryOp(*this);
}

Expr *Expr_UnaryOp::CloneOptimized(Environment &env, Signal sig) const
{
	return _func.Optimize(env, sig, ExprList(GetExprChild()->CloneOptimized(env, sig)));
}

Expr *Expr_UnaryOp::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	return _func.Diff(env, sig, GetExprList(), pSymbolVar);
}

String Expr_UnaryOp::ToString(Signal sig) const
{
	String str(_func.GetMathSymbol());
	if (GetExprChild()->IsUnaryOp() || GetExprChild()->IsBinaryOp()) {
		str += _T("(");
		str += GetExprChild()->ToString(sig);
		str += _T(")");
	} else {
		str += GetExprChild()->ToString(sig);
	}
	return str;
}

//-----------------------------------------------------------------------------
// Expr_BinaryOp
//-----------------------------------------------------------------------------
bool Expr_BinaryOp::IsBinaryOp() const { return true; }
bool Expr_BinaryOp::IsPlus() const { return _func.IsPlus(); }
bool Expr_BinaryOp::IsMinus() const { return _func.IsMinus(); }
bool Expr_BinaryOp::IsMultiply() const { return _func.IsMultiply(); }
bool Expr_BinaryOp::IsDivide() const { return _func.IsDivide(); }
bool Expr_BinaryOp::IsPower() const { return _func.IsPower(); }
bool Expr_BinaryOp::IsContainCheck() const { return _func.IsContainCheck(); }

Expr_BinaryOp::Expr_BinaryOp(const Function &func, Expr *pExprLeft, Expr *pExprRight) :
							Expr_Binary(pExprLeft, pExprRight), _func(func)
{
}

Expr_BinaryOp::~Expr_BinaryOp()
{
}

Value Expr_BinaryOp::Exec(Environment &env, Signal sig) const
{
	return _func.EvalExpr(env, sig, ContextExpr(GetExprList()));
}

Expr *Expr_BinaryOp::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	return _func.Diff(env, sig,
		ExprList(const_cast<Expr *>(GetExprLeft()), const_cast<Expr *>(GetExprRight())),
		pSymbolVar);
}

Expr *Expr_BinaryOp::Clone() const
{
	return new Expr_BinaryOp(*this);
}

Expr *Expr_BinaryOp::CloneOptimized(Environment &env, Signal sig) const
{
	return _func.Optimize(env, sig, ExprList(
				GetExprLeft()->CloneOptimized(env, sig),
				GetExprRight()->CloneOptimized(env, sig)));
}

String Expr_BinaryOp::ToString(Signal sig) const
{
	String str;
	if (GetExprLeft()->IsUnaryOp() || GetExprLeft()->IsBinaryOp()) {
		str += _T("(");
		str += GetExprLeft()->ToString(sig);
		str += _T(")");
	} else {
		str += GetExprLeft()->ToString(sig);
	}
	str += _T(" ");
	str += _func.GetMathSymbol();
	str += _T(" ");
	if (GetExprRight()->IsUnaryOp() || GetExprRight()->IsBinaryOp()) {
		str += _T("(");
		str += GetExprRight()->ToString(sig);
		str += _T(")");
	} else {
		str += GetExprRight()->ToString(sig);
	}
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Quote
//-----------------------------------------------------------------------------
bool Expr_Quote::IsQuote() const { return true; }

Expr_Quote::~Expr_Quote()
{
}

Expr *Expr_Quote::Clone() const
{
	return new Expr_Quote(*this);
}

const Expr *Expr_Quote::Unquote() const
{
	return GetExprChild();
}

Value Expr_Quote::Exec(Environment &env, Signal sig) const
{
	Value value;
	if (GetExprChild()->IsSymbol()) {
		const Expr_Symbol *pExprSym =
						dynamic_cast<const Expr_Symbol *>(GetExprChild());
		value.SetSymbol(pExprSym->GetSymbol());
	} else {
		value.InitAsExpr(env, GetExprChild()->IncRef());
	}
	return value;
}

Expr *Expr_Quote::Diff(Environment &env, Signal sig, const Symbol *pSymbolVar) const
{
	return GetExprChild()->Diff(env, sig, pSymbolVar);
}

ValueType Expr_Quote::GetStaticValueType() const
{
	return GetExprChild()->IsSymbol()? VTYPE_Symbol : VTYPE_Expr;
}

String Expr_Quote::ToString(Signal sig) const
{
	String str;
	str += _T("`");
	str += GetExprChild()->ToString(sig);
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Force
//-----------------------------------------------------------------------------
bool Expr_Force::IsForce() const { return true; }

Expr_Force::~Expr_Force()
{
}

Expr *Expr_Force::Clone() const
{
	return new Expr_Force(*this);
}

Value Expr_Force::Exec(Environment &env, Signal sig) const
{
	return GetExprChild()->Exec(env, sig);
}

String Expr_Force::ToString(Signal sig) const
{
	String str;
	str += _T("!!");
	str += GetExprChild()->ToString(sig);
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Prefix
//-----------------------------------------------------------------------------
bool Expr_Prefix::IsPrefix() const { return true; }

Expr_Prefix::~Expr_Prefix()
{
}

Expr *Expr_Prefix::Clone() const
{
	return new Expr_Prefix(*this);
}

Value Expr_Prefix::Exec(Environment &env, Signal sig) const
{
	sig.SetError(ERR_SyntaxError, _T("invalid expression"));
	return Value::Null;
}

String Expr_Prefix::ToString(Signal sig) const
{
	String str;
	str += _pSymbol->GetName();
	str += GetExprChild()->ToString(sig);
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Suffix
//-----------------------------------------------------------------------------
bool Expr_Suffix::IsSuffix() const { return true; }

Expr_Suffix::~Expr_Suffix()
{
}

Expr *Expr_Suffix::Clone() const
{
	return new Expr_Suffix(*this);
}

Value Expr_Suffix::Exec(Environment &env, Signal sig) const
{
	sig.SetError(ERR_SyntaxError, _T("invalid expression"));
	return Value::Null;
}

OccurPattern Expr_Suffix::GetOccurPattern() const
{
	return
		(_pSymbol->IsIdentical(AScript_Symbol(Char_Multiply)))?	OCCUR_ZeroOrMore :
		(_pSymbol->IsIdentical(AScript_Symbol(Char_Plus)))?		OCCUR_OnceOrMore :
		(_pSymbol->IsIdentical(AScript_Symbol(Char_Question)))?	OCCUR_ZeroOrOnce :
		OCCUR_Invalid;
}

String Expr_Suffix::ToString(Signal sig) const
{
	String str;
	str += GetExprChild()->ToString(sig);
	str += _pSymbol->GetName();
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Assign
//-----------------------------------------------------------------------------
bool Expr_Assign::IsAssign() const { return true; }

Expr_Assign::~Expr_Assign()
{
}

Expr *Expr_Assign::Clone() const
{
	return new Expr_Assign(*this);
}

Value Expr_Assign::Exec(Environment &env, Signal sig) const
{
	return Exec(env, sig, env, NULL);
}

Value Expr_Assign::Exec(Environment &env, Signal sig,
					Environment &envDst, const SymbolSet *pSymbolsAssignable) const
{
	Value value;
	const Expr *pExpr = GetExprLeft();
	bool funcAssignFlag = false;
	if (pExpr->IsFunction()) {
		if (_pFuncToApply != NULL) {
			sig.SetError(ERR_SyntaxError, _T("invalid operation"));
			return Value::Null;
		}
		if (GetExprRight()->IsForce()) {
			value = GetExprRight()->Exec(env, sig);
			if (sig.IsSignalled()) return Value::Null;
		} else {
			Expr *pExprBody = GetExprRight()->Unquote()->IncRef();
			value.InitAsExpr(env, pExprBody);
		}
	} else {
		value = GetExprRight()->Exec(env, sig);
		if (sig.IsSignalled()) return Value::Null;
		if (_pFuncToApply != NULL) {
			Value valueLeft = pExpr->Exec(env, sig);
			if (sig.IsSignalled()) return Value::Null;
			ValueList valListArg(valueLeft, value);
			Context context(valListArg);
			value = _pFuncToApply->IsApplicable(valListArg)?
							_pFuncToApply->Eval(env, sig, context) :
							_pFuncToApply->EvalMap(env, sig, context);
			if (sig.IsSignalled()) return Value::Null;
		}
	}
	return GetExprLeft()->DoAssign(envDst, sig, value, pSymbolsAssignable);
}

String Expr_Assign::ToString(Signal sig) const
{
	String str;
	str += GetExprLeft()->ToString(sig);
	str += _T(" ");
	if (_pFuncToApply != NULL) str += _pFuncToApply->GetMathSymbol();
	str += _T("= ");
	str += GetExprRight()->ToString(sig);
	return str;
}

//-----------------------------------------------------------------------------
// Expr_DictAssign
//-----------------------------------------------------------------------------
bool Expr_DictAssign::IsDictAssign() const { return true; }

Expr_DictAssign::~Expr_DictAssign()
{
}

Expr *Expr_DictAssign::Clone() const
{
	return new Expr_DictAssign(*this);
}

Value Expr_DictAssign::Exec(Environment &env, Signal sig) const
{
	Value result;
	ValueList &valList = result.InitAsList(env);
	const Expr *pExprLeft = GetExprLeft()->Unquote();
	if (pExprLeft->IsValue()) {
		// value => value
		const Expr_Value *pExprValue =
						dynamic_cast<const Expr_Value *>(pExprLeft);
		valList.push_back(pExprValue->GetValue());
	} else if (pExprLeft->IsSymbol()) {
		// symbol => value
		const Expr_Symbol *pExprSymbol =
						dynamic_cast<const Expr_Symbol *>(pExprLeft);
		valList.push_back(Value(pExprSymbol->GetSymbol()));
	} else {
		sig.SetError(ERR_KeyError, _T("key must be a value or symbol"));
		return Value::Null;
	}
	Value value = GetExprRight()->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	valList.push_back(value);
	return result;
}

String Expr_DictAssign::ToString(Signal sig) const
{
	String str;
	str += GetExprLeft()->Unquote()->ToString(sig);
	str += _T(" => ");
	str += GetExprRight()->ToString(sig);
	return str;
}

Value Expr_DictAssign::GetKey(Signal sig) const
{
	const Expr *pExpr = GetExprLeft()->Unquote();
	if (pExpr->IsSymbol()) {
		const Symbol *pSymbol = dynamic_cast<const Expr_Symbol *>(pExpr)->GetSymbol();
		return Value(pSymbol);
	} else if (pExpr->IsValue()) {
		return dynamic_cast<const Expr_Value *>(pExpr)->GetValue();
	} else {
		sig.SetError(ERR_KeyError,
				_T("l-value of dictionary assignment must be a symbol or a constant value"));
		return Value::Null;
	}
}

//-----------------------------------------------------------------------------
// Expr_Field
//-----------------------------------------------------------------------------
bool Expr_Field::IsField() const { return true; }

Expr_Field::~Expr_Field()
{
}

Expr *Expr_Field::Clone() const
{
	return new Expr_Field(*this);
}

Value Expr_Field::Exec(Environment &env, Signal sig) const
{
	Value valueSelf = GetExprLeft()->Exec(env, sig);
	ObjectBase *pObj = valueSelf.ExtractObject(sig);
	if (sig.IsSignalled()) return Value::Null;
	// see Expr_Function::Exec() as well
	if (GetFieldDepthLevel() == 0) {
		return GetExprRight()->Exec(*pObj, sig);
	} else if (pObj->IsList()) {
		Value result;
		Object_List *pObjList = dynamic_cast<Object_List *>(pObj);
		if (pObjList->GetList().empty()) {
			result.InitAsList(env);		// create an empty list
			return result;
		}
		ValueList *pValList = NULL;
		size_t n = 0;
		foreach_const (ValueList, pValue, pObjList->GetList()) {
			Value valueSelfEach = *pValue;
			ObjectBase *pObjEach = valueSelfEach.ExtractObject(sig);
			if (sig.IsSignalled()) return Value::Null;
			Value valueEach = GetExprRight()->Exec(*pObjEach, sig);
			if (sig.IsSignalled()) return Value::Null;
			if (valueEach.IsValid()) {
				if (pValList == NULL) {
					pValList = &result.InitAsList(env, n, Value::Null);
				}
				pValList->push_back(valueEach);
			} else if (pValList != NULL) {
				pValList->push_back(valueEach);
			}
			n++;;
		}
		return result;
	} else {
		return GetExprRight()->Exec(*pObj, sig);
	}
}

Value Expr_Field::DoAssign(Environment &env, Signal sig,
					Value &value, const SymbolSet *pSymbolsAssignable) const
{
	Value valueSelf = GetExprLeft()->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	ObjectBase *pObj = valueSelf.ExtractObject(sig);
	if (sig.IsSignalled()) return Value::Null;
	if (GetFieldDepthLevel() == 0) {
		return GetExprRight()->DoAssign(*pObj, sig, value, pSymbolsAssignable);
	} else if (pObj->IsList()) {
		Object_List *pObjList = dynamic_cast<Object_List *>(pObj);
		const ValueList &valListDst = pObjList->GetList();
		ValueList::const_iterator pValueDst = valListDst.begin();
		if (value.IsList()) {
			ValueList &valListSrc = value.GetList();
			ValueList::iterator pValueSrc = valListSrc.begin();
			for ( ; pValueDst != valListDst.end() && pValueSrc != valListSrc.end();
														pValueDst++, pValueSrc++) {
				Value valueSelfEach = *pValueDst;
				ObjectBase *pObjEach = valueSelfEach.ExtractObject(sig);
				if (sig.IsSignalled()) return Value::Null;
				GetExprRight()->DoAssign(*pObjEach, sig, *pValueSrc, pSymbolsAssignable);
			}
		} else {
			for ( ; pValueDst != valListDst.end(); pValueDst++) {
				Value valueSelfEach = *pValueDst;
				ObjectBase *pObjEach = valueSelfEach.ExtractObject(sig);
				if (sig.IsSignalled()) return Value::Null;
				GetExprRight()->DoAssign(*pObjEach, sig, value, pSymbolsAssignable);
			}
		}
		return value;
	} else {
		return GetExprRight()->DoAssign(*pObj, sig, value, pSymbolsAssignable);
	}
}

String Expr_Field::ToString(Signal sig) const
{
	String str;
	str += GetExprLeft()->ToString(sig);
	str += _T(".");
	str += GetExprRight()->ToString(sig);
	return str;
}

}
