/*
 *  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.
 */
#include "adp.h"


PObject *BinaryObjectFormat::readObject( string &str, PObjectArray *pobjs, size_t &pos )
{
	int code = BinaryObjectFormat::get_int(str, pos);
	long long objlen = BinaryObjectFormat::get_long_long(str, pos + 4);
	if ( objlen + 16 + pos > str.size() ) return 0;
	string buf = str.substr(pos + 16, (size_t)objlen);
	pos += (size_t)objlen + 16;
	PObject *po = poFactory.createPObjectBload( code, pobjs);
	if ( po == 0 || !po->Bread(buf, pobjs) ) return 0;
	return po;
}


PObject *PString::compile(CompileContext &c, bool)
{
	if ( *c != '"' && *c != '\'' ) return compileSymbol(c);	// "や'から始まらないと、シンボルとしてコンパイル

	value.clear();
	while ( isMyObject(*c) ) {
		int	schar = *c;
		c.next_noskip();	// skip head char
		while ( *c != schar ) {
			if ( c.eof() ) {
				c.err( "C0003: unexpected EOF expect \" in string ");
				return 0;
			}
			if ( *c == '\\' && schar == '"' ) {
				c.next_noskip();
				if ( c.eof() ) {
					c.err( "C0003: unexpected EOF in string ");
					return 0;
				}
				switch (*c) {
				case 'n' :
					value.push_back('\n');
					c.next_noskip();
					break;
				case 'r' :
					value.push_back('\r');
					c.next_noskip();
					break;
				case '"' :
					value.push_back('"');
					c.next_noskip();
					break;
				case '\\' :
					value.push_back('\\');
					c.next_noskip();
					break;
				default :				
					c.err( cformat("C0004: illegal charactor(%c) after \\ in string ", *c));
				}
			} else {
				value.push_back(*c);
				c.next_noskip();
			}
			if ( *c == '\'' && schar == '\'' ) {
				c.next_noskip();
				if ( *c == '\'' ) {
					value.push_back('\'');
					c.next_noskip();
				} else {
					c.push_back();
				}
			}
		}
		c.next();	// skip "
	}
	return this;
}

PObject *PString::parseJson(const string &src, size_t &pos, PObjectArray *pobjs)
{
	if ( src[pos] != '"' ) return 0;	// "ではじまるはず
	pos++;
	if ( pos >= src.size() ) return 0;
	
	value.clear();
	while ( src[pos] != '"' ) {
		if ( pos >= src.size() ) return 0;
		if ( src[pos] == '\\') {
			pos++;
			if ( pos >= src.size() ) return 0;
			switch (src[pos]) {
			case '"' :
				value.push_back('"');
				pos++;
				break;
			case '\\' :
				value.push_back('\\');
				pos++;
				break;
			case '/' :
				value.push_back('/');
				pos++;
				break;
			case 'b' :
				value.push_back('\b');
				pos++;
				break;
			case 'f' :
				value.push_back('\f');
				pos++;
				break;
			case 'n' :
				value.push_back('\n');
				pos++;
				break;
			case 'r' :
				value.push_back('\r');
				pos++;
				break;
			case 't' :
				value.push_back('\t');
				pos++;
				break;
			case 'u' :
				pos++;
				if ( pos + 4 >= src.size() ) return 0;
				int	v;
				sscanf( src.c_str() + pos, "%4x", &v);
				unicode_to_utf8( v, value);
				pos+=4;
				break;
			default :				
				value.push_back('\\');
			}
		} else {
			value.push_back(src[pos]);
			pos++;
		}
	}
	pos++;
	return this;
}


PObject *PString::compileSymbol(CompileContext &c)
{
	// シンボルは文字列と同じだがハッシュのキーで使われる。
	// シンボルはスペース（または,）で終わりとする。
	// シンボルは:または.(左に変項があるときのみ）で始まり、その後、英文字、数値、_ が使える（述語名と同じ条件）

	if ( *c != ':' && *c != '.' ) {
		c.err( cformat("C0005: illegal charactor(%c) in symbol ", *c));
		return 0;
	}
	c.next_noskip();	// skip head char
	value.clear();

	if ( isalpha(*c) == 0 ) {
		c.err( cformat("C0006: illegal charactor(%c) in symbol head ", *c));
		return 0;
	}

	do {
		value.push_back(*c);
		c.next_noskip();	
	} while ( isalpha(*c) || isdigit(*c) || *c == '_' );
	
	c.skip(); // spaceのスキップ
	
	return this;
}


PObject *PDouble::compile(CompileContext &c, bool)
{
	string	buf;
	bool	floatflg = false;
	bool	hexflg = false;
	
	if ( *c == '0' ) {
		c.next_noskip();
		if ( *c == 'x' ) { // 16進数
			c.next_noskip();
			hexflg = true;
		} else {
			c.push_back();
		}
	} else if ( *c == '-' ) {
		buf.push_back(*c);
		c.next();
	}
	
	while ( isdigit(*c) || (!hexflg && *c == '.') || (hexflg && (('A' <= *c && *c <= 'F') || ('a' <= *c && *c <= 'f'))) ) {
		if ( c.eof() ) {
			c.err( "C0007: unexpected EOF in number. ");
			return 0;
		}
		if ( *c == '.' ) floatflg = true;
		buf.push_back(*c);
		c.next();
	}

	if ( floatflg == true ) {
		value = atof(buf.c_str());
	} else {
		PINTEGER value_ = strtoll( buf.c_str(), 0, hexflg ? 16 : 10);
		PInteger *p = poFactory.createObject<PInteger>();
		p->value = value_;
		return p;
	}
	return this;
}


PObject *PDouble::parseJson(const string &src, size_t &pos, PObjectArray *pobjs)
{
	string	buf;
	bool	floatflg = false;

	if ( src[pos] == '-' ) {
		buf.push_back(src[pos]);
		pos++;
	}
	
	while ( (isdigit(src[pos]) || src[pos] == '.') && pos < src.size() ) {
		if ( src[pos] == '.' ) {
			if ( floatflg == true ) break;
			floatflg = true;
		}
		buf.push_back(src[pos]);
		pos++;
	}
	if ( floatflg == true ) {
		if ( pos < src.size() ) {
			if ( src[pos] == 'e' || src[pos] == 'E' ) {
				string fa;
				fa += src[pos];
				pos++;
				if ( pos >= src.size() ) return 0;
				if ( src[pos] == '+' || src[pos] == '-' ) {
					fa += src[pos];
					pos++;
				}
				if ( pos >= src.size() ) return 0;
				while ( isdigit(src[pos]) ) {
					fa += src[pos];
					pos++;
				}
				buf += fa;
			}
		}
		value = atof(buf.c_str());
	} else {
		PINTEGER value_ = strtoll( buf.c_str(), 0, 10);
		PInteger *p = poFactory.createObject<PInteger>();
		p->value = value_;
		return p;
	}
	return this;
}


PObject *PVeriable::compile(CompileContext &c, bool)
{
	name = "";
	args = false;
	if ( *c == '@' ) args = true;	// 引数展開
	if ( isMyObject(*c) ) c.next();	// skip head char
	while ( isalpha(*c) || isdigit(*c) || *c == '_'  ) {
		name.push_back(*c);
		c.next();
	}
	if ( c.eof() ) {
		c.err( "C0008: unexpected EOF in veriable. ");
		return 0;
	}
	if ( name.empty() ) {
		PWildCard *p = &pwildcard;
		return p;
	}
	addVary(c);
	return this;
}

void PVeriable::makeVeriable(CompileContext &c, const string &name_, bool argflg)
{
	name = name_;
	addVary(c);
	args = argflg;
}

bool PVeriable::makeVeriable(CompileContext &c, const PObject *obj, bool argflg)
{
	if ( !obj->c_str() ) {
		c.err( "C0009: The object must be string. ");
		return false;
	}
	name = string(obj->c_str());
	addVary(c);
	args = argflg;
	return true;
}

void PVeriable::addVary(CompileContext &c)
{
	VNames::iterator i;
	if ( (i = find(c.vary.begin(), c.vary.end(), name)) == c.vary.end() ) {
		c.vary.push_back(name);
		i = c.vary.end() - 1;
	}
	idx = i - c.vary.begin();
}


PObject *PList::compile(CompileContext &c, bool funcflg)
{
	bool listflg = false;
	if ( isMyObject(*c) ) { 
		listflg = true; 
		c.next(); // skip head char
	} else if ( *c == ',' ) {
		c.next();	// カンマでキタ場合
	}
	c.skip();
	if ( *c == ']' ) {	 // カラリスト
		if ( listflg ) c.next(); 
		constant = true; 
		return this; 
	}

	ExpressionCompileContext	ec(",|]");
	lvalue = ec.compileExpression(c, false);
	if ( lvalue == 0 ) return 0;
	c.skip();
	if ( *c == ',' ) {
		rvalue = poFactory.createObject<PList>();
		rvalue = rvalue->compile(c, funcflg);
		if ( rvalue == 0 ) return 0;
	} else if ( *c == '|' ) {
		c.next();
		ExpressionCompileContext	ec(']');
		rvalue = ec.compileExpression(c, false);
		if ( rvalue == 0 ) return 0;
	}
	if ( listflg ) {
		if ( *c == ']' ) {
			c.next();  
		} else {
			c.err( cformat("C0010: illegal charactor(%c) in list ", *c) );
		}
	}
	constant = ((lvalue == 0 || lvalue->isc()) && (rvalue == 0 || rvalue->isc()) );
	return this;
}

PObject *PArray::compile(CompileContext &c, bool funcflg)
{
	brace = true;
	constant = true;
	if ( isMyObject(*c) ) { 
		c.next(); // skip head char
	} else if ( *c == ',' ) {
		c.next();	// カンマでキタ場合
	}
	c.skip();
	while ( *c != '}' && !c.eof() ) {
		ExpressionCompileContext	ec(',');
		PObject *item = ec.compileExpression(c, false);
		if ( item == 0 ) return 0;
		c.skip();
		if ( *c == ',' || *c == '}' ) {
			value.push_back( item );
			if ( !item->isc() ) constant = false;
			if ( *c == ',' ) {
				c.next();
			}
			continue;
		} else if ( *c == '=' ) {
			c.next_noskip(); 
			string key;
			if ( *c == '>' && item->cnv_string(key) ) {
				c.next();
				ExpressionCompileContext	ec(',');
				PObject *vitem = ec.compileExpression(c, true);
				c.skip();
				if ( *c == ',' || *c == '}' ) {
					value.push_back( vitem );
					hamap[key] = value.size() - 1;
					if ( !vitem->isc() ) constant = false;
					if ( *c == ',' ) {
						c.next();
					}
					continue;
				}
			}
		}
		if ( *c == '}' || c.eof() )  {
			break;
		}
		// コンパイルエラー
		c.err( cformat("C0011: illegal charactor(%c) in array ", *c) );
		return 0;
	}
	c.next();
	return this;
}

PObject *PArray::parseJson(const string &src, size_t &pos, PObjectArray *pobjs)
{
	brace = true;
	char echar;
	if ( src[pos] == '[' ) echar = ']';
	if ( src[pos] == '{' ) echar = '}';
	pos++;
	
	while ( src[pos] != echar && pos < src.size() ) {
		while ( (src[pos] == ' ' ||	src[pos] == '\t') && pos < src.size() ) {
			pos++;
		}
		if ( pos >= src.size() ) break;
		
		PObject *po = poFactory.createPObjectJSON( src, pos, pobjs);
		if ( po != 0 ) { po = po->parseJson(src, pos, pobjs); }
		if ( po == 0 ) return 0;

		// 空白
		if ( pos >= src.size() ) return 0;
		while ( (src[pos] == ' ' ||	src[pos] == '\t') && pos < src.size() ) {
			pos++;
		}
		if ( pos >= src.size() ) return 0;

		// : あり
		if ( src[pos] == ':' ) {
			pos++;
			if ( pos >= src.size() ) return 0;
			PString *ps = dynamic_cast<PString*>(po);
			if ( ps == 0 ) return 0;
			while ( (src[pos] == ' ' ||	src[pos] == '\t') && pos < src.size() ) {
				pos++;
			}
			if ( pos >= src.size() ) return 0;
			po = poFactory.createPObjectJSON( src, pos, pobjs);
			if ( po != 0 ) { po = po->parseJson(src, pos, pobjs); }
			if ( po == 0 ) return 0;
			value.push_back( po );
			hamap[ps->value] = value.size() - 1;
		} else { // ：なし
			value.push_back( po );
		}


		// 空白
		if ( pos >= src.size() ) return 0;
		while ( (src[pos] == ' ' ||	src[pos] == '\t') && pos < src.size() ) {
			pos++;
		}
		if ( pos >= src.size() ) return 0;

		if ( src[pos] == ',' ) {
			pos++;
		} else if ( src[pos] != echar ) {
			return 0;
		}
	}
	pos++;
	constant = true;
	return this;
}


PObject *PPredicate::compile(CompileContext &c, bool funcflg)
{
	return compile(c, funcflg, 0, 0);
}

PObject *PPredicate::compile(CompileContext &c, bool funcflg, const PObject *firstarg, const PObject *primaryarg)
{
	// 以下関数形式のチェック
	if ( funcflg == true ) {
		if ( !c.goalcontext ) {
			c.err( cformat("C0012: unexpected method call(no goal context) near (%c) ", *c));
			return 0;
		}
	}
	PObject *obj = compilePredicate(c, funcflg, firstarg, primaryarg);
	if ( obj != this && !funcflg ) {
	
			c.err( cformat("C0013: unexpected method call near (%c) ", *c));
		return 0;
	}
	if ( ncmp("NIL") ) return &pnil; // キーワードNIL。// このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
	if ( ncmp("TRUE") ) return &ptrue; // キーワードTRUEになる。// このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
	if ( ncmp("FALSE") ) return &pzero; // キーワードFALSEになる。// このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
	if ( ncmp("FILE") ) {
		PString *p = poFactory.createObject<PString>();
		p->value = c.fname;
		return p; // キーワードFILEになる。// このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
	}
	return obj;
}

PObject *PPredicate::compilePredicate(CompileContext &c, bool funcflg, const PObject *firstarg, const PObject *primaryarg)
{
	// firstargは、メソッド呼び出し形式の時設定される

	PObject *pobj = this;
	
	while ( true ) {
		name = 0;
		arglist.clear();
		opt.clear();
		if ( !compileName(c) ) return 0;
		if ( ncmp("NIL") ) return this; // キーワードNIL // このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
		if ( ncmp("TRUE") ) return this; // キーワードTRUE// このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
		if ( ncmp("FALSE") ) return this; // キーワードFALSE // このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
		if ( ncmp("FILE") ) return this; // キーワードFILE // このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
		// 述語リストが空の述語
		c.skip();
		if ( *c == '(' ) {
			c.next();	// skip '('
			if ( !compileArglist(c) ) return 0;
		}
		// メソッド形式の左側の引数
		if ( firstarg && !ncmp("pipe") ) {
			if ( firstarg->isc() ) { arglist.constant = false ; constant = false; }
			constant = firstarg->isc();
			arglist.insert_front(firstarg);
			firstarg = 0;
		}
		if ( primaryarg ) {
			if ( primaryarg->isc() ) { arglist.constant = false ; constant = false; }
			arglist.insert_front(primaryarg);
			primaryarg = 0;
		}
		if ( (funcflg || *c == '.') ) {
			if ( !c.goalcontext ) {
				c.err( cformat("C0014: unexpected method call near (%c) ", *c));
				return 0;
			}

			// =で続く述語呼び出しおよびメソッド形式は、引数リストの最後に自身の名前~数字の変項が追加される。
			if ( !ncmp("pipe") ) {
				PVeriable *v = poFactory.createObject<PVeriable>();
				string vname;
				if ( name->c_str() ) vname = name->c_str();
				vname += cformat("~%u", c.goalcontext->size());
				v->makeVeriable(c, vname, opt.result_array );
				arglist.push_back(v);
				constant = false;
				if ( funcflg ) {
					pobj = v;
				}
			}
			PObject *p = poFactory.clone(this);
			c.goalcontext->addBody(p);
		}
		if ( *c == '.' ) {
			c.next();
			if ( !ncmp("pipe") ) firstarg = arglist.back();
		} else {
			break;	// 述語の連結終わり
		}
	}

	return pobj;
}

bool PPredicate::compileName(CompileContext &c)
{
	if ( *c == '$' ) {
		// 名称（変項)のコンパイル
		PObject *p = poFactory.createPObject(*c);
		p = p->compile(c, false);
		setName(p);
	} else if ( isMyObject(*c) ) {
		// 名称または名前空間のコンパイル
		string n;
		while ( !c.eof() ) {
			if ( !isalpha(*c) && !isdigit(*c) && *c != '_' ) break;
			n.push_back(*c);
			c.next_noskip();
		}
		if ( *c == ':' ) {
			c.next_noskip();
			if ( *c == ':' ) {
				// 名前空間
				c.next_noskip();
				nspace = n;
				n.clear();
				if ( *c == '$' ) {
					// 名称のコンパイル(変更として)
					PObject *p = poFactory.createPObject(*c);
					p = p->compile(c, false);
					setName(p);
				} else {
					// 名称のコンパイル(文字列として)
					while ( !c.eof() ) {
						if ( !isalpha(*c) && !isdigit(*c) && *c != '_' ) break;
						n.push_back(*c);
						c.next_noskip();
					}
				}
			} else {
				; // n は名前
			}
		}
		if ( !name ) {
			PString *p = poFactory.createObject<PString>();
			setName(p);
			p->value = n;
			if ( p->value.empty() && *c == '!' ) {	// cut
				p->value.push_back(*c);
				c.next_noskip();
			}
		}
	} else {
		c.err( cformat("C0015: illegal charactor(%c) in predicate name. ", *c) );
		return false;
	}

	// postfixのコンパイル、
	for ( int cnt = 0; cnt < 4; cnt++ ) {
		if ( *c == '@' ) {
			opt.result_array = true;
			arglist.args = true;
		} else if ( *c == '$' ) {
			opt.cachable = true;
		} else if ( *c == '?' ) {
			opt.result_return = true;
		} else if ( *c == '!' ) {
			opt.only_one_call = true;
		} else {
			break;
		}
		c.next_noskip();
	}
	if ( *c == '~' ) {	// 述語の診断 
		for ( int cnt = 0; cnt < 5; cnt++ ) {
			c.next_noskip();
			if ( *c == '!' ) {
				opt.first_true = true;
				opt.backtrack_false = true;
			} else if ( *c == '?' ) {
				opt.first_true = false;
				opt.backtrack_false = true;
			} else if ( *c == '+' ) {
				opt.first_true = true;
				opt.backtrack_false = false;
			} else if ( *c == '*' ) {
				opt.first_true = true;
				opt.backtrack_false = true;
			} else if ( *c == 'd' ) {
				opt.debug = true;
			} else {
				break;
			}
		}
	}
	if ( name->isc() ) constant = true;
	c.skip();	
	
	return true;
}

bool PPredicate::compileArglist(CompileContext &c, char endlist, bool ppflg)
{
	c.skip();
	// 述語リストのコンパイル
	while ( *c != endlist && !c.eof() ) {
		if ( *c == '%' && ppflg == true) {
			c.next_noskip();
			if ( *c == '>' ) { c.push_back(); break; }
			c.err( cformat( "C0016: unexpected charactor '%c' in argment list ", *c));
		} else {
			ExpressionCompileContext	ec(',');
			PObject *o = ec.compileExpression(c, ppflg);
			if ( o == 0 ) return false;
			arglist.push_back(o);
			if ( o->isc() == false ) { arglist.constant = false ; constant = false; }
			if ( o->isargs() == true ) { arglist.args = true; }
		}
		c.skip();
		if ( *c == ',' ) c.next();	// skip ,
		c.skip();
	}
	if ( *c == endlist ) c.next();
	return true;
}

bool PPredicate::compilecode_argments(const string &code, CompileContext &c)
{
	PString *p = poFactory.createObject<PString>();
	name = p;
	p->value = code;
	return compileArglist(c, ')', true);
}

void PPredicate::make_code_onearg(const string &code, PObject *obj)
{
	PString *p = poFactory.createObject<PString>();
	name = p;
	p->value = code;
	arglist.push_back(obj);
	constant = obj->isc();
}

void PPredicate::make_code_onearg(const string &code, const string &str)
{
	PString *arg = poFactory.createObject<PString>();
	arg->value = str;
	make_code_onearg(code, arg);
}


PObject *PPredicate::make3Operator(CompileContext &c, string ope, PObject *src1, PObject *src2, PObject *dst, bool funcflg)
{
	PString *p = poFactory.createObject<PString>();
	name = p;
	p->value = ope;
	arglist.push_back(src1);
	arglist.push_back(src2);
	arglist.push_back(dst);
	constant = src1->isc() && src2->isc() && dst->isc();
	if ( funcflg ) {
		c.goalcontext->addBody(this);
		return dst;
	} else {
		return this;
	}
}

PObject *PPredicate::make3Operator(CompileContext &c, string ope, PObject *src1, PObject *src2, bool funcflg)
{
	PString *p = poFactory.createObject<PString>();
	name = p;
	p->value = ope;
	arglist.push_back(src1);
	arglist.push_back(src2);
	// =で続く述語呼び出しは、引数リストの最後に自身の名前~数字の変項が追加される。
	if ( funcflg ) {
		PVeriable *v = poFactory.createObject<PVeriable>();
		string vname = cformat( "%s~%u", name->c_str(), c.goalcontext->size());
		v->makeVeriable(c, vname);
		arglist.push_back(v);
		constant = false;
		c.goalcontext->addBody(this);
		return v;
	} else {
		constant = src1->isc() && src2->isc();
		return this;
	}
}

PObject *PPredicate::make2Operator(CompileContext &c, string ope, PObject *src, PObject *dst, bool funcflg)
{
	PString *p = poFactory.createObject<PString>();
	name = p;
	p->value = ope;
	arglist.push_back(src);
	arglist.push_back(dst);
	constant = src->isc() && dst->isc();
	if ( funcflg ) {
		c.goalcontext->addBody(this);
		return dst;
	} else {
		return this;
	}
}

PObject *PPredicate::make1Operator(CompileContext &c, string ope, PObject *src, bool funcflg)
{
	PString *p = poFactory.createObject<PString>();
	name = p;
	p->value = ope;
	arglist.push_back(src);
	// =で続く述語呼び出しは、引数リストの最後に自身の名前~数字の変項が追加される。
	if ( funcflg ) {
		PVeriable *v = poFactory.createObject<PVeriable>();
		string vname = cformat( "%s~%u", name->c_str(), c.goalcontext->size());
		v->makeVeriable(c, vname);
		arglist.push_back(v);
		constant = false;
		c.goalcontext->addBody(this);
		return v;
	} else {
		constant = src->isc();
		return this;
	}
}


PObject *PGoal::compile(CompileContext &c, bool funcflg)
{
	BackupGoalContext back( c, this);
	if ( isMyObject(*c) ) c.next();	// skip head char
	body.clear();
	constant = true;

	// ゴール節のコンパイル
	bool	ppprtflg = false;
	int		rawmode = 1; // 1:awpescape 2:htmlescape 3:rawmode
	while ( *c!= ';' ) {
		if ( c.eof() ) {
			c.err( "C0017: unexpected EOF in goal expect ';' ");
			return 0;
		}
		do {
			if ( ppprtflg ) {
				PPredicate *q = poFactory.createObject<PPredicate>();
				switch ( rawmode ) {
					case 1:
						q->compilecode_argments("_ppout_awpescape", c);
						break;
					case 2:
						q->compilecode_argments("_ppout_htmlescape", c);
						break;
					case 3:
						q->compilecode_argments("_ppout", c);
						break;
					case 4:
						q->compilecode_argments("_ppout_urlencode", c);
						break;
				}
				addBody(q);
			} else {
				ExpressionCompileContext	ec(',');
				PObject *o = ec.compileExpression(c, funcflg);
				//PObject *o = c.createObject(poFactory, false);
				if ( o != 0 ) {
					if ( typeid(*o) != typeid(PPredicate) && typeid(*o) != typeid(PVeriable) ) {
						c.err( cformat("C0018: unexpected class %s(%c) expect pridicate or veriable. ", typeid(*o).name(), *c) );
						return 0;
					}
					addBody(o);
					if ( o->isc() == false ) constant = false;
					c.skip();
					if ( *c == ',' ) {
						c.next();	// skip ,
					} else if ( *c != ';' && *c != '%' ) {
						c.err( cformat( "C0019: unexpected charactor '%c' in goal expect ':' or '%%' ", *c));
					}
					c.skip();
					break;
				}
			}
			if ( *c == '%' ) {
				c.next_noskip();
				if ( *c == '>' ) {
					c.next_noskip();
					if ( *c == '\r' ) c.next_noskip();
					if ( *c == '\n' ) c.next_noskip();
					string	str;
					/* コンスタント表示 PP用 */
					char	skipc = 0;
					while ( !c.eof() && !(skipc == '<' && *c == '%') ) {
						if ( *c == '<' ) {
							skipc = '<';
							c.next_noskip();
							continue;
						}
						if ( skipc ) str.push_back(skipc);
						skipc = 0;
						str.push_back(*c);
						c.next_noskip();
					}
					if ( !c.eof() ) {
						c.next();
						PPredicate *p = poFactory.createObject<PPredicate>();
						p->make_code_onearg("_ppout", str);
						addBody(p);
						if ( *c == '=' ) {
							c.next();
							ppprtflg = true;
							switch ( *c ) {
								case 'u':
									c.next();
									rawmode = 4;
									break;
								case 'r':
									c.next();
									rawmode = 3;
									break;
								case 'h':
									c.next();
									rawmode = 2;
									break;
								default:
									rawmode = 1;
							}
						} else {
							if ( *c == ',' ) c.next();
							ppprtflg = false;
						}
						break;
					}
				}
			}
			c.err( cformat( "C0020: unexpected charactor '%c' in goal ", *c));
			return 0;
		} while ( false );
	}
	c.next();	// skip ;
	// バックトラックの最適化
	if ( !body.empty() ) {
		const PPredicate *p = dynamic_cast<const PPredicate *>(body.back());
		if ( p != 0 ) {
			if ( p->ncmp("!") ) {
				body.pop_back();
				nobacktrack = true;
			}
		}
	}
	return this;
}

void PGoal::compileOutcode_htmlescape(CompileContext &c)
{
	BackupGoalContext back( c, this);
	PPredicate *p = poFactory.createObject<PPredicate>();
	p->compilecode_argments("_prt_htmlescape", c);
	addBody(p);
}

void PGoal::compileOutcode_awpescape(CompileContext &c)
{
	BackupGoalContext back( c, this);
	PPredicate *p = poFactory.createObject<PPredicate>();
	p->compilecode_argments("_prt_awpescape", c);
	addBody(p);
}

void PGoal::compileOutcode_raw(CompileContext &c)
{
	BackupGoalContext back( c, this);
	PPredicate *p = poFactory.createObject<PPredicate>();
	p->compilecode_argments("print", c);
	addBody(p);
}


void PGoal::compileOutcode_urlencode(CompileContext &c)
{
	BackupGoalContext back( c, this);
	PPredicate *p = poFactory.createObject<PPredicate>();
	p->compilecode_argments("_prt_urlencode", c);
	addBody(p);
}

void PGoal::make_prt_code(const string &str)
{
	PPredicate *p = poFactory.createObject<PPredicate>();
	p->make_code_onearg("prt", str);
	addBody(p);
}

PObject *PHorn::compile(CompileContext &c, bool funcflg)
{
	c.vary.clear();
	if ( isMyObject(*c) ) c.next();	// skip head char
	if ( *c == ',' || *c ==';' ) {	// Horn headの繰り返し省略
		if ( c.p_head == 0 ) {
			c.err( "C0021: illegal repeated horn head, no former predicate ");
		} else {
			head = *c.p_head;
			c.vary = c.p_vary;
		}
		if ( *c == ',' ) c.next();
	} else {
		head.compile(c, funcflg);
		c.p_head = &head;
		c.p_vary = c.vary;
		c.skip();
	}

	if ( !head.name ) {
		c.err( "C0038: none horn name ");
		return 0;
	}

	// 組み込み述語名の場合、エラーとする  
	if ( head.name->c_str() ) {
#if 0
		// ver 0.7 から以下のエラーチェックはしない（但し、将来コード診断でワーニングとして出す可能性あり。）
		if ( head.nspace.empty() ) {
			string name(head.name->c_str());
			if ( check_ExecContext_Factory(&name) ) {
				c.err( "C0022: This predicate name is already used by system enrolling predicate.");
			}
		} else 
#endif		
		if ( strcmp( head.nspace.c_str(), "sys") == 0 ) {
			c.err( "C0023: Namespace 'sys' is already used by system enrolling predicate namespace. ");
		}
	}

	if ( *c != ';' ) {
		body.compile(c, funcflg);
	} else {
		c.next();	// skip ;
	}
	vcnt = c.vary.size();
	vnames = c.vary;
	constant = (head.isc() && body.isc() );
	return this;
}


PObject *PHorns::compile(CompileContext &c, bool funcflg)
{
	PHorn	*p = poFactory.createObject<PHorn>();
	p = dynamic_cast<PHorn*>(p->compile(c, funcflg));
	if ( !p ) return 0;
	horns.push_back(p);
	if ( p->isc() == false ) constant = false;
	return this;
}

void PHorns::addHorn(PHorn *horn_)
{
	horns.push_back(horn_);
}

void PHorns::addGoal( PGoal &goal_, VNames &vnames_)
{
	PHorn	*p = poFactory.createObject<PHorn>();
	p->setGoal( goal_, vnames_);
	horns.push_back(p);
	if ( p->isc() == false ) constant = false;
}

void PHorns::erase(size_t i)
{
	horns.erase( horns.begin() + i + 1, horns.end());
}

void PHorns::addPHorns(PHorns &src)
{
	horns.insert( horns.end(), src.horns.begin(), src.horns.end());
	constant &= src.constant;
}

PObject *PHornBase::compile(CompileContext &c, bool funcflg)
{
	PHorn	*p = poFactory.createObject<PHorn>();
	p = dynamic_cast<PHorn*>(p->compile(c, funcflg));
	if ( !p ) return 0;

	string name("");
	p->headName(name);

	PHorns	*hbase = upHorns(name);
	if ( hbase == 0 ) {
		hbase = poFactory.createObject<PHorns>();
		hornbase.insert( pair<string,PHorns*>(name, hbase) );
	}
	hbase->addHorn(p);
	if ( p->isc() == false ) constant = false;
	return this;
}

void PHornBase::addPHornBase( const PHornBase &src )
{
	hornbase.insert( src.hornbase.begin(), src.hornbase.end());
	constant &= src.constant;
}
