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

/*****************************************************************************
 *	JTFUNCALL
 *****************************************************************************/

typedef struct _JTFUNCALL {
	int refcnt;
	JTCODE_INTERFACE* jtcode_interface;
	//
	JTSYMBOL_INTERFACE** symbol;			/* 関数名を表すシンボル */
	LIST/*<JTCODE_INTERFACE**>*/ * args_list;	/* 実引数リスト */
} JTFUNCALL;

IMPLEMENT_JTCODE_INTERFACE(JTFUNCALL, jtfuncall)

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

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

	/* 関数名を表すシンボルを格納します。 */
	safe_assign(this->symbol, symbol);

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

	return &this->jtcode_interface;
}

static void
jtfuncall_delete(JTFUNCALL* this)
{
	/* 関数名を表すシンボルを解放します。 */
	safe_release(this->symbol);

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

	free(this);
}

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

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

	/* 現在の関数フレームの、実行対象オブジェクト、または、NULLを取得します。 */
	safe_attach(object, joytoy_get_object());

	/* シンボルに対応する、関数を取得します。 */
	safe_attach(code, joytoy_get_symbol_value(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);
	}

	/* 関数、または、メソッドを呼び出します。
	 * - 現在の関数フレームに、実行対象オブジェクトがあれば、すなわち、メソッドの実行中ならば、引数objectは常に指定します。
	 *   ただし、引数objectを指定した場合であっても、呼び出し先が通常の関数ならば、呼び出し先の処理によって、無視されます。
	 */
	safe_attach(code, (*fun)->call(fun, args_list, object));

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

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

	return code;
}

