/****************************************************************************
 * KONOHA COPYRIGHT, LICENSE NOTICE, AND DISCRIMER  
 * 
 * Copyright (c) 2005-2008, Kimio Kuramitsu <kimio at ynu.ac.jp>
 *           (c) 2008-      Konoha Software Foundation  
 * All rights reserved.
 * 
 * You may choose one of the following two licenses when you use konoha. 
 * See www.konohaware.org/license.html for further information.
 * 
 * (1) GNU General Public License 2.0      (with    KONOHA_UNDER_GPL2)
 * (2) Konoha Software Foundation License 1.0
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *  
 ****************************************************************************/

/* ************************************************************************ */

#include"commons.h"

/* ************************************************************************ */

#ifdef __cplusplus 
extern "C" {
#endif

/* ======================================================================== */
/* [CONST] */

Token* new_TokenCONST(Ctx *ctx, Any *fln, Any *data)
{
	knh_Token_t *o = (Token*)new_Object__RAW(ctx, FLAG_Token, CLASS_Token, sizeof(knh_Token));
	knh_Token_struct_init(ctx, DP(o), 0, NULL);
	DP(o)->flag = KNH_FLAG_TKF_GENERATED;
	DP(o)->tt = TT_CONST;
	KNH_INITv(DP(o)->data, data);
	DP(o)->type = knh_Object_cid(DP(o)->data);
	if(IS_NOTNULL(DP(o)->data)) {
		DP(o)->type = CLASS_TONNTYPE(DP(o)->type);
	}
	knh_Token_setTyped(o, 1);
	return o;
}

/* ------------------------------------------------------------------------ */

void knh_Token_setCONST(Ctx *ctx, Token *o, Any *data)
{
	DP(o)->tt = TT_CONST;
	KNH_SETv(ctx, DP(o)->data, data);
	DP(o)->type = knh_Object_cid(DP(o)->data);
	if(IS_NOTNULL(DP(o)->data)) {
		DP(o)->type = CLASS_TONNTYPE(DP(o)->type);
	}
	knh_Token_setTyped(o, 1);
}

/* ------------------------------------------------------------------------ */

void knh_Token_toCONST(Token *o)
{
	DP(o)->tt = TT_CONST;
	DP(o)->type = knh_Object_cid(DP(o)->data);
	if(IS_NOTNULL(DP(o)->data)) {
		DP(o)->type = CLASS_TONNTYPE(DP(o)->type);
	}
	knh_Token_setTyped(o, 1);
}

/* ======================================================================== */
/* [type] */

knh_type_t knh_Token_totype(Ctx *ctx, Token *o, knh_class_t defc, NameSpace *ns)
{
	KNH_ASSERT(IS_Token(o));
	if(DP(o)->tt == TT_ASIS) {
		return TYPE_Any;
	}
	else if(DP(o)->tt == TT_CID) {
		return CLASS_TONNTYPE(DP(o)->cid);
	}
	else {
		knh_bytes_t name = knh_Token_tobytes(o);
		knh_type_t cid;
		if(ISB(name, "void")) {
			return TYPE_void;
		}

		cid = knh_NameSpace_getClass(ctx, ns, name);
		if(cid == CLASS_unknown) {
			cid = defc; 
			knh_Token_perror(ctx, o, KMSG_UCLASSN);
			knh_Token_perrata(ctx, o, CLASSN(defc));
		}

		if(knh_Token_isIteratorType(o)) {
			cid = knh_pmzclass(ctx, CLASS_Iterator, cid, CLASS_Any);
		}
		else if(knh_Token_isArrayType(o)) {
			cid = knh_pmzclass(ctx, CLASS_Array, cid, CLASS_Any);
		}
		if(knh_Token_isNotNullType(o)) {
			return CLASS_TONNTYPE(cid);
		}
		else {
			return cid;
		}
	}
}

/* ------------------------------------------------------------------------ */
/* [fieldn] */

/* ------------------------------------------------------------------------ */

knh_class_t knh_Token_toclass(Ctx *ctx, Token *o, knh_class_t defc, NameSpace *ns)
{
	DEBUG3_ASSERT(IS_Token(o));
	if(DP(o)->tt == TT_CID) {
		return DP(o)->cid;
	}
	else {
		knh_bytes_t name = knh_Token_tobytes(o);
		knh_class_t cid;
		if(knh_Token_isExceptionType(o)) {
			return CLASS_Exception;
		}
		
		cid = knh_NameSpace_getClass(ctx, ns, name);
		if(cid == CLASS_unknown) {
			
			if(defc == CLASS_unknown) {
				return cid;
			}
			cid = defc;
			if(knh_Token_isIteratorType(o)) {
				cid = knh_pmzclass(ctx, CLASS_Iterator, cid, CLASS_Any);
			}
			else if(knh_Token_isArrayType(o)) {
				cid = knh_pmzclass(ctx, CLASS_Iterator, cid, CLASS_Any);
			}
			knh_Token_perror(ctx, o, KMSG_UCLASSN);
			knh_Token_perrata(ctx, o, CLASSN(cid));
		}
		if(knh_Token_isIteratorType(o)) {
			cid = knh_pmzclass(ctx, CLASS_Iterator, cid, CLASS_Any);
		}
		else if(knh_Token_isArrayType(o)) {
			cid = knh_pmzclass(ctx, CLASS_Iterator, cid, CLASS_Any);
		}
		return cid;
	}
}

/* ------------------------------------------------------------------------ */

int knh_Token_isLCONSTN(Token *tk)
{
	knh_bytes_t t = knh_Token_tobytes(tk);
	int i;
	for(i = 0; i < t.len; i++) {
		if(islower(t.buf[i])) return 0;
	}
	return 1;
}

/* ------------------------------------------------------------------------ */

void knh_Token_setLCONST(Ctx *ctx, Token *tk, NameSpace *ns)
{
	DEBUG3_ASSERT(DP(tk)->tt == TT_TYPEN);
	knh_bytes_t t = knh_Token_tobytes(tk);
	int idx = -1;
	knh_type_t type;
	
	if(knh_bytes_equals(t, STEXT("CTX"))) {
		idx = VM_CONST_CTX;
		type = NNTYPE_Context;
	}
	else if(knh_bytes_equals(t, STEXT("STDIN")) || knh_bytes_equals(t, STEXT("IN"))) {
		idx = VM_CONST_STDIN;
		type = NNTYPE_InputStream;
	}
	else if(knh_bytes_equals(t, STEXT("STDOUT")) || knh_bytes_equals(t, STEXT("OUT"))) {
		idx = VM_CONST_STDOUT;
		type = NNTYPE_OutputStream;
	}
	else if(knh_bytes_equals(t, STEXT("STDERR")) || knh_bytes_equals(t, STEXT("ERR"))) {
		idx = VM_CONST_STDERR;
		type = NNTYPE_OutputStream;
	}
	else if(knh_bytes_equals(t, STEXT("EOL"))) {
		knh_Token_setCONST(ctx, tk, TS_EOL);
		return ;
	}
	else if(knh_bytes_equals(t, STEXT("BEGIN"))) {
		knh_Token_setCONST(ctx, tk, TS_BEGIN);
		return ;
	}
	else if(knh_bytes_equals(t, STEXT("END"))) {
		knh_Token_setCONST(ctx, tk, TS_END);
		return ;
	}
	
	if(idx != -1) {
		DP(tk)->tt = TT_SYSCONST;
		DP(tk)->index = idx;
		DP(tk)->type = type;
		knh_Token_setTyped(tk, 1);
	}
	else {
		if(knh_NameSpace_existsLocalConst(ctx, ns, t)) {
			knh_Token_setCONST(ctx, tk, knh_NameSpace_getLocalConst(ctx, ns, t));
		}
		else {
			knh_Token_perror(ctx, tk, KMSG_UCONSTN);
			knh_Token_perrata(ctx, tk, "null");
			knh_Token_setCONST(ctx, tk, KNH_NULL);
		}
	}
}

/* ------------------------------------------------------------------------ */

static
void knh_Token_constCLASS(Ctx *ctx, Token *o, NameSpace *ns)
{
	knh_class_t cid = knh_Token_toclass(ctx, o, CLASS_unknown, ns);
	if(cid == CLASS_unknown) {
		if(knh_Token_isLCONSTN(o)) {
			knh_Token_setLCONST(ctx, o, ns);
		}
		else {
			knh_Token_perror(ctx, o, KMSG_UCLASSN);
			knh_Token_perrata(ctx, o, "null");
			knh_Token_setCONST(ctx, o, KNH_NULL);
		}
		return;
	}
	else if(knh_Token_isNotNullType(o)) {
		knh_Token_perror(ctx, o, KMSG_IGNNTYPE);
	}
	DEBUG_ASSERT_cid(cid);
	knh_Token_setCONST(ctx, o, knh_tClass[cid].class);
}

/* ------------------------------------------------------------------------ */
/* [CMETHODN] */

static
void knh_Token_constCMETHODN(Ctx *ctx, Token *o, NameSpace *ns)
{
	knh_bytes_t t = knh_Token_tobytes(o);
	knh_index_t idx = knh_bytes_index(t, '.');
	if(idx == -1) {
		return;
	}
	knh_bytes_t cname = knh_bytes_first(t, idx);
	knh_class_t cid = knh_NameSpace_getClass(ctx, ns, cname);
	if(cid == CLASS_unknown) {
		knh_Token_perror(ctx, o, KMSG_UCLASSN);
		knh_Token_perrata(ctx, o, "null");
		knh_Token_setCONST(ctx, o, KNH_NULL);
		return;
	}
	t = knh_bytes_last(t, idx+1);
	knh_methodn_t mn = knh_tName_getMethodn(ctx, t, METHODN_NONAME);
	if(mn == METHODN_NONAME) {
		knh_Token_perror(ctx, o, KMSG_UMETHODN);
		knh_Token_perrata(ctx, o, "null");
		knh_Token_setCONST(ctx, o, KNH_NULL);
		return;
	}
	Method *mtd = knh_Class_getMethod(ctx, cid, mn);
	if(IS_NULL(mtd)) {
		knh_Token_perror(ctx, o, KMSG_UMETHODN);
		knh_Token_perrata(ctx, o, "null");
		knh_Token_setCONST(ctx, o, KNH_NULL);
	}
	knh_Token_setCONST(ctx, o, mtd);
}

/* ------------------------------------------------------------------------ */
/* [NUM] */

static
knh_int_t knh_Token_toint(Ctx *ctx, Token *o)
{
	knh_bytes_t t = knh_Token_tobytes(o);
	knh_uint_t n = 0, prev = 0, base = 10;
	int i = 0;
	
	if(t.len > 1) {
		if(t.buf[0] == '0') {
			if(t.buf[1] == 'x') {
				base = 16; i = 2;
			}
			else if(t.buf[1] == 'b') {
				base = 2;  i = 2;
			}
		}else if(t.buf[0] == '-') {
			base = 10; i = 1;
		}
	}
	
	for(;i < t.len; i++) {
		int c = t.buf[i];
		if('0' <= c && c <= '9') {
			prev = n;
			n = n * base + (c - '0');       
		}else if(base == 16) {
			if('A' <= c && c <= 'F') {
				prev = n;
				n = n * 16 + (10 + c - 'A');       
			}else if('a' <= c && c <= 'f') {
				prev = n;
				n = n * 16 + (10 + c - 'a');
			}else {
				break;
			}
		}else if(c == '_') {
			continue;
		}else {
			break;
		}
		if(!(n >= prev)) {
			knh_Token_perror(ctx, o, KMSG_INTOVERFLOW);
			knh_Token_perrata(ctx, o, "0");
			return 0;
		}
	}
	if(t.buf[0] == '-') return (knh_int_t)-n;
	return (knh_int_t)n;
}

/* ------------------------------------------------------------------------ */

static
knh_int64_t knh_Token_toint64(Ctx *ctx, Token *o)
{
	knh_bytes_t t = knh_Token_tobytes(o);
	knh_int64_t n = 0, prev = 0, base = 10;
	int i = 0;
	
	if(t.len > 1) {
		if(t.buf[0] == '0') {
			if(t.buf[1] == 'x') {
				base = 16; i = 2;
			}
			else if(t.buf[1] == 'b') {
				base = 2;  i = 2;
			}
		}else if(t.buf[0] == '-') {
			base = 10; i = 1;
		}
	}
	
	for(;i < t.len; i++) {
		int c = t.buf[i];
		if('0' <= c && c <= '9') {
			prev = n;
			n = n * base + (c - '0');       
		}else if(base == 16) {
			if('A' <= c && c <= 'F') {
				prev = n;
				n = n * 16 + (10 + c - 'A');       
			}else if('a' <= c && c <= 'f') {
				prev = n;
				n = n * 16 + (10 + c - 'a');
			}else {
				break;
			}
		}else if(c == '_') {
			continue;
		}else {
			break;
		}
		if(!(n >= prev)) {
			knh_Token_perror(ctx, o, KMSG_INT64OVERFLOW);
			knh_Token_perrata(ctx, o, "0L");
			return 0;
		}
	}
	if(t.buf[0] == '-') return (knh_int64_t)-n;
	return (knh_int64_t)n;
}

/* ------------------------------------------------------------------------ */

static
knh_float_t knh_Token_tofloat(Ctx *ctx, Token *o)
{
	knh_bytes_t t = knh_Token_tobytes(o);
	if(t.buf[0] == '0' && (t.buf[1] == 'x' || t.buf[1] == 'b')) {
		knh_int64_t n = knh_Token_toint64(ctx, o);
		return (knh_float_t)n;
	}
	else {
		int i = 0, c = 1;
		knh_float_t v = 0.0, prev;

		if(t.buf[0] == '-') i = 1;
	
		for(;i < t.len; i++) {
			if('0' <= t.buf[i] && t.buf[i] <= '9') {
				prev = v;
				v = v * 10 + (t.buf[i] - '0');
			}
			else if(t.buf[i] == '.') {
				i++;
				break;
			}
			else {
				return (t.buf[0] == '-') ? -v : v;
			}
			if(!(v > prev)) {
				knh_Token_perror(ctx, o, KMSG_FLOATOVERFLOW);
				knh_Token_perrata(ctx, o, "0.0");
				return 0.0;
			}
		}
	
		for(; i < t.len; i++) {
			if('0' <= t.buf[i] && t.buf[i] <= '9') {
				prev = v;
				v = v * 10 + (t.buf[i] - '0');
				c *= 10;
			}else {
				break;
			}
			if(!(v > prev)) {
				knh_Token_perror(ctx, o, KMSG_FLOATOVERFLOW);
				knh_Token_perrata(ctx, o, "0.0");
				return 0.0;
			}
		}
		return (t.buf[0] == '-') ? (-v /c) : (v / c) ;
	}
}

/* ------------------------------------------------------------------------ */

static
knh_class_t knh_Token_tagcNUM(Ctx *ctx, Token *o, knh_class_t reqc, NameSpace *ns)
{
	knh_bytes_t t = knh_Token_tobytes(o), tag = STEXT("");
	int i = 1, ishex = 0;
	if(t.buf[0] == '0' && (t.buf[1] == 'x' || t.buf[1] == 'b')) {
		i = 2;
		ishex = 1;
	}
	for(; i < t.len; i++) {
		if(isdigit(t.buf[i]) || t.buf[i] == '_' || t.buf[i] == '.') continue;
		if((t.buf[i] == 'L' || t.buf[i] == 'l')) {
			if(t.buf[i+1] == 0) {
				return reqc;
			}
			else if(t.buf[i+1] == '[' || t.buf[i+1] == ':') {
				continue;
			}
		}
		if(t.buf[i] == '[') {
			int loc;
			tag.buf = t.buf + i + 1;
			tag.len = t.len - (i + 1);
			loc = knh_bytes_index(tag, ']');
			if(loc > 0) {
				tag = knh_bytes_first(tag, loc);
			}
			break;
		}
		else if(t.buf[i] == ':') {
			tag.buf = t.buf + i + 1;
			tag.len = t.len - (i + 1);
			break;
		}
		else {
			tag.buf = t.buf + i;
			tag.len = t.len - (i);
			break;
		}
	}
	if(tag.len == 0 || ishex) {
		return reqc;
	}
	else {
		knh_class_t tagc = knh_NameSpace_tagcid(ctx, ns, reqc, tag);
		if(tagc == CLASS_unknown) {
			knh_Token_perror(ctx, o, KMSG_UTAG);
			return reqc;
		}
		return tagc;
	}
}

/* ------------------------------------------------------------------------ */

static
knh_class_t knh_bytes_guessNUMcid(Ctx *ctx, knh_bytes_t t)
{
	int i;
	for(i = 1; i < t.len; i++) {
		if(t.buf[i] == '_') {
#ifdef CLASS_Decimal
			return CLASS_Decimal;
#endif
		}
		else if(t.buf[i] == '.') {
			return CLASS_Float;
		}
		else if(t.buf[i+1] == 0 || t.buf[i+1] == '[' || t.buf[i+1] == ':') {
			if(t.buf[i] == 'L' || t.buf[i] == 'l') {
				return CLASS_Int64;
			}
		}
		if(!isdigit(t.buf[i])) break;
	}
	return CLASS_Int;
}

/* ------------------------------------------------------------------------ */

static
void knh_Token_constNUM(Ctx *ctx, Token *o, knh_class_t reqc, NameSpace *ns)
{
	DEBUG_ASSERT_cid(reqc);
	knh_class_t req_bcid = knh_tClass[reqc].bcid;
	L_TAIL:;
	if(req_bcid == CLASS_Int) {
		knh_int_t n = knh_Token_toint(ctx, o);
		knh_class_t tagc = knh_Token_tagcNUM(ctx, o, req_bcid, ns);
		if(tagc == reqc) {
			knh_Token_setCONST(ctx, o, new_IntX(ctx, reqc, n));
		}else{
			knh_Token_setCONST(ctx, o, new_IntX(ctx, tagc, n));
		}
	}
	else if(req_bcid == CLASS_Float) {
		knh_float_t n = knh_Token_tofloat(ctx, o);
		knh_class_t tagc = knh_Token_tagcNUM(ctx, o, req_bcid, ns);
		if(tagc == reqc) {
			knh_Token_setCONST(ctx, o, new_FloatX(ctx, reqc, n));
		}else{
			knh_Token_setCONST(ctx, o, new_FloatX(ctx, tagc, n));
		}
	}
	else if(req_bcid == CLASS_Int64) {
		TODO();
	}
#ifdef CLASS_Decimal
	else if(req_bcid == CLASS_Decimal) {
		TODO();
	}
#endif
	else {
		knh_bytes_t t = knh_Token_tobytes(o);
		if(t.buf[0] == '0' && t.buf[1] == 'x') { /* 0x12abcdef */
			if(t.len > 8+2) {
				knh_int64_t n = knh_Token_toint64(ctx, o);
				knh_class_t tagc = knh_Token_tagcNUM(ctx, o, CLASS_Int64, ns);
				knh_Token_setCONST(ctx, o, new_Int64X(ctx, tagc, n));
			}else {
				knh_int_t n = knh_Token_toint(ctx, o);
				knh_class_t tagc = knh_Token_tagcNUM(ctx, o, CLASS_Int, ns);
				knh_Token_setCONST(ctx, o, new_IntX(ctx, tagc, n));
			}
		}
		else if(t.buf[0] == '0' && t.buf[1] == 'b') { /* 0b0101011100 */
			if(t.len > 32+2) {
				knh_int64_t n = knh_Token_toint64(ctx, o);
				knh_class_t tagc = knh_Token_tagcNUM(ctx, o, CLASS_Int64, ns);
				knh_Token_setCONST(ctx, o, new_Int64X(ctx, tagc, n));
			}else {
				knh_int_t n = knh_Token_toint(ctx, o);
				knh_class_t tagc = knh_Token_tagcNUM(ctx, o, CLASS_Int, ns);
				knh_Token_setCONST(ctx, o, new_IntX(ctx, tagc, n));
			}
		}
		else {
			req_bcid = knh_bytes_guessNUMcid(ctx, t);
			reqc = req_bcid;
			goto L_TAIL;
		}
	}
}

/* ------------------------------------------------------------------------ */

static
void knh_Token_constTSTR(Ctx *ctx, Token *o, knh_class_t reqc, NameSpace *ns)
{
	knh_bytes_t t = knh_Token_tobytes(o);
	knh_index_t loc = knh_bytes_index(t, ':');
	if(loc <= -1) {
		KNH_ASSERT(IS_String(DP(o)->data));
		knh_Token_toCONST(o);
	}
	else {
		TODO();
		knh_Token_toCONST(o);
	}
}


/* ------------------------------------------------------------------------ */

knh_bool_t knh_Token_isSystemVariable(Token *tk)
{
	knh_bytes_t t = knh_Token_tobytes(tk);
	return (knh_bytes_startsWith(t, STEXT("__")) && knh_bytes_endsWith(t, STEXT("__")));
}

/* ------------------------------------------------------------------------ */

void knh_Token_constSystemVariable(Ctx *ctx, Token *tk, Compiler *cpr)
{
	knh_bytes_t t = knh_Token_tobytes(tk);
	if (t.len - 1 > 0 && t.buf[t.len-1] == '_' && t.buf[t.len-2] == '_') {
		if(knh_bytes_equals(t, STEXT("__stdin__"))) {
			knh_Token_setCONST(ctx, tk, KNH_STDIN);
		}
		else if(knh_bytes_equals(t, STEXT("__stdout__"))) {
			knh_Token_setCONST(ctx, tk, KNH_STDOUT);
		}
		else if(knh_bytes_equals(t, STEXT("__stderr__"))) {
			knh_Token_setCONST(ctx, tk, KNH_STDERR);
		}
		else if(knh_bytes_equals(t, STEXT("__"))) {
			knh_Token_setCONST(ctx, tk, knh_Compiler_getScript(ctx, cpr));
		}
		else if(knh_bytes_equals(t, STEXT("__line__"))) {
			knh_Token_setCONST(ctx, tk, new_Int(ctx, (knh_int_t)DP(tk)->line));
		}
		else if(knh_bytes_equals(t, STEXT("__file__"))) {
			knh_Token_setCONST(ctx, tk, knh_tfileid_name(DP(tk)->fileid));
		}
		else if(knh_bytes_equals(t, STEXT("__method__")) || knh_bytes_equals(t, STEXT("__FUNCTION__"))) {
			knh_Token_setCONST(ctx, tk, knh_Method_getURN(ctx, DP(cpr)->method));
		}
		else if(knh_bytes_equals(t, STEXT("__namespace__"))
				|| knh_bytes_equals(t, STEXT("__ns__"))) {
			NameSpace *ns = knh_Compiler_getNameSpace(ctx, cpr, KNH_NULL);
			knh_Token_setCONST(ctx, tk, DP(ns)->nsname);
		}
		else {
			knh_Token_perror(ctx, tk, KMSG_USYSTEMVARN);
			knh_Token_perrata(ctx, tk, "null");
			knh_Token_setCONST(ctx, tk, KNH_NULL);
		}
	}
}

/* ------------------------------------------------------------------------ */

static
void knh_Token_constCONSTN(Ctx *ctx, Token *o, NameSpace *ns)
{
	knh_bytes_t t = knh_Token_tobytes(o);
	knh_index_t loc = knh_bytes_rindex(t, '.');
	if(loc == -1) {
		if(knh_NameSpace_existsLocalConst(ctx, ns, t)) {
			knh_Token_setCONST(ctx, o, knh_NameSpace_getLocalConst(ctx, ns, t));
		}
		else {
			knh_Token_perror(ctx, o, KMSG_UCONSTN);
			knh_Token_perrata(ctx, o, "null");
			knh_Token_setCONST(ctx, o, KNH_NULL);
		}
		return;
	}
	knh_class_t cid = knh_NameSpace_getClass(ctx, ns, knh_bytes_first(t, loc));
	if(cid == CLASS_unknown) {
		knh_Token_perror(ctx, o, KMSG_UCONSTN);
		knh_Token_perrata(ctx, o, "null");
		knh_Token_setCONST(ctx, o, KNH_NULL);
	}
	else {
		char buf[CLASSNAME_BUFSIZ*2];
		knh_snprintf(buf, sizeof(buf), "%s.%s", CLASSN(cid), &t.buf[loc+1]);
		t = B(buf);
		if(knh_tConst_exists(ctx, t)) {
			knh_Token_setCONST(ctx, o, knh_tConst_value(ctx, t));
		}else{
			knh_Token_perror(ctx, o, KMSG_UCONSTN);
			knh_Token_perrata(ctx, o, "null");
			knh_Token_setCONST(ctx, o, KNH_NULL);
		}
	}
}

/* ------------------------------------------------------------------------ */
/* [Token] */

Token *knh_Token_const(Ctx *ctx, Token *o, knh_class_t reqc, NameSpace *ns)
{
	switch(DP(o)->tt) {
		case TT_CMETHODN:
			knh_Token_constCMETHODN(ctx, o, ns);
			return o;
	
		case TT_TYPEN: case TT_CID: 
			knh_Token_constCLASS(ctx, o, ns);
			return o;
	
		case TT_NUM:
			knh_Token_constNUM(ctx, o, reqc, ns);
			if(reqc == CLASS_Boolean) {
				Object *value = (Object*)DP(o)->data;
				if(IS_FALSE(value)) {
					knh_Token_setCONST(ctx, o, KNH_FALSE);
				}
				else if(IS_Int(value)) {
					knh_Token_perror(ctx, o, KMSG_WTRUEFALSE);
					if(((Int*)value)->value == 0) {
						knh_perrata(ctx, DP(o)->fileid, DP(o)->line, "0", "false");
						knh_Token_setCONST(ctx, o, KNH_FALSE);
					}
					else {
						char bufn[80];
						knh_snprintf(bufn, sizeof(bufn), "%d", (int)((Int*)value)->value);
						knh_perrata(ctx, DP(o)->fileid, DP(o)->line, bufn, "true");
						knh_Token_setCONST(ctx, o, KNH_TRUE);
					}
				}
				else {
					knh_Token_setCONST(ctx, o, KNH_TRUE);
				}
			}
			return o;
	
		case TT_URN: 
			KNH_ASSERT(IS_String(DP(o)->data));
			knh_Token_toCONST(o);
			return o;
	
		case TT_STR:
			KNH_ASSERT(IS_String(DP(o)->data));
			knh_Token_toCONST(o);
			return o;
	
		case TT_CONSTN: 
			knh_Token_constCONSTN(ctx, o, ns);
			return o;
	
		case TT_TSTR:
			knh_Token_constTSTR(ctx, o, reqc, ns);
			return o;

		case TT_ASIS:
		case TT_CONST: 
		case TT_ERR: 
			return o;
	
	}
	TODO();
	DEBUG3("unknown const token tt=%s", knh_token_tochar(DP(o)->tt));
	return o;
}
	
/* ------------------------------------------------------------------------ */

#ifdef __cplusplus
}
#endif
