621 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			621 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include "mod-hawk.h"
 | |
| #include "hawk-prv.h"
 | |
| #include <hawk-mtx.h>
 | |
| 
 | |
| 
 | |
| struct mod_data_t
 | |
| {
 | |
| 	hawk_mtx_t mq_mtx;
 | |
| };
 | |
| typedef struct mod_data_t mod_data_t;
 | |
| /* ----------------------------------------------------------------- */
 | |
| 
 | |
| /*
 | |
|  * function abc(a, b, c) { return a + b + c; }
 | |
|  * BEGIN { print hawk::call("abc", 10, 20, 30); }
 | |
|  */
 | |
| struct pafs_t
 | |
| {
 | |
| 	int is_fun;
 | |
| 
 | |
| 	const hawk_ooch_t* argspec_ptr;
 | |
| 	hawk_oow_t argspec_len;
 | |
| 
 | |
| 	hawk_oow_t stack_base;
 | |
| 	hawk_oow_t start_index;
 | |
| 	hawk_oow_t end_index;
 | |
| };
 | |
| 
 | |
| static hawk_oow_t push_args_from_stack (hawk_rtx_t* rtx, hawk_nde_fncall_t* call, void* data)
 | |
| {
 | |
| 	struct pafs_t* pasf = (struct pafs_t*)data;
 | |
| 	hawk_oow_t org_stack_base, i, j;
 | |
| 	hawk_val_t* v;
 | |
| 
 | |
| 	if (HAWK_RTX_STACK_AVAIL(rtx) < pasf->end_index - pasf->start_index + 1)
 | |
| 	{
 | |
| 		hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ESTACK);
 | |
| 		return (hawk_oow_t)-1;
 | |
| 	}
 | |
| 
 | |
| 	org_stack_base = rtx->stack_base;
 | |
| 	for (i = pasf->start_index, j = 0; i <= pasf->end_index; i++, j++)
 | |
| 	{
 | |
| 		hawk_ooch_t spec;
 | |
| 
 | |
| 		rtx->stack_base = pasf->stack_base;
 | |
| 		v = HAWK_RTX_STACK_ARG(rtx, i);
 | |
| 		rtx->stack_base = org_stack_base;
 | |
| 
 | |
| 		/* if not sufficient number of spec characters given, take the last value and use it */
 | |
| 		spec = (pasf->argspec_len <= 0)? '\0': pasf->argspec_ptr[((j < pasf->argspec_len)? j: pasf->argspec_len - 1)];
 | |
| 
 | |
| 		if (HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_REF)
 | |
| 		{
 | |
| 			if (pasf->is_fun)
 | |
| 			{
 | |
| 				/* take out the actual value and pass it to the callee
 | |
| 				 * only if the callee is a user-defined function */
 | |
| 				v = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)v);
 | |
| 			}
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 			if (spec == 'r') /* 'R' allows a normal value. so only checking 'r' here */
 | |
| 			{
 | |
| 				hawk_rtx_seterrnum (rtx, &call->loc, HAWK_ENOTREF);
 | |
| 				return (hawk_oow_t)-1;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		HAWK_RTX_STACK_PUSH (rtx, v);
 | |
| 		hawk_rtx_refupval (rtx, v);
 | |
| 	}
 | |
| 
 | |
| 	return pasf->end_index - pasf->start_index + 1;
 | |
| }
 | |
| 
 | |
| static int fnc_call (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_fun_t* fun;
 | |
| 	hawk_oow_t nargs, f_nargs;
 | |
| 	hawk_nde_fncall_t call;
 | |
| 	struct pafs_t pafs;
 | |
| 	hawk_val_t* v;
 | |
| 
 | |
| 	/* this function is similar to hawk_rtx_callfun() but it is more simplified */
 | |
| 	HAWK_MEMSET (&call, 0, HAWK_SIZEOF(call));
 | |
| 	nargs = hawk_rtx_getnargs(rtx);
 | |
| 	f_nargs = nargs - 1;
 | |
| 
 | |
| 	fun = hawk_rtx_valtofun(rtx, hawk_rtx_getarg(rtx, 0));
 | |
| 	if (fun)
 | |
| 	{
 | |
| 		if (f_nargs > fun->nargs)
 | |
| 		{
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EARGTM);
 | |
| 			return -1; /* hard failure */
 | |
| 		}
 | |
| 
 | |
| 		/* user-defined function call */
 | |
| 		call.type = HAWK_NDE_FNCALL_FUN;
 | |
| 		call.u.fun.name = fun->name;
 | |
| 
 | |
| 		pafs.is_fun = 1;
 | |
| 		pafs.argspec_ptr = fun->argspec;
 | |
| 		pafs.argspec_len = fun->argspec? hawk_count_oocstr(fun->argspec): 0;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		/* find the name in the modules */
 | |
| 		hawk_fnc_t fnc, * fncp;
 | |
| 		mod_data_t* md;
 | |
| 
 | |
| 		md = (mod_data_t*)fi->mod->ctx;
 | |
| 
 | |
| 		/* hawk_querymodulewithname() called by hawk_rtx_valtofnc()
 | |
| 		 * may update some shared data under the hawk object.
 | |
| 		 * use a mutex for shared data safety */
 | |
| 		/* TODO: this mutex protection is wrong in that if a call to hawk_querymodulewithname()
 | |
| 		 *       is made outside this hawk module, the call is not protected under
 | |
| 		 *       the same mutex. FIX THIS */
 | |
| 		hawk_mtx_lock(&md->mq_mtx, HAWK_NULL);
 | |
| 		fncp = hawk_rtx_valtofnc(rtx, hawk_rtx_getarg(rtx, 0), &fnc);
 | |
| 		hawk_mtx_unlock(&md->mq_mtx);
 | |
| 		if (!fncp) return -1; /* hard failure */
 | |
| 
 | |
| 		if (f_nargs < fnc.spec.arg.min  || f_nargs > fnc.spec.arg.max)
 | |
| 		{
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EARGTM);
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		call.type = HAWK_NDE_FNCALL_FNC;
 | |
| 		call.u.fnc.info.name.ptr = fnc.name.ptr;
 | |
| 		call.u.fnc.info.name.len = fnc.name.len;
 | |
| 		call.u.fnc.info.mod = fnc.mod;
 | |
| 		call.u.fnc.spec = fnc.spec;
 | |
| 
 | |
| 		pafs.is_fun = 0;
 | |
| 		pafs.argspec_ptr = call.u.fnc.spec.arg.spec;
 | |
| 		pafs.argspec_len = call.u.fnc.spec.arg.spec? hawk_count_oocstr(call.u.fnc.spec.arg.spec): 0;
 | |
| 	}
 | |
| 
 | |
| 	call.nargs = f_nargs;
 | |
| 	/* keep HAWK_NULL in call.args so that hawk_rtx_evalcall() knows it's a fake call structure */
 | |
| 	call.arg_base = rtx->stack_base + 5; /* 5 = 4(stack frame prologue) + 1(the first argument to hawk::call()) */
 | |
| 
 | |
| 	pafs.stack_base = rtx->stack_base;
 | |
| 	pafs.start_index = 1;
 | |
| 	pafs.end_index = nargs - 1;
 | |
| 
 | |
| 	v = hawk_rtx_evalcall(rtx, &call, fun, push_args_from_stack, (void*)&pafs, HAWK_NULL, HAWK_NULL);
 | |
| 	if (HAWK_UNLIKELY(!v)) return -1; /* hard failure */
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, v);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* hawk::function_exists("xxxx");
 | |
|  * hawk::function_exists("sys::getpid") */
 | |
| static int fnc_function_exists (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_oocs_t name;
 | |
| 	int rx;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 	name.ptr = hawk_rtx_getvaloocstr(rtx, a0, &name.len);
 | |
| 	if (HAWK_UNLIKELY(!name.ptr))
 | |
| 	{
 | |
| 		rx = 0;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (hawk_count_oocstr(name.ptr) != name.len) rx = 0;
 | |
| 		else
 | |
| 		{
 | |
| 			rx = (hawk_rtx_findfunwithoocstr(rtx, name.ptr) != HAWK_NULL);
 | |
| 			if (!rx)
 | |
| 			{
 | |
| 				rx = (hawk_findfncwithoocs(hawk_rtx_gethawk(rtx), &name) != HAWK_NULL);
 | |
| 				if (!rx)
 | |
| 				{
 | |
| 					hawk_mod_sym_t sym;
 | |
| 					mod_data_t* md;
 | |
| 
 | |
| 					md = (mod_data_t*)fi->mod->ctx;
 | |
| 					/* hawk_query_module_with_name() may update some shared data under
 | |
| 					 * the hawk object. use a mutex for shared data safety */
 | |
| 					hawk_mtx_lock(&md->mq_mtx, HAWK_NULL);
 | |
| 					rx = (hawk_querymodulewithname(hawk_rtx_gethawk(rtx), name.ptr, &sym) != HAWK_NULL);
 | |
| 					hawk_mtx_unlock(&md->mq_mtx);
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 		hawk_rtx_freevaloocstr(rtx, a0, name.ptr);
 | |
| 	}
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, rx));
 | |
| 	return 0;
 | |
| }
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| static int fnc_cmgr_exists (hawk_rtx_t* rtx, const hawk_fnc_info_t*  fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_ooch_t* str;
 | |
| 	hawk_oow_t len;
 | |
| 	int rx;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 	str = hawk_rtx_getvaloocstr(rtx, a0, &len);
 | |
| 	if (HAWK_UNLIKELY(!str))
 | |
| 	{
 | |
| 		rx = 0;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		rx = (hawk_get_cmgr_by_name(str) != HAWK_NULL);
 | |
| 		hawk_rtx_freevaloocstr(rtx, a0, str);
 | |
| 	}
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, rx));
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| /*
 | |
|    hawk::gc();
 | |
|    hawk::gc_get_threshold(gen)
 | |
|    hawk::gc_set_threshold(gen, threshold)
 | |
|    hawk::GC_NUM_GENS
 | |
|  */
 | |
| 
 | |
| static int fnc_gc (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_int_t gen = -1;
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 	if (hawk_rtx_getnargs(rtx) >= 1 && hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 0), &gen) <= -1) gen = -1;
 | |
| 	gen = hawk_rtx_gc(rtx, gen);
 | |
| #endif
 | |
| 
 | |
| 	HAWK_ASSERT(HAWK_IN_INT_RANGE(gen));
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, gen));
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_gc_get_pressure (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_int_t gen;
 | |
| 	hawk_int_t pressure;
 | |
| 
 | |
| 	if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 0), &gen) <= -1) gen = 0;
 | |
| 	if (gen < 0) gen = 0;
 | |
| 	else if (gen >= HAWK_COUNTOF(rtx->gc.g)) gen = HAWK_COUNTOF(rtx->gc.g) - 1;
 | |
| 
 | |
| 	pressure = rtx->gc.pressure[gen];
 | |
| 
 | |
| 	HAWK_ASSERT(HAWK_IN_INT_RANGE(pressure));
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, pressure));
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_gc_get_threshold (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_int_t gen;
 | |
| 	hawk_int_t threshold;
 | |
| 
 | |
| 	if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 0), &gen) <= -1) gen = 0;
 | |
| 	if (gen < 0) gen = 0;
 | |
| 	else if (gen >= HAWK_COUNTOF(rtx->gc.g)) gen = HAWK_COUNTOF(rtx->gc.g) - 1;
 | |
| 
 | |
| 	threshold = rtx->gc.threshold[gen];
 | |
| 
 | |
| 	HAWK_ASSERT(HAWK_IN_INT_RANGE(threshold));
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, threshold));
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_gc_set_threshold (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_int_t gen;
 | |
| 	hawk_int_t threshold;
 | |
| 
 | |
| 	if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 0), &gen) <= -1) gen = 0;
 | |
| 	if (gen < 0) gen = 0;
 | |
| 	else if (gen >= HAWK_COUNTOF(rtx->gc.g)) gen = HAWK_COUNTOF(rtx->gc.g) - 1;
 | |
| 
 | |
| 	if (hawk_rtx_valtoint(rtx, hawk_rtx_getarg(rtx, 1), &threshold) <= -1) threshold = -1;
 | |
| 
 | |
| 	if (threshold >= 0)
 | |
| 	{
 | |
| 		if (threshold >= HAWK_INT_MAX) threshold = HAWK_INT_MAX;
 | |
| 		rtx->gc.threshold[gen] = threshold; /* update */
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		threshold = rtx->gc.threshold[gen]; /* no update. but retrieve the existing value */
 | |
| 	}
 | |
| 
 | |
| 	HAWK_ASSERT(HAWK_IN_INT_RANGE(threshold));
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, threshold));
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_gcrefs (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, HAWK_VTR_IS_POINTER(a0)? a0->v_refs: 0));
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| static int fnc_size (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	/* similar to length, but it returns the ubound + 1 for the array */
 | |
| 	return hawk_fnc_length (rtx, fi, 1);
 | |
| }
 | |
| 
 | |
| static int fnc_length (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	return hawk_fnc_length (rtx, fi, 0);
 | |
| }
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| static int fnc_array (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* tmp;
 | |
| 	hawk_oow_t nargs, i;
 | |
| 
 | |
| 	nargs = hawk_rtx_getnargs(rtx);
 | |
| 
 | |
| 	tmp = hawk_rtx_makearrval(rtx, ((nargs > 0)? nargs: -1));
 | |
| 	if (HAWK_UNLIKELY(!tmp)) return -1; /* hard failure */
 | |
| 
 | |
| 	for (i = 0; i < nargs; i++)
 | |
| 	{
 | |
| 		if (HAWK_UNLIKELY(hawk_rtx_setarrvalfld(rtx, tmp, i + 1, hawk_rtx_getarg(rtx, i)) == HAWK_NULL))
 | |
| 		{
 | |
| 			hawk_rtx_freeval(rtx, tmp, 0);
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, tmp);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_map (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* tmp;
 | |
| 	hawk_oow_t nargs, i;
 | |
| 	hawk_ooch_t idxbuf[HAWK_IDX_BUF_SIZE];
 | |
| 
 | |
| 	tmp = hawk_rtx_makemapval(rtx);
 | |
| 	if (HAWK_UNLIKELY(!tmp)) return -1; /* hard failure */
 | |
| 
 | |
| 	nargs = hawk_rtx_getnargs(rtx);
 | |
| 
 | |
| 	for (i = 0; i < nargs; i++)
 | |
| 	{
 | |
| 		hawk_rtx_valtostr_out_t out;
 | |
| 		hawk_val_t* v;
 | |
| 
 | |
| 		v = hawk_rtx_getarg(rtx, i);
 | |
| 		out.type = HAWK_RTX_VALTOSTR_CPLCPY;
 | |
| 		out.u.cplcpy.ptr = idxbuf;
 | |
| 		out.u.cplcpy.len = HAWK_COUNTOF(idxbuf);
 | |
| 		if (hawk_rtx_valtostr(rtx, v, &out) <= -1)
 | |
| 		{
 | |
| 			out.type = HAWK_RTX_VALTOSTR_CPLDUP;
 | |
| 			if (hawk_rtx_valtostr(rtx, v, &out) <= -1)
 | |
| 			{
 | |
| 				hawk_rtx_freeval(rtx, tmp, 0);
 | |
| 				return -1;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		v = (++i >= nargs)? hawk_val_nil: hawk_rtx_getarg(rtx, i);
 | |
| 		v = hawk_rtx_setmapvalfld(rtx, tmp, out.u.cpldup.ptr, out.u.cpldup.len, v);
 | |
| 		if (out.u.cpldup.ptr != idxbuf) hawk_rtx_freemem(rtx, out.u.cpldup.ptr);
 | |
| 
 | |
| 		if (HAWK_UNLIKELY(!v))
 | |
| 		{
 | |
| 			hawk_rtx_freeval(rtx, tmp, 0);
 | |
| 			return -1;
 | |
| 		}
 | |
| 
 | |
| 		/* if (i >= nargs) break;  this check is probably not needed. another i++ in the 3rd segment of the for statement should be mostly harmless. potential overflow issue is not a real issue as the number of arguments can be so high. */
 | |
| 	}
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, tmp);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| static int fnc_isnil (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_val_t* r;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 
 | |
| 	r = hawk_rtx_makeintval(rtx, HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_NIL);
 | |
| 	if (HAWK_UNLIKELY(!r)) return -1;
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, r);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_ismap (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_val_t* r;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 
 | |
| 	r = hawk_rtx_makeintval(rtx, HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_MAP);
 | |
| 	if (HAWK_UNLIKELY(!r)) return -1;
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, r);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_isarr (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_val_t* r;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 
 | |
| 	r = hawk_rtx_makeintval(rtx, HAWK_RTX_GETVALTYPE(rtx, a0) == HAWK_VAL_ARR);
 | |
| 	if (HAWK_UNLIKELY(!r)) return -1;
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, r);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_modlibdirs (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | |
| 	hawk_val_t* r;
 | |
| 
 | |
| 	r = hawk_rtx_makestrvalwithoocstr(rtx, (hawk->opt.mod[0].len > 0)? (const hawk_ooch_t*)hawk->opt.mod[0].ptr: (const hawk_ooch_t*)HAWK_T(HAWK_DEFAULT_MODLIBDIRS));
 | |
| 	if (HAWK_UNLIKELY(!r)) return -1;
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, r);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_type (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_val_t* r;
 | |
| 	int _type;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 	_type = hawk_rtx_getvaltype(rtx, a0);
 | |
| 
 | |
| 	r = hawk_rtx_makeintval(rtx, _type);
 | |
| 	if (HAWK_UNLIKELY(!r)) return -1;
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, r);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int fnc_typename (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_val_t* r;
 | |
| 	const hawk_ooch_t* name;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 	name = hawk_rtx_getvaltypename(rtx, a0);
 | |
| 
 | |
| 	r = hawk_rtx_makestrvalwithoocstr(rtx, name);
 | |
| 	if (HAWK_UNLIKELY(!r)) return -1;
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, r);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| static int fnc_hash (hawk_rtx_t* rtx, const hawk_fnc_info_t* fi)
 | |
| {
 | |
| 	hawk_val_t* a0;
 | |
| 	hawk_int_t v;
 | |
| 	const hawk_ooch_t* name;
 | |
| 
 | |
| 	a0 = hawk_rtx_getarg(rtx, 0);
 | |
| 	v = hawk_rtx_hashval(rtx, a0); /* ignore v <= -1 which is an error */
 | |
| 
 | |
| 	hawk_rtx_setretval(rtx, hawk_rtx_makeintval(rtx, v));
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* -------------------------------------------------------------------------- */
 | |
| 
 | |
| #define A_MAX HAWK_TYPE_MAX(hawk_oow_t)
 | |
| 
 | |
| static hawk_mod_fnc_tab_t fnctab[] =
 | |
| {
 | |
| 	/* keep this table sorted for binary search in query(). */
 | |
| 	{ HAWK_T("array"),            { { 0, A_MAX, HAWK_NULL     },  fnc_array,                 0 } },
 | |
| 	{ HAWK_T("call"),             { { 1, A_MAX, HAWK_T("vR")  },  fnc_call,                  0 } },
 | |
| 	{ HAWK_T("cmgr_exists"),      { { 1, 1,     HAWK_NULL     },  fnc_cmgr_exists,           0 } },
 | |
| 	{ HAWK_T("function_exists"),  { { 1, 1,     HAWK_NULL     },  fnc_function_exists,       0 } },
 | |
| 	{ HAWK_T("gc"),               { { 0, 1,     HAWK_NULL     },  fnc_gc,                    0 } },
 | |
| 	{ HAWK_T("gc_get_pressure"),  { { 1, 1,     HAWK_NULL     },  fnc_gc_get_pressure,       0 } },
 | |
| 	{ HAWK_T("gc_get_threshold"), { { 1, 1,     HAWK_NULL     },  fnc_gc_get_threshold,      0 } },
 | |
| 	{ HAWK_T("gc_set_threshold"), { { 2, 2,     HAWK_NULL     },  fnc_gc_set_threshold,      0 } },
 | |
| 	{ HAWK_T("gcrefs"),           { { 1, 1,     HAWK_NULL     },  fnc_gcrefs,                0 } },
 | |
| 	{ HAWK_T("hash"),             { { 1, 1,     HAWK_NULL     },  fnc_hash,                  0 } },
 | |
| 	{ HAWK_T("isarray"),          { { 1, 1,     HAWK_NULL     },  fnc_isarr,                 0 } },
 | |
| 	{ HAWK_T("ismap"),            { { 1, 1,     HAWK_NULL     },  fnc_ismap,                 0 } },
 | |
| 	{ HAWK_T("isnil"),            { { 1, 1,     HAWK_NULL     },  fnc_isnil,                 0 } },
 | |
| 	{ HAWK_T("length"),           { { 1, 1,     HAWK_NULL     },  fnc_length,                0 } },
 | |
| 	{ HAWK_T("map"),              { { 0, A_MAX, HAWK_NULL     },  fnc_map,                   0 } },
 | |
| 	{ HAWK_T("modlibdirs"),       { { 0, 0,     HAWK_NULL     },  fnc_modlibdirs,            0 } },
 | |
| 	{ HAWK_T("size"),             { { 1, 1,     HAWK_NULL     },  fnc_size,                  0 } },
 | |
| 	{ HAWK_T("type"),             { { 1, 1,     HAWK_NULL     },  fnc_type,                  0 } },
 | |
| 	{ HAWK_T("typename"),         { { 1, 1,     HAWK_NULL     },  fnc_typename,              0 } }
 | |
| };
 | |
| 
 | |
| static hawk_mod_int_tab_t inttab[] =
 | |
| {
 | |
| 	/* keep this table sorted for binary search in query(). */
 | |
| 	{ HAWK_T("GC_NUM_GENS"), { HAWK_GC_NUM_GENS } },
 | |
| 
 | |
| 	/* synchronize this table with enum hawk_val_type_t in hawk.h */
 | |
| 	/* the names follow the val_type_name table in val.c */
 | |
| 	{ HAWK_T("VAL_ARRAY"),  { HAWK_VAL_ARR } },
 | |
| 	{ HAWK_T("VAL_BCHAR"),  { HAWK_VAL_BCHR } },
 | |
| 	{ HAWK_T("VAL_BOB"),    { HAWK_VAL_BOB } },
 | |
| 	{ HAWK_T("VAL_CHAR"),   { HAWK_VAL_CHAR } },
 | |
| 	{ HAWK_T("VAL_FLT"),    { HAWK_VAL_FLT } },
 | |
| 	{ HAWK_T("VAL_FUN"),    { HAWK_VAL_FUN } },
 | |
| 	{ HAWK_T("VAL_INT"),    { HAWK_VAL_INT } },
 | |
| 	{ HAWK_T("VAL_MAP"),    { HAWK_VAL_MAP } },
 | |
| 	{ HAWK_T("VAL_MBS"),    { HAWK_VAL_MBS } },
 | |
| 	{ HAWK_T("VAL_NIL"),    { HAWK_VAL_NIL } },
 | |
| 	{ HAWK_T("VAL_STR"),    { HAWK_VAL_STR } },
 | |
| 
 | |
| 	{ HAWK_T("VAL_REF"),    { HAWK_VAL_REF } },
 | |
| 	{ HAWK_T("VAL_REX"),    { HAWK_VAL_REX } }
 | |
| };
 | |
| 
 | |
| static int query (hawk_mod_t* mod, hawk_t* hawk, const hawk_ooch_t* name, hawk_mod_sym_t* sym)
 | |
| {
 | |
| 	if (hawk_findmodsymfnc_noseterr(hawk, fnctab, HAWK_COUNTOF(fnctab), name, sym) >= 0) return 0;
 | |
| 	return hawk_findmodsymint(hawk, inttab, HAWK_COUNTOF(inttab), name, sym);
 | |
| }
 | |
| 
 | |
| static int init (hawk_mod_t* mod, hawk_rtx_t* rtx)
 | |
| {
 | |
| 	/* nothing to do */
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static void fini (hawk_mod_t* mod, hawk_rtx_t* rtx)
 | |
| {
 | |
| 	/* nothing to do */
 | |
| }
 | |
| 
 | |
| static void unload (hawk_mod_t* mod, hawk_t* hawk)
 | |
| {
 | |
| 	mod_data_t* md = (mod_data_t*)mod->ctx;
 | |
| 
 | |
| 	hawk_mtx_fini(&md->mq_mtx);
 | |
| 	hawk_freemem(hawk, md);
 | |
| }
 | |
| 
 | |
| int hawk_mod_hawk (hawk_mod_t* mod, hawk_t* hawk)
 | |
| {
 | |
| 	mod_data_t* md;
 | |
| 
 | |
| 	md = hawk_allocmem(hawk, HAWK_SIZEOF(*md));
 | |
| 	if (HAWK_UNLIKELY(!md)) return -1;
 | |
| 
 | |
| 	hawk_mtx_init(&md->mq_mtx, hawk_getgem(hawk));
 | |
| 
 | |
| 	mod->query = query;
 | |
| 	mod->unload = unload;
 | |
| 
 | |
| 	mod->init = init;
 | |
| 	mod->fini = fini;
 | |
| 	mod->ctx = md;
 | |
| 
 | |
| 	return 0;
 | |
| }
 |