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

/*****************************************************************************
 *	JTUNEXPR
 *****************************************************************************/

typedef struct _JTUNEXPR {
	int refcnt;
	JTCODE_INTERFACE* jtcode_interface;
	//
	int op;				/* 演算子 */
	JTCODE_INTERFACE** code;	/* 値 */
} JTUNEXPR;

IMPLEMENT_JTCODE_INTERFACE(JTUNEXPR, jtunexpr)

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

JTCODE_INTERFACE**
jtunexpr_create(int op, JTCODE_INTERFACE** code)
{
	JTUNEXPR* this = calloc(1, sizeof(JTUNEXPR));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, jtunexpr_interface_map);

	/* 演算子、値を格納します。 */
	this->op = op;
	safe_assign(this->code, code);

	return &this->jtcode_interface;
}

static void
jtunexpr_delete(JTUNEXPR* this)
{
	/* 値を解放します。 */
	safe_release(this->code);

	free(this);
}

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

static JTCODE_INTERFACE**
jtcode_run(JTCODE_INTERFACE** intf)
{
	JTUNEXPR* this = CONTAINING_RECORD(intf, JTUNEXPR, jtcode_interface);
	//
	JTCODE_INTERFACE** code = NULL;
	ARITHMETIC_INTERFACE** arithmetic = NULL;
	LOGICAL_INTERFACE** logical = NULL;

	/* 値を解決します。 */
	safe_attach(code, (*this->code)->run(this->code));

	/* 演算子によって... */
	switch(this->op) {
	case '-':
		safe_assign_interface(arithmetic, code, ARITHMETIC_INTERFACE);
		if(!arithmetic) {
			DIE(); /* 算術演算不可 */
		}
		safe_attach(code, (*arithmetic)->neg(arithmetic));
		break;

	case '!':
		safe_assign_interface(logical, code, LOGICAL_INTERFACE);
		if(!logical) {
			DIE(); /* 論理演算不可 */
		}
		safe_attach(code, (*logical)->not(logical));
		break;

	default:
		DIE(); /* 不明な演算子 */
	}

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

	return code;
}

