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

namespace AScript {

//-----------------------------------------------------------------------------
// basic operator
//-----------------------------------------------------------------------------
// -v
bool Func_Neg::IsNeg() const { return true; }

Func_Neg::Func_Neg(Environment &env) : Function(_T("__neg__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("-"));
	DeclareArg(env, _T("value"), VTYPE_AnyType);
}

Value Func_Neg::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &value = context.GetValue(0);
	Value result;
	if (value.IsNumber()) {
		result.SetNumber(-value.GetNumber());
		return result;
	} else if (value.IsComplex()) {
		result.SetComplex(-value.GetComplex());
		return result;
	}
	SetError_InvalidValType(sig, value);
	return result;
}

Expr *Func_Neg::Diff(Environment &env, Signal sig,
					const ExprList &exprArgs, const Symbol *pSymbolVar) const
{
	const Expr *pExprChild = exprArgs[0];
	Expr *pExprChildGen = pExprChild->Diff(env, sig, pSymbolVar);
	if (pExprChildGen == NULL) return NULL;
	return Optimize(env, sig, ExprList(pExprChildGen));
}

Expr *Func_Neg::Optimize(Environment &env, Signal sig, ExprList &exprArgs) const
{
	Expr *pExpr = exprArgs[0];
	if (pExpr->IsValue()) {
		Value value = dynamic_cast<Expr_Value *>(pExpr)->GetValue();
		Expr::Delete(pExpr);
		return new Expr_Value(DoEval(env, sig, Context(ValueList(value))));
	} else if (pExpr->IsNeg()) {
		// -(-x) = x
		Expr *pExprInner =
				dynamic_cast<Expr_UnaryOp *>(pExpr)->GetExprChild()->IncRef();
		Expr::Delete(pExpr);
		return pExprInner;
	}
	return new Expr_UnaryOp(env.GetFunc_Neg(), pExpr);
}

// ~v
Func_Invert::Func_Invert(Environment &env) : Function(_T("__invert__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("~"));
	DeclareArg(env, _T("value"), VTYPE_AnyType);
}

Value Func_Invert::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &value = context.GetValue(0);
	Value result;
	if (value.IsNumber()) {
		unsigned long num = ~static_cast<unsigned long>(value.GetNumber());
		result.SetNumber(static_cast<Number>(num));
		return result;
	}
	SetError_InvalidValType(sig, value);
	return result;
}

// !v
Func_Not::Func_Not(Environment &env) : Function(_T("__not__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("!"));
	DeclareArg(env, _T("flag"), VTYPE_Boolean);
}

Value Func_Not::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	result.SetBoolean(!context.GetBoolean(0));
	return result;
}

// v = v + v
bool Func_Plus::IsPlus() const { return true; }

Func_Plus::Func_Plus(Environment &env) : Function(_T("__add__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("+"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Plus::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		result.SetNumber(valueLeft.GetNumber() + valueRight.GetNumber());
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsComplex()) {
		result.SetComplex(valueLeft.GetComplex() + valueRight.GetComplex());
		return result;
	} else if (valueLeft.IsNumber() && valueRight.IsComplex()) {
		result.SetComplex(valueLeft.GetNumber() + valueRight.GetComplex());
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsNumber()) {
		result.SetComplex(valueLeft.GetComplex() + valueRight.GetNumber());
		return result;
	} else if (valueLeft.IsString() && valueRight.IsString()) {
		String str(valueLeft.GetString());
		str += valueRight.GetString();
		result = Value(env, str.c_str());
		return result;
	} else if (valueLeft.IsString()) {
		String str(valueLeft.GetString());
		str += valueRight.ToString(sig);
		result = Value(env, str.c_str());
		return result;
	} else if (valueRight.IsString()) {
		String str(valueLeft.ToString(sig));
		str += valueRight.GetString();
		result = Value(env, str.c_str());
		return result;
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return Value::Null;
}

Expr *Func_Plus::Diff(Environment &env, Signal sig,
					const ExprList &exprArgs, const Symbol *pSymbolVar) const
{
	const Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	// (f(x) + g(x))' = f'(x) + g'(x)
	Expr *pExprLeftGen = pExprLeft->Diff(env, sig, pSymbolVar);
	if (pExprLeftGen == NULL) return NULL;
	Expr *pExprRightGen = pExprRight->Diff(env, sig, pSymbolVar);
	if (pExprRightGen == NULL) {
		Expr::Delete(pExprLeftGen);
		return NULL;
	}
	return Optimize(env, sig, ExprList(pExprLeftGen, pExprRightGen));
}

Expr *Func_Plus::Optimize(Environment &env, Signal sig, ExprList &exprArgs) const
{
	Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	if (pExprLeft->IsValue() && pExprRight->IsValue()) {
		Value valueLeft = dynamic_cast<Expr_Value *>(pExprLeft)->GetValue();
		Value valueRight = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return new Expr_Value(env.GetFunc_Plus().Eval(env, sig,
								Context(ValueList(valueLeft, valueRight))));
	} else if (pExprLeft->IsConstZero()) {
		// 0 + y = y
		Expr::Delete(pExprLeft);
		return pExprRight;
	} else if (pExprRight->IsConstZero()) {
		// x + 0 = x
		Expr::Delete(pExprRight);
		return pExprLeft;
	} else if (pExprRight->IsConstMinus()) {
		// x + (-n) = x - n
		Value value = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprRight);
		return env.GetFunc_Minus().Optimize(env, sig,
			ExprList(pExprLeft, new Expr_Value(-value.GetNumber())));
	} else if (pExprRight->IsNeg()) {
		// x + (-y) = x - y
		Expr *pExprInner =
			dynamic_cast<Expr_UnaryOp *>(pExprRight)->GetExprChild()->IncRef();
		Expr::Delete(pExprRight);
		return env.GetFunc_Minus().Optimize(env, sig, ExprList(pExprLeft, pExprInner));
	} else if (pExprLeft->IsValue() && !pExprRight->IsValue()) {
		// C + x = x + C
		return env.GetFunc_Plus().Optimize(env, sig, ExprList(pExprRight, pExprLeft));
	}
	return new Expr_BinaryOp(env.GetFunc_Plus(), pExprLeft, pExprRight);
}

// v = v - v
bool Func_Minus::IsMinus() const { return true; }

Func_Minus::Func_Minus(Environment &env) : Function(_T("__sub__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("-"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Minus::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		result.SetNumber(valueLeft.GetNumber() - valueRight.GetNumber());
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsComplex()) {
		result.SetComplex(valueLeft.GetComplex() - valueRight.GetComplex());
		return result;
	} else if (valueLeft.IsNumber() && valueRight.IsComplex()) {
		result.SetComplex(valueLeft.GetNumber() - valueRight.GetComplex());
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsNumber()) {
		result.SetComplex(valueLeft.GetComplex() - valueRight.GetNumber());
		return result;
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

Expr *Func_Minus::Diff(Environment &env, Signal sig,
					const ExprList &exprArgs, const Symbol *pSymbolVar) const
{
	const Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	// (f(x) - g(x))' = f'(x) - g'(x)
	Expr *pExprLeftGen = pExprLeft->Diff(env, sig, pSymbolVar);
	if (sig.IsSignalled()) return NULL;
	Expr *pExprRightGen = pExprRight->Diff(env, sig, pSymbolVar);
	if (sig.IsSignalled()) {
		Expr::Delete(pExprLeftGen);
		return NULL;
	}
	return Optimize(env, sig, ExprList(pExprLeftGen, pExprRightGen));
}

Expr *Func_Minus::Optimize(Environment &env, Signal sig, ExprList &exprArgs) const
{
	Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	if (pExprLeft->IsValue() && pExprRight->IsValue()) {
		Value valueLeft = dynamic_cast<Expr_Value *>(pExprLeft)->GetValue();
		Value valueRight = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return new Expr_Value(env.GetFunc_Minus().Eval(env, sig,
								Context(ValueList(valueLeft, valueRight))));
	} else if (pExprLeft->IsConstZero()) {
		// 0 + y = y
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(pExprRight));
	} else if (pExprRight->IsConstZero()) {
		// x + 0 = x
		return pExprLeft;
	} else if (pExprRight->IsConstMinus()) {
		// x - (-n) = x + n
		Value value = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprRight);
		return env.GetFunc_Plus().Optimize(env, sig,
			ExprList(pExprLeft, new Expr_Value(-value.GetNumber())));
	} else if (pExprRight->IsNeg()) {
		// x - (-y) = x + y
		Expr *pExprInner =
			dynamic_cast<Expr_UnaryOp *>(pExprRight)->GetExprChild()->IncRef();
		Expr::Delete(pExprRight);
		return env.GetFunc_Plus().Optimize(env, sig, ExprList(pExprLeft, pExprInner));
	} else if (pExprLeft->IsValue() && !pExprRight->IsValue()) {
		// C - x = -x + C
		return env.GetFunc_Plus().Optimize(env, sig, ExprList(
			env.GetFunc_Neg().Optimize(env, sig, ExprList(pExprRight)),
			pExprLeft));
	}
	return new Expr_BinaryOp(env.GetFunc_Minus(), pExprLeft, pExprRight);
}

// v = v * v
bool Func_Multiply::IsMultiply() const { return true; }

Func_Multiply::Func_Multiply(Environment &env) : Function(_T("__mul__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("*"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Multiply::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		result.SetNumber(valueLeft.GetNumber() * valueRight.GetNumber());
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsComplex()) {
		result.SetComplex(valueLeft.GetComplex() * valueRight.GetComplex());
		return result;
	} else if (valueLeft.IsNumber() && valueRight.IsComplex()) {
		result.SetComplex(valueLeft.GetNumber() * valueRight.GetComplex());
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsNumber()) {
		result.SetComplex(valueLeft.GetComplex() * valueRight.GetNumber());
		return result;
	} else if (valueLeft.IsFunction()) {
		const Function *pFunc = valueLeft.GetFunction();
		if (pFunc->IsUnary()) {
			result = pFunc->Eval(env, sig, Context(ValueList(valueRight)));
			if (sig.IsSignalled()) return Value::Null;
		} else {
			sig.SetError(ERR_TypeError, _T("unary function is expected for multiplier-form applier"));
			return Value::Null;
		}
		return result;
	} else if (valueLeft.IsString() && valueRight.IsNumber()) {
		String str;
		for (int cnt = valueRight.GetNumber(); cnt > 0; cnt--) {
			str += valueLeft.GetString();
		}
		result = Value(env, str.c_str());
		return result;
	} else if (valueLeft.IsNumber() && valueRight.IsString()) {
		String str;
		for (int cnt = valueLeft.GetNumber(); cnt > 0; cnt--) {
			str += valueRight.GetString();
		}
		result = Value(env, str.c_str());
		return result;
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

Expr *Func_Multiply::Diff(Environment &env, Signal sig,
					const ExprList &exprArgs, const Symbol *pSymbolVar) const
{
	const Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	// (f(x)g(x))' = f'(x)g(x) + f(x)g'(x)
	Expr *pExprLeftGen = pExprLeft->Diff(env, sig, pSymbolVar);
	if (sig.IsSignalled()) return NULL;
	Expr *pExprRightGen = pExprRight->Diff(env, sig, pSymbolVar);
	if (sig.IsSignalled()) {
		Expr::Delete(pExprLeftGen);
		return NULL;
	}
	return env.GetFunc_Plus().Optimize(env, sig, ExprList(
		env.GetFunc_Multiply().Optimize(env, sig,
						ExprList(pExprLeftGen, pExprRight->IncRef())),
		env.GetFunc_Multiply().Optimize(env, sig,
						ExprList(pExprLeft->IncRef(), pExprRightGen))));
}

Expr *Func_Multiply::Optimize(Environment &env, Signal sig, ExprList &exprArgs) const
{
	Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	if (pExprLeft->IsValue() && pExprRight->IsValue()) {
		Value valueLeft = dynamic_cast<Expr_Value *>(pExprLeft)->GetValue();
		Value valueRight = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return new Expr_Value(env.GetFunc_Multiply().Eval(env, sig,
								Context(ValueList(valueLeft, valueRight))));
	} else if (pExprLeft->IsConstZero()) {
		// 0 * y = 0
		Expr::Delete(pExprRight);
		return pExprLeft;
	} else if (pExprRight->IsConstZero()) {
		// x * 0 = 0
		Expr::Delete(pExprLeft);
		return pExprRight;
	} else if (pExprLeft->IsConstOne()) {
		// 1 * y = y
		Expr::Delete(pExprLeft);
		return pExprRight;
	} else if (pExprRight->IsConstOne()) {
		// x * 1 = x
		Expr::Delete(pExprRight);
		return pExprLeft;
	} else if (pExprLeft->IsConstMinusOne()) {
		// -1 * y = -y
		Expr::Delete(pExprLeft);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(pExprRight));
	} else if (pExprRight->IsConstMinusOne()) {
		// x * (-1) = -x
		Expr::Delete(pExprRight);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(pExprLeft));
	} else if (pExprRight->IsValue()) {
		// x * C = C * x
		return env.GetFunc_Multiply().Optimize(env, sig, ExprList(pExprRight, pExprLeft));
	} else if (pExprLeft->IsNeg()) {
		// (-x) * y = -(x * y)
		Expr *pExprLeftInner =
			dynamic_cast<Expr_UnaryOp *>(pExprLeft)->GetExprChild()->IncRef();
		Expr::Delete(pExprLeft);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(
				env.GetFunc_Multiply().Optimize(env, sig,
								ExprList(pExprLeftInner, pExprRight))));
	} else if (pExprRight->IsNeg()) {
		// x * (-y) = -(x * y)
		Expr *pExprRightInner =
			dynamic_cast<Expr_UnaryOp *>(pExprRight)->GetExprChild()->IncRef();
		Expr::Delete(pExprRight);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(
				env.GetFunc_Multiply().Optimize(env, sig,
								ExprList(pExprLeft, pExprRightInner))));
	}
	return new Expr_BinaryOp(env.GetFunc_Multiply(), pExprLeft, pExprRight);
}

// v = v / v
bool Func_Divide::IsDivide() const { return true; }

Func_Divide::Func_Divide(Environment &env) : Function(_T("__div__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("/"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Divide::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		Number numRight = valueRight.GetNumber();
		if (numRight == 0) {
			SetError_DivideByZero(sig);
			return Value::Null;
		}
		result.SetNumber(valueLeft.GetNumber() / numRight);
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsComplex()) {
		Complex numRight = valueRight.GetComplex();
		if (numRight == Complex(0.)) {
			SetError_DivideByZero(sig);
			return Value::Null;
		}
		result.SetComplex(valueLeft.GetComplex() / valueRight.GetComplex());
		return result;
	} else if (valueLeft.IsNumber() && valueRight.IsComplex()) {
		Complex numRight = valueRight.GetComplex();
		if (numRight == Complex(0.)) {
			SetError_DivideByZero(sig);
			return Value::Null;
		}
		result.SetComplex(valueLeft.GetNumber() / numRight);
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsNumber()) {
		Number numRight = valueRight.GetNumber();
		if (numRight == 0) {
			SetError_DivideByZero(sig);
			return Value::Null;
		}
		result.SetComplex(valueLeft.GetComplex() / numRight);
		return result;
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

Expr *Func_Divide::Diff(Environment &env, Signal sig,
					const ExprList &exprArgs, const Symbol *pSymbolVar) const
{
	const Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	// (f(x) / g(x))' = (f'(x)g(x) - f(x)g'(x)) / {g(x)}**2
	Expr *pExprLeftGen = pExprLeft->Diff(env, sig, pSymbolVar);
	if (sig.IsSignalled()) return NULL;
	Expr *pExprRightGen = pExprRight->Diff(env, sig, pSymbolVar);
	if (sig.IsSignalled()) {
		Expr::Delete(pExprLeftGen);
		return NULL;
	}
	return env.GetFunc_Divide().Optimize(env, sig, ExprList(
		env.GetFunc_Minus().Optimize(env, sig, ExprList(
			env.GetFunc_Multiply().Optimize(env, sig,
						ExprList(pExprLeftGen, pExprRight->IncRef())),
			env.GetFunc_Multiply().Optimize(env, sig,
						ExprList(pExprLeft->IncRef(), pExprRightGen)))),
		env.GetFunc_Power().Optimize(env, sig,
						ExprList(pExprRight->IncRef(), new Expr_Value(2.)))));
}

Expr *Func_Divide::Optimize(Environment &env, Signal sig, ExprList &exprArgs) const
{
	Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	if (pExprLeft->IsValue() && pExprRight->IsValue()) {
		Value valueLeft = dynamic_cast<Expr_Value *>(pExprLeft)->GetValue();
		Value valueRight = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return new Expr_Value(env.GetFunc_Divide().Eval(env, sig,
								Context(ValueList(valueLeft, valueRight))));
	} else if (pExprLeft->IsConstZero()) {
		// 0 / y = 0
		Expr::Delete(pExprRight);
		return pExprLeft;
	} else if (pExprRight->IsConstZero()) {
		// x / 0 = error
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		SetError_DivideByZero(sig);
		return new Expr_Value(0.);
	} else if (pExprRight->IsConstOne()) {
		// x / 1 = x
		Expr::Delete(pExprRight);
		return pExprLeft;
	} else if (pExprRight->IsConstMinusOne()) {
		// x / (-1) = -x
		Expr::Delete(pExprRight);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(pExprLeft));
	} else if (pExprRight->IsConstMinus()) {
		// x / (-n) = -(x / n)
		Value value = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprRight);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(
			env.GetFunc_Divide().Optimize(env, sig,
				ExprList(pExprLeft, new Expr_Value(-value.GetNumber())))));
	} else if (pExprLeft->IsNeg() && pExprRight->IsNeg()) {
		// (-x) / (-y) = x / y
		Expr *pExprLeftInner =
			dynamic_cast<Expr_UnaryOp *>(pExprLeft)->GetExprChild()->IncRef();
		Expr *pExprRightInner =
			dynamic_cast<Expr_UnaryOp *>(pExprRight)->GetExprChild()->IncRef();
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return env.GetFunc_Divide().Optimize(env, sig,
							ExprList(pExprLeftInner, pExprRightInner));
	} else if (pExprLeft->IsNeg()) {
		// (-x) / y = -(x / y)
		Expr *pExprLeftInner =
			dynamic_cast<Expr_UnaryOp *>(pExprLeft)->GetExprChild()->IncRef();
		Expr::Delete(pExprLeft);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(
			env.GetFunc_Divide().Optimize(env, sig,
							ExprList(pExprLeftInner, pExprRight))));
	} else if (pExprRight->IsNeg()) {
		// x / (-y) = -(x / y)
		Expr *pExprRightInner =
			dynamic_cast<Expr_UnaryOp *>(pExprRight)->GetExprChild()->IncRef();
		Expr::Delete(pExprRight);
		return env.GetFunc_Neg().Optimize(env, sig, ExprList(
			env.GetFunc_Divide().Optimize(env, sig,
									ExprList(pExprLeft, pExprRightInner))));
	}
	return new Expr_BinaryOp(env.GetFunc_Divide(), pExprLeft, pExprRight);
}

// num = mod(num, num):map
bool Func_Modulo::IsModulo() const { return true; }

Func_Modulo::Func_Modulo(Environment &env) : Function(_T("mod"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("%"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Modulo::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		result.SetNumber(::fmod(valueLeft.GetNumber(), valueRight.GetNumber()));
		return result;
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValType(sig, valueLeft, valueRight);
	return result;
}

// v = v ** v
bool Func_Power::IsPower() const { return true; }

Func_Power::Func_Power(Environment &env) : Function(_T("__pow__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("**"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Power::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		result.SetNumber(::pow(valueLeft.GetNumber(), valueRight.GetNumber()));
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsComplex()) {
		result.SetComplex(std::pow(valueLeft.GetComplex(), valueRight.GetComplex()));
		return result;
	} else if (valueLeft.IsNumber() && valueRight.IsComplex()) {
		result.SetComplex(std::pow(valueLeft.GetNumber(), valueRight.GetComplex()));
		return result;
	} else if (valueLeft.IsComplex() && valueRight.IsNumber()) {
		result.SetComplex(std::pow(valueLeft.GetComplex(), valueRight.GetNumber()));
		return result;
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

Expr *Func_Power::Diff(Environment &env, Signal sig,
					const ExprList &exprArgs, const Symbol *pSymbolVar) const
{
	const Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	bool depFlagLeft = pExprLeft->FindSymbol(pSymbolVar);
	bool depFlagRight = pExprRight->FindSymbol(pSymbolVar);
	if (!depFlagLeft && !depFlagRight) {
		return new Expr_Value(0.);
	} else if (depFlagLeft && !depFlagRight) {
		// (f(x) ** a)' = a * (f(x) ** (a - 1)) * (f(x))'
		Expr *pExprLeftGen = pExprLeft->Diff(env, sig, pSymbolVar);
		if (pExprLeftGen == NULL) return NULL;
		return env.GetFunc_Multiply().Optimize(env, sig, ExprList(
			pExprRight->IncRef(),
			env.GetFunc_Multiply().Optimize(env, sig, ExprList(
				env.GetFunc_Power().Optimize(env, sig, ExprList(
					pExprLeft->IncRef(),
					env.GetFunc_Minus().Optimize(env, sig, ExprList(
						pExprRight->IncRef(),
						new Expr_Value(1.))))),
				pExprLeftGen))));
	} else if (!depFlagLeft && depFlagRight) {
		// (a ** g(x))' = (a ** g(x)) * log(a) * (g(x))'
		Expr *pExprRightGen = pExprRight->Diff(env, sig, pSymbolVar);
		if (pExprRightGen == NULL) return NULL;
		return env.GetFunc_Multiply().Optimize(env, sig, ExprList(
			env.GetFunc_Multiply().Optimize(env, sig, ExprList(
				env.GetFunc_Power().Optimize(env, sig,
					ExprList(pExprLeft->IncRef(), pExprRight->IncRef())),
				new Expr_Function(&env.GetFunc_log(), pExprLeft->IncRef()))),
			pExprRightGen));
	} else {
		// nothing to do
	}
	sig.SetError(ERR_ArithmeticError, _T("can't generate differential expression"));
	return NULL;
}

Expr *Func_Power::Optimize(Environment &env, Signal sig, ExprList &exprArgs) const
{
	Expr *pExprLeft = exprArgs[0], *pExprRight = exprArgs[1];
	if (pExprLeft->IsValue() && pExprRight->IsValue()) {
		Value valueLeft = dynamic_cast<Expr_Value *>(pExprLeft)->GetValue();
		Value valueRight = dynamic_cast<Expr_Value *>(pExprRight)->GetValue();
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return new Expr_Value(env.GetFunc_Power().Eval(env, sig,
								Context(ValueList(valueLeft, valueRight))));
	} else if (pExprLeft->IsConstZero()) {
		// 0 ** x = 0
		Expr::Delete(pExprRight);
		return pExprLeft;
	} else if (pExprRight->IsConstZero()) {
		// x ** 0 = 1
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return new Expr_Value(1.);
	} else if (pExprLeft->IsConstOne()) {
		// 1 ** x = 1
		Expr::Delete(pExprLeft);
		Expr::Delete(pExprRight);
		return new Expr_Value(1.);
	} else if (pExprRight->IsConstOne()) {
		// x ** 1 = x
		Expr::Delete(pExprRight);
		return pExprLeft;
	}
	return new Expr_BinaryOp(env.GetFunc_Power(), pExprLeft, pExprRight);
}

// v == v
Func_Equal::Func_Equal(Environment &env) : Function(_T("__eq__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("=="));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Equal::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	do {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	} while (0);
	int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
	result.SetBoolean(cmp == 0);
	return result;
}

// v != v
Func_NotEqual::Func_NotEqual(Environment &env) : Function(_T("__ne__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("!="));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_NotEqual::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	do {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	} while (0);
	int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
	result.SetBoolean(cmp != 0);
	return result;
}

// v > v
Func_Greater::Func_Greater(Environment &env) : Function(_T("__gt__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T(">"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Greater::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	do {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	} while (0);
	int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
	result.SetBoolean(cmp > 0);
	return result;
}

// v < v
Func_Less::Func_Less(Environment &env) : Function(_T("__lt__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("<"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Less::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	do {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	} while (0);
	int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
	result.SetBoolean(cmp < 0);
	return result;
}

// v >= v
Func_GreaterEq::Func_GreaterEq(Environment &env) : Function(_T("__ge__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T(">="));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_GreaterEq::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	do {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	} while (0);
	int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
	result.SetBoolean(cmp >= 0);
	return result;
}

// v <= v
Func_LessEq::Func_LessEq(Environment &env) : Function(_T("__le__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("<="));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_LessEq::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	do {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	} while (0);
	int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
	result.SetBoolean(cmp <= 0);
	return result;
}

// v <=> v
Func_Compare::Func_Compare(Environment &env) : Function(_T("__cmp__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("<=>"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Compare::DoEval(Environment &env, Signal sig, Context &context) const
{
	do {
		bool evaluatedFlag = false;
		Value result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	} while (0);
	int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
	return Value(static_cast<Number>(cmp));
}

// v in v
bool Func_ContainCheck::IsContainCheck() const { return true; }

Func_ContainCheck::Func_ContainCheck(Environment &env) : Function(_T("in"), FUNCTYPE_Function)
{
	SetMathSymbol(_T("in"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_ContainCheck::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	if (context.IsList(0)) {
		ValueList &valList = result.InitAsList(env);
		if (context.IsList(1)) {
			const ValueList &valListToFind = context.GetList(1);
			foreach_const (ValueList, pValue, context.GetList(0)) {
				valList.push_back(valListToFind.IsContain(*pValue));
			}
		} else {
			const Value &valueToCompare = context.GetValue(1);
			foreach_const (ValueList, pValue, context.GetList(0)) {
				valList.push_back(Value::Compare(*pValue, valueToCompare) == 0);
			}
		}
	} else {
		if (context.IsList(1)) {
			result.SetBoolean(context.GetList(1).IsContain(context.GetValue(0)));
		} else {
			int cmp = Value::Compare(context.GetValue(0), context.GetValue(1));
			result.SetBoolean(cmp == 0);
		}
	}
	return result;
}

// v | v
Func_Or::Func_Or(Environment &env) : Function(_T("__or__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("|"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Or::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		unsigned long num = static_cast<unsigned long>(valueLeft.GetNumber()) |
							static_cast<unsigned long>(valueRight.GetNumber());
		result.SetNumber(num);
		return result;
	} else if (valueLeft.IsBoolean() && valueRight.IsBoolean()) {
		return valueLeft.GetBoolean() || valueRight.GetBoolean();
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

// v & v
Func_And::Func_And(Environment &env) : Function(_T("__and__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("&"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_And::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		unsigned long num = static_cast<unsigned long>(valueLeft.GetNumber()) &
							static_cast<unsigned long>(valueRight.GetNumber());
		result.SetNumber(num);
		return result;
	} else if (valueLeft.IsBoolean() && valueRight.IsBoolean()) {
		return valueLeft.GetBoolean() && valueRight.GetBoolean();
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

// v ^ v
Func_Xor::Func_Xor(Environment &env) : Function(_T("__xor__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("^"));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Xor::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		unsigned long num = static_cast<unsigned long>(valueLeft.GetNumber()) ^
							static_cast<unsigned long>(valueRight.GetNumber());
		result.SetNumber(num);
		return result;
	} else if (valueLeft.IsBoolean() && valueRight.IsBoolean()) {
		bool flagLeft = valueLeft.GetBoolean();
		bool flagRight = valueRight.GetBoolean();
		return (flagLeft && !flagRight) || (!flagLeft && flagRight);
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

// v || v
// this function takes quoted values as its arguments to implement
// a short-circuit evaluation.
Func_OrOr::Func_OrOr(Environment &env) : Function(_T("__oror__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("||"));
	DeclareArg(env, _T("valueLeft"), VTYPE_Quote);
	DeclareArg(env, _T("valueRight"), VTYPE_Quote);
}

Value Func_OrOr::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	result = context.GetExpr(0)->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	if (result.GetBoolean()) return result;
	result = context.GetExpr(1)->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	return result;
}

// v && v
// this function takes quoted values as its arguments to implement
// a short-circuit evaluation.
Func_AndAnd::Func_AndAnd(Environment &env) : Function(_T("__andand__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T("&&"));
	DeclareArg(env, _T("valueLeft"), VTYPE_Quote);
	DeclareArg(env, _T("valueRight"), VTYPE_Quote);
}

Value Func_AndAnd::DoEval(Environment &env, Signal sig, Context &context) const
{
	Value result;
	result = context.GetExpr(0)->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	if (!result.GetBoolean()) return result;
	result = context.GetExpr(1)->Exec(env, sig);
	if (sig.IsSignalled()) return Value::Null;
	return result;
}

// v .. v
Func_Sequence::Func_Sequence(Environment &env) : Function(_T("__seq__"), FUNCTYPE_Function)
{
	SetMode(RSLTMODE_Normal, MAP_On);
	SetMathSymbol(_T(".."));
	DeclareArg(env, _T("valueLeft"), VTYPE_AnyType);
	DeclareArg(env, _T("valueRight"), VTYPE_AnyType);
}

Value Func_Sequence::DoEval(Environment &env, Signal sig, Context &context) const
{
	const Value &valueLeft = context.GetValue(0);
	const Value &valueRight = context.GetValue(1);
	Value result;
	if (valueLeft.IsNumber() && valueRight.IsNumber()) {
		Number numBegin = valueLeft.GetNumber();
		Number numEnd = valueRight.GetNumber();
		ValueList &valList = result.InitAsList(env);
		if (numBegin <= numEnd) {
			for (Number num = numBegin; num <= numEnd; num += 1.) {
				valList.push_back(Value(num));
			}
		} else {
			for (Number num = numBegin; num >= numEnd; num -= 1.) {
				valList.push_back(Value(num));
			}
		}
		return result;
	} else {
		bool evaluatedFlag = false;
		result = EvalOverride(sig, context, evaluatedFlag);
		if (evaluatedFlag) return result;
	}
	SetError_InvalidValTypeM(sig, valueLeft, valueRight);
	return result;
}

}
