/*
 *	jtwhile.c
 *
 *	JoyToyインタプリタ
 *
 *	* Sun Jan 01 00:00:00 JST 2006 Naoyuki Sawa
 *	- 作成開始。
 *	* Tue Jan 31 00:00:00 JST 2006 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Jun 17 05:26:02 JST 2006 Naoyuki Sawa
 *	- FIELD_OFFSET()→offsetof()に変更。
 */
#include "app.h"

/*****************************************************************************
 *	JTWHILE
 *****************************************************************************/

typedef struct _JTWHILE {
	int refcnt;
	JTCODE_INTERFACE* jtcode_interface;
	//
	JTCODE_INTERFACE** cond;	/* 条件式 */
	JTCODE_INTERFACE** body;	/* 条件式が真の間、実行し続ける文 */
} JTWHILE;

IMPLEMENT_JTCODE_INTERFACE(JTWHILE, jtwhile)

const INTERFACE_MAP jtwhile_interface_map[] = {
	{ JTCODE_INTERFACE_ID, offsetof(JTWHILE, jtcode_interface), &jtcode_interface },
	{ 0/*終端*/ },
};

JTCODE_INTERFACE**
jtwhile_create(JTCODE_INTERFACE** cond, JTCODE_INTERFACE** body)
{
	JTWHILE* this = calloc(1, sizeof(JTWHILE));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, jtwhile_interface_map);

	/* 条件式、条件式が真の間、実行し続ける文を格納します。 */
	safe_assign(this->cond, cond);
	safe_assign(this->body, body);

	return &this->jtcode_interface;
}

static void
jtwhile_delete(JTWHILE* this)
{
	/* 条件式、条件式が真の間、実行し続ける文を解放します。 */
	safe_release(this->cond);
	safe_release(this->body);

	free(this);
}

/*****************************************************************************
 *	JTCODE_INTERFACE
 *****************************************************************************/

static JTCODE_INTERFACE**
jtcode_run(JTCODE_INTERFACE** intf)
{
	JTWHILE* this = CONTAINING_RECORD(intf, JTWHILE, jtcode_interface);
	//
	JTCODE_INTERFACE** code = NULL;
	JTCODE_INTERFACE** cond = NULL;
	JTBOOL_INTERFACE** jtbool = NULL;

	for(;;) {
		/* 条件式を実行します。 */
		safe_attach(cond, (*this->cond)->run(this->cond));
		safe_assign_interface(jtbool, cond, JTBOOL_INTERFACE);
		if(!jtbool) {
			DIE(); /* JTBOOL_INTERFACEが必要 */
		}

		/* 実行結果が偽ならば、抜けます。 */
		if(!(*jtbool)->get_value(jtbool)) {
			break;
		}

		/* 条件式が真の間、実行し続ける文を実行します。 */
		safe_attach(code, (*this->body)->run(this->body));
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(cond);
	safe_release(jtbool);

	return code;
}

