/*
 *  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

#ifdef _WIN32
#include <direct.h>
#include <process.h>
#else
#include <sys/stat.h>
#include <sys/wait.h>
#endif

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);
		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_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);
		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_Now : public ExecContextRoot {
	ExecContext_Now(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextRoot(p_, f_, pred_, l) {}
	virtual bool first(PException &excp) { 
		if ( pred->size() != 1 && pred->size() != 2 ) return RERR_argment_number(excp, 1);
		const PObject *out = (*pred)[pred->size()-1];
		time_t	now_t;
		time(&now_t);
		if ( pred->size() == 2 ) {
			const PINTEGER *dif = (*pred)[0]->c_integer(this);
			if ( !dif ) return RERR_argment_type(excp, 0);
			now_t += *dif;
		}
		char	buf[64]; // ctimeが返す文字列は26文字
		strcpy( buf, ctime(&now_t));
		buf[strlen(buf) - 1] = '\0'; // \nを取る
		const PString  *result = pmm.newPString( pobjs, buf);
		return out->unify(*result, this);
	}
};


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

			vector<char const *> argv;
			argv.push_back(cmd->c_str());
			vector<string>		argsvector;
			string arg;
			for ( size_t vidx = 1; vidx < siz - 1; vidx++ ) {
				arg.clear();
				const PObject	*argobj = get<PString>(vidx);
				if ( !argobj || !argobj->cnv_string(arg) ) return RERR_argment_type(excp, vidx);
				argsvector.push_back(arg);
				argv.push_back(argsvector.back().c_str());
			}
			argv.push_back(0);
#ifdef _WIN32
			intptr_t	ret = _spawnvp( _P_WAIT, cmd->c_str(), &argv[0]);
#else
			int ret = -1;	// vforkエラーは-1
			pid_t cpid = fork();
			if ( cpid == 0 ) {
				if ( execvp( cmd->c_str(), (char**)&argv[0]) == -1 ) {
					exit(-1);
				}
			} else if ( cpid != -1 ) {
				if ( wait(&ret) == -1 ) {
					ret = -1;	// waitエラーも-1（本当は例外が良いかも）
				}
			} 
#endif
			if ( ret == -1 ) return false;
			const PInteger *result = pmm.newPInteger( pobjs, ret);
			const PObject *out = (*pred)[siz-1];
			return out->unify(*result, this);
		} catch (exception &) {
			return false;
		}
		return true;
	}
};

struct ExecContext_Env : public ExecContextBase {
	ExecContext_Env(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextBase(p_, f, pred_,l) {}

	ssmap::iterator	i;
	ssmap::iterator iend;
	const PObject *okey;

	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		okey = get<PObject>(0);

		string key;
		if ( okey->cnv_string(key) ) {
			i = envmap.find(key);
			if ( i == envmap.end() ) return false;
			iend = i;
			iend++;
		} else if ( okey->isveriable() ) {
			i = envmap.begin();
			iend = envmap.end();
		}
		return backtrack(excp);
	}

	virtual bool backtrack(PException &excp) { 
		if ( i != iend ) {
			const PString *result_2 = pmm.newPString( pobjs, i->second);
			if ( !unify<PString>( 1, result_2, excp) ) return false;
			if ( okey->isveriable() ) {
				const PString *result_1 = pmm.newPString( pobjs, i->first);
				if ( !unify<PString>( 0, result_1, excp) ) return false;
			}
		} else {
			return false;
		}
		i++;
		return true;
	}

};

struct ExecContext_Arg : public ExecContextBase {
	PINTEGER	pos;
	PINTEGER	epos;
	const PObject *okey;

	ExecContext_Arg(ExecContext *p_,  void *f_, const PPredicate *pred_, VLocal *l) : ExecContextBase(p_, f_, pred_, l) {}

	virtual bool first(PException &excp) { 
		if ( pred->size() != 2 ) return RERR_argment_number(excp, 2);
		okey = get<PObject>(0);

		if ( okey->cnv_integer(pos) ) {
			if ( pos >= argvector.size() ) return false;
			epos = pos + 1;
		} else if ( okey->isveriable() ) {
			pos = 0;
			epos = argvector.size();
		}
		return backtrack(excp);
	}

	virtual bool backtrack(PException &excp) { 
		if ( pos < epos ) {
			const PString *p = pmm.newPString( pobjs, argvector[static_cast<size_t>(pos)]);
			if ( !unify<PString>( 1, p, excp) ) return false;
			if ( okey->isveriable() ) {
				const PInteger *p = pmm.newPInteger( pobjs, pos);
				if ( !unify<PInteger>( 0, p, excp) ) return false;
			}
		} else {
			return false;
		}
		pos++;
		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_Sleep : public ExecContextRoot {
	ExecContext_Sleep(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);

		PINTEGER msec;
		if ( !item->cnv_integer(msec) )  return RERR_argment_type(excp, 0);

		mySleep((long long)msec*1000*1000);

		return true;
	}
};

struct ExecContext_Exit : public ExecContextRoot {
	ExecContext_Exit(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);

		PINTEGER exit_code;
		if ( !item->cnv_integer(exit_code) )  return RERR_argment_type(excp, 0);

		exit(static_cast<int>(exit_code));

		return false;
	}
};

struct ExecContext_Transfer : public ExecContextRoot {
	ExecContext_Transfer(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);

		string path;
		if ( !item->cnv_string(path) )  return RERR_argment_type(excp, 0);

		GlobalContext	c;
		if ( !c.compile( path, true) ) return RERR_Compile( excp);
		
		gc->hbase.addPHornBase( c.hbase );
		gc->topgoals.erase( gc->goalidx );
		gc->topgoals.addPHorns( c.topgoals );

		return true;
	}
};

struct ExecContext_Platform : public ExecContextRoot {
	ExecContext_Platform(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 _WIN32
	string result_ = "Windows";
#else 
 #if unix
	string result_ = "Unix";
 #else
	string result_ = "Other";
 #endif
#endif
		const PString  *result = pmm.newPString(pobjs,result_);
		return (*pred)[0]->unify( *result, this);
	}
};


struct ExecContext_Pathsep : public ExecContextRoot {
	ExecContext_Pathsep(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);
		string result_;
		result_.push_back(pseparator);
		const PString  *result = pmm.newPString(pobjs,result_);
		return (*pred)[0]->unify( *result, this);
	}
};


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
