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

/*****************************************************************************
 *	JTPRIM
 *****************************************************************************/

/* 組み込み関数の実装を簡単にするための、共通基底クラスに相当します。 */

typedef struct _JTPRIM {
	int refcnt;
	JTCODE_INTERFACE* jtcode_interface;
	JTFUN_INTERFACE* jtfun_interface;
	//
	JTSYMBOL_INTERFACE** name;						/* 組み込み関数名を表すシンボル */
	JTCODE_INTERFACE** (*call)(LIST/*<JTCODE_INTERFACE**>*/ * args_list);	/* 組み込み関数の処理を行う関数 */
} JTPRIM;

IMPLEMENT_JTCODE_INTERFACE(JTPRIM, jtprim)
IMPLEMENT_JTFUN_INTERFACE(JTPRIM, jtprim)

const INTERFACE_MAP jtprim_interface_map[] = {
	{ JTCODE_INTERFACE_ID, offsetof(JTPRIM, jtcode_interface), &jtcode_interface },
	{ JTFUN_INTERFACE_ID, offsetof(JTPRIM, jtfun_interface), &jtfun_interface },
	{ 0/*終端*/ },
};

JTCODE_INTERFACE**
jtprim_create(const char* name, JTCODE_INTERFACE** (*call)(LIST/*<JTCODE_INTERFACE**>*/ * args_list))
{
	JTPRIM* this = calloc(1, sizeof(JTPRIM));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, jtprim_interface_map);

	/* 組み込み関数名を表すシンボルを作成し、格納します。 */
	{
		JTCODE_INTERFACE** code = NULL;
		JTSYMBOL_INTERFACE** symbol = NULL;
		//
		safe_attach(code, jtsymbol_intern(name));
		safe_assign_interface(symbol, code, JTSYMBOL_INTERFACE);
		if(!symbol) {
			DIE(); /* 有り得ない */
		}
		safe_assign(this->name, symbol);
		//
		safe_release(code);
		safe_release(symbol);
	}

	/* 組み込み関数の処理を行う関数を格納します。 */
	this->call = call;

	return &this->jtcode_interface;
}

static void
jtprim_delete(JTPRIM* this)
{
	/* 組み込み関数名を表すシンボルを開放します。 */
	safe_release(this->name);

	free(this);
}

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

static JTCODE_INTERFACE**
jtcode_run(JTCODE_INTERFACE** intf)
{
	JTPRIM* this = CONTAINING_RECORD(intf, JTPRIM, jtcode_interface);

	/* ローカル変数テーブル、または、グローバル変数テーブルに、組み込み関数を登録します。 */
	joytoy_def_symbol_value(this->name, intf);

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

/*****************************************************************************
 *	JTFUN_INTERFACE
 *****************************************************************************/

static JTSYMBOL_INTERFACE**
jtfun_get_name(JTFUN_INTERFACE** intf)
{
	JTPRIM* this = CONTAINING_RECORD(intf, JTPRIM, jtfun_interface);

	/* 組み込み関数名を表すシンボルを返します。 */
	return safe_addref(this->name); /* 呼び出し元のために+1 */
}

static JTCODE_INTERFACE**
jtfun_call(JTFUN_INTERFACE** intf, LIST/*<JTCODE_INTERFACE**>*/ * args_list, JTOBJECT_INTERFACE** object)
{
	JTPRIM* this = CONTAINING_RECORD(intf, JTPRIM, jtfun_interface);

	/* 組み込み関数の処理を行う関数を実行します。 */
	return this->call(args_list);
}

