/*
 *  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 = get_gc()->factory.createPObjectBload( code, pobjs);
	if ( po == 0 || !po->Bread(buf, pobjs) ) return 0;
	return po;
}


PObject *PString::compile(CompileContext &c)
{
	if ( *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: string syntax error: unexpected end of file ");
				return 0;
			}
			if ( *c == '\\' && schar == '"' ) {
				c.next_noskip();
				if ( c.eof() ) {
					c.err( "C0003: string syntax error: unexpected end of file ");
					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: invalid 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::compileSymbol(CompileContext &c)
{
	// シンボルは文字列と同じだがハッシュのキーで使われる。
	// シンボルはスペース（または,）で終わりとする。
	// シンボルは:または.(左に変項があるときのみ）で始まり、その後、英文字、数値、_ が使える（述語名と同じ条件）

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

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

	do {
		value.push_back(*c);
		c.next_noskip();	
	} while ( isalpha(*c) || isdigit(*c) || *c == '_' );
	
	return this;
}

PObject *PString::compileHere(CompileContext &c, bool strip_firstcrlf )
{
	// %>・・・・<% で、・・・・はヒア文字として扱われる 
	// %ZZZ> ・・・・ <ZZZ%　というようにZZZを入れることができる 
	// awpモード時に対応する為、%>・・・EOFでも有効とする 
	if ( *c != '%' ) {
		c.err( cformat("C0041: invalid charactor '%c' at head of here document ", *c));
		return 0;
	}
	string endstr;
	endstr.push_back('<');
	c.next_noskip();
	while ( !c.eof() && *c != '>' ) {
		if ( isalpha(*c) || *c == '_' ) {
			endstr.push_back(*c);
			c.next_noskip();
		} else {
			c.err( cformat("C0046: invalid charactor '%c' at here tag ", *c));
			return 0;
		}
	}
	c.next_noskip();
	if ( strip_firstcrlf ) {
		// ヒア文字列の開始直後の改行は無視する 
		if ( *c == '\r' ) c.next_noskip(); 
		if ( *c == '\n' ) c.next_noskip();
	}
	endstr.push_back('%');
	value.clear();
	ptrdiff_t idx = -static_cast<ptrdiff_t>(endstr.size());
	const char	*endp = endstr.c_str();
	while ( idx < 0 || strcmp(value.c_str() + idx, endp) != 0 ) {
		if ( c.eof() ) {
			c.err( "C0045: here document syntax error: unexpected end of file, expect '<%' ");
			return 0;
		}
		value.push_back(*c);
		c.next_noskip();
		idx++;
	}
	if ( value.size() > endstr.size() ) {
		value.resize( value.size() - endstr.size());
	} else {
		value.clear();
	}
	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 *PDouble::compile(CompileContext &c)
{
	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: number syntax error: unexpected end of file ");
			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 = get_gc()->factory.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 = get_gc()->factory.createObject<PInteger>();
		p->value = value_;
		return p;
	}
	return this;
}


PObject *PVeriable::compile(CompileContext &c)
{
	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: veriable syntax error: unexpected end of file ");
		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: invalid data type for variable name ");
		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 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 = get_gc()->factory.createObject<PList>();
		rvalue = rvalue->compile(c);
		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)
{
	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) ) {	
				// itemは不要となる 
				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: invalid 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 = get_gc()->factory.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 = get_gc()->factory.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)
{
	if ( *c == '%' ) return compileHere(c);

	PObject *obj = this;

	name = 0;
	arglist.clear();
	opt.clear();
	constant = false;
	if ( !compileName(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 = get_gc()->factory.createObject<PString>();
		p->value = c.fname;
		return p; // キーワードFILEになる。// このObjectのNewが余分（本来はこの呼出し元でDelete出来るハズ）
	}
	// 述語リスト
	c.skip();
	if ( *c == '(' ) {
		c.next();	// skip '('
		if ( !compileArglist(c) ) return 0;
	}
	return obj;
}

bool PPredicate::compileName(CompileContext &c)
{
	if ( *c == '$' ) {
		// 名称（変項)のコンパイル
		PObject *p = get_gc()->factory.createPObject(*c);
		p = p->compile(c);
		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 = get_gc()->factory.createPObject(*c);
					p = p->compile(c);
					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 = get_gc()->factory.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: invalid charactor '%c' for 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;
	
	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: invalid charactor '%c' for 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 ,
	}
	if ( *c == endlist ) c.next();
	return true;
}

PObject *PPredicate::compileHere(CompileContext &c)
{
	if ( c.here == true ) {
		c.err( cformat( "C0043: cannot allow nesting here document ", *c));
		return 0;
	}
	c.here = true;
	PString *n = get_gc()->factory.createObject<PString>();
	n->value = "%";
	name = n;
	arglist.clear();
	opt.clear();
	constant = false;
	bool strip_crlf = true;
	while ( *c == '%' ) {
		PString *p = get_gc()->factory.createObject<PString>();
		p->compileHere(c, strip_crlf);
		arglist.push_back(p);

		if ( *c != '=' ) {
			c.skip();
			if ( dispwarn && *c != ','  && *c != ';' ) {
				c.warn( cformat( "W0001: Here document terminates in expression. (forgot ',' or ';' ?)  " ) );
			}
			break;	// ヒア文字列の終了 
		}
		// テンプレート出力指定子 <%= 
		strip_crlf = false;
		c.next_noskip();
		PPredicate	*cnv = 0;
		string pname;
		if ( *c == 'u' ) {
			cnv = get_gc()->factory.createObject<PPredicate>();
			pname = "urlencode";
			c.next();
		} else if ( *c == 'r' ) {
			// 変換しない 
			c.next();
		} else if ( *c == 'h' ) {
			cnv = get_gc()->factory.createObject<PPredicate>();
			pname = "htmlescape";
			c.next();
		} else {
			cnv = get_gc()->factory.createObject<PPredicate>();
			pname = "awpescape";
		}
		ExpressionCompileContext	ec;
		PObject *o = ec.compileExpression(c, true);
		if ( o == 0 ) {
			c.here = false;
			return 0;
		}
		if ( cnv ) {
			cnv->make_code_onearg( pname, o);
			o = cnv->addResultArg(c);
		}
		arglist.push_back(o);
		c.skip();
		if ( *c != '%' ) {
			c.err( cformat( "C0042: invalid charactor '%c' in here expression", *c));
			c.here = false;
			return 0;
		}
	}
	c.here = false;
	// 最適化（空文字列の場合はNILを返す（ゴールでコード生成ない） 
	const PString *p;
	if ( arglist.size() == 1 && (p = dynamic_cast<const PString*>(arglist[0])) != 0 && p->value.empty() ) {
		return &pnil;
	}

	return this;
}

void PPredicate::compileHereName(CompileContext &c, bool func)
{
	// ヒアドキュメントの述語名の変換（%→cat または prt）を行う。 
	PString *n = dynamic_cast<PString*>(const_cast<PObject*>(name));
	if ( n != 0 && n->value[0] == '%' ) {
		if ( func ) {
			n->value = "cat";
		} else {
			n->value = "_ppout";
		}
	}
}


// 戻り値の追加（こっちは最後に加えたオブジェクトを返す） 
PObject *PPredicate::addResultArg(CompileContext &c)
{
	PVeriable *v = get_gc()->factory.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;
	c.goalcontext->addBody(this);
	return v;
}

// 戻り値の追加（こっちはもらったものを単純についかする）  
void PPredicate::addMethodArg(CompileContext &c, PObject *l, PObject *dst)
{
	arglist.insert_front(l);
	if ( dst ) {
		if ( opt.result_array ) {
			PVeriable *v = dynamic_cast<PVeriable*>(dst);
			if ( v ) v->args = true;
		}
		arglist.push_back(dst);
	}
}

void PPredicate::make_code_onearg(const string &code, PObject *obj)
{
	PString *p = get_gc()->factory.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 = get_gc()->factory.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, bool result_return)
{
	PString *p = get_gc()->factory.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();
	opt.result_return = result_return;
	if ( funcflg ) {
		c.goalcontext->addBody(this);
		return dst;
	} else {
		return this;
	}
}

PObject *PPredicate::make3Operator(CompileContext &c, string ope, PObject *src1, PObject *src2, bool funcflg, bool result_return)
{
	PString *p = get_gc()->factory.createObject<PString>();
	name = p;
	p->value = ope;
	arglist.push_back(src1);
	arglist.push_back(src2);
	opt.result_return = result_return;
	// =で続く述語呼び出しは、引数リストの最後に自身の名前~数字の変項が追加される。
	if ( funcflg ) {
		PVeriable *v = get_gc()->factory.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 = get_gc()->factory.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 = get_gc()->factory.createObject<PString>();
	name = p;
	p->value = ope;
	arglist.push_back(src);
	// =で続く述語呼び出しは、引数リストの最後に自身の名前~数字の変項が追加される。
	if ( funcflg ) {
		PVeriable *v = get_gc()->factory.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)
{
	BackupGoalContext back( c, this);
	if ( isMyObject(*c) ) c.next();	// skip head char
	body.clear();
	constant = true;

	// ゴール節のコンパイル
	while ( *c != ';' ) {
		if ( c.eof() ) {
			if ( c.awp == false ) {
				c.err( "C0017: goal syntax error: unexpected end of file, expect ';' ");
				return 0;
			}
		}
		ExpressionCompileContext	ec;
		PObject *o = 0;
		o = ec.compileExpression(c,false);
		if ( o != 0 ) {
			if ( o == &pnil ) {
				; // ゴール要素のオブジェクトがNILの場合はコード生成しない(ヒアドキュメントで""が指定された時にpnilを返す  
			} else {
				if ( typeid(*o) != typeid(PPredicate) && typeid(*o) != typeid(PVeriable) ) {
					c.err( cformat("C0018: invalid goal entity %s, expect pridicate or veriable ", typeid(*o).name()) );
					return 0;
				}
				addBody(o);
				if ( o->isc() == false ) constant = false;
			}
			c.skip();
			if ( *c == ',' ) {
				c.next();	// skip ,
			} else if ( *c != ';' && !c.eof() ) {
				c.err( cformat( "C0019: invalid charactor '%c' in goal, expect ',' or ';' ", *c));
			}
		} else {
			c.err( cformat( "C0020: invalid charactor '%c' in goal entity ", *c));
		}
	}
	if ( *c == ';' ) 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;
}

PObject *PHorn::compile(CompileContext &c)
{
	if ( c.horn == true ) {
		c.err( "C0044: cannot allow nesting horn clause ");
		return 0;
	}
	c.horn = true;
	c.vary.clear();
	if ( isMyObject(*c) ) c.next_noskip();	// skip head char
	if ( *c == ',' || *c ==';' ) {	// Horn headの繰り返し省略
		if ( c.p_head == 0 ) {
			c.err( "C0021: invalid the horn head repeate: no former predicate ");
		} else {
			head = *c.p_head;
			c.vary = c.p_vary;
		}
		if ( *c == ',' ) c.next();
	} else {
		head.compile(c);
		c.p_head = &head;
		c.p_vary = c.vary;
	}

	if ( !head.name ) {
		c.err( "C0038: invalid empty string for horn name ");
		c.horn = false;
		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( cformat("C0022: This predicate name(%s) already used by system ", name));
			}
		} else 
#endif		
		if ( strcmp( head.nspace.c_str(), "sys") == 0 ) {
			c.err( "C0023: namespace 'sys' already used by system ");
		}
	}

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


PObject *PHorns::compile(CompileContext &c)
{
	PHorn	*p = get_gc()->factory.createObject<PHorn>();
	p = dynamic_cast<PHorn*>(p->compile(c));
	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 = get_gc()->factory.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)
{
	PHorn	*p = get_gc()->factory.createObject<PHorn>();
	p = dynamic_cast<PHorn*>(p->compile(c));
	if ( !p ) return 0;

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

	PHorns	*hbase = upHorns(name);
	if ( hbase == 0 ) {
		hbase = get_gc()->factory.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;
}
