/*
 *	jtif.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"

/*****************************************************************************
 *	JTIF
 *****************************************************************************/

typedef struct _JTIF {
	int refcnt;
	JTCODE_INTERFACE* jtcode_interface;
	//
	JTCODE_INTERFACE** cond;	/* 条件式 */
	JTCODE_INTERFACE** then_body;	/* 条件式が真のときに実行する文 */
	JTCODE_INTERFACE** else_body;	/* 条件式が偽のときに実行する文、または、NULL */
} JTIF;

IMPLEMENT_JTCODE_INTERFACE(JTIF, jtif)

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

JTCODE_INTERFACE**
jtif_create(JTCODE_INTERFACE** cond, JTCODE_INTERFACE** then_body, JTCODE_INTERFACE** else_body)
{
	JTIF* this = calloc(1, sizeof(JTIF));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, jtif_interface_map);

	/* 条件式、条件式が真のときに実行する文、条件式が偽のときに実行する文を格納します。 */
	safe_assign(this->cond, cond);
	safe_assign(this->then_body, then_body);
	safe_assign(this->else_body, else_body);

	return &this->jtcode_interface;
}

static void
jtif_delete(JTIF* this)
{
	/* 条件式、条件式が真のときに実行する文、条件式が偽のときに実行する文を解放します。 */
	safe_release(this->cond);
	safe_release(this->then_body);
	safe_release(this->else_body);

	free(this);
}

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

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

	/* 条件式を実行します。 */
	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)) {
		safe_assign(body, this->then_body);
	} else {
		safe_assign(body, this->else_body); /* NULL: elseブロック無し */
	}

	/* 選択された文を実行します。
	 * 実行結果が偽で、elseブロックが無い場合のために、NULL判定が必要です。
	 */
	if(body) {
		safe_attach(code, (*body)->run(body));
	}

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

	return code;
}

