/*
 *  ADP (Another Data Processor) www.adp.la
 *  Copyright (C) 2010 Katsuhisa Ohfuji <katsuhisa@ohfuji.name>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA 02110-1301, USA.
 */

#ifndef ADP_BUILTIN_H
#define ADP_BUILTIN_H

struct ExecContext_Err : public ExecContextRoot {
	ExecContext_Err(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		firstflg = false;
		print_header();
		string	txt;
		PObjectArray::const_iterator i = pred->begin();
		PObjectArray::const_iterator end = pred->end();
		for (; i < end; i++ ) {
			const PObject *  item = (*i)->getval( this, gl);
			item->print(stderr);
		}
		return true;
	};
};

struct ExecContext_ErrN : public ExecContextRoot {
	ExecContext_ErrN(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		print_header();
		string	txt;
		PObjectArray::const_iterator i = pred->begin();
		PObjectArray::const_iterator end = pred->end();
		for (; i < end; i++ ) {
			const PObject *  item = (*i)->getval( this, gl);
			item->print(stderr);
		}
		fputs("\n",stderr);
		return true;
	};
};

struct ExecContext_Print : public ExecContextRoot {
	ExecContext_Print(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		firstflg = false;
		print_header();
		string	txt;
		PObjectArray::const_iterator i = pred->begin();
		PObjectArray::const_iterator end = pred->end();
		for (; i < end; i++ ) {
			const PObject *  item = (*i)->getval( this, gl);
			item->print(stdout);
		}
		return true;
	};
};

struct ExecContext_PrintN : public ExecContextRoot {
	ExecContext_PrintN(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		print_header();
		string	txt;
		PObjectArray::const_iterator i = pred->begin();
		PObjectArray::const_iterator end = pred->end();
		for (; i < end; i++ ) {
			const PObject *  item = (*i)->getval( this, gl);
			item->print(stdout);
		}
		fputs("\n",stdout);
		return true;
	};
};

struct ExecContext_Prt_htmlescape : public ExecContextRoot {
	ExecContext_Prt_htmlescape(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		for ( size_t i = 0; i < pred->size(); i++ ) {
			const PObject *item = get<PObject>(i);
			string	txt;
			if ( item->cnv_string(txt) ) {
				htmlescape(txt, false);
				fwrite( txt.c_str(), txt.size(), 1, stdout);
			}
		}
		return true;
	};
};

struct ExecContext_Prt_awpescape : public ExecContextRoot {
	ExecContext_Prt_awpescape(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		for ( size_t i = 0; i < pred->size(); i++ ) {
			const PObject *item = get<PObject>(i);
			string	txt;
			if ( item->cnv_string(txt) ) {
				htmlescape(txt, true);
				fwrite( txt.c_str(), txt.size(), 1, stdout);
			}
		}
		return true;
	};
};

struct ExecContext_Prt_urlencode : public ExecContextRoot {
	ExecContext_Prt_urlencode(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		for ( size_t i = 0; i < pred->size(); i++ ) {
			const PObject *item = get<PObject>(i);
			string	txt,out;
			if ( item->cnv_string(txt) ) {
				urlencode(txt.begin(), txt.end(), out);
				fwrite( out.c_str(), out.size(), 1, stdout);
			}
		}
		return true;
	};
};

struct ExecContext_Ppout : public ExecContextRoot {
	ExecContext_Ppout(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( !p ) return false;
		for ( size_t i = 0; i < pred->size(); i++ ) {
			const PObject *item = get<PObject>(i);
			string	txt;
			if ( item->cnv_string(txt) ) {
				p->ppoutbuf += txt;
			}
		}
		return true;
	};
};


struct ExecContext_Ppout_htmlescape : public ExecContextRoot {
	ExecContext_Ppout_htmlescape(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( !p ) return false;
		for ( size_t i = 0; i < pred->size(); i++ ) {
			const PObject *item = get<PObject>(i);
			string	txt;
			if ( item->cnv_string(txt) ) {
				htmlescape(txt, false);
				p->ppoutbuf += txt;
			}
		}
		return true;
	};
};

struct ExecContext_Ppout_awpescape : public ExecContextRoot {
	ExecContext_Ppout_awpescape(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( !p ) return false;
		for ( size_t i = 0; i < pred->size(); i++ ) {
			const PObject *item = get<PObject>(i);
			string	txt;
			if ( item->cnv_string(txt) ) {
				htmlescape(txt, true);
				p->ppoutbuf += txt;
			}
		}
		return true;
	};
};

struct ExecContext_Ppout_urlencode : public ExecContextRoot {
	ExecContext_Ppout_urlencode(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( !p ) return false;
		for ( size_t i = 0; i < pred->size(); i++ ) {
			const PObject *item = get<PObject>(i);
			string	txt,out;
			if ( item->cnv_string(txt) ) {
				urlencode(txt.begin(),txt.end(),out);
				p->ppoutbuf += out;
			}
		}
		return true;
	};
};


struct ExecContext_Add : public ExecContextRoot {
	ExecContext_Add(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}

	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = add(args[0], args[1], pobjs, false);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Sub : public ExecContextRoot {
	ExecContext_Sub(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}

	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = sub(args[0], args[1], pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Neg : public ExecContextRoot {
	PInteger	zero;
	ExecContext_Neg(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l), zero(0) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();

		const PINTEGER *a1 = args[0]->c_integer(this);
		if ( a1 ) {
			const PInteger *result = pmm.newPInteger( pobjs, - *a1);
			return args[1]->unify( *result, this);
		}

		PObject *dst = zero.sub(*args[0]->getval(this),pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);

		return args[1]->unify(*dst, this);
	};
};

struct ExecContext_Mul : public ExecContextRoot {
	ExecContext_Mul(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}

	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = mul(args[0], args[1], pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Div : public ExecContextRoot {
	ExecContext_Div(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}

	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = div(args[0], args[1], pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Mod : public ExecContextRoot {
	ExecContext_Mod(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}

	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = mod(args[0], args[1], pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Pow : public ExecContextRoot {
	ExecContext_Pow(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}

	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		const PObject *args0 = args[0];
		const PObject *args1 = args[1];
		// 両方が整数の場合
		const PINTEGER *a1 = args0->c_integer(this);
		const PINTEGER *a2 = args1->c_integer(this);
		if ( a1 && a2 ) {
			PObject *dst = pmm.newPInteger( pobjs, mypow(*a1, *a2));
			return args[2]->unify(*dst, this);
		}
		// 浮動小数点に変換
		double d1;
		double d2;
		if ( !args0->getval(this)->cnv_double(d1) ) return RERR_argment_type( excp, 0);
		if ( !args1->getval(this)->cnv_double(d2) ) return RERR_argment_type( excp, 1);
		PObject *dst = pmm.newPDouble( pobjs, pow( d1, d2));
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Equ : public ExecContextRoot {
	ExecContext_Equ(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();
		return args[0]->unify( *args[1], this);
	};
};

struct ExecContext_Neq : public ExecContextRoot {
	ExecContext_Neq(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();
		return !args[0]->unify( *args[1], this);
	};
};

struct ExecContext_CMP : public ExecContextRoot {
	ExecContext_CMP(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();

		// 試しの最適化
		const PINTEGER *a1 = args[0]->c_integer(this);
		const PINTEGER *a2 = args[1]->c_integer(this);
		if ( a1 && a2 ) {
			const PInteger *result = pmm.newPInteger( pobjs, sign(*a1 - *a2));
			return args[2]->unify( *result, this);
		}

		int result_ = 0;
		if ( !args[0]->getval(this)->cmp(*args[1]->getval(this), result_) ) RERR_NOTSUPPORT_EXPRESSION(excp);

		const PInteger *result = pmm.newPInteger( pobjs, result_);
		return args[2]->unify(*result, this);
	};
};

struct ExecContext_LT : public ExecContextRoot {
	ExecContext_LT(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();

		// 試しの最適化
		const PINTEGER *a1 = args[0]->c_integer(this);
		const PINTEGER *a2 = args[1]->c_integer(this);
		if ( a1 && a2 ) {
			return *a1 < *a2;
		}

		int result_ = 0;
		if ( !args[0]->getval(this)->cmp(*args[1]->getval(this), result_) ) RERR_NOTSUPPORT_EXPRESSION(excp);
		return result_ < 0;
	};
};

struct ExecContext_LE : public ExecContextRoot {
	ExecContext_LE(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();

		// 試しの最適化
		const PINTEGER *a1 = args[0]->c_integer(this);
		const PINTEGER *a2 = args[1]->c_integer(this);
		if ( a1 && a2 ) {
			return *a1 <= *a2;
		}

		int result_ = 0;
		if ( !args[0]->getval(this)->cmp(*args[1]->getval(this), result_) ) RERR_NOTSUPPORT_EXPRESSION(excp);
		return result_ <= 0;
	};
};

struct ExecContext_GT : public ExecContextRoot {
	ExecContext_GT(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();

		// 試しの最適化
		const PINTEGER *a1 = args[0]->c_integer(this);
		const PINTEGER *a2 = args[1]->c_integer(this);
		if ( a1 && a2 ) {
			return *a1 > *a2;
		}

		int result_ = 0;
		if ( !args[0]->getval(this)->cmp(*args[1]->getval(this), result_) ) RERR_NOTSUPPORT_EXPRESSION(excp);
		return result_ > 0;
	};
};

struct ExecContext_GE : public ExecContextRoot {
	ExecContext_GE(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();

		// 試しの最適化
		const PINTEGER *a1 = args[0]->c_integer(this);
		const PINTEGER *a2 = args[1]->c_integer(this);
		if ( a1 && a2 ) {
			return *a1 >= *a2;
		}

		int result_ = 0;
		if ( !args[0]->getval(this)->cmp(*args[1]->getval(this), result_) ) RERR_NOTSUPPORT_EXPRESSION(excp);
		return result_ >= 0;
	};
};

struct ExecContext_And : public ExecContextRoot {
	ExecContext_And(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = _and(args[0], args[1], pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Or : public ExecContextRoot {
	ExecContext_Or(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = _or(args[0], args[1], pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Xor : public ExecContextRoot {
	ExecContext_Xor(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 3 ) return RERR_argment_number(excp, 3);
		const PObject **args = &pred->arglist.value.front();
		PObject *dst = _xor(args[0], args[1], pobjs);
		if ( !dst ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		return args[2]->unify(*dst, this);
	};
};

struct ExecContext_Not : public ExecContextRoot {
	ExecContext_Not(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject **args = &pred->arglist.value.front();

		// 試しの最適化
		const PINTEGER *a1 = args[0]->c_integer(this);
		if ( a1 ) {
			const PInteger *result = pmm.newPInteger( pobjs, ~*a1);
			return args[1]->unify( *result, this);
		}
		return RERR_NOTSUPPORT_EXPRESSION(excp);
	};
};

struct ExecContext_Let : public ExecContextBase {
	ExecContext_Let(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextBase(p_, f_, pred_, l) {}
	void let( const PObject *value, const PVeriable *dst) {
		ExecContext	*ec = dynamic_cast<ExecContext*>(p);
		if ( ec ) {
			for ( ExecContextRootArray::iterator i = ec->ecs.begin(); i <= ec->ecs.begin() + ec->goalidx; i++ ) {
				ExecContextBase *ec = dynamic_cast<ExecContextBase*>(*i);
				if ( ec ) {
					(*ec->gl)[dst->idx] = value;
					ec->backup[dst->idx] = value;
				}
			}
		}
	}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject *src = get<PObject>(0);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !src || typeid(*src) == typeid(PEVeriable) ) return RERR_argment_type(excp, 0);
		if ( !dst ) return RERR_argment_type(excp, 1);
		// ↓これだとsrcがコンパイル時に定義される定数だと後に2重削除となる
		//p->pobjs.push_back(src);
		PObject	*value = const_cast<PObject*>(src)->clone(p->pobjs); // 2重削除を防止する為、コピーする。
		let( value, dst);
		return true;
	};
};

struct ExecContext_LetAdd : public ExecContext_Let {
	ExecContext_LetAdd(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = add(args[1], args[0], p->pobjs, true);	// debug 
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};

struct ExecContext_LetSub : public ExecContext_Let {
	ExecContext_LetSub(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = sub(args[1], args[0], p->pobjs);
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};

struct ExecContext_LetMul : public ExecContext_Let {
	ExecContext_LetMul(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = mul(args[1], args[0], p->pobjs);
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};

struct ExecContext_LetDiv : public ExecContext_Let {
	ExecContext_LetDiv(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = div(args[1], args[0], p->pobjs);
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};

struct ExecContext_LetMod : public ExecContext_Let {
	ExecContext_LetMod(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = mod(args[1], args[0], p->pobjs);
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};

struct ExecContext_LetAnd : public ExecContext_Let {
	ExecContext_LetAnd(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = _and(args[1], args[0], p->pobjs);
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};

struct ExecContext_LetOr : public ExecContext_Let {
	ExecContext_LetOr(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = _or(args[1], args[0], p->pobjs);
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};

struct ExecContext_LetXor : public ExecContext_Let {
	ExecContext_LetXor(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContext_Let(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PVeriable *dst = dynamic_cast<const PVeriable*>((*pred)[1]);
		if ( !dst ) return RERR_argment_type(excp, 1);

		const PObject **args = &pred->arglist.value.front();
		PObject *result = _xor(args[1], args[0], p->pobjs);
		if ( !result ) return RERR_NOTSUPPORT_EXPRESSION(excp);
		let( result, dst);
		return true;
	};
};




struct ExecContext_CStr : public ExecContextRoot {
	ExecContext_CStr(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject *item = get<PObject>(0);
		string result_;
		if ( !item->cnv_string(result_) )  return RERR_argment_type(excp, 0);
		const PString  *result = pmm.newPString(pobjs,result_);
		return (*pred)[1]->unify( *result, this);
	}
};

struct ExecContext_Cdbl : public ExecContextRoot {
	ExecContext_Cdbl(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject *item = get<PObject>(0);
		double result_;
		if ( !item->cnv_double(result_) )  return RERR_argment_type(excp, 0);
		const PDouble  *result = pmm.newPDouble(pobjs, result_);
		return (*pred)[1]->unify( *result, this);
	}
};

struct ExecContext_Cint : public ExecContextRoot {
	ExecContext_Cint(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject *item = get<PObject>(0);
		PINTEGER result_;
		if ( !item->cnv_integer(result_) )  return RERR_argment_type(excp, 0);
		const PInteger  *result = pmm.newPInteger(pobjs, result_);
		return (*pred)[1]->unify( *result, this);
	}
};

struct ExecContext_GetHash : public ExecContextRoot {
	ExecContext_GetHash(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		const PObject *item = get<PObject>(0);
		PINTEGER result = item->chash();
		const PInteger *p = pmm.newPInteger( pobjs, result);
		return unify<PInteger>(1, p, excp);
	}
};

struct ExecContext_Counter : public ExecContextBase {
	PINTEGER			c_start;
	PINTEGER			c_skip;
	PINTEGER			c_end;

	ExecContext_Counter(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextBase(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 4 ) return RERR_argment_number(excp, 4);
		const PObject *arg1 = geto(0);
		const PObject *arg2 = geto(1);
		const PObject *arg3 = geto(2);

		if ( !arg1->cnv_integer(c_start) ) return RERR_argment_type(excp, 0);
		if ( !arg2->cnv_integer(c_skip)  ) return RERR_argment_type(excp, 1);
		if ( !arg3->cnv_integer(c_end) ) return RERR_argment_type(excp, 2);

		if ( c_skip == 0 ) return false;
		if ( c_skip > 0 && c_end < c_start ) return false;
		if ( c_skip < 0 && c_end > c_start ) return false;
		
		return backtrack(excp);
	}
	virtual bool backtrack(PException &excp) {
		if ( c_end < c_start ) return false;
		const PObject *arg4 = (*pred)[3];
		const PInteger  *result = pmm.newPInteger(pobjs, c_start);
		c_start += c_skip;
		return arg4->unify(*result, this);
	}
};

struct ExecContext_Times : public ExecContextRoot {
	size_t	counter;
	// ExecContextRootを継承してメンバ変数を使う場合、funcflg = falseとする
	// またはreinit()をオーバーロードしメンバ変数の初期化を行う。
	ExecContext_Times(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l){ counter = 1; delflg = false; }
	virtual void recreate(const PPredicate *pred_, VLocal *l) { ExecContextRoot::init(pred_, l); delflg = false; }
	virtual void recreate(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) { ExecContextRoot::init(p_,f,pred_, l); delflg = false; }
	virtual void reinit(const PPredicate *pred_, VLocal *l) { ExecContextRoot::init(pred_, l); delflg = false; }
	virtual void reinit(ExecContext *p_, void *f_, const PPredicate *pred_, VLocal *l) { ExecContextRoot::init(p_,f,pred_, l); delflg = false; }

	virtual bool first(PException &excp) { 
		if ( pred->size() != 1 ) return RERR_argment_number(excp, 1);
		const PInteger *p = pmm.newPInteger( pobjs, counter++);
		if ( !unify<PInteger>( 0, p, excp, 0) ) return false;
		return true;
	}
};

struct ExecContext_SRand : public ExecContextRoot {
	ExecContext_SRand(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() > 1 ) return RERR_argment_number(excp, 1);

		if ( pred->size() == 1 ) {
			const PObject *item = get<PObject>(0);
			PINTEGER result;
			if ( !item->cnv_integer(result) )  return RERR_argment_type(excp, 0);

			mysrand((unsigned int)result);
		} else {
			mysrand();
		}

		return true;
	}
};

struct ExecContext_Rand : public ExecContextRoot {
	ExecContext_Rand(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 1 ) return RERR_argment_number(excp, 1);
		const PObject *item = get<PObject>(0);
		int result = myrand();
		const PInteger *p = pmm.newPInteger( pobjs, result);
		return unify<PInteger>(0, p, excp);
	}
};

struct ExecContext_Rkey : public ExecContextRoot {
	ExecContext_Rkey(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 1 ) return RERR_argment_number(excp, 1);

		mysrand();

		string dummy, result_;
		if ( !make_rkey( dummy, result_) ) return false;
		const PString  *result = pmm.newPString(pobjs,result_);
		return unify<PString>(0, result, excp);
	}
};



struct ExecContext_AddAllowTag : public ExecContextRoot {
	ExecContext_AddAllowTag(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}

	bool getParameterAboutElement( size_t idx, const char *& el, int &typ, PException &excp) {
		if ( idx + 1 >= pred->size() ) return true;
		const PString *oel = get<PString>(idx);
		if ( !oel ) return true;
		const PInteger *otp = get<PInteger>(idx+1);
		if ( !otp ) return true;
		if ( otp->value < 1 || 5 < otp->value ) return RERR_argment_type(excp, idx+1);
		el = oel->value.c_str();
		typ = static_cast<int>(otp->value);
		return true;
	}

	virtual bool first(PException &excp) { 
		if ( pred->size() < 1 || pred->size() > 15 ) return RERR_argment_number(excp, 1);
		if ( (pred->size() % 2 ) == 0 ) return RERR_argment_number(excp, 1);
		const PString *tag = get<PString>(0);
		if ( !tag ) return RERR_argment_type(excp, 0);

		const char *el1 = 0; int  tp1 = 0;
		const char *el2 = 0; int  tp2 = 0;
		const char *el3 = 0; int  tp3 = 0;
		const char *el4 = 0; int  tp4 = 0;
		const char *el5 = 0; int  tp5 = 0;
		const char *el6 = 0; int  tp6 = 0;
		const char *el7 = 0; int  tp7 = 0;
		
		if ( !getParameterAboutElement( 1, el1, tp1, excp) ) return false;
		if ( !getParameterAboutElement( 3, el2, tp2, excp) ) return false;
		if ( !getParameterAboutElement( 5, el3, tp3, excp) ) return false;
		if ( !getParameterAboutElement( 7, el4, tp4, excp) ) return false;
		if ( !getParameterAboutElement( 9, el5, tp5, excp) ) return false;
		if ( !getParameterAboutElement(11, el6, tp6, excp) ) return false;
		if ( !getParameterAboutElement(13, el7, tp7, excp) ) return false;
		
		return add_allowtags( tag->value, el1, tp1, el2, tp2,  el3, tp3, el4, tp4, el5, tp5, el6, tp6, el7, tp7);
	}
};

struct ExecContext_RemoveAllowTag : public ExecContextRoot {
	ExecContext_RemoveAllowTag(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 1 ) return RERR_argment_number(excp, 1);
		const PString *tag = get<PString>(0);
		if ( !tag ) return RERR_argment_type(excp, 0);

		remove_allowtags( tag->value);
		return true;
	}
};


#endif
