#include "ascript/Expr.h"
#include "ascript/Function.h"
#include "ascript/Module.h"
#include "ascript/Parser.h"
#include "ascript/Object_List.h"
#include "ascript/Object_Function.h"
#include "ascript/Operator.h"

namespace AScript {

//-----------------------------------------------------------------------------
// ExprType
//-----------------------------------------------------------------------------
const char *GetExprTypeName(ExprType exprType)
{
	static const struct {
		ExprType exprType;
		const char *name;
	} tbl[] = {
		{ EXPRTYPE_UnaryOp,		"unaryop",		},
		{ EXPRTYPE_Quote,		"quote",		},
		{ EXPRTYPE_Force,		"force",		},
		{ EXPRTYPE_Prefix,		"prefix",		},
		{ EXPRTYPE_Suffix,		"suffix",		},
		{ EXPRTYPE_BinaryOp,	"binaryop",		},
		{ EXPRTYPE_Assign,		"assign",		},
		{ EXPRTYPE_DictAssign,	"dictassign",	},
		{ EXPRTYPE_Field,		"field",		},
		{ EXPRTYPE_Root,		"root",			},
		{ EXPRTYPE_BlockParam,	"blockparam",	},
		{ EXPRTYPE_Block,		"block",		},
		{ EXPRTYPE_Lister,		"lister",		},
		{ EXPRTYPE_Indexer,		"indexer",		},
		{ EXPRTYPE_Caller,		"caller",		},
		{ EXPRTYPE_Value,		"value",		},
		{ EXPRTYPE_Symbol,		"symbol",		},
		{ EXPRTYPE_String,		"string",		},
	};
	for (int i = 0; i < NUMBEROF(tbl); i++) {
		if (tbl[i].exprType == exprType) return tbl[i].name;
	}
	return "unknown";
}

//-----------------------------------------------------------------------------
// Expr
// [class hierarchy under Expr]
// Expr <-+- Expr_Unary <-----+- Expr_UnaryOp
//        |                   +- Expr_Quote
//        |                   +- Expr_Force
//        |                   +- Expr_Prefix
//        |                   `- Expr_Suffix
//        +- Expr_Binary <----+- Expr_BinaryOp
//        |                   +- Expr_Assign
//        |                   +- Expr_DictAssign
//        |                   `- Expr_Field
//        +- Expr_Container <-+- Expr_Root
//        |                   +- Expr_BlockParam
//        |                   +- Expr_Block
//        |                   `- Expr_Lister
//        +- Expr_Compound <--+- Expr_Indexer
//        |                   `- Expr_Caller
//        +- Expr_Value
//        +- Expr_Symbol
//        `- Expr_String
//-----------------------------------------------------------------------------
Expr::~Expr()
{
}

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

const char *Expr::GetPathName() const
{
	return (_pExprParent == NULL)? NULL : _pExprParent->GetPathName();
}

bool Expr::ExecInArg(Environment &env, Signal sig,
					ValueList &valListArg, size_t &nElems, bool quoteFlag) const
{
	if (quoteFlag) {
		Value value;
		value.InitAsExpr(env, IncRef());
		valListArg.push_back(value);
		nElems = 1;
	} else if (IsSuffix()) {
		const Expr_Suffix *pExprSuffix = dynamic_cast<const Expr_Suffix *>(this);
		if (!pExprSuffix->GetSymbol()->IsIdentical(AScript_Symbol(Char_Multiply))) {
			SetError(sig, ERR_SyntaxError, "invalid argument");
			return false;
		}
		Value value = pExprSuffix->GetChild()->Exec(env, sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return false;
		}
		if (value.IsList()) {
			const ValueList &valList = value.GetList();
			nElems = valList.size();
			foreach_const (ValueList, pValue, valList) {
				valListArg.push_back(*pValue);
			}
		} else {
			nElems = 1;
			valListArg.push_back(value);
		}
	} else {
		Value value = Exec(env, sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return false;
		}
		valListArg.push_back(value);
		nElems = 1;
	}
	return true;
}

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

Expr *Expr::MathDiff(Environment &env, Signal sig, const Symbol *pSymbol) const
{
	SetError(sig, ERR_ValueError,
				"differential operation is not supported for this expression");
	return NULL;
}

Expr *Expr::MathOptimize(Environment &env, Signal sig) const
{
	SetError(sig, ERR_ValueError,
				"mathematical optimization is not supported for this expression");
	return NULL;
}

Function *Expr::ToFunction(Environment &env, Signal sig,
				const ValueList &valListArg, const SymbolSet &attrs) const
{
	Expr_Block *pExprBlock;
	if (IsBlock()) {
		pExprBlock = dynamic_cast<Expr_Block *>(IncRef());
	} else {
		pExprBlock = new Expr_Block();
		pExprBlock->AddExpr(IncRef());
	}
	Value result;
	FunctionCustom *pFunc = FunctionCustom::CreateBlockFunc(env, sig,
					AScript_Symbol(_anonymous_), pExprBlock, FUNCTYPE_Function);
	if (sig.IsSignalled()) return NULL;
	if (!valListArg.empty()) {
		if (!pFunc->GetDeclOwner().empty()) {
			sig.SetError(ERR_TypeError, "argument declaration conflicts");
			Function::Delete(pFunc);
			return NULL;
		}
		ExprList exprListArg;
		foreach_const (ValueList, pValue, valListArg) {
			exprListArg.push_back(const_cast<Expr *>(pValue->GetExpr()));
		}
		Args args(exprListArg, Value::Null, NULL, false, NULL, attrs);
		if (!pFunc->CustomDeclare(env, sig, SymbolSet::Null, args)) {
			Function::Delete(pFunc);
			return NULL;
		}
	}
	return pFunc;
}

bool Expr::IsAtSameLine(const Expr *pExpr) const
{
	if (GetLineNoTop() != pExpr->GetLineNoTop()) return false;
	const char *pathName1 = GetPathName();
	const char *pathName2 = pExpr->GetPathName();
	if (pathName1 == NULL && pathName2 == NULL) return true;
	if (pathName1 == NULL || pathName2 == NULL) return false;
	return ::strcmp(pathName1, pathName2) == 0;
}

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

void Expr::GatherSimpleLambdaArgs(ExprList &exprListArg) const
{
	ExprVisitor_GatherSimpleLambdaArgs visitor(exprListArg);
	Accept(visitor);
}

// this function makes a list of symbols chained by field operator "."
bool Expr::GetChainedSymbolList(SymbolList &symbolList) const
{
	for (const Expr *pExpr = this; ; ) {
		if (pExpr->IsField()) {
			const Expr_Field *pExprField = dynamic_cast<const Expr_Field *>(pExpr);
			if (pExprField->GetRight()->IsSymbol()) {
				const Expr_Symbol *pExprSymbol =
						dynamic_cast<const Expr_Symbol *>(pExprField->GetRight());
				symbolList.insert(symbolList.begin(), pExprSymbol->GetSymbol());
				pExpr = pExprField->GetLeft();
			} else {
				return false;
			}
		} else if (pExpr->IsSymbol()) {
			const Expr_Symbol *pExprSymbol = dynamic_cast<const Expr_Symbol *>(pExpr);
			symbolList.insert(symbolList.begin(), pExprSymbol->GetSymbol());
			break;
		} else {
			return false;
		}
	}
	return true;
}

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

bool Expr::NeedParenthesis(const Function &funcOuter,
									const Function &func, bool rightFlag)
{
	Parser::Precedence prec = Parser::LookupPrec(
									funcOuter.GetElemType(), func.GetElemType());
	if (prec == Parser::PREC_EQ || funcOuter.GetElemType() == func.GetElemType()) {
		return rightFlag;
	} else if (prec == Parser::PREC_GT) {
		return true;
	} else {
		return false;
	}
}

bool Expr::IsConstNumber(Number num) const
{
	if (!IsValue()) return false;
	const Value &value = dynamic_cast<const Expr_Value *>(this)->GetValue();
	return value.IsNumber() && value.GetNumber() == num;
}

bool Expr::IsConstEvenNumber() const
{
	if (!IsValue()) return false;
	const Value &value = dynamic_cast<const Expr_Value *>(this)->GetValue();
	return value.IsNumber() && ::fmod(value.GetNumber(), 2) == 0;
}

bool Expr::IsConstNegNumber() const
{
	if (!IsValue()) return false;
	const Value &value = dynamic_cast<const Expr_Value *>(this)->GetValue();
	return value.IsNumber() && value.GetNumber() < 0;
}

bool Expr::IsOperatorNeg() const
{
	return IsUnaryOp() &&
			dynamic_cast<const Expr_UnaryOp *>(this)->GetFunction().IsNeg();
}

bool Expr::IsOperatorMultiply() const
{
	return IsBinaryOp() &&
		dynamic_cast<const Expr_BinaryOp *>(this)->GetFunction().IsMultiply();
}

bool Expr::IsOperatorPower() const
{
	return IsBinaryOp() &&
		dynamic_cast<const Expr_BinaryOp *>(this)->GetFunction().IsPower();
}

bool Expr::IsOperatorSequence() const
{
	return IsBinaryOp() &&
		dynamic_cast<const Expr_BinaryOp *>(this)->GetFunction().IsSequence();
}

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::IsUnaryOp() const		{ return false; }

bool Expr::IsBinary() const			{ return false; }
bool Expr::IsAssign() const			{ return false; }
bool Expr::IsDictAssign() const		{ return false; }
bool Expr::IsBinaryOp() const		{ return false; }
bool Expr::IsField() const			{ return false; }

bool Expr::IsContainer() const		{ return false; }
bool Expr::IsRoot() const			{ return false; }
bool Expr::IsBlockParam() const		{ return false; }
bool Expr::IsBlock() const			{ return false; }
bool Expr::IsLister() const			{ return false; }

bool Expr::IsCompound() const		{ return false; }
bool Expr::IsIndexer() const		{ return false; }
bool Expr::IsCaller() const			{ return false; }

bool Expr::IsValue() const			{ return false; }
bool Expr::IsSymbol() const			{ return false; }
bool Expr::IsString() const			{ return false; }

bool Expr::IsParentOf(const Expr *pExpr) const
{
	return false;
}

void Expr::SetError(Signal sig, ErrorType errType, const char *format, ...) const
{
	va_list list;
	va_start(list, format);
	sig.SetErrorV(errType, format, list);
	sig.AddExprCause(this);
	va_end(list);
}

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

//-----------------------------------------------------------------------------
// Expr::ExprVisitor_GatherSymbol
//-----------------------------------------------------------------------------
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;
}

//-----------------------------------------------------------------------------
// Expr::ExprVisitor_GatherSimpleLambdaArgs
//-----------------------------------------------------------------------------
bool Expr::ExprVisitor_GatherSimpleLambdaArgs::Visit(const Expr *pExpr)
{
	if (pExpr->IsCaller()) {
		// avoid searching in a simple lambda inside
		const Expr *pExprCar =
					dynamic_cast<const Expr_Caller *>(pExpr)->GetCar();
		if (pExprCar->IsSymbol()) {
			const Symbol *pSymbol =
					dynamic_cast<const Expr_Symbol *>(pExprCar)->GetSymbol();
			if (pSymbol->IsIdentical(AScript_Symbol(Char_And))) return false;
		}
		
	} else if (pExpr->IsSymbol()) {
		const Symbol *pSymbol =
						dynamic_cast<const Expr_Symbol *>(pExpr)->GetSymbol();
		if (pSymbol->GetName()[0] == '$' &&
								_symbolSet.find(pSymbol) == _symbolSet.end()) {
			_exprListArg.push_back(const_cast<Expr *>(pExpr));
			_symbolSet.insert(pSymbol);
		}
	}
	return true;
}

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

Expr_Unary::Expr_Unary(ExprType exprType, Expr *pExprChild) : Expr(exprType)
{
	_exprOwner.reserve(1);
	_exprOwner.push_back(pExprChild);
	_exprOwner.SetParent(this);
}

Expr_Unary::Expr_Unary(const Expr_Unary &expr) : Expr(expr), _exprOwner(expr._exprOwner)
{
	_exprOwner.SetParent(this);
}

Expr_Unary::~Expr_Unary()
{
	_exprOwner.SetParent(GetParent());
}

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

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

bool Expr_Unary::IsParentOf(const Expr *pExpr) const
{
	return _exprOwner.IsContained(pExpr);
}

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

Expr_Binary::Expr_Binary(ExprType exprType, Expr *pExprLeft, Expr *pExprRight) : Expr(exprType)
{
	_exprOwner.reserve(2);
	_exprOwner.push_back(pExprLeft); _exprOwner.push_back(pExprRight);
	_exprOwner.SetParent(this);
}

Expr_Binary::Expr_Binary(const Expr_Binary &expr) : Expr(expr), _exprOwner(expr._exprOwner)
{
	_exprOwner.SetParent(this);
}

Expr_Binary::~Expr_Binary()
{
	_exprOwner.SetParent(GetParent());
}

Expr *Expr_Binary::IncRef() const
{
	GetLeft()->IncRef();
	GetRight()->IncRef();
	return Expr::IncRef();
}

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

bool Expr_Binary::IsParentOf(const Expr *pExpr) const
{
	return _exprOwner.IsContained(pExpr);
}

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

Expr_Container::Expr_Container(const Expr_Container &expr) : Expr(expr), _exprOwner(expr._exprOwner)
{
	foreach (ExprOwner, ppExpr, _exprOwner) (*ppExpr)->SetParent(this);
}

Expr_Container::~Expr_Container()
{
	_exprOwner.SetParent(GetParent());
}

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

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

bool Expr_Container::IsParentOf(const Expr *pExpr) const
{
	return _exprOwner.IsContained(pExpr);
}

//-----------------------------------------------------------------------------
// 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);
	} else if (_value.IsStringEmb()) {
		String str = Parser().EvalEmbeddedString(env, sig, _value.GetString());
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		return Value(env, str.c_str());
	} else if (_value.IsBinaryEmb()) {
		Binary binary = Parser().EvalEmbeddedBinary(env, sig, _value.GetBinary());
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		Value result;
		result.InitAsBinary(env, binary);
		return result;
	} else {
		return _value;
	}
}

Expr *Expr_Value::MathDiff(Environment &env, Signal sig, const Symbol *pSymbol) const
{
	return new Expr_Value(0);
}

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

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

String Expr_Value::ToString() const
{
	Signal sig;
	String str = _value.ToString(sig);
	if (_value.IsNumberOrComplex() && str[0] == '-') {
		str = "(" + str + ")";
	}
	return str;
}

//-----------------------------------------------------------------------------
// Expr_String
//-----------------------------------------------------------------------------
bool Expr_String::IsString() const { return true; }

Expr_String::~Expr_String()
{
}

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

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

Value Expr_String::Exec(Environment &env, Signal sig) const
{
	return Value(env, _str.c_str());
}

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

String Expr_String::ToString() const
{
	String str;
	str += '"';
	EscapeString(str, _str.c_str());
	str += '"';
	return str;
}

//-----------------------------------------------------------------------------
// 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);
}

Value Expr_Symbol::Exec(Environment &env, Signal sig) const
{
	return env.PropGet(sig, GetSymbol());
}

Value Expr_Symbol::DoAssign(Environment &env, Signal sig, Value &value,
					const SymbolSet *pSymbolsAssignable, bool escalateFlag) const
{
	bool evaluatedFlag = false;
	Value result = env.DoPropSet(sig, GetSymbol(), value, evaluatedFlag);
	if (sig.IsSignalled()) return Value::Null;
	if (evaluatedFlag) return result;
	if (pSymbolsAssignable != NULL && !pSymbolsAssignable->IsSet(GetSymbol())) {
		SetError_NotAssignableSymbol(sig, GetSymbol());
		return Value::Null;
	}
	if (_attrs.IsSet(AScript_Symbol(extern_))) {
		escalateFlag = true;
		if (env.LookupValue(GetSymbol(), true) == NULL) {
			sig.SetError(ERR_ValueError, "undefined symbol '%s'",
												GetSymbol()->GetName());
			return Value::Null;
		}
	}
	if (_attrs.IsSet(AScript_Symbol(local))) {
		escalateFlag = false;
	}
	ValueType valTypeCast = VTYPE_Any;
	if (!_attrFront.empty()) {
		const ValueTypeInfo *pValueTypeInfo = env.LookupValueType(_attrFront);
		if (pValueTypeInfo != NULL) {
			valTypeCast = pValueTypeInfo->GetValueType();
		}
	}
	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()) {
			ValueTypeInfo *pValueTypeInfo =
								ValueTypePool::GetInstance()->Add(GetSymbol());
			pValueTypeInfo->SetClass(pClassToConstruct);
			env.AssignValueType(pValueTypeInfo);
		}
	}
	if (valTypeCast != VTYPE_Any) {
		Declaration *pDecl = new Declaration(GetSymbol(), valTypeCast,
												OCCUR_Once, false, false, NULL);
		pDecl->ValidateAndCast(env, sig, value);
		Declaration::Delete(pDecl);
		if (sig.IsSignalled()) return Value::Null;
	}
	env.AssignValue(GetSymbol(), value, escalateFlag);
	return value;
}

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

Expr *Expr_Symbol::MathDiff(Environment &env, Signal sig, const Symbol *pSymbol) const
{
	Number num = GetSymbol()->IsIdentical(pSymbol)? 1 : 0;
	return new Expr_Value(num);
}

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

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

//-----------------------------------------------------------------------------
// Expr_Root
//-----------------------------------------------------------------------------
bool Expr_Root::IsRoot() const { return true; }

Expr_Root::~Expr_Root()
{
}

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

const char *Expr_Root::GetPathName() const
{
	return _pathName.c_str();
}

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

String Expr_Root::ToString() const
{
	return GetExprList().ToString();
}

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

Expr_Block::Expr_Block(const Expr_Block &expr) : Expr_Container(expr),
		_pExprBlockParam((expr._pExprBlockParam == NULL)? NULL :
				dynamic_cast<Expr_BlockParam *>(expr._pExprBlockParam->Clone()))
{
	if (_pExprBlockParam != NULL) _pExprBlockParam->SetParent(this);
}

Expr_Block::~Expr_Block()
{
	if (_pExprBlockParam != NULL) {
		_pExprBlockParam->SetParent(GetParent());
		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.IsType(ENVTYPE_Lister)) {
		return _exprOwner.ExecForList(env, sig, false, true);
	}
	return _exprOwner.Exec(env, sig, true);
}

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

String Expr_Block::ToString() const
{
	String str;
	str += "{";
	if (_pExprBlockParam != NULL) {
		str += _pExprBlockParam->ToString();
	}
	str += " ";
	str += GetExprList().ToString();
	if (!GetExprList().empty()) str += " ";
	str += "}";
	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, false);
}

String Expr_BlockParam::ToString() const
{
	String str;
	str += "|";
	str += GetExprList().ToString();
	str += "|";
	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);
}

Value Expr_Lister::Exec(Environment &env, Signal sig) const
{
	Value result;
	ValueList &valList = result.InitAsList(env);
	foreach_const (ExprOwner, ppExpr, _exprOwner) {
		const Expr *pExpr = *ppExpr;
		Value value = pExpr->Exec(env, sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		if (value.IsIterator()) {
			Iterator *pIterator = value.CreateIterator(sig);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
			if (pIterator->IsInfinite()) {
				Iterator::SetError_InfiniteNotAllowed(sig);
				Iterator::Delete(pIterator);
				sig.AddExprCause(this);
				return Value::Null;
			}
			Value value;
			while (pIterator->Next(env, sig, value)) {
				valList.push_back(value);
			}
			Iterator::Delete(pIterator);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
		} else {
			valList.push_back(value);
		}
	}
	return result;
}

Value Expr_Lister::DoAssign(Environment &env, Signal sig, Value &value,
					const SymbolSet *pSymbolsAssignable, bool escalateFlag) const
{
	const ExprList &exprList = GetExprList();
	if (value.IsList()) {
		ValueList *pValList = NULL;
		ExprList::const_iterator ppExpr = exprList.begin();
		foreach (ValueList, pValue, value.GetList()) {
			if (pValList != NULL) {
				pValList->push_back(*pValue);
				continue;
			}
			if (ppExpr == exprList.end()) break;
			const Expr *pExpr = *ppExpr;
			OccurPattern occurPattern = OCCUR_Once;
			if (pExpr->IsSuffix()) {
				const Expr_Suffix *pExprSuffix =
								dynamic_cast<const Expr_Suffix *>(pExpr);
				pExpr = pExprSuffix->GetChild();
				occurPattern = pExprSuffix->GetOccurPattern();
				if (occurPattern == OCCUR_Invalid) {
					SetError(sig, ERR_SyntaxError,
								"invalid expression of array assignment");
					return Value::Null;
				}
			}
			if (occurPattern == OCCUR_ZeroOrMore || occurPattern == OCCUR_OnceOrMore) {
				Value value;
				pValList = &value.InitAsList(env);
				pExpr->DoAssign(env, sig, value, pSymbolsAssignable, escalateFlag);
				if (sig.IsSignalled()) {
					sig.AddExprCause(this);
					return Value::Null;
				}
				pValList->push_back(*pValue);
			} else {
				pExpr->DoAssign(env, sig, *pValue, pSymbolsAssignable, escalateFlag);
				if (sig.IsSignalled()) {
					sig.AddExprCause(this);
					return Value::Null;
				}
			}
			ppExpr++;
		}
		for ( ; ppExpr != exprList.end(); ppExpr++) {
			const Expr *pExpr = *ppExpr;
			OccurPattern occurPattern = OCCUR_Once;
			if (pExpr->IsSuffix()) {
				const Expr_Suffix *pExprSuffix =
								dynamic_cast<const Expr_Suffix *>(pExpr);
				pExpr = pExprSuffix->GetChild();
				occurPattern = pExprSuffix->GetOccurPattern();
			}
			if (occurPattern == OCCUR_ZeroOrMore) {
				Value value;
				pValList = &value.InitAsList(env);
				pExpr->DoAssign(env, sig, value, pSymbolsAssignable, escalateFlag);
				if (sig.IsSignalled()) {
					sig.AddExprCause(this);
					return Value::Null;
				}
			} else if (occurPattern == OCCUR_Once || occurPattern == OCCUR_OnceOrMore) {
				SetError(sig, ERR_ValueError,
						"not enough value to initialize arrayed variables");
				return Value::Null;
			}
		}
	} else {
		foreach_const (ExprList, ppExpr, exprList) {
			const Expr *pExpr = *ppExpr;
			pExpr->DoAssign(env, sig, value, pSymbolsAssignable, escalateFlag);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
		}
	}
	return value;
}

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

//-----------------------------------------------------------------------------
// Expr_Compound
//-----------------------------------------------------------------------------
bool Expr_Compound::IsCompound() const { return true; }

Expr_Compound::Expr_Compound(ExprType exprType, Expr *pExprCar, Expr_Lister *pExprLister) :
			Expr(exprType), _pExprCar(pExprCar), _pExprLister(pExprLister)
{
	_pExprCar->SetParent(this);
	_pExprLister->SetParent(this);
}

Expr_Compound::Expr_Compound(const Expr_Compound &expr) : Expr(expr),
			_pExprCar(expr._pExprCar->Clone()),
			_pExprLister(dynamic_cast<Expr_Lister *>(expr._pExprLister->Clone()))
{
	_pExprCar->SetParent(this);
	_pExprLister->SetParent(this);
}

Expr_Compound::~Expr_Compound()
{
	_pExprCar->SetParent(GetParent());
	_pExprLister->SetParent(GetParent());
	Expr::Delete(_pExprCar);
	Expr::Delete(_pExprLister);
}

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

bool Expr_Compound::IsParentOf(const Expr *pExpr) const
{
	return _pExprCar == pExpr || _pExprLister == pExpr ||
			_pExprCar->IsParentOf(pExpr) || _pExprLister->IsParentOf(pExpr);
}

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

Expr_Indexer::~Expr_Indexer()
{
}

Expr *Expr_Indexer::IncRef() const
{
	return Expr_Compound::IncRef();
}

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

Value Expr_Indexer::Exec(Environment &env, Signal sig) const
{
	Value valueCar = GetCar()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	const ExprList &exprList = GetLister()->GetExprList();
	Object &objCar = *valueCar.GetObject();
	if (exprList.empty()) {
		return objCar.EmptyIndexGet(sig);
	}
	Value valueIdx = exprList.ExecForList(env, sig, true, false);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	ValueList &valIdxList = valueIdx.GetList();
	if (valIdxList.size() == 0) return Value::Null;
	if (!valueCar.IsObject()) {
		SetError(sig, ERR_ValueError, "object should be specified as l-value of indexer");
		return Value::Null;
	}
	Value result;
	if (valIdxList.size() == 1 && !valIdxList.front().IsListOrIterator()) {
		// obj[idx]
		result = objCar.IndexGet(sig, valIdxList.front());
	} else {
		// obj[idx, idx, ..]
		ValueList &valListDst = result.InitAsList(env);
		foreach_const (ValueList, pValueIdx, valIdxList) {
			if (pValueIdx->IsList() || pValueIdx->IsIterator()) {
				Iterator *pIteratorIdx = pValueIdx->CreateIterator(sig);
				if (sig.IsSignalled()) break;
				Value valueIdxEach;
				while (pIteratorIdx->Next(env, sig, valueIdxEach)) {
					Value value = objCar.IndexGet(sig, valueIdxEach);
					if (sig.IsSignalled()) {
						if (sig.GetErrorType() == ERR_IndexError &&
												pIteratorIdx->IsInfinite()) {
							sig.ClearSignal();
						}
						break;
					}
					valListDst.push_back(value);
				}
				Iterator::Delete(pIteratorIdx);
			} else {
				Value value = objCar.IndexGet(sig, *pValueIdx);
				if (sig.IsSignalled()) break;
				valListDst.push_back(value);
			}
		}
	}
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	return result;
}

Value Expr_Indexer::DoAssign(Environment &env, Signal sig, Value &value,
					const SymbolSet *pSymbolsAssignable, bool escalateFlag) const
{
	Value valueDst = GetCar()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	if (!valueDst.IsObject()) {
		SetError(sig, ERR_ValueError, "object is expected as l-value of indexer");
		return Value::Null;
	}
	const ExprList &exprList = GetLister()->GetExprList();
	Object &objDst = *valueDst.GetObject();
	if (exprList.empty()) {
		objDst.EmptyIndexSet(sig, value);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		return value;
	}
	if (exprList.size() == 1) {
		// obj[idx] = v / obj[idx] = [v, v, ..]
		Value valueIdx = exprList.front()->Exec(env, sig);
		if (sig.IsSignalled()) goto done;
		if (valueIdx.IsList() || valueIdx.IsIterator()) {
			Iterator *pIteratorIdx = valueIdx.CreateIterator(sig);
			if (sig.IsSignalled()) goto done;
			if (value.IsList() || value.IsIterator()) {
				Iterator *pIterator = value.CreateIterator(sig);
				if (sig.IsSignalled()) goto done;
				Value valueIdxEach, valueEach;
				while (pIteratorIdx->Next(env, sig, valueIdxEach) &&
											pIterator->Next(env, sig, valueEach)) {
					objDst.IndexSet(sig, valueIdxEach, valueEach);
					if (sig.IsSignalled()) break;
				}
			} else {
				Value valueIdxEach;
				while (pIteratorIdx->Next(env, sig, valueIdxEach)) {
					objDst.IndexSet(sig, valueIdxEach, value);
				}
			}
		} else {
			objDst.IndexSet(sig, valueIdx, value);
		}
	} else if (value.IsList() || value.IsIterator()) {
		// obj[idx, idx, ..] = [v, v, ..]
		Iterator *pIterator = value.CreateIterator(sig);
		if (sig.IsSignalled()) goto done;
		foreach_const (ExprList, ppExprCdr, exprList) {
			Value valueIdx = (*ppExprCdr)->Exec(env, sig);
			if (sig.IsSignalled()) break;
			if (valueIdx.IsList() || valueIdx.IsIterator()) {
				Iterator *pIteratorIdx = valueIdx.CreateIterator(sig);
				if (sig.IsSignalled()) break;
				Value valueIdxEach, valueEach;
				while (pIteratorIdx->Next(env, sig, valueIdxEach) &&
											pIterator->Next(env, sig, valueEach)) {
					objDst.IndexSet(sig, valueIdxEach, valueEach);
					if (sig.IsSignalled()) break;
				}
				Iterator::Delete(pIteratorIdx);
			} else {
				Value valueEach;
				if (!pIterator->Next(env, sig, valueEach)) break;
				objDst.IndexSet(sig, valueIdx, valueEach);
				if (sig.IsSignalled()) break;
			}
		}
		Iterator::Delete(pIterator);
	} else {
		// obj[idx, idx, ..] = v
		foreach_const (ExprList, ppExprCdr, exprList) {
			Value valueIdx = (*ppExprCdr)->Exec(env, sig);
			if (sig.IsSignalled()) goto done;
			if (valueIdx.IsList() || valueIdx.IsIterator()) {
				Iterator *pIteratorIdx = valueIdx.CreateIterator(sig);
				if (sig.IsSignalled()) break;
				Value valueIdxEach;
				while (pIteratorIdx->Next(env, sig, valueIdxEach)) {
					objDst.IndexSet(sig, valueIdxEach, value);
					if (sig.IsSignalled()) break;
				}
				Iterator::Delete(pIteratorIdx);
				if (sig.IsSignalled()) break;
			} else {
				objDst.IndexSet(sig, valueIdx, value);
				if (sig.IsSignalled()) break;
			}
		}
	}
done:
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	return value;
}

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

String Expr_Indexer::ToString() const
{
	String str;
	str += GetCar()->ToString();
	str += "[";
	str += GetLister()->GetExprList().ToString();
	str += "]";
	return str;
}

//-----------------------------------------------------------------------------
// Expr_Caller
//-----------------------------------------------------------------------------
bool Expr_Caller::IsCaller() const { return true; }

Expr_Caller::Expr_Caller(Expr *pExprCar, Expr_Lister *pExprLister, Expr_Block *pExprBlock) :
		Expr_Compound(EXPRTYPE_Caller,
				pExprCar, (pExprLister == NULL)? new Expr_Lister() : pExprLister),
		_pExprBlock(pExprBlock), _pExprCallerSucc(NULL)
{
	if (_pExprBlock != NULL) _pExprBlock->SetParent(this);
}

Expr_Caller::Expr_Caller(const Expr_Caller &expr) : Expr_Compound(expr),
		_pExprBlock((expr._pExprBlock == NULL)? NULL :
					dynamic_cast<Expr_Block *>(expr._pExprBlock->Clone())),
		_pExprCallerSucc((expr._pExprCallerSucc == NULL)? NULL :
					dynamic_cast<Expr_Caller *>(expr._pExprCallerSucc->Clone())),
		_attrs(expr._attrs), _attrsOpt(expr._attrsOpt)
{
	if (_pExprBlock != NULL) _pExprBlock->SetParent(this);
}

Expr_Caller::~Expr_Caller()
{
	if (_pExprBlock != NULL) {
		_pExprBlock->SetParent(GetParent());
		Expr::Delete(_pExprBlock);
	}
	if (_pExprCallerSucc != NULL) {
		_pExprCallerSucc->SetParent(GetParent());
		Expr::Delete(_pExprCallerSucc);
	}
}

Expr *Expr_Caller::IncRef() const
{
	if (_pExprBlock != NULL) _pExprBlock->IncRef();
	if (_pExprCallerSucc != NULL) _pExprCallerSucc->IncRef();
	return Expr_Compound::IncRef();
}

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

Value Expr_Caller::Exec(Environment &env, Signal sig) const
{
	Value result;
	const Function *pFuncSuccRequester = NULL;
	for (const Expr_Caller *pExprCaller = this; pExprCaller != NULL;
									pExprCaller = pExprCaller->GetSucceeding()) {
		result = pExprCaller->DoExec(env, sig, &pFuncSuccRequester);
		if (pFuncSuccRequester == NULL) break;
	}
	// if there's an error suspended by try() function, it would be resumed below.
	// otherwise, nothing would happen and any error would be kept intact.
	sig.ResumeError();
	return result;
}

Value Expr_Caller::DoExec(Environment &env, Signal sig,
									const Function **ppFuncSuccRequester) const
{
	// Expr_Caller::Exec(), Expr_Field::Exec() and Expr_Field::DoAssign()
	// correspond to method-calling, property-getting and property-setting.
	if (!_pExprCar->IsField()) {
		Value valueCar = _pExprCar->Exec(env, sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		ICallable *pCallable = valueCar.GetObject();
		if (pCallable == NULL) {
			SetError(sig, ERR_TypeError, "object is not callable");
			return Value::Null;
		}
		return pCallable->Call(env, sig, Value::Null, NULL, false,
									this, GetExprList(), ppFuncSuccRequester);
	}
	const Expr_Field *pExprField = dynamic_cast<Expr_Field *>(_pExprCar);
	Value valueSelf = pExprField->GetLeft()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	if (valueSelf.IsInvalid()) return valueSelf;
	Expr_Field::Mode mode = pExprField->GetMode();
	if (mode != Expr_Field::MODE_Normal) {
		ObjectBase *pObj = valueSelf.ExtractObject(sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		Iterator *pIteratorSelf = pObj->CreateIterator(sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		if (pIteratorSelf == NULL) {
			// nothing to do
		} else if (mode == Expr_Field::MODE_MapAlong) {
			Value valueSelfEach;
			if (!pIteratorSelf->Next(env, sig, valueSelfEach)) return Value::Null;
			return EvalEach(env, sig, valueSelfEach,
						pIteratorSelf, valueSelf.IsList(), ppFuncSuccRequester);
		} else {
			Iterator *pIteratorMap = new Iterator_MethodMap(env,
						pIteratorSelf, dynamic_cast<Expr_Caller *>(IncRef()));
			if (mode == Expr_Field::MODE_MapToIter) {
				return Value(env, pIteratorMap);
			}
			Value result = pIteratorMap->ToList(env, sig, false, false);
			Iterator::Delete(pIteratorMap);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
			return result;
		}
	}
	return EvalEach(env, sig, valueSelf, NULL, false, ppFuncSuccRequester);
}

Value Expr_Caller::EvalEach(Environment &env, Signal sig, const Value &valueSelf,
	Iterator *pIteratorSelf, bool listSelfFlag, const Function **ppFuncSuccRequester) const
{
	const Expr_Field *pExprField = dynamic_cast<Expr_Field *>(_pExprCar);
	const Expr *pExprRight = pExprField->GetRight();
	Value valueCar;
	ICallable *pCallable = NULL;
	ObjectBase *pObj;
	if (valueSelf.IsPrimitive()) {
		pObj = env.LookupClass(valueSelf.GetType());
	} else {
		pObj = valueSelf.ExtractObject(sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
	}
	if (pExprRight->IsSymbol()) {
		pCallable = pObj->GetCallable(sig,
					dynamic_cast<const Expr_Symbol *>(pExprRight)->GetSymbol());
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
	}
	if (pCallable == NULL) {
		valueCar = pExprRight->Exec(*pObj, sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		pCallable = valueCar.GetObject();
	}
	if (pCallable == NULL) {
		SetError(sig, ERR_TypeError, "object is not callable");
		return Value::Null;
	}
	return pCallable->Call(env, sig, valueSelf, pIteratorSelf, listSelfFlag,
								this, GetExprList(), ppFuncSuccRequester);
}

Value Expr_Caller::DoAssign(Environment &env, Signal sig, Value &value,
					const SymbolSet *pSymbolsAssignable, bool escalateFlag) const
{
	if (!value.IsExpr()) {
		SetError(sig, ERR_SyntaxError, "invalid function expression");
		return Value::Null;
	}
	Expr *pExprBody = value.GetExpr()->IncRef();
	// get symbol part of function's declaration
	const Symbol *pSymbol;
	if (GetCar()->IsField()) {
		const Expr_Field *pExprField =
						dynamic_cast<const Expr_Field *>(GetCar());
		if (pExprField->GetRight()->IsSymbol()) {
			const Expr_Symbol *pExprSym =
						dynamic_cast<const Expr_Symbol *>(pExprField->GetRight());
			pSymbol = pExprSym->GetSymbol();
		}
	} else if (GetCar()->IsSymbol()) {
		const Expr_Symbol *pExprSym =
						dynamic_cast<const Expr_Symbol *>(GetCar());
		pSymbol = pExprSym->GetSymbol();
	} else {
		SetError(sig, ERR_SyntaxError, "invalid function expression");
		return Value::Null;
	}
	if (pSymbolsAssignable != NULL && !pSymbolsAssignable->IsSet(pSymbol)) {
		SetError_NotAssignableSymbol(sig, pSymbol);
		return Value::Null;
	}
	FunctionType funcType = !env.IsClass()? FUNCTYPE_Function :
		GetAttrs().IsSet(AScript_Symbol(static_))? FUNCTYPE_Class : FUNCTYPE_Instance;
	FunctionCustom *pFunc = new FunctionCustom(env, pSymbol, pExprBody, funcType);
	Args args(GetExprList(), Value::Null, NULL, false, NULL, GetAttrs(), GetAttrsOpt(), _pExprBlock);
	if (!pFunc->CustomDeclare(env, sig, SymbolSet::Null, args)) {
		sig.AddExprCause(this);
		Function::Delete(pFunc);
		return Value::Null;
	}
	Value valueFunc(env, pFunc, Value::Null);
	GetCar()->DoAssign(env, sig, valueFunc, pSymbolsAssignable, escalateFlag);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	return valueFunc;
}

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

bool Expr_Caller::IsParentOf(const Expr *pExpr) const
{
	if (Expr_Compound::IsParentOf(pExpr)) return true;
	if (_pExprBlock == pExpr || _pExprCallerSucc == pExpr) return true;
	if (_pExprBlock != NULL && _pExprBlock->IsParentOf(pExpr)) return true;
	if (_pExprCallerSucc != NULL && _pExprCallerSucc->IsParentOf(pExpr)) return true;
	return false;
}

Expr *Expr_Caller::MathDiff(Environment &env, Signal sig, const Symbol *pSymbol) const
{
	// f(g(x))' = f(u)'g(x)'
	if (GetExprList().size() != 1) return NULL;
	const Expr *pExprArg = GetExprList().front();
	Value value = GetCar()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return NULL;
	}
	if (!value.IsFunction()) {
		SetError(sig, ERR_ValueError, "object must be a function");
		return NULL;
	}
	Expr *pExprArgDiff = pExprArg->MathDiff(env, sig, pSymbol);
	if (pExprArgDiff == NULL) return NULL;
	if (pExprArgDiff->IsConstNumber(0)) {
		return pExprArgDiff;
	}
	Expr *pExprFuncDiff = value.GetFunction()->DiffUnary(env, sig, pExprArg, pSymbol);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return NULL;
	}
	if (pExprArgDiff->IsConstNumber(1)) {
		Expr::Delete(pExprArgDiff);
		return pExprFuncDiff;
	}
	return Func_Multiply::OptimizedExpr(env, sig, pExprFuncDiff, pExprArgDiff);
}

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

String Expr_Caller::ToString() const
{
	String str;
	str += _pExprCar->ToString();
	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 += " ";
		}
	}
	if (argListFlag) {
		str += "(";
		str += GetExprList().ToString();
		str += ")";
	}
	foreach_const (SymbolSet, ppSymbol, _attrs) {
		const Symbol *pSymbol = *ppSymbol;
		str += ":";
		str += pSymbol->GetName();
	}
	if (_pExprBlock != NULL) {
		str += " ";
		str += _pExprBlock->ToString();
	}
	if (_pExprCallerSucc != NULL) {
		str += " ";
		str += _pExprCallerSucc->ToString();
	}
	return str;
}

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

Expr_UnaryOp::~Expr_UnaryOp()
{
}

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

Value Expr_UnaryOp::Exec(Environment &env, Signal sig) const
{
	Args args(GetExprList());
	Value result = _func.EvalExpr(env, sig, args);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	return result;
}

Expr *Expr_UnaryOp::MathDiff(Environment &env, Signal sig, const Symbol *pSymbol) const
{
	return _func.DiffUnary(env, sig, GetChild(), pSymbol);
}

Expr *Expr_UnaryOp::MathOptimize(Environment &env, Signal sig) const
{
	Expr *pExprOpt = GetChild()->MathOptimize(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return NULL;
	}
	return _func.OptimizeUnary(env, sig, pExprOpt);
}

String Expr_UnaryOp::ToString() const
{
	bool needParenthesisFlag = false;
	if (GetParent() != NULL) {
		needParenthesisFlag = (GetParent()->IsUnaryOp() ||
					GetParent()->IsBinaryOp() || GetParent()->IsField());
	}
	String str;
	if (needParenthesisFlag) str += "(";
	if (!_suffixSymbolFlag) str += _func.GetMathSymbol();
	str += GetChild()->ToString();
	if (_suffixSymbolFlag) str += _func.GetMathSymbol();
	if (needParenthesisFlag) str += ")";
	return str;
}

//-----------------------------------------------------------------------------
// Expr_BinaryOp
//-----------------------------------------------------------------------------
bool Expr_BinaryOp::IsBinaryOp() const { return true; }

Expr_BinaryOp::~Expr_BinaryOp()
{
}

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

Value Expr_BinaryOp::Exec(Environment &env, Signal sig) const
{
	Args args(GetExprList());
	Value result = _func.EvalExpr(env, sig, args);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	return result;
}

Expr *Expr_BinaryOp::MathDiff(Environment &env, Signal sig, const Symbol *pSymbol) const
{
	return _func.DiffBinary(env, sig, GetLeft(), GetRight(), pSymbol);
}

Expr *Expr_BinaryOp::MathOptimize(Environment &env, Signal sig) const
{
	Expr *pExprOpt1 = GetLeft()->MathOptimize(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return NULL;
	}
	Expr *pExprOpt2 = GetRight()->MathOptimize(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		Expr::Delete(pExprOpt1);
		return NULL;
	}
	return _func.OptimizeBinary(env, sig, pExprOpt1, pExprOpt2);
}

String Expr_BinaryOp::ToString() const
{
	bool needParenthesisFlag = false;
	if (GetParent() == NULL) {
		// nothing to do
	} else if (GetParent()->IsUnaryOp()) {
		const Expr_UnaryOp *pExprOuter =
								dynamic_cast<const Expr_UnaryOp *>(GetParent());
		needParenthesisFlag = NeedParenthesis(pExprOuter->GetFunction(),
							GetFunction(), false);
	} else if (GetParent()->IsBinaryOp()) {
		const Expr_BinaryOp *pExprOuter =
								dynamic_cast<const Expr_BinaryOp *>(GetParent());
		needParenthesisFlag = NeedParenthesis(pExprOuter->GetFunction(),
							GetFunction(), pExprOuter->GetRight() == this);
	} else if (GetParent()->IsField()) {
		needParenthesisFlag = true;
	}
	String str;
	if (needParenthesisFlag) str += "(";
	str += GetLeft()->ToString();
	str += " ";
	str += _func.GetMathSymbol();
	str += " ";
	str += GetRight()->ToString();
	if (needParenthesisFlag) str += ")";
	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 GetChild();
}

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

String Expr_Quote::ToString() const
{
	String str;
	str += "`";
	str += GetChild()->ToString();
	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
{
	Value result = GetChild()->Exec(env, sig);
	return result;
}

String Expr_Force::ToString() const
{
	String str;
	str += "!!";
	str += GetChild()->ToString();
	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
{
	SetError(sig, ERR_SyntaxError, "invalid expression");
	return Value::Null;
}

String Expr_Prefix::ToString() const
{
	String str;
	str += _pSymbol->GetName();
	str += GetChild()->ToString();
	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
{
	SetError(sig, ERR_SyntaxError, "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() const
{
	String str;
	str += GetChild()->ToString();
	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 = GetLeft();
	bool funcAssignFlag = false;
	if (pExpr->IsCaller()) {
		if (_pFuncToApply != NULL) {
			SetError(sig, ERR_SyntaxError, "invalid operation");
			return Value::Null;
		}
		if (GetRight()->IsForce()) {
			value = GetRight()->Exec(env, sig);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
		} else {
			Expr *pExprBody = GetRight()->Unquote()->IncRef();
			value.InitAsExpr(env, pExprBody);
		}
	} else {
		value = GetRight()->Exec(env, sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		if (_pFuncToApply != NULL) {
			Value valueLeft = pExpr->Exec(env, sig);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
			ValueList valListArg(valueLeft, value);
			Args args(valListArg);
			value = _pFuncToApply->GetDeclOwner().ShouldImplicitMap(valListArg)?
							_pFuncToApply->EvalMap(env, sig, args) :
							_pFuncToApply->Eval(env, sig, args);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
		}
	}
	return GetLeft()->DoAssign(envDst, sig, value, pSymbolsAssignable, true);
}

String Expr_Assign::ToString() const
{
	String str;
	str += GetLeft()->ToString();
	str += " ";
	if (_pFuncToApply != NULL) str += _pFuncToApply->GetMathSymbol();
	str += "= ";
	str += GetRight()->ToString();
	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);
	Value valueKey = GetLeft()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	Value value = GetRight()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	valList.reserve(2);
	valList.push_back(valueKey);
	valList.push_back(value);
	return result;
}

String Expr_DictAssign::ToString() const
{
	String str;
	str += GetLeft()->Unquote()->ToString();
	str += " => ";
	str += GetRight()->ToString();
	return str;
}

Value Expr_DictAssign::GetKey(Environment &env, Signal sig) const
{
	const Expr *pExpr = GetLeft()->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 if (pExpr->IsString()) {
		return Value(env, dynamic_cast<const Expr_String *>(pExpr)->GetString());
	} else {
		SetError(sig, ERR_KeyError,
				"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
{
	// Expr_Caller::Exec(), Expr_Field::Exec() and Expr_Field::DoAssign()
	// correspond to method-calling, property-getting and property-setting.
	Value valueSelf = GetLeft()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	if (valueSelf.IsInvalid()) return valueSelf;
	ObjectBase *pObj = valueSelf.ExtractObject(sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	Mode mode = GetMode();
	if (mode != MODE_Normal) {
		Iterator *pIterator = pObj->CreateIterator(sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		if (pIterator != NULL) {
			Iterator *pIteratorMap =
					new Iterator_MemberMap(pIterator, GetRight()->IncRef());
			if (mode == MODE_MapToIter) {
				return Value(env, pIteratorMap);
			}
			Value result = pIteratorMap->ToList(env, sig, false, false);
			Iterator::Delete(pIteratorMap);
			if (sig.IsSignalled()) {
				sig.AddExprCause(this);
				return Value::Null;
			}
			return result;
		}
	}
	Value result;
	if (pObj->IsModule()) {
		Environment envLocal(pObj, ENVTYPE_Field);
		result = GetRight()->Exec(envLocal, sig);
	} else {
		result = GetRight()->Exec(*pObj, sig);
	}
	if (result.IsFunction()) {
		Object_Function *pObjFunc =
			dynamic_cast<Object_Function *>(result.GetFunctionObj()->Clone());
		pObjFunc->SetSelf(valueSelf);
		result = Value(pObjFunc);
	}
	return result;
}

Value Expr_Field::DoAssign(Environment &env, Signal sig, Value &value,
					const SymbolSet *pSymbolsAssignable, bool escalateFlag) const
{
	// Expr_Caller::Exec(), Expr_Field::Exec() and Expr_Field::DoAssign()
	// correspond to method-calling, property-getting and property-setting.
	Value valueSelf = GetLeft()->Exec(env, sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	ObjectBase *pObj = valueSelf.ExtractObject(sig);
	if (sig.IsSignalled()) {
		sig.AddExprCause(this);
		return Value::Null;
	}
	Mode mode = GetMode();
	if (mode == MODE_Normal) {
		return GetRight()->DoAssign(*pObj, sig, value, pSymbolsAssignable, escalateFlag);
	}
	Iterator *pIteratorSelf = pObj->CreateIterator(sig);
	if (pIteratorSelf == NULL) {
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		return GetRight()->DoAssign(*pObj, sig, value, pSymbolsAssignable, escalateFlag);
	}
	if (value.IsList() || value.IsIterator()) {
		Iterator *pIteratorValue = value.CreateIterator(sig);
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			return Value::Null;
		}
		Value value;
		Value valueSelfEach;
		while (pIteratorSelf->Next(env, sig, valueSelfEach) &&
								pIteratorValue->Next(env, sig, value)) {
			ObjectBase *pObjEach = valueSelfEach.ExtractObject(sig);
			if (sig.IsSignalled()) break;
			GetRight()->DoAssign(*pObjEach, sig, value,
									pSymbolsAssignable, escalateFlag);
			if (sig.IsSignalled()) break;
		}
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			Iterator::Delete(pIteratorValue);
			Iterator::Delete(pIteratorSelf);
			return Value::Null;
		}
	} else {
		Value valueSelfEach;
		while (pIteratorSelf->Next(env, sig, valueSelfEach)) {
			ObjectBase *pObjEach = valueSelfEach.ExtractObject(sig);
			if (sig.IsSignalled()) break;
			GetRight()->DoAssign(*pObjEach, sig, value, pSymbolsAssignable, escalateFlag);
			if (sig.IsSignalled()) break;
		}
		if (sig.IsSignalled()) {
			sig.AddExprCause(this);
			Iterator::Delete(pIteratorSelf);
			return Value::Null;
		}
	}
	Iterator::Delete(pIteratorSelf);
	return value;
}

String Expr_Field::ToString() const
{
	String str;
	str += GetLeft()->ToString();
	str +=
		(_mode == MODE_Normal)? "." :
		(_mode == MODE_MapToList)? "::" :
		(_mode == MODE_MapToIter)? ":*" :
		(_mode == MODE_MapAlong)? ":::" : "????";
	str += GetRight()->ToString();
	return str;
}

//-----------------------------------------------------------------------------
// 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, bool evalSymFuncFlag) const
{
	Value result;
	foreach_const (ExprList, ppExpr, *this) {
		result = (*ppExpr)->Exec(env, sig);
		if (sig.IsSignalled()) {
			break;
		}
		if (evalSymFuncFlag && result.IsFunction() &&
									result.GetFunction()->IsSymbolFunc()) {
			// symbol functions are only evaluated by a sequence of block.
			// in the folloiwng example, "return" shall be evaluated by a block
			// of "if" function.
			//   repeat { if (flag) { return } }
			// in the following example, "&&" operator returns "return" function
			// object as its result, and then the block of "repeat" shall evaluate it.
			//   repeat { flag && return }
			const Function *pFunc = result.GetFunction();
			Args args(ExprList::Null);
			Value result = pFunc->EvalExpr(env, sig, args);
			if (sig.IsSignalled()) {
				sig.AddExprCause(*ppExpr);
				return Value::Null;
			}
		}
	}
	return result;
}

Value ExprList::ExecInRoot(Environment &env, Signal sig) const
{
	Value result;
	foreach_const (ExprList, ppExpr, *this) {
		result = (*ppExpr)->Exec(env, sig);
		if (sig.IsError()) {
			Stream *pConsole = env.GetConsole(false);
			if (pConsole != NULL) {
				String str;
				str += sig.GetErrString();
				str += "\n";
				str += sig.GetErrTrace();
				pConsole->Print(sig, str.c_str());
			}
			sig.ClearSignal();
			return Value::Null;
		} else if (sig.IsSignalled()) {
			Stream *pConsole = env.GetConsole(false);
			if (pConsole != NULL) {
				pConsole->Println(sig, sig.GetSignalName());
			}
			sig.ClearSignal();
		} else if (!env.GetEchoFlag()) {
			// nothing to do
		} else if (result.IsValid()) {
			Stream *pConsole = env.GetConsole(false);
			if (pConsole != NULL) {
				pConsole->Println(sig, result.ToString(sig).c_str());
			}
		}
	}
	return result;
}

Value ExprList::ExecForList(Environment &env, Signal sig,
									bool flattenFlag, bool evalSymFuncFlag) 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 (evalSymFuncFlag && value.IsFunction() &&
									value.GetFunction()->IsSymbolFunc()) {
			const Function *pFunc = result.GetFunction();
			Args args(ExprList::Null);
			Value result = pFunc->EvalExpr(env, sig, args);
			if (sig.IsSignalled()) {
				sig.AddExprCause(*ppExpr);
				return Value::Null;
			}
		} else if (flattenFlag && value.IsList()) {
			ValueVisitorEx visitor(valList);
			value.Accept(sig, visitor);
		} else {
			valList.push_back(value);
		}
	}
	return result;
}

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

bool ExprList::IsContained(const Expr *pExpr) const
{
	return std::find(begin(), end(), const_cast<Expr *>(pExpr)) != end();
}

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

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

void ExprList::SetParent(const Expr *pExpr)
{
	foreach_const (ExprList, ppExpr, *this) {
		(*ppExpr)->SetParent(pExpr);
	}
}

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

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

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

}
