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


/* ======================================================================== */
/* [DECL] */

static
Stmt *new_StmtDECL(Ctx *ctx, Token *tk_TYPEN, knh_tokens_t *tc, int start)
{
	Stmt *stmt_b = new_Stmt(ctx, 0, STT_DECL);
	knh_tokens_t comma_tc = {NULL, 0, 0};
	if(start != 0) {
		knh_StmtMETA_add_prestmt(ctx, stmt_b, tc, start);
	}
	knh_tokens_stepFirstComma(ctx, tc, &comma_tc);
	knh_Stmt_add(ctx, stmt_b, TM(tk_TYPEN));
	knh_Stmt_add_VARN(ctx, stmt_b, &comma_tc);
	if(comma_tc.c == comma_tc.e) {
		knh_Stmt_add_ASIS(ctx, stmt_b);
		goto L_NEXT;
	}
	if(SP(comma_tc.ts[comma_tc.c])->tt == TT_LET) {
		comma_tc.c += 1;
		knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &comma_tc, KNH_RVALUE));
	}
	else {
		knh_tokens_ignore(ctx, &comma_tc);
		knh_Stmt_add_ASIS(ctx, stmt_b);
	}

	L_NEXT:;
	//DEBUG3("N tc->c=%d, tc->e=%d comma.c=%d comma.e=%d", tc->c, tc->e, comma_tc.c, comma_tc.e);
	if(tc->c < tc->e) {
		if(SP(tc->ts[tc->c])->tt == TT_SEMICOLON || knh_token_isEndOfStmt(SP(tc->ts[tc->c])->tt)) {
			return stmt_b;
		}
		else {
			Stmt *stmt_n = new_StmtDECL(ctx, tk_TYPEN, tc, 0);
			KNH_SETv(ctx, DP(stmt_n)->metaDictMap, DP(stmt_b)->metaDictMap);
			knh_Stmt_tail_append(ctx, stmt_b, stmt_n);
		}
	}
	return stmt_b;
}

/* ======================================================================== */
/* [LET] */

static
int knh_Token_isLVALUE(Token *tk)
{
	if(SP(tk)->tt == TT_TYPEN && knh_Token_isLCONSTN(tk)) {
		SP(tk)->tt = TT_CONSTN;
	}
	return knh_Token_isVARN(tk) || SP(tk)->tt == TT_CONSTN;
}

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

static
void knh_Stmt_toLVALUE(Ctx *ctx, Stmt *stmt_b, int pe)
{
	if(SP(stmt_b)->stt == STT_CALL) {
		Token *tk = (Token*)DP(stmt_b)->tokens[0];
		DEBUG3_ASSERT(IS_Token(tk));
		if(knh_Token_isGetter(tk)) {
			knh_Token_setGetter(tk, 0);
			knh_Token_setSetter(tk, 1);
			return ;
		}
		else if(SP(tk)->tt == TT_MN) {
			knh_methodn_t mn = DP(tk)->mn;
			if(METHODN_IS_SETTER(mn)) {
				return ;
			}
			else if(METHODN_IS_GETTER(mn)) {
				mn = METHODN_TOFIELDN(mn);
				DP(tk)->mn = METHODN_TO_SETTER(mn);
				TODO();
				return ;
			}
		}
		else if(SP(tk)->tt == TT_FN) {
			TODO();
		}
		else {
			TODO();
		}
	}
	DEBUG3("stt=%s", knh_stmt_tochar(SP(stmt_b)->stt));
	SP(stmt_b)->stt = STT_ERR;
	knh_perror(ctx, SP(stmt_b)->fileid, SP(stmt_b)->line, pe, NULL);
}

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

static
Stmt *new_StmtLET(Ctx *ctx, knh_tokens_t *lvalue_tc, knh_tokens_t *rvalue_tc)
{
	Term *lval = new_TermEXPR(ctx, lvalue_tc, KNH_LVALUE);
	if(IS_Token(lval)) {
		if(knh_Token_isLVALUE((Token*)lval)) {
			Stmt *stmt_b = new_Stmt(ctx, 0, STT_LET);
			knh_Stmt_add(ctx, stmt_b, lval);
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, rvalue_tc, KNH_RVALUE));
			return stmt_b;
		}
		else {
			knh_Token_perror(ctx, (Token*)lval, KMSG_ELVALUE);
			return new_StmtERR(ctx, lvalue_tc);
		}
	}
	else {
		Stmt *stmt_b = (Stmt*)lval;
		KNH_ASSERT(IS_Stmt(stmt_b));
		knh_Stmt_toLVALUE(ctx, stmt_b, KMSG_ELVALUE);
		if(SP(stmt_b)->stt != STT_ERR) {
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, rvalue_tc, KNH_RVALUE));
		}
		return stmt_b;
	}
}

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

static
Stmt *new_StmtLETOP(Ctx *ctx, knh_tokens_t *lvalue_tc, Token *tkl, knh_tokens_t *rvalue_tc)
{
	SP(tkl)->tt = SP(tkl)->tt - (TT_ADDE - TT_ADD);
	rvalue_tc->c = lvalue_tc->c;
	return new_StmtLET(ctx, lvalue_tc, rvalue_tc);
}

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

static
Stmt *new_StmtLETMULTI(Ctx *ctx, knh_tokens_t *lvalue_tc, knh_tokens_t *rvalue_tc)
{
	knh_tokens_t cma_tc;
	knh_tokens_stepFirstComma(ctx, lvalue_tc, &cma_tc);
	{
		Stmt *stmt_head = new_StmtLET(ctx, &cma_tc, rvalue_tc);
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_LETMULTI);
		while(cma_tc.c < cma_tc.e) {
			DEBUG3_STC("cma_tc", cma_tc);
			knh_Stmt_add_VARN(ctx, stmt_b, &cma_tc);
			knh_tokens_ignore(ctx, &cma_tc);
			knh_tokens_stepFirstComma(ctx, lvalue_tc, &cma_tc);
		}
		knh_Stmt_tail_append(ctx, stmt_head, stmt_b);
		return stmt_head;
	}
}

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

static
Stmt *new_StmtLETMULTI2(Ctx *ctx, knh_tokens_t *lvalue_tc, knh_tokens_t *rvalue_tc)
{
	Stmt *stmt_head = NULL;
	knh_tokens_t ltc, rtc;
	knh_tokens_stepFirstComma(ctx, lvalue_tc, &ltc);
	knh_tokens_stepFirstComma(ctx, rvalue_tc, &rtc);
	while(ltc.c < ltc.e && rtc.c < rtc.e) {
		Stmt *stmt_b = new_StmtLET(ctx, &ltc, &rtc);
		if(stmt_head == NULL) {
			stmt_head = stmt_b;
		}
		else {
			knh_Stmt_tail_append(ctx, stmt_head, stmt_b);
		}
		knh_tokens_stepFirstComma(ctx, lvalue_tc, &ltc);
		knh_tokens_stepFirstComma(ctx, rvalue_tc, &rtc);
	}
	knh_tokens_ignore(ctx, lvalue_tc);
	knh_tokens_ignore(ctx, rvalue_tc);
	KNH_ASSERT(stmt_head != NULL);
	return stmt_head;
}

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

static Token *knh_tokens_findLETNULL(knh_tokens_t *tc)
{
	Token **ts = tc->ts;
	int i;
	for(i = tc->c; i < tc->e; i++) {
		KNH_ASSERT(!knh_token_isEndOfStmt(SP(ts[i])->tt));
		if(TT_LET <= SP(ts[i])->tt && SP(ts[i])->tt <= TT_ALTLET) return ts[i];
	}
	return NULL;
}

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

static
void knh_tokens_divideLET(knh_tokens_t *tc, knh_tokens_t *ltc, knh_tokens_t *rtc)
{
	Token **ts = tc->ts;
	int i;
	for(i = tc->c; i < tc->e; i++) {
		if(TT_LET <= SP(ts[i])->tt && SP(ts[i])->tt <= TT_ALTLET) {
			break;
		}
	}
	ltc->ts = tc->ts;
	ltc->c = tc->c;
	ltc->e = i;
	rtc->ts = tc->ts;
	rtc->c = rtc->c = i + 1;
	rtc->e = tc->e;
}


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

Stmt* new_StmtLETEXPR(Ctx *ctx, knh_tokens_t *tc)
{
	Token *tkl = NULL;
	knh_tokens_t expr_tc;
	knh_tokens_stepFirstStmt(ctx, tc, &expr_tc, 1);

	tkl = knh_tokens_findLETNULL(&expr_tc);
	if(tkl != NULL) {
		knh_tokens_t lvalue_tc, rvalue_tc;
		knh_tokens_divideLET(&expr_tc, &lvalue_tc, &rvalue_tc);
		if(SP(tkl)->tt != TT_LET) {
			return new_StmtLETOP(ctx, &lvalue_tc, tkl, &rvalue_tc);
		}
		else{
			int lc = knh_tokens_count(&lvalue_tc, TT_COMMA);
			int rc = knh_tokens_count(&rvalue_tc, TT_COMMA);
			if(lc == 0) {
				return new_StmtLET(ctx, &lvalue_tc, &rvalue_tc);
			}
			else if(rc == 0) {
				return new_StmtLETMULTI(ctx, &lvalue_tc, &rvalue_tc);
			}
			else {
				return new_StmtLETMULTI2(ctx, &lvalue_tc, &rvalue_tc);
			}
		}
	}
	else {
		//DEBUG3_STC("S expr_tc", expr_tc);
		Term *term = new_TermEXPR(ctx, &expr_tc, KNH_STT_RVALUE);
		//DEBUG3_STC("E expr_tc", expr_tc);
		KNH_ASSERT(term != NULL);
		if(IS_Token(term)) {
			Stmt *stmt = new_Stmt(ctx, 0, STT_CALL1);
			knh_Stmt_add(ctx, stmt, term);
			return stmt;
		}
		KNH_ASSERT(IS_Stmt(term));
		return (Stmt*)term;
	}
}

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

void knh_Stmt_add_EXPR(Ctx *ctx, Stmt *stmt_b, knh_tokens_t *tc)
{
	knh_tokens_t expr_tc;
	knh_tokens_stepFirstStmt(ctx, tc, &expr_tc, 1);
	if(expr_tc.c < expr_tc.e) {
		knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &expr_tc, KNH_RVALUE));
	}
	else {
		knh_tokens_perror(ctx, tc, KMSG_EEMPTYEXPR);
	}
}

/* ======================================================================== */
/* [VALUE] */

static
Stmt *new_Stmt__stmt(Ctx *ctx, Stmt *stmt)
{
	Stmt *stmt_b = new_Stmt(ctx, 0, STT_CALL);
	knh_Stmt_add(ctx, stmt_b, TM(stmt));
	return stmt_b;
}

/* ======================================================================== */
/* [NAME] */

static
Token *new_TokenTHIS(Ctx *ctx, Token *tk)
{
	return new_TokenASIS(ctx, FL(tk));
}

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

static
Token *new_TokenFUNCNAME(Ctx *ctx, Token *tk, knh_bytes_t name, int isfunc, int lr)
{
	if(!isfunc) {
		knh_fieldn_t fn = knh_tName_get_fnq(ctx, name, FIELDN_NEWID);
		Token *tkfunc = new_TokenFN(ctx, FL(tk), fn);
		knh_Token_setGetter(tkfunc, 1);
		return tkfunc;
	}
	else {
		knh_methodn_t mn = knh_tName_getMethodn(ctx, name, METHODN_NEWID);
		return new_TokenMN(ctx, FL(tk), mn);
	}
}

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

static
Token *new_TokenVARN(Ctx *ctx, Token *tk, knh_bytes_t name)
{
	knh_fieldn_t fn = knh_tName_get_fnq(ctx, name, FIELDN_NEWID);
	return new_TokenFN(ctx, FL(tk), fn);
}

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

static
int knh_bytes_isCLASSN(knh_bytes_t t)
{
	knh_index_t i;
	if(!isupper(t.buf[0])) return 0;
	for(i = 1; i < t.len; i++) {
		if(!isalnum(t.buf[i])) return 0;
	}
	return 1;
}

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

Token *new_TokenCLASSN(Ctx *ctx, Token *tk, knh_bytes_t name)
{
	knh_NameSpace_t *ns = knh_Context_getNameSpace(ctx);
	return new_Token__S(ctx, FL(tk), TT_TYPEN, new_String__DictSet(ctx, DP(ns)->name2cidDictSet, name));
}

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

static
int knh_bytes_isCONSTN(knh_bytes_t t)
{
	knh_index_t loc = knh_bytes_rindex(t, '.');
	if(loc == -1 || !knh_bytes_isCLASSN(knh_bytes_first(t, loc))) return 0;
	t = knh_bytes_last(t,loc+1);
	knh_index_t i;
	if(!isupper(t.buf[0])) return 0;
	for(i = 1; i < t.len; i++) {
		if(!isupper(t.buf[i]) && !isdigit(t.buf[i]) && t.buf[i] != '_') return 0;
	}
	return 1;
}

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

Token *new_TokenCONSTN(Ctx *ctx, Token *tk, knh_bytes_t name)
{
	return new_Token__S(ctx, FL(tk), TT_CONSTN, new_String(ctx, name, NULL));
}

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

static
void knh_Stmt_add_FIRSTNAME(Ctx *ctx, Stmt *stmt_b, Token *tk, knh_bytes_t name, int lr)
{
	knh_index_t idx = knh_bytes_rindex(name, '.');
	knh_bool_t isfunc = (DP(tk)->tt_next == TT_PARENTHESIS) ? 1 : 0;
	KNH_ASSERT(DP(stmt_b)->size == 0);
	KNH_ASSERT(idx != -1);

	L_NAMEDIV:;
	{
		knh_bytes_t fname = knh_bytes_first(name, idx);
		knh_bytes_t lname = knh_bytes_last(name,  idx+1);

		knh_Stmt_add(ctx, stmt_b, TM(new_TokenFUNCNAME(ctx, tk, lname, isfunc, lr)));

		//DEBUG("**1 idx=%d, len=%d", (int)idx, fn.len);
		idx = knh_bytes_rindex(fname, '.');
		if(idx == -1) {
			if(knh_bytes_isCLASSN(fname)) {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenCLASSN(ctx, tk, fname)));
			}
			else if(knh_bytes_isCONSTN(fname)) {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenCONSTN(ctx, tk, fname)));
			}
			else {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenVARN(ctx, tk, fname)));
			}
			return;
		}
		else {
			Stmt *stmt_in = new_Stmt(ctx, 0, STT_CALL);
			knh_Stmt_add(ctx, stmt_b, TM(stmt_in));
			stmt_b = stmt_in;
			isfunc = 0;
			lr = KNH_RVALUE;
			name = fname;
		}
		goto L_NAMEDIV;
	}
}

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

static
void knh_Stmt_swap01(Stmt *stmt_b)
{
	KNH_ASSERT(DP(stmt_b)->size > 1);
	Term *temp = DP(stmt_b)->terms[0];
	DP(stmt_b)->terms[0] = DP(stmt_b)->terms[1];
	DP(stmt_b)->terms[1] = temp;
}

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

static
Stmt* knh_Stmt_add_SECONDNAME(Ctx *ctx, Stmt *stmt_b, Token *tk, int lr)
{
	KNH_ASSERT(SP(tk)->tt == TT_NAME);
	KNH_ASSERT(DP(stmt_b)->size == 1);
	{
		Stmt *stmt_head = stmt_b;
		knh_bytes_t name = knh_Token_tobytes(tk);
		knh_index_t idx = knh_bytes_index(name, '.');
		while(idx > 0) {
			knh_Stmt_add(ctx, stmt_head, TM(new_TokenFUNCNAME(ctx, tk, knh_bytes_first(name, idx), 0, KNH_RVALUE)));
			knh_Stmt_swap01(stmt_head);
			stmt_head = new_Stmt__stmt(ctx, stmt_head);
			name = knh_bytes_last(name, idx+1);
			idx = knh_bytes_index(name, '.');
		}
		knh_Stmt_add(ctx, stmt_head, TM(new_TokenFUNCNAME(ctx, tk, name, DP(tk)->tt_next == TT_PARENTHESIS, lr)));
		knh_Stmt_swap01(stmt_head);
		return stmt_head;
	}
}

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

static
Term *new_TermNAME(Ctx *ctx, Token *tk, int lr)
{
	KNH_ASSERT(SP(tk)->tt == TT_NAME);
	{
		knh_bytes_t t = knh_Token_tobytes(tk);
		if(knh_bytes_rindex(t, '.') == -1) {
			return TM(tk);
		}
		else {
			Stmt* stmt_b = new_Stmt(ctx, 0, STT_CALL);
			knh_Stmt_add_FIRSTNAME(ctx, stmt_b, tk, t, lr);
			return TM(stmt_b);
		}
	}
}

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

static
Stmt *new_StmtNAME1(Ctx *ctx, Token *tk, int lr)
{
	KNH_ASSERT(SP(tk)->tt == TT_NAME);
	{
		knh_bytes_t t = knh_Token_tobytes(tk);
		if(knh_bytes_rindex(t, '.') == -1) {
			Stmt *stmt_b = new_Stmt(ctx, 0, STT_CALL);
			knh_Stmt_add(ctx, stmt_b, TM(tk));
			return stmt_b;
		}
		else {
			Stmt* stmt_b = new_Stmt(ctx, 0, STT_CALL);
			knh_Stmt_add_FIRSTNAME(ctx, stmt_b, tk, t, lr);
			return new_Stmt__stmt(ctx, stmt_b);
		}
	}
}

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

static
Stmt *new_StmtNAME2(Ctx *ctx, Token *tk, int lr)
{
	DEBUG3_ASSERT(SP(tk)->tt == TT_NAME || SP(tk)->tt == TT_CMETHODN);
	knh_bytes_t t = knh_Token_tobytes(tk);
	if(knh_bytes_rindex(t, '.') == -1) {
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_CALL);
		knh_Stmt_add(ctx, stmt_b, TM(tk));
		knh_Stmt_add(ctx, stmt_b, TM(new_TokenTHIS(ctx, tk)));
		return stmt_b;
	}
	else {
		Stmt* stmt_b = new_Stmt(ctx, 0, STT_CALL);
		knh_Stmt_add_FIRSTNAME(ctx, stmt_b, tk, t, lr);
		return stmt_b;
	}
}

/* ======================================================================== */
/* [list] */

static
Term *new_TermTUPLE(Ctx *ctx, Token *tk)
{
	knh_tokens_t tc;
	int c;
	knh_Token_tc(tk, &tc);
	if(tc.e == 0) {
		return TM(new_TokenCONST(ctx, FL(tk), KNH_NULL));
	}
	c = knh_tokens_count(&tc, TT_COMMA);
	if(c == 0) {
		return new_TermEXPR(ctx, &tc, KNH_RVALUE);
	}
	else {
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_NEW);
		Token *tk_new = new_TokenMN(ctx, FL(tk), METHODN_new__init);
		knh_Stmt_add(ctx, stmt_b, TM(tk_new));
		knh_Stmt_add(ctx, stmt_b, TM(tk_new) /* DUMMY new_Token__T(ctx, tk, STEXT("Tuple"))*/);
		knh_Stmt_add_EXPRs(ctx, stmt_b, &tc);
		c = DP(stmt_b)->size - 2;
		if(c == 2) {
			KNH_SETv(ctx, DP(stmt_b)->terms[1], new_TokenCID(ctx, FL(tk), CLASS_Tuple2));
		}
#ifdef CLASS_Triple
		else if(c == 3){
			KNH_SETv(ctx, DP(stmt_b)->terms[1], new_TokenCID(ctx, FL(tk), CLASS_Triple));
		}
#endif
		else {
			KNH_SETv(ctx, DP(stmt_b)->terms[1], new_TokenCID(ctx, FL(tk), CLASS_Array));
		}
		return TM(stmt_b);
	}
}

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

static
Token *knh_tokens_findIDXNULL(knh_tokens_t *tc)
{
	int i;
	for(i = tc->c; i < tc->e; i++) {
		knh_token_t tt = SP(tc->ts[i])->tt;
		KNH_ASSERT(!knh_token_isEndOfStmt(tt));
		if(tt == TT_SUBSET || tt == TT_OFFSET || tt == TT_SLICE) {
			return tc->ts[i];
		}
	}
	return NULL;
}

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

static
Stmt *new_StmtARRAY(Ctx *ctx, Token *tk)
{
	knh_tokens_t tc;
	Token *tkidx;
	knh_Token_tc(tk, &tc);
	if((tkidx = knh_tokens_findIDXNULL(&tc)) == NULL) {
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_NEW);
		knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tk), METHODN_new__init)));
		knh_Stmt_add(ctx, stmt_b, TM(new_TokenCID(ctx, FL(tk), CLASS_Array)));
		knh_Stmt_add_EXPRs(ctx, stmt_b, &tc);
		return stmt_b;
	}
	else {
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_NEW);
		knh_tokens_t first_tc;
		knh_tokens_stepFirstEMPTYEXPR(ctx, &tc, SP(tkidx)->tt, &first_tc);
		if(SP(tkidx)->tt == TT_SUBSET) {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tk), METHODN_new)));
		}
		else if(SP(tkidx)->tt == TT_OFFSET) {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tk), METHODN_new__offset)));
		}
		else {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tk), METHODN_new__slice)));
		}
		knh_Stmt_add(ctx, stmt_b, TM(new_TokenCID(ctx, FL(tk), CLASS_Range)));
		if(first_tc.c == first_tc.e) {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenCONST(ctx, FL(tkidx), KNH_NULL)));
		}
		else {
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &first_tc, KNH_RVALUE));
		}
		if(tc.c == tc.e) {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenCONST(ctx, FL(tkidx), KNH_NULL)));
		}
		else {
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &tc, KNH_RVALUE));
		}
		return stmt_b;
	}
}

/* ======================================================================== */

static
void knh_Stmt_add_IDX(Ctx *ctx, Stmt *stmt_b, Token *tkb, int lr)
{
	KNH_ASSERT(SP(tkb)->tt == TT_BRANCET);
	{
		knh_tokens_t tc;
		Token *tkidx = NULL;

		knh_Token_tc(tkb, &tc);
		if(tc.e == 0) {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tkb), METHODN_getSize)));
			knh_Stmt_swap01(stmt_b);
			return ;
		}
		if((tkidx = knh_tokens_findIDXNULL(&tc)) == NULL) {
			if(lr == KNH_LVALUE) {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tkb), METHODN_set)));
			}
			else{
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tkb), METHODN_get)));
			}
			knh_Stmt_swap01(stmt_b);
			knh_Stmt_add_EXPRs(ctx, stmt_b, &tc);
//			if(DP(stmt_b)->size == 4) {
//				if(lr == KNH_LVALUE) {
//					DP(DP(stmt_b)->tokens[0])->mn = METHODN_set__2;
//				}
//				else{
//					DP(DP(stmt_b)->tokens[0])->mn = METHODN_get__2;
//				}
//			}
//			else if(DP(stmt_b)->size == 5){
//				if(lr == KNH_LVALUE) {
//					DP(DP(stmt_b)->tokens[0])->mn = METHODN_set__3;
//				}
//				else{
//					DP(DP(stmt_b)->tokens[0])->mn = METHODN_set__3;
//				}
//			}
		}
		else {
			knh_tokens_t first_tc;
			knh_tokens_stepFirstEMPTYEXPR(ctx, &tc, SP(tkidx)->tt, &first_tc);
			if(SP(tkidx)->tt == TT_SUBSET) {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tkb), METHODN_opSubset)));
			}
			else if(SP(tkidx)->tt == TT_OFFSET) {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tkb), METHODN_opOffset)));
			}
			else {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tkb), METHODN_opSlice)));
			}
			knh_Stmt_swap01(stmt_b);
			if(first_tc.c == first_tc.e) {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenCONST(ctx, FL(tkidx), KNH_NULL)));
			}
			else {
				knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &first_tc, KNH_RVALUE));
			}
			if(tc.c == tc.e) {
				knh_Stmt_add(ctx, stmt_b, TM(new_TokenCONST(ctx, FL(tkidx), KNH_NULL)));
			}
			else {
				knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &tc, KNH_RVALUE));
			}
		}
		knh_Token_tokens_empty(ctx, tkb);
	}
}

/* ======================================================================== */
/* [HashMap] */

static
void knh_tokens_stepFirstColon(knh_tokens_t *tc, knh_tokens_t *first_tc)
{
	int i;
	first_tc->c = tc->c;
	first_tc->ts = tc->ts;
	for(i = tc->c; i < tc->e; i++) {
		if(SP(tc->ts[i])->tt == TT_LABEL) {
			first_tc->e = i+1;
			tc->c = i + 1;
			return;
		}
		if(SP(tc->ts[i])->tt == TT_COLON) {
			first_tc->e = i;
			tc->c = i + 1;
			return ;
		}
	}
	first_tc->e = tc->e;
	tc->c = tc->e;
}

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

static
void knh_Stmt_add_PAIR(Ctx *ctx, Stmt *stmt_b, knh_tokens_t *tc)
{
	knh_tokens_t ctc;
	knh_tokens_stepFirstColon(tc, &ctc);
	if(ctc.c == ctc.e || tc->c == tc->e) {
		DEBUG3("empty!!");
		return;
	}

	if(SP(ctc.ts[ctc.e-1])->tt == TT_LABEL) {
		knh_Stmt_add(ctx, stmt_b, TM(new_TokenCONST(ctx, FL(ctc.ts[ctc.c]), UP(knh_tokens_toString(ctx, &ctc)))));
	}
	else {
		knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &ctc, KNH_RVALUE));
	}
	{
		int c = knh_tokens_count(tc, TT_COMMA);
		if(c == 0) {
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, tc, KNH_RVALUE));
		}
		else {
			Stmt *lstmt = new_Stmt(ctx, 0, STT_NEW);
			knh_Stmt_add(ctx, lstmt, TM(new_TokenMN(ctx, FL(tc->ts[tc->c]), METHODN_new__init)));
			knh_Stmt_add(ctx, lstmt, TM(new_TokenCID(ctx, FL(tc->ts[tc->c]), CLASS_Array)));
			knh_Stmt_add_EXPRs(ctx, lstmt, tc);
			knh_Stmt_add(ctx, stmt_b, TM(lstmt));
		}
	}
}

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

static
Stmt *new_StmtDICTMAP(Ctx *ctx, Token *ctk, Token *tk)
{
	int c;
	knh_tokens_t tc;
	knh_Token_tc(tk, &tc);
	c = knh_tokens_count(&tc, TT_SEMICOLON);
	if(c == 0) {
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_NEW);
		knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tk), METHODN_new__init)));
		if(IS_NULL(ctk)) {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenCID(ctx, FL(tk), CLASS_DictMap)));
		}
		else {
			knh_Stmt_add(ctx, stmt_b, TM(ctk));
		}
		while(tc.c < tc.e) {
			knh_tokens_t sub_tc;
			knh_tokens_stepFirstComma(ctx, &tc, &sub_tc);
			if(sub_tc.c < sub_tc.e) {
				knh_Stmt_add_PAIR(ctx, stmt_b, &sub_tc);
			}
		}
		return stmt_b;
	}
	else {
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_NEW);
		knh_Stmt_add(ctx, stmt_b, TM(new_TokenMN(ctx, FL(tk), METHODN_new__init)));
		if(IS_NULL(ctk)) {
			knh_Stmt_add(ctx, stmt_b, TM(new_TokenCID(ctx, FL(tk), CLASS_DictMap)));
		}
		else {
			knh_Stmt_add(ctx, stmt_b, TM(ctk));
		}
		while(tc.c < tc.e) {
			knh_tokens_t sub_tc;
			knh_tokens_stepFirstEXPR(ctx, &tc, TT_SEMICOLON, &sub_tc);
			if(sub_tc.c < sub_tc.e) {
				knh_Stmt_add_PAIR(ctx, stmt_b, &sub_tc);
			}
		}
		return stmt_b;
	}
}

/* ======================================================================== */
/* [PROPN] */

static
Stmt *new_StmtPROPN(Ctx *ctx, Token *tk, int lr)
{
	Stmt *stmt = new_Stmt(ctx, 0, STT_CALL);
	if(lr == KNH_LVALUE) {
		knh_Stmt_add(ctx, stmt, TM(new_TokenMN(ctx, FL(tk), METHODN_setProperty)));
	}else{
		knh_Stmt_add(ctx, stmt, TM(new_TokenMN(ctx, FL(tk), METHODN_getProperty)));
	}
	knh_Stmt_add(ctx, stmt, TM(new_TokenCID(ctx, FL(tk), CLASS_Context)));
	knh_Token_toCONST(tk);
	knh_Stmt_add(ctx, stmt, TM(tk));
	return stmt;
}

///* ======================================================================== */
///* [print] */
//
//void knh_Stmt_add_printname(Ctx *ctx, Stmt *stmt_b, Token **ts, int s, int e)
//{
//	//DEBUG("s=%d, e=%d", s, e);
//	if(s + 1 == e) {
//		knh_wbuf_t cb = knh_Context_wbuf(ctx);
//		if(DP(stmt_b)->size > 2) {
//			knh_putc(ctx, cb.w, ',');
//			knh_putc(ctx, cb.w, ' ');
//		}
//		int pn = 0;
//		switch(ts[s]->tt) {
//		case TT_NAME:
//			knh_write(ctx, cb.w, knh_Token_tobytes(ts[s]));
//			pn = 1;
//			break;
//		case TT_PROPN:
//			knh_putc(ctx, cb.w, '$');
//			knh_write(ctx, cb.w, knh_Token_tobytes(ts[s]));
//			pn = 1;
//			break;
//		}
//		if(pn == 1) {
////			knh_putc(ctx, cb.w, ' ');
//			knh_putc(ctx, cb.w, '=');
//			knh_Stmt_add(ctx, stmt_b, new_Token__RAW(ctx, 0, ts[s], new_StringX__buffer(ctx, CLASS_String, cb)));
//		}
//		else {
//			knh_wbuf_clear(cb);
//		}
//	}
//	;
//}
//

/* ======================================================================== */
/* [VALUE] */

static
Term *new_TermVALUE(Ctx *ctx, Token *tk, int lr)
{
	switch(SP(tk)->tt) {
		case TT_NAME:
		{
			knh_bytes_t t = knh_Token_tobytes(tk);
			if(ISB(t, "null")) {
				knh_Token_setCONST(ctx, tk, KNH_NULL);
				return TM(tk);
			}
			if(ISB(t, "true")) {
				knh_Token_setCONST(ctx, tk, KNH_TRUE);
				return TM(tk);
			}
			if(ISB(t, "false")) {
				knh_Token_setCONST(ctx, tk, KNH_FALSE);
				return TM(tk);
			}
			return new_TermNAME(ctx, tk, lr);
		}
		case TT_PARENTHESIS:
			return new_TermTUPLE(ctx, tk);
		case TT_BRANCET:
			return TM(new_StmtARRAY(ctx, tk));
		case TT_BRACE:
			return TM(new_StmtDICTMAP(ctx, (Token*)KNH_NULL, tk));
		case TT_PROPN:
			return TM(new_StmtPROPN(ctx, tk, lr));
		case TT_FMTSTR:
			TODO();
		case TT_STR:
		case TT_NUM:
		case TT_TSTR:
		case TT_URN:
		case TT_TYPEN:
		case TT_CONSTN:
		case TT_CMETHODN:
		case TT_ERR:
			return TM(tk);
	}
	DBG2_P("unexpected value: (tt=%s) %s", knh_token_tochar(SP(tk)->tt), knh_Token_tochar(tk));
	return TM(tk);
}

/* ======================================================================== */
/* [FUNCEXPR] */

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

Stmt* new_StmtFUNCEXPR(Ctx *ctx, knh_tokens_t *tc)
{
	Token** ts = tc->ts;
	int c = tc->c;
	KNH_ASSERT(c < tc->e);

	if(SP(ts[c])->tt == TT_TYPEN) {  /* @TEST int func(n) { ... } */
		if(DP(ts[c])->tt_next == TT_NAME && DP(ts[c+1])->tt_next == TT_PARENTHESIS) {
			return new_StmtMETHOD(ctx, tc);
		}
		if(DP(ts[c])->tt_next == TT_CMETHODN && DP(ts[c+1])->tt_next == TT_PARENTHESIS) { /* @TEST float Math.abs() */
			return new_StmtMETHOD(ctx, tc);
		}
		if(DP(ts[c])->tt_next == TT_NAME && knh_Token_isVARN(ts[c+1])) {  /* @TEST int name; */
			Token *tk_TYPEN = ts[c];
			tc->c += 1;
			return new_StmtDECL(ctx, tk_TYPEN, tc, -2);
		}
		if(DP(ts[c])->tt_next == TT_PARENTHESIS && DP(ts[c+1])->tt_next== TT_BRACE) { /* @TEST int (n) {...} */
			return new_StmtMETHOD(ctx, tc);
		}
	}
	/* @TEST f(n) { ... } */
	if(SP(ts[c])->tt == TT_NAME) {
		if(DP(ts[c])->tt_next == TT_PARENTHESIS && DP(ts[c+1])->tt_next== TT_BRACE) {
			return new_StmtMETHOD(ctx, tc);
		}
	}
	return new_StmtLETEXPR(ctx, tc);
}

/* ======================================================================== */
/* [STMT] */

Stmt *new_StmtINSTMT(Ctx *ctx, Token *tk)
{
	knh_tokens_t tc;
	Stmt *stmt_b = NULL;
#if defined(KONOHA_SAFEMODE)
	int prev = 0;
#endif

	KNH_ASSERT(SP(tk)->tt == TT_BRACE);
	knh_Token_tc(tk, &tc);

	while(tc.c < tc.e) {
		//DEBUG("S s = %d, c = %d, e = %d", (int)s, (int)c, (int)e);
		if(SP(tc.ts[tc.c])->tt == TT_SEMICOLON) {
			tc.c++;
			continue;
		}
#if defined(KONOHA_SAFEMODE)
		prev = tc.c;
#endif
		if(stmt_b == NULL) {
			Stmt *stmt_b2 = new_StmtSTMT1(ctx, &tc);
			if(stmt_b2 != NULL) stmt_b = stmt_b2;
		}else{
			knh_Stmt_tail_append(ctx, stmt_b, new_StmtSTMT1(ctx, &tc));
		}
#if defined(KONOHA_SAFEMODE)
		if(prev == tc.c) { /* infinate loop */
			DEBUG("Infinate loop? prev = %d, c = %d, e = %d", prev, tc.c, tc.e);
			break;
		}
#endif
	}
	if(stmt_b == NULL) {
		stmt_b = new_StmtDONE(ctx);
	}
	//DEBUG("E s = %d, c = %d, e = %d", (int)s, (int)c, (int)e);
	return stmt_b;
}

/* ======================================================================== */
/* [EXPR] */

static
void knh_tokens_checkLET(Ctx *ctx, knh_tokens_t *tc)
{
	int i;
	for(i = tc->c; i < tc->e; i++) {
		KNH_ASSERT(!knh_token_isEndOfStmt(SP(tc->ts[i])->tt));
		if(SP(tc->ts[i])->tt == TT_LET) {
			knh_Token_perror(ctx, tc->ts[i], KMSG_WLET);
			knh_Token_perrata(ctx, tc->ts[i], "==");
			SP(tc->ts[i])->tt = TT_EQ;
		}
	}
}

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

Term *new_TermPEXPR(Ctx *ctx, Token *tk)
{
	KNH_ASSERT(SP(tk)->tt == TT_PARENTHESIS);
	{
		knh_tokens_t p_tc;
		knh_Token_tc(tk, &p_tc);
		if(p_tc.e == 0) {
			knh_perror(ctx, SP(tk)->fileid, SP(tk)->line, KMSG_WEMPTYPEXPR, "()");
			knh_perrata(ctx, SP(tk)->fileid, SP(tk)->line, "()", "(false)");
			return TM(new_TokenCONST(ctx, FL(tk), KNH_FALSE));
		}
		knh_tokens_checkLET(ctx, &p_tc);
		return new_TermEXPR(ctx, &p_tc, KNH_RVALUE);
	}
}

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

void knh_Stmt_add_PEXPR(Ctx *ctx, Stmt *stmt_b, knh_tokens_t *tc)
{
	if(SP(stmt_b)->stt == STT_ERR) return;
	if(tc->c < tc->e) {
		if(SP(tc->ts[tc->c])->tt == TT_PARENTHESIS) {
			knh_Stmt_add(ctx, stmt_b, new_TermPEXPR(ctx, tc->ts[tc->c]));
			tc->c += 1;
			return ;
		}
	}
	knh_Stmt_perror(ctx, stmt_b, tc, KMSG_TPEXPR);
}

/* ======================================================================== */
/* [OP] */

static
Token *knh_tokens_findOPNULL(knh_tokens_t *tc)
{
	int i;
	Token *op = NULL, **ts = tc->ts;
	knh_token_t op_type = TT_NAME;
	for(i = tc->c; i < tc->e; i++) {
		if(TT_ALTLET < SP(ts[i])->tt && SP(ts[i])->tt < op_type) {
			op = ts[i];
			op_type = SP(ts[i])->tt;
		}
	}
	if (op == NULL) return op;
	if(knh_token_tomethodn(SP(op)->tt) != METHODN_NONAME
			|| SP(op)->tt == TT_AND || SP(op)->tt == TT_OR || SP(op)->tt == TT_ALT || SP(op)->tt == TT_QUESTION) {
		return op;
	}
	return NULL;
}

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


static
Stmt *new_StmtNEXT(Ctx *ctx, Token *op, knh_tokens_t *tc)
{
	Stmt *stmt = new_Stmt(ctx, 0, STT_CALL);
	if(SP(op)->tt == TT_NEXT) {
		knh_Stmt_add(ctx, stmt, TM(new_TokenMN(ctx, FL(op), METHODN_opNext)));
	}
	else {
		knh_Stmt_add(ctx, stmt, TM(new_TokenMN(ctx, FL(op), METHODN_opPrev)));
	}
	knh_Stmt_add(ctx, stmt, new_TermEXPR(ctx, tc, KNH_RVALUE));
	return stmt;
}

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

static
Stmt *new_StmtOP(Ctx *ctx, knh_tokens_t *tc, Token *op)
{
	knh_stmt_t stt = STT_OP;
	switch(SP(op)->tt) {
		case TT_AND: stt = STT_AND; break;
		case TT_OR:  stt = STT_OR; break;
		case TT_ALT: stt = STT_ALT; break;
		case TT_QUESTION: goto L_TRINARY;
		case TT_NEXT: case TT_PREV: goto L_NEXT;
	}
	{
		Stmt *stmt;
		if(tc->ts[tc->c] == op) {
			stmt = new_Stmt(ctx, KNH_FLAG_STMTF_ADPOSITION, stt);
			tc->c += 1;
		}
		else{
			stmt = new_Stmt(ctx, 0, stt);
		}
		if(stt == STT_OP) {
			knh_Stmt_add(ctx, stmt, TM(op));
		}
		while(tc->c < tc->e) {
			knh_tokens_t op_tc;
			knh_tokens_stepFirstEXPR(ctx, tc, SP(op)->tt, &op_tc);
			knh_Stmt_add(ctx, stmt, new_TermEXPR(ctx, &op_tc, KNH_RVALUE));
		}
		return stmt;

	}
	L_TRINARY:; {
		Stmt *stmt_b = new_Stmt(ctx, 0, STT_TRINARY);
		knh_tokens_t expr_tc;
		knh_tokens_stepFirstEXPR(ctx, tc, SP(op)->tt, &expr_tc);
		knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &expr_tc, KNH_RVALUE));
		knh_tokens_stepFirstColon(tc, &expr_tc);
		if(expr_tc.c < expr_tc.e && tc->c < tc-> e) {
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &expr_tc, KNH_RVALUE));
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, tc, KNH_RVALUE));
		}
		else {
			knh_Stmt_perror(ctx, stmt_b, &expr_tc, KMSG_ETRINARY);
		}
		return stmt_b;
	}
	L_NEXT:; {
		knh_tokens_t ltc, rtc;
		if(tc->ts[tc->c] == op) {
			tc->c += 1;
		}
		knh_tokens_stepFirstEXPR(ctx, tc, SP(op)->tt, &ltc);
		rtc = ltc;
		{
			Term *lval = new_TermEXPR(ctx, &ltc, KNH_LVALUE);
			if(IS_Token(lval)) {
				if(knh_Token_isLVALUE((Token*)lval)) {
					Stmt *stmt_b = new_Stmt(ctx, 0, STT_LET);
					knh_Stmt_add(ctx, stmt_b, lval);
					knh_Stmt_add(ctx, stmt_b, TM(new_StmtNEXT(ctx, op, &rtc)));
					return stmt_b;
				}
				else {
					knh_Token_perror(ctx, op, KMSG_ENEXTPREV);
					return new_StmtERR(ctx, &ltc);
				}
			}
			else {
				Stmt *stmt_b = (Stmt*)lval;
				KNH_ASSERT(IS_Stmt(stmt_b));
				knh_Stmt_toLVALUE(ctx, stmt_b, KMSG_ENEXTPREV);
				if(SP(stmt_b)->stt != STT_ERR) {
					knh_Stmt_add(ctx, stmt_b, TM(new_StmtNEXT(ctx, op, &rtc)));
				}
				return stmt_b;
			}
		}
	}
}

/* ======================================================================== */
/* [CAST] */

static
Token *knh_Token_findCASTNULL(Ctx *ctx, Token *tk)
{
	if(SP(tk)->tt == TT_PARENTHESIS) {
		knh_tokens_t tc;
		knh_Token_tc(tk, &tc);
		if(tc.e != 1) return NULL;
		if(SP(tc.ts[0])->tt == TT_MUL) {
			DEBUG3("* => any");
			SP(tc.ts[0])->tt = TT_CID;
			DP(tc.ts[0])->cid = CLASS_Any;
			return tc.ts[0];
		}
		if(knh_Token_isTYPEN(tc.ts[0])) {
			return tc.ts[0];
		}
	}
	return NULL;
}

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

static
Stmt *new_StmtCAST(Ctx *ctx, Token *tk_cast, knh_tokens_t *tc)
{
	Stmt *stmt = new_Stmt(ctx, 0, STT_MAPCAST);
	knh_Stmt_add(ctx, stmt, TM(tk_cast));
	knh_Stmt_add(ctx, stmt, new_TermEXPR(ctx, tc, KNH_RVALUE));
	return stmt;
}

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

static
int knh_Token_isNEW(Token *tk)
{
	char *p = knh_Token_tochar(tk);
	return (p[0]=='n' && p[1] == 'e' && p[2] == 'w' && (p[3]==0 || p[3]==':'));
 }

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

Term *new_TermEXPR(Ctx *ctx, knh_tokens_t *tc, int lr)
{
	Token **ts = tc->ts;
	int oc = tc->c, e = tc->e;
	int fc = 0, pc = 0;

	Stmt *stmt = NULL;
#ifdef KNH_DBGMODE2
	if(!(oc < e)) {
		DBG2_P("tc->c=%d, tc->e=%d", (int)oc, (int)e);
		KNH_ASSERT(oc < e);
	}
#endif

	if (oc + 1 == e) {
		return new_TermVALUE(ctx, ts[oc], lr);
	}

	for(pc = oc; pc < e; pc++) {
		if(SP(ts[pc])->tt == TT_ERR) {
			//tc->c = pc + 1;
			knh_tokens_ignore(ctx, tc);
			tc->c = tc->e;
			return TM(ts[pc]);
		}
	}
	pc = 0;

	if(SP(ts[oc])->tt == TT_NAME || SP(ts[oc])->tt == TT_CMETHODN) {
		if(DP(ts[oc])->tt_next == TT_STR || DP(ts[oc])->tt_next == TT_TSTR) { /* @TEST a.f "text" + 1 */
			stmt = new_StmtNAME2(ctx,ts[oc], KNH_RVALUE);
			tc->c = oc + 1;
			knh_Stmt_add(ctx, stmt, new_TermEXPR(ctx, tc, KNH_RVALUE));
			return TM(stmt);
		}
	}

	if(SP(ts[oc])->tt == TT_PARENTHESIS && DP(ts[oc])->tt_next == TT_NAME && knh_Token_isTopDot(ts[oc+1])) {
		if(DP(ts[oc+1])->tt_next == TT_STR || DP(ts[oc+1])->tt_next == TT_TSTR) { /* @TEST (a).f "text" + 1 */
			stmt = new_Stmt(ctx, 0, STT_CALL);
			knh_Stmt_add(ctx, stmt, new_TermVALUE(ctx, ts[oc], KNH_RVALUE));
			stmt = knh_Stmt_add_SECONDNAME(ctx, stmt, ts[oc+1], KNH_RVALUE);
			tc->c = oc + 2;
			knh_Stmt_add(ctx, stmt, new_TermEXPR(ctx, tc, KNH_RVALUE));
			return TM(stmt);
		}
	}

	/* OPERATOR */ {
		Token *tk_op = knh_tokens_findOPNULL(tc);
		if(tk_op != NULL) {
			//DEBUG("found op %s", knh_Token_tochar(op));
			return TM(new_StmtOP(ctx, tc, tk_op));
		}
	}

	/* cast operator (C)a */ {
		Token *cast_op = knh_Token_findCASTNULL(ctx, ts[oc]);
		if(cast_op != NULL) {
			tc->c += 1;
			return TM(new_StmtCAST(ctx, cast_op, tc));
		}
	}

	/** first **/
	KNH_ASSERT(fc < e);
	if(SP(ts[oc])->tt == TT_NAME || SP(ts[oc])->tt == TT_CMETHODN) {
		if(knh_Token_isNEW(ts[oc])) {  /* @TEST new:gc Person("naruto") */
			if(DP(ts[oc])->tt_next == TT_TYPEN) {
				if(DP(ts[oc+1])->tt_next == TT_PARENTHESIS) {
					stmt = new_Stmt(ctx, 0, STT_NEW);
					knh_Stmt_add(ctx, stmt, TM(ts[oc]));
					knh_Stmt_add(ctx, stmt, TM(ts[oc+1]));
					pc = oc + 2;
					goto L_PARAM;
				}
				if(DP(ts[oc+1])->tt_next == TT_BRANCET) {   /* @TEST new Int[10] */
					stmt = new_Stmt(ctx, 0, STT_NEW);
					knh_Stmt_add(ctx, stmt, TM(new_TokenMN(ctx, FL(ts[oc]), METHODN_new__array)));
					knh_Stmt_add(ctx, stmt, TM(ts[oc+1]));
					knh_Token_setArrayType(ts[oc+1], 1);
					pc = oc + 2;
					KNH_ASSERT(SP(ts[pc])->tt == TT_BRANCET);
					SP(ts[pc])->tt = TT_PARENTHESIS;
					goto L_PARAM;
				}
				tc->c = oc + 2;
				knh_tokens_perror(ctx, tc, KMSG_TARGS);  /* @TEST new Int j */
				return TM(new_StmtERR(ctx, tc));
			}
			else if(DP(ts[oc])->tt_next == TT_NAME && ISB(knh_Token_tobytes(ts[oc+1]), "byte") && DP(ts[oc+1])->tt_next == TT_BRANCET) {
				stmt = new_Stmt(ctx, 0, STT_NEW);
				knh_Stmt_add(ctx, stmt, TM(new_TokenMN(ctx, FL(ts[oc]), METHODN_new)));
				knh_Stmt_add(ctx, stmt, TM(new_Token__S(ctx, FL(ts[oc]), TT_TYPEN, knh_tClass[CLASS_Bytes].sname)));
				pc = oc + 2;
				KNH_ASSERT(SP(ts[pc])->tt == TT_BRANCET);
				SP(ts[pc])->tt = TT_PARENTHESIS;
				goto L_PARAM;
			}
			else {
				knh_Token_perror(ctx, ts[oc+1], KMSG_TCLASSN);
				return TM(new_StmtERR(ctx, tc));
			}
		}
		if(DP(ts[oc])->tt_next == TT_PARENTHESIS) {   /* @TEST func(a) */
			stmt = new_StmtNAME2(ctx, ts[oc], lr);
			pc = oc + 1;
			goto L_PARAM;
		}
		if(DP(ts[oc])->tt_next == TT_BRANCET) {    /* @TEST d[a] */
			stmt = new_StmtNAME1(ctx, ts[oc], KNH_RVALUE);
			fc = oc + 1;
			goto L_FUNC;
		}
		else {
			tc->c = oc + 1;
			knh_tokens_ignore(ctx, tc);
			return new_TermVALUE(ctx, ts[oc], lr);
		}
	}/* DP(ts[oc])->tt == TT_NAME */

	if(SP(ts[oc])->tt == TT_MT) {  /* @TEST %s(a) */
		if(DP(ts[oc])->tt_next != TT_PARENTHESIS) {
			tc->c = oc + 1;
			knh_tokens_perror(ctx, tc, KMSG_TARGS);
			return TM(new_StmtERR(ctx, tc));
		}
		stmt = new_Stmt(ctx, 0, STT_MT);
		knh_Stmt_add(ctx, stmt, TM(ts[oc]));
		pc = oc + 1;
		goto L_PARAM;
	}/* DP(ts[oc])->TT == TT_MT */

	if(knh_Token_isTYPEN(ts[oc])) {
		if(DP(ts[oc])->tt_next == TT_PARENTHESIS) {
			if(DP(ts[fc])->tt_next == TT_BRACE) {  /* @TEST Class (a,b) { ... } */
				tc->c = oc;
				stmt = new_Stmt(ctx, 0, STT_CLOSURE);
				knh_Stmt_add_TYPEN(ctx, stmt, tc);
				knh_Stmt_add_PARAMs(ctx, stmt, tc);
				knh_Stmt_add_STMT1(ctx, stmt, tc);
				fc = tc->c;
				goto L_NEXTFUNC;
			}
			else { /* @TEST Class (o, n) */
				stmt = new_Stmt(ctx, 0, STT_MAPCAST);
				knh_Stmt_add(ctx, stmt, TM(ts[oc]));
				pc = oc + 1;
				goto L_PARAM;
			}
		}
		if(DP(ts[oc])->tt_next == TT_BRACE) {  /* @TEST Class {..} */
			stmt = new_StmtDICTMAP(ctx, ts[oc], ts[oc+1]);
			tc->c = oc + 2;
			knh_tokens_ignore(ctx, tc);
			return TM(stmt);
		}
		tc->c = oc + 1;
		knh_tokens_ignore(ctx, tc);
		return TM(ts[oc]);
	}

	KNH_ASSERT(stmt == NULL);
	{
		Term *tm = new_TermVALUE(ctx, ts[oc], lr);
		if(IS_Token(tm) && SP((Token*)tm)->tt == TT_ERR) {
			return tm;
		}
		stmt = new_Stmt(ctx, 0, STT_CALL);
		knh_Stmt_add(ctx, stmt, tm);
		fc = oc + 1;
	}

	L_FUNC:; /* function name */
	KNH_ASSERT(stmt != NULL);
	KNH_ASSERT(DP(stmt)->size == 1);
	KNH_ASSERT(fc > 0);
	DEBUG3("Funcname %s", knh_token_tochar(SP(ts[fc])->tt));

	if(SP(ts[fc])->tt == TT_NAME && knh_Token_isTopDot(ts[fc])) {
		stmt = knh_Stmt_add_SECONDNAME(ctx, stmt, ts[fc], lr);
		if(DP(ts[fc])->tt_next == TT_PARENTHESIS) {  /* @TEST (a).f(a) */
			pc = fc + 1;
			goto L_PARAM;
		}
		else if(DP(ts[fc])->tt_next == TT_BRANCET) { /* @TEST (a).f[a] */
			KNH_ASSERT(DP(stmt)->size == 2);
			stmt = new_Stmt__stmt(ctx, stmt);
			fc = fc + 1;
			goto L_FUNC;
		}
		else {
			tc->c = fc + 1;
			knh_tokens_ignore(ctx, tc);
		}
		return TM(stmt);
	}
	if(SP(ts[fc])->tt == TT_BRANCET) {
		knh_Stmt_add_IDX(ctx, stmt, ts[fc], lr);
		fc = fc + 1;
		goto L_NEXTFUNC;
	}
	else {
		tc->c = fc;
		knh_tokens_ignore(ctx, tc);
	}
	return TM(stmt);

	/** third *************************************************************/

	L_PARAM:;
	KNH_ASSERT(stmt != NULL);
	KNH_ASSERT(pc > 0);
	KNH_ASSERT(SP(ts[pc])->tt == TT_PARENTHESIS);
	{
		knh_tokens_t ptc;
		knh_Token_tc(ts[pc], &ptc);
		knh_Stmt_add_EXPRs(ctx, stmt, &ptc);
	}
	if(DP(stmt)->size == 1) {
		knh_perror(ctx, SP(ts[pc])->fileid, SP(ts[pc])->line, KMSG_WEMPTYARGS, "()");
		knh_perrata(ctx, SP(ts[pc])->fileid, SP(ts[pc])->line, "()", "(null)");
		knh_Stmt_add(ctx, stmt, TM(new_TokenCONST(ctx, FL(ts[oc]), KNH_NULL)));
	}
	fc = pc + 1; pc = 0;

	L_NEXTFUNC:;
	if(fc < e) {
		stmt = new_Stmt__stmt(ctx, stmt);
		goto L_FUNC;
	}
	return TM(stmt);
}

/* ======================================================================== */
/* [(expr,expr,expr)] */

void knh_Stmt_add_EXPRs(Ctx *ctx, Stmt *stmt_b, knh_tokens_t *tc)
{
	while(tc->c < tc->e) {
		knh_tokens_t sub_tc;
		if(SP(tc->ts[tc->c])->tt == TT_SEMICOLON || knh_token_isEndOfStmt(SP(tc->ts[tc->c])->tt)) {
			return ;
		}
		//DEBUG3_PTC("tc", tc);
		knh_tokens_stepFirstComma(ctx, tc, &sub_tc);
		if(sub_tc.c < sub_tc.e) {
			knh_Stmt_add(ctx, stmt_b, new_TermEXPR(ctx, &sub_tc, KNH_RVALUE));
		}
	}
}


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

#ifdef __cplusplus
}
#endif
