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

/*****************************************************************************
 *	JTINT
 *****************************************************************************/

typedef struct _JTINT {
	int refcnt;
	JTCODE_INTERFACE* jtcode_interface;
	JTINT_INTERFACE* jtint_interface;
	ARITHMETIC_INTERFACE* arithmetic_interface;
	COMPARE_INTERFACE* compare_interface;
	//
	int value;
} JTINT;

IMPLEMENT_JTCODE_INTERFACE(JTINT, jtint)
IMPLEMENT_JTINT_INTERFACE(JTINT, jtint)
IMPLEMENT_ARITHMETIC_INTERFACE(JTINT, jtint)
IMPLEMENT_COMPARE_INTERFACE(JTINT, jtint)

const INTERFACE_MAP jtint_interface_map[] = {
	{ JTCODE_INTERFACE_ID, offsetof(JTINT, jtcode_interface), &jtcode_interface },
	{ JTINT_INTERFACE_ID, offsetof(JTINT, jtint_interface), &jtint_interface },
	{ ARITHMETIC_INTERFACE_ID, offsetof(JTINT, arithmetic_interface), &arithmetic_interface },
	{ COMPARE_INTERFACE_ID, offsetof(JTINT, compare_interface), &compare_interface },
	{ 0/*終端*/ },
};

JTCODE_INTERFACE**
jtint_create(int value)
{
	JTINT* this = calloc(1, sizeof(JTINT));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, jtint_interface_map);

	/* 値を格納します。 */
	this->value = value;

	return &this->jtcode_interface;
}

static void
jtint_delete(JTINT* this)
{
	free(this);
}

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

static JTCODE_INTERFACE**
jtcode_run(JTCODE_INTERFACE** intf)
{
	return safe_addref(intf); /* 呼び出し元のために+1 */
}

/*****************************************************************************
 *	JTINT_INTERFACE
 *****************************************************************************/

static int
jtint_get_value(JTINT_INTERFACE** intf)
{
	JTINT* this = CONTAINING_RECORD(intf, JTINT, jtint_interface);

	/* 値を返します。 */
	return this->value;
}

/*****************************************************************************
 *	ARITHMETIC_INTERFACE
 *****************************************************************************/

static JTCODE_INTERFACE**
arithmetic_neg(ARITHMETIC_INTERFACE** intf)
{
	JTINT* this = CONTAINING_RECORD(intf, JTINT, arithmetic_interface);

	return jtint_create(-this->value);
}

static JTCODE_INTERFACE**
arithmetic_add(ARITHMETIC_INTERFACE** intf, JTCODE_INTERFACE** code)
{
	JTINT* this = CONTAINING_RECORD(intf, JTINT, arithmetic_interface);
	//
	JTINT_INTERFACE** jtint = NULL;
	int value;

	safe_assign_interface(jtint, code, JTINT_INTERFACE);
	if(!jtint) {
		DIE(); /* JTINT_INTERFACEが必要 */
	}
	value = (*jtint)->get_value(jtint);
	safe_release(jtint);

	return jtint_create(this->value + value);
}

static JTCODE_INTERFACE**
arithmetic_sub(ARITHMETIC_INTERFACE** intf, JTCODE_INTERFACE** code)
{
	JTINT* this = CONTAINING_RECORD(intf, JTINT, arithmetic_interface);
	//
	JTINT_INTERFACE** jtint = NULL;
	int value;

	safe_assign_interface(jtint, code, JTINT_INTERFACE);
	if(!jtint) {
		DIE(); /* JTINT_INTERFACEが必要 */
	}
	value = (*jtint)->get_value(jtint);
	safe_release(jtint);

	return jtint_create(this->value - value);
}

static JTCODE_INTERFACE**
arithmetic_mul(ARITHMETIC_INTERFACE** intf, JTCODE_INTERFACE** code)
{
	JTINT* this = CONTAINING_RECORD(intf, JTINT, arithmetic_interface);
	//
	JTINT_INTERFACE** jtint = NULL;
	int value;

	safe_assign_interface(jtint, code, JTINT_INTERFACE);
	if(!jtint) {
		DIE(); /* JTINT_INTERFACEが必要 */
	}
	value = (*jtint)->get_value(jtint);
	safe_release(jtint);

	return jtint_create(this->value * value);
}

static JTCODE_INTERFACE**
arithmetic_div(ARITHMETIC_INTERFACE** intf, JTCODE_INTERFACE** code)
{
	JTINT* this = CONTAINING_RECORD(intf, JTINT, arithmetic_interface);
	//
	JTINT_INTERFACE** jtint = NULL;
	int value;

	safe_assign_interface(jtint, code, JTINT_INTERFACE);
	if(!jtint) {
		DIE(); /* JTINT_INTERFACEが必要 */
	}
	value = (*jtint)->get_value(jtint);
	safe_release(jtint);

	return jtint_create(this->value / value);
}

/*****************************************************************************
 *	COMPARE_INTERFACE
 *****************************************************************************/

static int
compare_compare(COMPARE_INTERFACE** intf, JTCODE_INTERFACE** code)
{
	JTINT* this = CONTAINING_RECORD(intf, JTINT, compare_interface);
	//
	JTINT_INTERFACE** jtint = NULL;
	int value;

	safe_assign_interface(jtint, code, JTINT_INTERFACE);
	if(!jtint) {
		DIE(); /* JTINT_INTERFACEが必要 */
	}
	value = (*jtint)->get_value(jtint);
	safe_release(jtint);

	return (this->value > value) ?  1 :
	       (this->value < value) ? -1 : 0;
}

