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

/* ======================================================================== */
/* [struct] */

Token* knh_tokens_curToken(knh_tokens_t *tc)
{
	int c = tc->c;
	while(!(c < tc->e)) {
		if(c == 0) break;
		c--;
	}
	return tc->ts[c];
}

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

Token* knh_tokens_prevToken(knh_tokens_t *tc)
{
	int c = tc->c - 1;
	while(!(c < tc->e)) {
		if(c == 0) break;
		c--;
	}
	return tc->ts[c];
}
	
/* ------------------------------------------------------------------------ */
	
int knh_tokens_count(knh_tokens_t *tc, knh_token_t tt)
{
	Token **ts = tc->ts;
	int i, cnt = 0;
	for(i = tc->c; i < tc->e; i++) {
		if(DP(ts[i])->tt == tt) cnt++;
	}
	return cnt;
}

/* ------------------------------------------------------------------------ */
	
void
knh_tokens_nextStmt(knh_tokens_t *tc)
{
	Token **ts = tc->ts;
	int i;
	for(i = tc->c; i < tc->e; i++) {
		if(DP(ts[i])->tt == TT_SEMICOLON) {
			tc->c = i + 1;
			return;
		}
		if(knh_token_isEndOfStmt(DP(ts[i])->tt)) {
			tc->c = i;
			return;
		}
	}
	tc->c = tc->e;
}

/* ------------------------------------------------------------------------ */
	
void
knh_tokens_stepFirstStmt(Ctx *ctx, knh_tokens_t *tc, knh_tokens_t *sub, int needsSEMICOLON)
{
	Token **ts = tc->ts;
	int i;
	for(i = tc->c; i < tc->e; i++) {
		if(DP(ts[i])->tt == TT_SEMICOLON) {
			if(sub != NULL) {
				sub->ts = tc->ts;
				sub->c = tc->c;
				sub->e = i;
			}
			tc->c = i + 1;
			return;
		}
		if(knh_token_isEndOfStmt(DP(ts[i])->tt)) {
			break;
		}
	}
	//KNH_ASSERT(DP(ts[i])->tt != TT_SEMICOLON);
	if(sub != NULL) {
		sub->ts = tc->ts;
		sub->c = tc->c;
		sub->e = i;
	}
	tc->c = tc->e;
	if(needsSEMICOLON) {
		knh_Token_perror(ctx, knh_tokens_prevToken(tc), KMSG_WSEMICOLON);
	}
}
/* ------------------------------------------------------------------------ */

void
knh_tokens_ignore(Ctx *ctx, knh_tokens_t *tc)
{
	if(tc->c < tc->e) {
		Token *tks = tc->ts[tc->c], *tke = tc->ts[tc->e - 1];
		if(tks == tke) {
			knh_perror(ctx, DP(tks)->fileid, DP(tks)->line, KMSG_WIGNORED, knh_Token_tochar(tks));
		}
		else {
			knh_bytes_t st = knh_Token_tobytes(tks), et = knh_Token_tobytes(tke);
			char sbuf[16], ebuf[16];
			int i;
			for(i = 0; i < 16; i++) {
				sbuf[i] = (char)st.buf[i];
				if(sbuf[i] == 0) break;
				if(st.buf[i] < 128 && i > 8) {
					sbuf[i+1] = 0;
					break;
				}
			}
			i = et.len - 8;
			if(i < 0) i = 0;
			for(; i < et.len; i++) {
				if(et.buf[i] < 128) break;
			}
			for(; i < et.len; i++) {
				ebuf[i] = (char)et.buf[i];
				if(ebuf[i] == 0) break;
			}
			ebuf[i] = 0;
			{
				char buf[40];
				snprintf(buf, sizeof(buf), "%s ... %s", sbuf, ebuf);
				knh_perror(ctx, DP(tks)->fileid, DP(tks)->line, KMSG_WIGNORED, buf);
			}
		}
		DEBUG3_PTC("tc", tc);
		tc->c = tc->e;
	}
}

/* ------------------------------------------------------------------------ */
	
void
knh_tokens_stepFirstEXPR(Ctx *ctx, knh_tokens_t *tc, knh_token_t tt, knh_tokens_t *sub)
{
	Token **ts = tc->ts;
	int i;
	for(i = tc->c; i < tc->e; i++) {
		if(DP(ts[i])->tt == tt) {
			if(tc->c == i) {
				DEBUG3("EMPTY BWTEWEEN two %ss", knh_token_tochar(tt)); 
				tc->c = i + 1;
				knh_tokens_stepFirstEXPR(ctx, tc, tt, sub);
				return;
			}
			if(sub != NULL) {
				sub->ts = tc->ts;
				sub->c = tc->c;
				sub->e = i;
			}
			tc->c = i + 1;
			return;
		}
		if(DP(ts[i])->tt == TT_SEMICOLON || knh_token_isEndOfStmt(DP(ts[i])->tt)) {
			DEBUG3("EXPR has ';' or statement");
			tc->e = i;
			break ;
		}
	}
	if(sub != NULL) {
		sub->ts = tc->ts;
		sub->c = tc->c;
		sub->e = i;
	}
	tc->c = tc->e;
}

/* ------------------------------------------------------------------------ */
	
void
knh_tokens_stepFirstEMPTYEXPR(Ctx *ctx, knh_tokens_t *tc, knh_token_t tt, knh_tokens_t *sub)
{
	Token **ts = tc->ts;
	int i;
	for(i = tc->c; i < tc->e; i++) {
		if(DP(ts[i])->tt == tt) {
			if(sub != NULL) {
				sub->ts = tc->ts;
				sub->c = tc->c;
				sub->e = i;
			}
			tc->c = i + 1;
			return;
		}
		if(DP(ts[i])->tt == TT_SEMICOLON || knh_token_isEndOfStmt(DP(ts[i])->tt)) {
			DEBUG3("EXPR has ';' or statement");
			tc->e = i;
			break ;
		}
	}
	if(sub != NULL) {
		sub->ts = tc->ts;
		sub->c = tc->c;
		sub->e = i;
	}
	tc->c = tc->e;
}

/* ------------------------------------------------------------------------ */
	
void
knh_tokens_stepFirstComma(Ctx *ctx, knh_tokens_t *tc, knh_tokens_t *sub)
{
	Token **ts = tc->ts;
	int i;
	for(i = tc->c; i < tc->e; i++) {
		if(DP(ts[i])->tt == TT_COMMA) {
			if(tc->c == i) { /* empty */
				DEBUG3("***EMPTY!!***");
				tc->c = i + 1;
				knh_tokens_stepFirstComma(ctx, tc, sub);
				return;
			}
			if(sub != NULL) {
				sub->ts = tc->ts;
				sub->c = tc->c;
				sub->e = i;
			}
			tc->c = i + 1;
			return;
		}
		if(DP(ts[i])->tt == TT_SEMICOLON || knh_token_isEndOfStmt(DP(ts[i])->tt)) {
			if(sub != NULL) {
				sub->ts = tc->ts;
				sub->c = tc->c;
				sub->e = i;
			}
			if(tc->c != i) {
				tc->c = i;
			}
			else {
				tc->c = i + 1;
			}
			return;
		}
	}
	if(sub != NULL) {
		sub->ts = tc->ts;
		sub->c = tc->c;
		sub->e = tc->e;
	}
	tc->c = tc->e;
}

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

String *knh_tokens_toString(Ctx *ctx, knh_tokens_t *tc)
{
	/* name: java => name */
	if(tc->c + 1 == tc->e && DP(tc->ts[tc->c])->tt == TT_LABEL) {
		KNH_ASSERT(IS_String(DP(tc->ts[tc->c])->data));
		return DP(tc->ts[tc->c])->str;
	}
	else {
		int i;
		knh_wbuf_t cb = knh_Context_wbuf(ctx);
		for(i = tc->c; i <tc->e; i++) {
			knh_Token__s(ctx, tc->ts[i], cb.w, KNH_NULL);
		}
		return new_String__wbuf(ctx, cb);
	}
}

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

#ifdef __cplusplus 
}
#endif
