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

/*****************************************************************************
 *	JTDOTCALL
 *****************************************************************************/

typedef struct _JTDOTCALL {
	int refcnt;
	JTCODE_INTERFACE* jtcode_interface;
	//
	JTCODE_INTERFACE** code;			/* オブジェクト */
	JTSYMBOL_INTERFACE** symbol;			/* メソッド名を表すシンボル */
	LIST/*<JTCODE_INTERFACE**>*/ * args_list;	/* 実引数リスト */
} JTDOTCALL;

IMPLEMENT_JTCODE_INTERFACE(JTDOTCALL, jtdotcall)

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

JTCODE_INTERFACE**
jtdotcall_create(JTCODE_INTERFACE** code, JTSYMBOL_INTERFACE** symbol, LIST/*<JTCODE_INTERFACE**>*/ * args_list)
{
	JTDOTCALL* this = calloc(1, sizeof(JTDOTCALL));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, jtdotcall_interface_map);

	/* オブジェクト、メソッド名を表すシンボルを格納します。 */
	safe_assign(this->code, code);
	safe_assign(this->symbol, symbol);

	/* 実引数リストを複製して、格納します。 */
	this->args_list = list_duplicate(args_list);

	return &this->jtcode_interface;
}

static void
jtdotcall_delete(JTDOTCALL* this)
{
	/* オブジェクト、メソッド名を表すシンボルを解放します。 */
	safe_release(this->code);
	safe_release(this->symbol);

	/* 実引数リストを削除します。 */
	list_delete(this->args_list);

	free(this);
}

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

static JTCODE_INTERFACE**
jtcode_run(JTCODE_INTERFACE** intf)
{
	JTDOTCALL* this = CONTAINING_RECORD(intf, JTDOTCALL, jtcode_interface);
	//
	JTCODE_INTERFACE** code = NULL;
	JTFUN_INTERFACE** fun = NULL;
	JTOBJECT_INTERFACE** object = NULL;
	//
	int i;
	int count;
	LIST/*<JTCODE_INTERFACE**>*/ * args_list;

	/* メソッドを呼び出す直前のタイミングで、オブジェクトを評価します。 */
	safe_attach(code, (*this->code)->run(this->code)); /* シンボルを解決して、オブジェクトを取得する処理など */
	safe_assign_interface(object, code, JTOBJECT_INTERFACE);
	if(!object) {
		DIE(); /* オブジェクトでない (読み込んだプログラムのエラー) */
	}

	/* シンボルに対応する、関数を取得します。 */
	safe_attach(code, (*object)->get_field_value(object, this->symbol));
	if(!code) {
		DIE(); /* 未定義 (読み込んだプログラムのエラー) */
	}
	safe_assign_interface(fun, code, JTFUN_INTERFACE);
	if(!fun) {
		DIE(); /* 関数でない (読み込んだプログラムのエラー) */
	}

	/* 一時的な実引数リストを作成します。(評価した実引数を格納するため) */
	args_list = list_create(&jtcode_list_info);

	/* メソッドを呼び出す直前のタイミングで、実引数を評価します。 */
	count = list_size(this->args_list);
	for(i = 0; i < count; i++) {
		safe_attach(code, list_get(this->args_list, i));
		safe_attach(code, (*code)->run(code));
		list_add(args_list, code);
	}

	/* メソッドを呼び出します。 */
	safe_attach(code, (*fun)->call(fun, args_list, object));

	/* 一時的な実引数リストを削除します。 */
	list_delete(args_list);

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

	return code;
}

