3405 lines
		
	
	
		
			84 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3405 lines
		
	
	
		
			84 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 "hawk-prv.h"
 | |
| 
 | |
| #define CHUNKSIZE HAWK_VAL_CHUNK_SIZE
 | |
| 
 | |
| /* this isn't necessary as the implemenation is context(rtx)-centric
 | |
|  * leave it here for experiment.
 | |
| #define USE_ATOMIC_REFCNT */
 | |
| 
 | |
| static hawk_val_nil_t hawk_nil = {
 | |
| 	HAWK_SFN(v_refs)   0,
 | |
| 	HAWK_SFN(v_type)   HAWK_VAL_NIL,
 | |
| 	HAWK_SFN(v_static) 1,
 | |
| 	HAWK_SFN(v_nstr)   0,
 | |
| 	HAWK_SFN(v_gc)     0
 | |
| };
 | |
| /* zero-length string */
 | |
| static hawk_val_str_t hawk_zls = {
 | |
| 	HAWK_SFN(v_refs)   0,
 | |
| 	HAWK_SFN(v_type)   HAWK_VAL_STR,
 | |
| 	HAWK_SFN(v_static) 1,
 | |
| 	HAWK_SFN(v_nstr)   0,
 | |
| 	HAWK_SFN(v_gc)     0,
 | |
| 	HAWK_SFN(val)      { HAWK_T(""), 0 }
 | |
| };
 | |
| /* zero-length byte string */
 | |
| static hawk_val_mbs_t hawk_zlbs = {
 | |
| 	HAWK_SFN(v_refs)   0,
 | |
| 	HAWK_SFN(v_type)   HAWK_VAL_MBS,
 | |
| 	HAWK_SFN(v_static) 1,
 | |
| 	HAWK_SFN(v_nstr)   0,
 | |
| 	HAWK_SFN(v_gc)     0,
 | |
| 	HAWK_SFN(val)      { HAWK_BT(""), 0 }
 | |
| };
 | |
| 
 | |
| hawk_val_t* hawk_val_nil = (hawk_val_t*)&hawk_nil;
 | |
| hawk_val_t* hawk_val_zls = (hawk_val_t*)&hawk_zls;
 | |
| hawk_val_t* hawk_val_zlbs = (hawk_val_t*)&hawk_zlbs;
 | |
| 
 | |
| static const hawk_ooch_t* val_type_name[] =
 | |
| {
 | |
| 	/* synchronize this table with enum hawk_val_type_t in hawk.h */
 | |
| 	HAWK_T("nil"),
 | |
| 	HAWK_T("char"),
 | |
| 	HAWK_T("bchar"),
 | |
| 	HAWK_T("int"),
 | |
| 	HAWK_T("flt"),
 | |
| 	HAWK_T("str"),
 | |
| 	HAWK_T("mbs"),
 | |
| 	HAWK_T("fun"),
 | |
| 	HAWK_T("map"),
 | |
| 	HAWK_T("array"),
 | |
| 
 | |
| 	HAWK_T("rex"),
 | |
| 	HAWK_T("ref"),
 | |
| 	HAWK_T("bob")
 | |
| };
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 
 | |
| /*
 | |
| BEGIN {
 | |
|   @local a, b, c, nil;
 | |
|   for (i = 1; i < 10; i++) a[i] = i;
 | |
|   a[11] = a;
 | |
|   a[12] = a;
 | |
|   a = @nil;
 | |
|   b[1] = a;
 | |
|   c[1] = 0;
 | |
| }
 | |
| 
 | |
| BEGIN {
 | |
|    @local a, b, c, nil;
 | |
|    j[1] = 20;
 | |
|    j[2] = 20;
 | |
|    for (i = 1; i < 10; i++) a[i] = i;
 | |
|    a[9] = j;
 | |
|    a[10] = "world";
 | |
|    a[11] = a;
 | |
|    a[12] = a;
 | |
|    a[13] = "hello";
 | |
|    j[3] = a;
 | |
|    a[14] = j;
 | |
|    a = @nil;
 | |
|    b[1] = a;
 | |
|    c[1] = 0;
 | |
| }
 | |
| 
 | |
| BEGIN {
 | |
|    @local a, b, c, j, nil;
 | |
|    j[1] = 20;
 | |
|    j[2] = 20;
 | |
|    for (i = 1; i < 10; i++) a[i] = i;
 | |
|    a[9] = j;
 | |
|    a[10] = "world";
 | |
|    a[11] = a;
 | |
|    a[12] = a;
 | |
|    a[13] = "hello";
 | |
|    j[3] = a;
 | |
|    a[14] = j;
 | |
|    a = @nil;
 | |
|    b[1] = a;
 | |
|    c[1] = 0;
 | |
| }
 | |
| 
 | |
| BEGIN {
 | |
|    @local a, b, c, nil;
 | |
|    j[1] = 20;
 | |
|    j[2] = 20;
 | |
|    for (i = 1; i < 10; i++) a[i] = i;
 | |
|    a[9] = j;
 | |
|    a[10] = "world";
 | |
|    a[11] = a;
 | |
|    a[12] = a;
 | |
|    a[13] = "hello";
 | |
|    j[3] = a;
 | |
|    a[14] = j;
 | |
|    a = @nil;
 | |
|    j = @nil; hawk::gc();
 | |
|    b[1] = a;
 | |
|    c[1] = 0;
 | |
| }
 | |
| 
 | |
| */
 | |
| 
 | |
| /*#define DEBUG_GC*/
 | |
| 
 | |
| #define GCH_MOVED HAWK_TYPE_MAX(hawk_uintptr_t)
 | |
| #define GCH_UNREACHABLE (GCH_MOVED - 1)
 | |
| 
 | |
| static HAWK_INLINE void gc_chain_gch (hawk_gch_t* list, hawk_gch_t* gch)
 | |
| {
 | |
| 	gch->gc_next = list;
 | |
| 	gch->gc_prev = list->gc_prev;
 | |
| 	gch->gc_prev->gc_next = gch;
 | |
| 	list->gc_prev = gch;
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE void gc_chain_val (hawk_gch_t* list, hawk_val_t* v)
 | |
| {
 | |
| 	gc_chain_gch (list, hawk_val_to_gch(v));
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE void gc_move_all_gchs (hawk_gch_t* src, hawk_gch_t* dst)
 | |
| {
 | |
| 	/* append src to dst */
 | |
| 	if (src->gc_next != src)
 | |
| 	{
 | |
| 		hawk_gch_t* last;
 | |
| 
 | |
| 		last = dst->gc_prev;
 | |
| 		last->gc_next = src->gc_next;
 | |
| 		last->gc_next->gc_prev = last;
 | |
| 		dst->gc_prev = src->gc_prev;
 | |
| 		dst->gc_prev->gc_next = dst;
 | |
| 	}
 | |
| 	src->gc_prev = src;
 | |
| 	src->gc_next = src;
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE void gc_unchain_gch (hawk_gch_t* gch)
 | |
| {
 | |
| 	gch->gc_prev->gc_next = gch->gc_next;
 | |
| 	gch->gc_next->gc_prev = gch->gc_prev;
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE void gc_unchain_val (hawk_val_t* v)
 | |
| {
 | |
| 	gc_unchain_gch (hawk_val_to_gch(v));
 | |
| }
 | |
| 
 | |
| static void gc_trace_refs (hawk_gch_t* list)
 | |
| {
 | |
| 	hawk_gch_t* gch;
 | |
| 	hawk_val_t* v, * iv;
 | |
| 	hawk_map_itr_t itr;
 | |
| 	hawk_map_pair_t* pair;
 | |
| 
 | |
| 	/* phase 1 - copy the reference count field from the value header to the gc header */
 | |
| 	gch = list->gc_next;
 | |
| 	while (gch != list)
 | |
| 	{
 | |
| 		gch->gc_refs = hawk_gch_to_val(gch)->v_refs;
 | |
| 		gch = gch->gc_next;
 | |
| 	}
 | |
| 
 | |
| 	/* phase 2 - decrement the reference count in the gc header whenever a reference is found */
 | |
| 	gch = list->gc_next;
 | |
| 	while (gch != list)
 | |
| 	{
 | |
| 		v = hawk_gch_to_val(gch);
 | |
| 
 | |
| 		if (v->v_type == HAWK_VAL_MAP)
 | |
| 		{
 | |
| 			hawk_map_t* map;
 | |
| 
 | |
| 			map = ((hawk_val_map_t*)v)->map;
 | |
| 			hawk_init_map_itr (&itr, 0);
 | |
| 			pair = hawk_map_getfirstpair(map, &itr);
 | |
| 			while (pair)
 | |
| 			{
 | |
| 				iv = (hawk_val_t*)HAWK_MAP_VPTR(pair);
 | |
| 				if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc)
 | |
| 				{
 | |
| 					hawk_val_to_gch(iv)->gc_refs--;
 | |
| 				}
 | |
| 				pair = hawk_map_getnextpair(map, &itr);
 | |
| 			}
 | |
| 		}
 | |
| 		else /* if (v->v_type == HAWK_VAL_ARR) */
 | |
| 		{
 | |
| 			hawk_oow_t size, i;
 | |
| 			hawk_arr_t* arr;
 | |
| 
 | |
| 			HAWK_ASSERT (v->v_type == HAWK_VAL_ARR); /* only HAWK_VAL_MAP and HAWK_VAL_ARR */
 | |
| 
 | |
| 			arr = ((hawk_val_arr_t*)v)->arr;
 | |
| 			size = HAWK_ARR_SIZE(arr);
 | |
| 			for (i = 0; i < size; i++)
 | |
| 			{
 | |
| 				if (HAWK_ARR_SLOT(arr, i))
 | |
| 				{
 | |
| 					iv = (hawk_val_t*)HAWK_ARR_DPTR(arr, i);
 | |
| 					if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc)
 | |
| 					{
 | |
| 						hawk_val_to_gch(iv)->gc_refs--;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		gch = gch->gc_next;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static void gc_dump_refs (hawk_rtx_t* rtx, hawk_gch_t* list)
 | |
| {
 | |
| 	hawk_gch_t* gch;
 | |
| 	hawk_oow_t count  = 0;
 | |
| 
 | |
| 	gch = list->gc_next;
 | |
| 	while (gch != list)
 | |
| 	{
 | |
| 		hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] GCH %p gc_refs %d\n", gch, (int)gch->gc_refs);
 | |
| 		gch = gch->gc_next;
 | |
| 	}
 | |
| 	hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] dumped %ju values\n", count);
 | |
| }
 | |
| 
 | |
| static void gc_move_reachables (hawk_gch_t* list, hawk_gch_t* reachable_list)
 | |
| {
 | |
| 	hawk_gch_t* gch, * tmp;
 | |
| 	hawk_val_t* v, * iv;
 | |
| 	hawk_map_itr_t itr;
 | |
| 	hawk_map_pair_t* pair;
 | |
| 
 | |
| 	gch = list->gc_next;
 | |
| 	while (gch != list)
 | |
| 	{
 | |
| 		tmp = gch->gc_next;
 | |
| 		if (gch->gc_refs > 0)
 | |
| 		{
 | |
| 			gc_unchain_gch (gch);
 | |
| 			gc_chain_gch (reachable_list, gch);
 | |
| 			gch->gc_refs = GCH_MOVED;
 | |
| 		}
 | |
| 		gch = tmp;
 | |
| 	}
 | |
| 
 | |
| 	gch = reachable_list->gc_next;
 | |
| 	while (gch != reachable_list)
 | |
| 	{
 | |
| 		v = hawk_gch_to_val(gch);
 | |
| 
 | |
| 		if (v->v_type == HAWK_VAL_MAP)
 | |
| 		{
 | |
| 			hawk_map_t* map;
 | |
| 
 | |
| 			/* the key part is a string. don't care. but if a generic value is allowed as a key, this should change... */
 | |
| 			map = ((hawk_val_map_t*)v)->map;
 | |
| 
 | |
| 			hawk_init_map_itr (&itr, 0);
 | |
| 			pair = hawk_map_getfirstpair(map, &itr);
 | |
| 			while (pair)
 | |
| 			{
 | |
| 				iv = (hawk_val_t*)HAWK_MAP_VPTR(pair);
 | |
| 				if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc)
 | |
| 				{
 | |
| 					tmp = hawk_val_to_gch(iv);
 | |
| 					if (tmp->gc_refs != GCH_MOVED)
 | |
| 					{
 | |
| 						gc_unchain_gch (tmp);
 | |
| 						gc_chain_gch (reachable_list, tmp);
 | |
| 						tmp->gc_refs = GCH_MOVED;
 | |
| 					}
 | |
| 				}
 | |
| 				pair = hawk_map_getnextpair(map, &itr);
 | |
| 			}
 | |
| 		}
 | |
| 		else /* if (v->v_type == HAWK_VAL_ARR) */
 | |
| 		{
 | |
| 			hawk_oow_t size, i;
 | |
| 			hawk_arr_t* arr;
 | |
| 
 | |
| 			HAWK_ASSERT (v->v_type == HAWK_VAL_ARR); /* only HAWK_VAL_MAP and HAWK_VAL_ARR */
 | |
| 
 | |
| 			arr = ((hawk_val_arr_t*)v)->arr;
 | |
| 			size = HAWK_ARR_SIZE(arr);
 | |
| 			for (i = 0; i < size; i++)
 | |
| 			{
 | |
| 				if (HAWK_ARR_SLOT(arr, i))
 | |
| 				{
 | |
| 					iv = (hawk_val_t*)HAWK_ARR_DPTR(arr, i);
 | |
| 					if (HAWK_VTR_IS_POINTER(iv) && iv->v_gc)
 | |
| 					{
 | |
| 						tmp = hawk_val_to_gch(iv);
 | |
| 						if (tmp->gc_refs != GCH_MOVED)
 | |
| 						{
 | |
| 							gc_unchain_gch (tmp);
 | |
| 							gc_chain_gch (reachable_list, tmp);
 | |
| 							tmp->gc_refs = GCH_MOVED;
 | |
| 						}
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		gch = gch->gc_next;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE void gc_free_val (hawk_rtx_t* rtx, hawk_val_t* v)
 | |
| {
 | |
| 	hawk_rtx_freemem (rtx, hawk_val_to_gch(v));
 | |
| }
 | |
| 
 | |
| static void gc_free_unreachables (hawk_rtx_t* rtx, hawk_gch_t* list)
 | |
| {
 | |
| 	hawk_gch_t* gch;
 | |
| 
 | |
| 	/* there might be recursive cross references among unreachable values.
 | |
| 	 * simple traversal and sequential disposal causes various issues */
 | |
| 
 | |
| 	/* mark all unreabale values */
 | |
| 	gch = list->gc_next;
 | |
| 	while (gch != list)
 | |
| 	{
 | |
| 		gch->gc_refs = GCH_UNREACHABLE;
 | |
| 	#if defined(DEBUG_GC)
 | |
| 		hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] MARKED UNREACHABLE GCH %p\n", gch);
 | |
| 	#endif
 | |
| 		gch = gch->gc_next;
 | |
| 	}
 | |
| 
 | |
| 	/* free the values without actually freeing the outer shell */
 | |
| 	gch = list->gc_next;
 | |
| 	while (gch != list)
 | |
| 	{
 | |
| 		hawk_rtx_freeval (rtx, hawk_gch_to_val(gch), HAWK_RTX_FREEVAL_GC_PRESERVE);
 | |
| 		gch = gch->gc_next;
 | |
| 	}
 | |
| 
 | |
| 	/* free the outer shell forcibly*/
 | |
| 	while (list->gc_next != list)
 | |
| 	{
 | |
| 		gch = list->gc_next; /* the first entry in the list */
 | |
| 
 | |
| 	#if defined(DEBUG_GC)
 | |
| 		hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] FREEING UNREACHABLE GCH %p gc_refs %zu v_refs %zu\n", gch, gch->gc_refs, hawk_gch_to_val(gch)->v_refs);
 | |
| 	#endif
 | |
| 		/* do what hawk_rtx_freeval() would do without HAWK_RTX_FREEVAL_GC_PRESERVE */
 | |
| 		gc_unchain_gch (gch);
 | |
| 		gc_free_val (rtx, hawk_gch_to_val(gch));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE void gc_collect_garbage_in_generation (hawk_rtx_t* rtx, int gen)
 | |
| {
 | |
| 	hawk_oow_t i, newgen;
 | |
| 
 | |
| #if defined(DEBUG_GC)
 | |
| 	hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR,  "[GC] **started - gen %d**\n", gen);
 | |
| #endif
 | |
| 
 | |
| 	newgen = (gen < HAWK_COUNTOF(rtx->gc.g) - 1)? (gen + 1): gen;
 | |
| 	for (i = 0; i < gen; i++)
 | |
| 	{
 | |
| 		gc_move_all_gchs (&rtx->gc.g[i], &rtx->gc.g[gen]);
 | |
| 	}
 | |
| 
 | |
| 	if (rtx->gc.g[gen].gc_next != &rtx->gc.g[gen])
 | |
| 	{
 | |
| 		hawk_gch_t reachable;
 | |
| 
 | |
| 		gc_trace_refs (&rtx->gc.g[gen]);
 | |
| 
 | |
| 		reachable.gc_prev = &reachable;
 | |
| 		reachable.gc_next = &reachable;
 | |
| 		gc_move_reachables (&rtx->gc.g[gen], &reachable);
 | |
| 
 | |
| 		/* only unreachables are left in rtx->gc.g[0] */
 | |
| 	#if defined(DEBUG_GC)
 | |
| 	/*gc_dump_refs (rtx, &rtx->gc.g[0]);*/
 | |
| 	#endif
 | |
| 		gc_free_unreachables (rtx, &rtx->gc.g[gen]);
 | |
| 		HAWK_ASSERT (rtx->gc.g[gen].gc_next == &rtx->gc.g[gen]);
 | |
| 
 | |
| 		/* move all reachables back to the main list */
 | |
| 		gc_move_all_gchs (&reachable, &rtx->gc.g[newgen]);
 | |
| 	}
 | |
| 
 | |
| 	/* [NOTE] pressure is greater than other elements by 1 in size.
 | |
| 	 *        i store the number of collections for gen 0 in pressure[1].
 | |
| 	 *        so i can avoid some comparison when doing this */
 | |
| 	rtx->gc.pressure[gen + 1]++; /* number of collections done for gen */
 | |
| 	rtx->gc.pressure[gen] = 0;   /* reset the number of collections of the previous generation */
 | |
| 	rtx->gc.pressure[0] = 0; /* reset the number of allocations since last gc. this line is redundant if gen is 0. */
 | |
| 
 | |
| #if defined(DEBUG_GC)
 | |
| 	hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR,  "[GC] **ended**\n");
 | |
| #endif
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE int gc_collect_garbage_auto (hawk_rtx_t* rtx)
 | |
| {
 | |
| 	hawk_oow_t i;
 | |
| 
 | |
| 	i = HAWK_COUNTOF(rtx->gc.g);
 | |
| 	while (i > 1)
 | |
| 	{
 | |
| 		--i;
 | |
| 		if (rtx->gc.pressure[i] >= rtx->gc.threshold[i])
 | |
| 		{
 | |
| 			gc_collect_garbage_in_generation (rtx, i);
 | |
| 			return i;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	gc_collect_garbage_in_generation (rtx, 0);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| int hawk_rtx_gc (hawk_rtx_t* rtx, int gen)
 | |
| {
 | |
| 	if (gen < 0)
 | |
| 	{
 | |
| 		return gc_collect_garbage_auto (rtx);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (gen >= HAWK_COUNTOF(rtx->gc.g)) gen = HAWK_COUNTOF(rtx->gc.g) - 1;
 | |
| 		gc_collect_garbage_in_generation (rtx, gen);
 | |
| 		return gen;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| static HAWK_INLINE hawk_val_t* gc_calloc_val (hawk_rtx_t* rtx, hawk_oow_t size)
 | |
| {
 | |
| 	hawk_gch_t* gch;
 | |
| 	int gc_gen = 0;
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(rtx->gc.pressure[0] >= rtx->gc.threshold[0]))
 | |
| 	{
 | |
| 		/* invoke generational garbage collection */
 | |
| 		gc_gen = gc_collect_garbage_auto(rtx);
 | |
| 	}
 | |
| 
 | |
| 	gch = (hawk_gch_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*gch) + size);
 | |
| 	if (HAWK_UNLIKELY(!gch))
 | |
| 	{
 | |
| 		if (gc_gen < HAWK_COUNTOF(rtx->gc.g) - 1)
 | |
| 		{
 | |
| 			/* perform full gc if full gc has not been triggerred at the beginning of this function */
 | |
| 			hawk_rtx_gc (rtx, HAWK_COUNTOF(rtx->gc.g) - 1);
 | |
| 		}
 | |
| 		gch = (hawk_gch_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*gch) + size);
 | |
| 		if (HAWK_UNLIKELY(!gch)) return HAWK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	rtx->gc.pressure[0]++; /* increment of the number of allocation attempt */
 | |
| 	return hawk_gch_to_val(gch);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| int hawk_get_val_type (hawk_val_t* val)
 | |
| {
 | |
| 	return HAWK_GET_VAL_TYPE(val);
 | |
| }
 | |
| 
 | |
| const hawk_ooch_t* hawk_get_val_type_name (hawk_val_t* val)
 | |
| {
 | |
| 	return val_type_name[HAWK_GET_VAL_TYPE(val)];
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_get_nil_val (void)
 | |
| {
 | |
| 	return (hawk_val_t*)&hawk_nil;
 | |
| }
 | |
| 
 | |
| int hawk_rtx_isnilval (hawk_rtx_t* rtx, const hawk_val_t* val)
 | |
| {
 | |
| 	return val == (hawk_val_t*)&hawk_nil || (HAWK_VTR_IS_POINTER(val) && val->v_type == HAWK_VAL_NIL);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenilval (hawk_rtx_t* rtx)
 | |
| {
 | |
| 	return (hawk_val_t*)&hawk_nil;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makecharval (hawk_rtx_t* rtx, hawk_ooch_t v)
 | |
| {
 | |
| 	return HAWK_CHAR_TO_VTR((hawk_oochu_t)v);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makebchrval (hawk_rtx_t* rtx, hawk_bch_t v)
 | |
| {
 | |
| 	return HAWK_BCHR_TO_VTR((hawk_bchu_t)v);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makeintval (hawk_rtx_t* rtx, hawk_int_t v)
 | |
| {
 | |
| 	hawk_val_int_t* val;
 | |
| 
 | |
| 	if (HAWK_IN_INT_RANGE(v)) return HAWK_INT_TO_VTR(v);
 | |
| 
 | |
| 	if (!rtx->vmgr.ifree)
 | |
| 	{
 | |
| 		hawk_val_ichunk_t* c;
 | |
| 		/*hawk_val_int_t* x;*/
 | |
| 		hawk_oow_t i;
 | |
| 
 | |
| 		/* use hawk_val_ichunk structure to avoid
 | |
| 		 * any alignment issues on platforms requiring
 | |
| 		 * aligned memory access - using the code commented out
 | |
| 		 * will cause a fault on such a platform */
 | |
| 		c = hawk_rtx_allocmem(rtx, HAWK_SIZEOF(hawk_val_ichunk_t));
 | |
| 		if (HAWK_UNLIKELY(!c)) return HAWK_NULL;
 | |
| 
 | |
| 		c->next = rtx->vmgr.ichunk;
 | |
| 		/*run->vmgr.ichunk = c;*/
 | |
| 		rtx->vmgr.ichunk = (hawk_val_chunk_t*)c;
 | |
| 
 | |
| 		/*x = (hawk_val_int_t*)(c + 1);
 | |
| 		for (i = 0; i < CHUNKSIZE-1; i++)
 | |
| 			x[i].nde = (hawk_nde_int_t*)&x[i+1];
 | |
| 		x[i].nde = HAWK_NULL;
 | |
| 
 | |
| 		run->vmgr.ifree = x;
 | |
| 		*/
 | |
| 
 | |
| 		for (i = 0; i < CHUNKSIZE-1; i++)
 | |
| 			c->slot[i].nde = (hawk_nde_int_t*)&c->slot[i+1];
 | |
| 		c->slot[i].nde = HAWK_NULL;
 | |
| 
 | |
| 		rtx->vmgr.ifree = &c->slot[0];
 | |
| 	}
 | |
| 
 | |
| 	val = rtx->vmgr.ifree;
 | |
| 	rtx->vmgr.ifree = (hawk_val_int_t*)val->nde;
 | |
| 
 | |
| 	val->v_type = HAWK_VAL_INT;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->i_val = v;
 | |
| 	val->nde = HAWK_NULL;
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("makeintval => %jd [%p] - [%O]\n"), (hawk_intmax_t)v, val, val);
 | |
| #endif
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makefltval (hawk_rtx_t* rtx, hawk_flt_t v)
 | |
| {
 | |
| 	hawk_val_flt_t* val;
 | |
| 
 | |
| 	if (rtx->vmgr.rfree == HAWK_NULL)
 | |
| 	{
 | |
| 		hawk_val_rchunk_t* c;
 | |
| 		hawk_oow_t i;
 | |
| 
 | |
| 		c = hawk_rtx_allocmem(rtx, HAWK_SIZEOF(hawk_val_rchunk_t));
 | |
| 		if (!c) return HAWK_NULL;
 | |
| 
 | |
| 		c->next = rtx->vmgr.rchunk;
 | |
| 		rtx->vmgr.rchunk = (hawk_val_chunk_t*)c;
 | |
| 
 | |
| 		for (i = 0; i < CHUNKSIZE-1; i++)
 | |
| 			c->slot[i].nde = (hawk_nde_flt_t*)&c->slot[i+1];
 | |
| 		c->slot[i].nde = HAWK_NULL;
 | |
| 
 | |
| 		rtx->vmgr.rfree = &c->slot[0];
 | |
| 	}
 | |
| 
 | |
| 	val = rtx->vmgr.rfree;
 | |
| 	rtx->vmgr.rfree = (hawk_val_flt_t*)val->nde;
 | |
| 
 | |
| 	val->v_type = HAWK_VAL_FLT;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->val = v;
 | |
| 	val->nde = HAWK_NULL;
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("makefltval => %Lf [%p] - [%O]\n"), (double)v, val, val);
 | |
| #endif
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE hawk_val_t* make_str_val (hawk_rtx_t* rtx, const hawk_ooch_t* str1, hawk_oow_t len1, const hawk_ooch_t* str2, hawk_oow_t len2)
 | |
| {
 | |
| 	hawk_val_str_t* val = HAWK_NULL;
 | |
| 	hawk_oow_t aligned_len;
 | |
| #if defined(HAWK_ENABLE_STR_CACHE)
 | |
| 	hawk_oow_t i;
 | |
| #endif
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(len1 <= 0 && len2 <= 0)) return hawk_val_zls;
 | |
| 	aligned_len = HAWK_ALIGN_POW2((len1 + len2 + 1), HAWK_STR_CACHE_BLOCK_UNIT);
 | |
| 
 | |
| #if defined(HAWK_ENABLE_STR_CACHE)
 | |
| 	i = aligned_len / HAWK_STR_CACHE_BLOCK_UNIT;
 | |
| 	if (i < HAWK_COUNTOF(rtx->str_cache_count))
 | |
| 	{
 | |
| 		if (rtx->str_cache_count[i] > 0)
 | |
| 		{
 | |
| 			val = rtx->str_cache[i][--rtx->str_cache_count[i]];
 | |
| 			goto init;
 | |
| 		}
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	val = (hawk_val_str_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(hawk_val_str_t) + (aligned_len * HAWK_SIZEOF(hawk_ooch_t)));
 | |
| 	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | |
| 
 | |
| #if defined(HAWK_ENABLE_STR_CACHE)
 | |
| init:
 | |
| #endif
 | |
| 	val->v_type = HAWK_VAL_STR;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->val.len = len1 + len2;
 | |
| 	val->val.ptr = (hawk_ooch_t*)(val + 1);
 | |
| 	if (HAWK_LIKELY(str1)) hawk_copy_oochars_to_oocstr_unlimited (&val->val.ptr[0], str1, len1);
 | |
| 	if (str2) hawk_copy_oochars_to_oocstr_unlimited (&val->val.ptr[len1], str2, len2);
 | |
| 	val->val.ptr[val->val.len] = '\0';
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("make_str_val => %p - [%O]\n"), val, val);
 | |
| #endif
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_t* ucs, hawk_oow_t len)
 | |
| {
 | |
| #if defined(HAWK_OOCH_IS_UCH)
 | |
| 	return make_str_val(rtx, ucs, len, HAWK_NULL, 0);
 | |
| #else
 | |
| 	hawk_val_t* v;
 | |
| 	hawk_bch_t* bcs;
 | |
| 	hawk_oow_t bcslen;
 | |
| 
 | |
| 	bcs = hawk_rtx_duputobchars(rtx, ucs, len, &bcslen);
 | |
| 	if (HAWK_UNLIKELY(!bcs)) return HAWK_NULL;
 | |
| 
 | |
| 	v = make_str_val(rtx, bcs, bcslen, HAWK_NULL, 0);
 | |
| 	hawk_rtx_freemem (rtx, bcs);
 | |
| 	return v;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithbchars (hawk_rtx_t* rtx, const hawk_bch_t* bcs, hawk_oow_t len)
 | |
| {
 | |
| #if defined(HAWK_OOCH_IS_UCH)
 | |
| 	hawk_val_t* v;
 | |
| 	hawk_uch_t* ucs;
 | |
| 	hawk_oow_t ucslen;
 | |
| 
 | |
| 	ucs = hawk_rtx_dupbtouchars(rtx, bcs, len, &ucslen, 1);
 | |
| 	if (HAWK_UNLIKELY(!ucs)) return HAWK_NULL;
 | |
| 
 | |
| 	v = make_str_val(rtx, ucs, ucslen, HAWK_NULL, 0);
 | |
| 	hawk_rtx_freemem (rtx, ucs);
 | |
| 	return v;
 | |
| #else
 | |
| 	return make_str_val(rtx, bcs, len, HAWK_NULL, 0);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithbcstr (hawk_rtx_t* rtx, const hawk_bch_t* bcs)
 | |
| {
 | |
| 	return hawk_rtx_makestrvalwithbchars(rtx, bcs, hawk_count_bcstr(bcs));
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithucstr (hawk_rtx_t* rtx, const hawk_uch_t* ucs)
 | |
| {
 | |
| 	return hawk_rtx_makestrvalwithuchars(rtx, ucs, hawk_count_ucstr(ucs));
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithucs (hawk_rtx_t* rtx, const hawk_ucs_t* ucs)
 | |
| {
 | |
| 	return hawk_rtx_makestrvalwithuchars(rtx, ucs->ptr, ucs->len);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithbcs (hawk_rtx_t* rtx, const hawk_bcs_t* bcs)
 | |
| {
 | |
| 	return hawk_rtx_makestrvalwithbchars(rtx, bcs->ptr, bcs->len);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithuchars2 (hawk_rtx_t* rtx, const hawk_uch_t* ucs1, hawk_oow_t len1, const hawk_uch_t* ucs2, hawk_oow_t len2)
 | |
| {
 | |
| #if defined(HAWK_OOCH_IS_UCH)
 | |
| 	return make_str_val(rtx, ucs1, len1, ucs2, len2);
 | |
| #else
 | |
| 	hawk_val_t* v;
 | |
| 	hawk_bch_t* bcs;
 | |
| 	hawk_oow_t bcslen;
 | |
| 
 | |
| 	bcs = hawk_rtx_dupu2tobchars(rtx, ucs1, len1, ucs2, len2, &bcslen);
 | |
| 	if (HAWK_UNLIKELY(!bcs)) return HAWK_NULL;
 | |
| 
 | |
| 	v = make_str_val(rtx, bcs, bcslen, HAWK_NULL, 0);
 | |
| 	hawk_rtx_freemem (rtx, bcs);
 | |
| 	return v;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makestrvalwithbchars2 (hawk_rtx_t* rtx, const hawk_bch_t* bcs1, hawk_oow_t len1, const hawk_bch_t* bcs2, hawk_oow_t len2)
 | |
| {
 | |
| #if defined(HAWK_OOCH_IS_UCH)
 | |
| 	hawk_val_t* v;
 | |
| 	hawk_uch_t* ucs;
 | |
| 	hawk_oow_t ucslen;
 | |
| 
 | |
| 	ucs = hawk_rtx_dupb2touchars(rtx, bcs1, len1, bcs2, len2, &ucslen, 1);
 | |
| 	if (HAWK_UNLIKELY(!ucs)) return HAWK_NULL;
 | |
| 
 | |
| 	v = make_str_val(rtx, ucs, ucslen, HAWK_NULL, 0);
 | |
| 	hawk_rtx_freemem (rtx, ucs);
 | |
| 	return v;
 | |
| #else
 | |
| 	return make_str_val(rtx, bcs1, len1, bcs2, len2);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenumorstrvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	int x;
 | |
| 	hawk_int_t l;
 | |
| 	hawk_flt_t r;
 | |
| 
 | |
| 	if (len == 1 && ptr[0] == '.') goto make_str;
 | |
| 
 | |
| 	if (HAWK_RTX_IS_NUMSTRDETECT_ON(rtx))
 | |
| 	{
 | |
| 		x = hawk_uchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r);
 | |
| 		if (x == 0) return hawk_rtx_makeintval(rtx, l);
 | |
| 		else if (x >= 1) return hawk_rtx_makefltval(rtx, r);
 | |
| 	}
 | |
| 
 | |
| make_str:
 | |
| 	return hawk_rtx_makestrvalwithuchars(rtx, ptr, len);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenumorstrvalwithbchars (hawk_rtx_t* rtx, const hawk_bch_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	int x;
 | |
| 	hawk_int_t l;
 | |
| 	hawk_flt_t r;
 | |
| 
 | |
| 	if (len == 1 && ptr[0] == '.') goto make_str;
 | |
| 
 | |
| 	if (HAWK_RTX_IS_NUMSTRDETECT_ON(rtx))
 | |
| 	{
 | |
| 		x = hawk_bchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r);
 | |
| 		if (x == 0) return hawk_rtx_makeintval(rtx, l);
 | |
| 		else if (x >= 1) return hawk_rtx_makefltval(rtx, r);
 | |
| 	}
 | |
| 
 | |
| make_str:
 | |
| 	return hawk_rtx_makestrvalwithbchars(rtx, ptr, len);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenstrvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	int x;
 | |
| 	hawk_val_t* v;
 | |
| 	hawk_int_t l;
 | |
| 	hawk_flt_t r;
 | |
| 
 | |
| 	x = hawk_uchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r);
 | |
| 	v = hawk_rtx_makestrvalwithuchars(rtx, ptr, len);
 | |
| 	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | |
| 
 | |
| 
 | |
| 	if (x >= 0)
 | |
| 	{
 | |
| 		/* set the numeric string flag if a string
 | |
| 		 * can be converted to a number */
 | |
| 		HAWK_ASSERT (x == 0 || x == 1);
 | |
| 		v->v_nstr = x + 1; /* long -> 1, real -> 2 */
 | |
| 	}
 | |
| 
 | |
| 	return v;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenstrvalwithbchars (hawk_rtx_t* rtx, const hawk_bch_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	int x;
 | |
| 	hawk_val_t* v;
 | |
| 	hawk_int_t l;
 | |
| 	hawk_flt_t r;
 | |
| 
 | |
| 	x = hawk_bchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r);
 | |
| 	v = hawk_rtx_makestrvalwithbchars(rtx, ptr, len);
 | |
| 	if (HAWK_UNLIKELY(!v)) return HAWK_NULL;
 | |
| 
 | |
| 	if (x >= 0)
 | |
| 	{
 | |
| 		/* set the numeric string flag if a string
 | |
| 		 * can be converted to a number */
 | |
| 		HAWK_ASSERT (x == 0 || x == 1);
 | |
| 		v->v_nstr = x + 1; /* long -> 1, real -> 2 */
 | |
| 	}
 | |
| 
 | |
| 	return v;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenstrvalwithucstr (hawk_rtx_t* rtx, const hawk_uch_t* str)
 | |
| {
 | |
| 	return hawk_rtx_makenstrvalwithuchars(rtx, str, hawk_count_ucstr(str));
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenstrvalwithbcstr (hawk_rtx_t* rtx, const hawk_bch_t* str)
 | |
| {
 | |
| 	return hawk_rtx_makenstrvalwithbchars(rtx, str, hawk_count_bcstr(str));
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenstrvalwithucs (hawk_rtx_t* rtx, const hawk_ucs_t* str)
 | |
| {
 | |
| 	return hawk_rtx_makenstrvalwithuchars(rtx, str->ptr, str->len);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenstrvalwithbcs (hawk_rtx_t* rtx, const hawk_bcs_t* str)
 | |
| {
 | |
| 	return hawk_rtx_makenstrvalwithbchars(rtx, str->ptr, str->len);
 | |
| }
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| static HAWK_INLINE hawk_val_t* make_mbs_val (hawk_rtx_t* rtx, const hawk_bch_t* mbs1, hawk_oow_t len1, const hawk_bch_t* mbs2, hawk_oow_t len2)
 | |
| {
 | |
| 	hawk_val_mbs_t* val = HAWK_NULL;
 | |
| 	hawk_oow_t aligned_len;
 | |
| #if defined(HAWK_ENABLE_MBS_CACHE)
 | |
| 	hawk_oow_t i;
 | |
| #endif
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(len1 <= 0 && len2 <= 0)) return hawk_val_zlbs;
 | |
| 	aligned_len = HAWK_ALIGN_POW2((len1 + len2 + 1), HAWK_MBS_CACHE_BLOCK_UNIT);
 | |
| 
 | |
| #if defined(HAWK_ENABLE_MBS_CACHE)
 | |
| 	i = aligned_len / HAWK_MBS_CACHE_BLOCK_UNIT;
 | |
| 	if (i < HAWK_COUNTOF(rtx->mbs_cache_count))
 | |
| 	{
 | |
| 		if (rtx->mbs_cache_count[i] > 0)
 | |
| 		{
 | |
| 			val = rtx->mbs_cache[i][--rtx->mbs_cache_count[i]];
 | |
| 			goto init;
 | |
| 		}
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	val = (hawk_val_mbs_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(hawk_val_mbs_t) + (aligned_len * HAWK_SIZEOF(hawk_bch_t)));
 | |
| 	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | |
| 
 | |
| #if defined(HAWK_ENABLE_MBS_CACHE)
 | |
| init:
 | |
| #endif
 | |
| 	val->v_type = HAWK_VAL_MBS;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->val.len = len1 + len2;
 | |
| 	val->val.ptr = (hawk_bch_t*)(val + 1);
 | |
| 	if (HAWK_LIKELY(mbs1)) hawk_copy_bchars_to_bcstr_unlimited (&val->val.ptr[0], mbs1, len1);
 | |
| 	if (mbs2) hawk_copy_bchars_to_bcstr_unlimited (&val->val.ptr[len1], mbs2, len2);
 | |
| 	val->val.ptr[val->val.len] = '\0';
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("make_mbs_val => %p - [%O]\n"), val, val);
 | |
| #endif
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithbchars (hawk_rtx_t* rtx, const hawk_bch_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	return make_mbs_val(rtx, ptr, len, HAWK_NULL, 0);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_t* ucs, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_val_t* val;
 | |
| 	hawk_bch_t* bcs;
 | |
| 	hawk_oow_t bcslen;
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(len <= 0)) return hawk_val_zlbs;
 | |
| 
 | |
| 	bcs = hawk_rtx_duputobchars(rtx, ucs, len, &bcslen);
 | |
| 	if (HAWK_UNLIKELY(!bcs)) return HAWK_NULL;
 | |
| 
 | |
| 	val = make_mbs_val(rtx, bcs, bcslen, HAWK_NULL, 0);
 | |
| 	hawk_rtx_freemem (rtx, bcs);
 | |
| 
 | |
| 	return val;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithbcs (hawk_rtx_t* rtx, const hawk_bcs_t* bcs)
 | |
| {
 | |
| 	return make_mbs_val(rtx, bcs->ptr, bcs->len, HAWK_NULL, 0);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithucs (hawk_rtx_t* rtx, const hawk_ucs_t* ucs)
 | |
| {
 | |
| 	return hawk_rtx_makembsvalwithuchars(rtx, ucs->ptr, ucs->len);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithbcstr (hawk_rtx_t* rtx, const hawk_bch_t* bcs)
 | |
| {
 | |
| 	return make_mbs_val(rtx, bcs, hawk_count_bcstr(bcs), HAWK_NULL, 0);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithucstr (hawk_rtx_t* rtx, const hawk_uch_t* ucs)
 | |
| {
 | |
| 	return hawk_rtx_makembsvalwithuchars(rtx, ucs, hawk_count_ucstr(ucs));
 | |
| }
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithuchars2 (hawk_rtx_t* rtx, const hawk_uch_t* ucs1, hawk_oow_t len1, const hawk_uch_t* ucs2, hawk_oow_t len2)
 | |
| {
 | |
| 	hawk_val_t* v;
 | |
| 	hawk_bch_t* bcs;
 | |
| 	hawk_oow_t bcslen;
 | |
| 
 | |
| 	bcs = hawk_rtx_dupu2tobchars(rtx, ucs1, len1, ucs2, len2, &bcslen);
 | |
| 	if (HAWK_UNLIKELY(!bcs)) return HAWK_NULL;
 | |
| 
 | |
| 	v = make_mbs_val(rtx, bcs, bcslen, HAWK_NULL, 0);
 | |
| 	hawk_rtx_freemem (rtx, bcs);
 | |
| 	return v;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makembsvalwithbchars2 (hawk_rtx_t* rtx, const hawk_bch_t* bcs1, hawk_oow_t len1, const hawk_bch_t* bcs2, hawk_oow_t len2)
 | |
| {
 | |
| 	return make_mbs_val(rtx, bcs1, len1, bcs2, len2);
 | |
| }
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenumormbsvalwithuchars (hawk_rtx_t* rtx, const hawk_uch_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	int x;
 | |
| 	hawk_int_t l;
 | |
| 	hawk_flt_t r;
 | |
| 
 | |
| 	if (len == 1 && ptr[0] == '.') goto make_str;
 | |
| 
 | |
| 	if (HAWK_RTX_IS_NUMSTRDETECT_ON(rtx))
 | |
| 	{
 | |
| 		x = hawk_uchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r);
 | |
| 		if (x == 0) return hawk_rtx_makeintval(rtx, l);
 | |
| 		else if (x >= 1) return hawk_rtx_makefltval(rtx, r);
 | |
| 	}
 | |
| 
 | |
| make_str:
 | |
| 	return hawk_rtx_makembsvalwithuchars(rtx, ptr, len);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makenumormbsvalwithbchars (hawk_rtx_t* rtx, const hawk_bch_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	int x;
 | |
| 	hawk_int_t l;
 | |
| 	hawk_flt_t r;
 | |
| 
 | |
| 	if (len == 1 && ptr[0] == '.') goto make_str;
 | |
| 
 | |
| 	if (HAWK_RTX_IS_NUMSTRDETECT_ON(rtx))
 | |
| 	{
 | |
| 		x = hawk_bchars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(1, 1, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), ptr, len, &l, &r);
 | |
| 		if (x == 0) return hawk_rtx_makeintval(rtx, l);
 | |
| 		else if (x >= 1) return hawk_rtx_makefltval(rtx, r);
 | |
| 	}
 | |
| 
 | |
| make_str:
 | |
| 	return hawk_rtx_makembsvalwithbchars(rtx, ptr, len);
 | |
| }
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makerexval (hawk_rtx_t* rtx, const hawk_oocs_t* str, hawk_tre_t* code[2])
 | |
| {
 | |
| 	hawk_val_rex_t* val;
 | |
| 	hawk_oow_t totsz;
 | |
| 
 | |
| 	/* the regular expression value holds:
 | |
| 	 * - header
 | |
| 	 * - a raw string plus with added a terminating '\0'
 | |
| 	 * the total size is just large enough for all these.
 | |
| 	 */
 | |
| 	totsz = HAWK_SIZEOF(*val) + (HAWK_SIZEOF(*str->ptr) * (str->len + 1));
 | |
| 	val = (hawk_val_rex_t*)hawk_rtx_callocmem(rtx, totsz);
 | |
| 	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | |
| 
 | |
| 	val->v_type = HAWK_VAL_REX;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->str.len = str->len;
 | |
| 
 | |
| 	val->str.ptr = (hawk_ooch_t*)(val + 1);
 | |
| 	hawk_copy_oochars_to_oocstr_unlimited (val->str.ptr, str->ptr, str->len);
 | |
| 
 | |
| 	val->code[0] = code[0];
 | |
| 	val->code[1] = code[1];
 | |
| 
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| static void free_arrval (hawk_arr_t* arr, void* dptr, hawk_oow_t dlen)
 | |
| {
 | |
| 	hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_arr_getxtn(arr);
 | |
| 	hawk_val_t* v = (hawk_val_t*)dptr;
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("refdown in arr free - [%O]\n"), v);
 | |
| #endif
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 	if (HAWK_VTR_IS_POINTER(v) && v->v_gc && hawk_val_to_gch(v)->gc_refs == GCH_UNREACHABLE)
 | |
| 	{
 | |
| 		/* do nothing if the element is unreachable.
 | |
| 		 * this behavior pairs up with gc_free_unreachables() to
 | |
| 		 * achieve safe disposal of a value */
 | |
| 		return;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	hawk_rtx_refdownval (rtx, v);
 | |
| }
 | |
| 
 | |
| static void same_arrval (hawk_arr_t* map, void* dptr, hawk_oow_t dlen)
 | |
| {
 | |
| 	hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_arr_getxtn(map);
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("refdown nofree in arr free - [%O]\n"), dptr);
 | |
| #endif
 | |
| 	hawk_rtx_refdownval_nofree (rtx, dptr);
 | |
| }
 | |
| 
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makearrval (hawk_rtx_t* rtx, hawk_ooi_t init_capa)
 | |
| {
 | |
| 	static hawk_arr_style_t style =
 | |
| 	{
 | |
| 	/* the key is copied inline into a pair and is freed when the pair
 | |
| 	 * is destroyed. not setting copier for a value means that the pointer
 | |
| 	 * to the data allocated somewhere else is remembered in a pair. but
 | |
| 	 * freeing the actual value is handled by free_arrval and same_arrval */
 | |
| 
 | |
| 		HAWK_ARR_COPIER_DEFAULT,
 | |
| 		free_arrval,
 | |
| 		HAWK_ARR_COMPER_DEFAULT,
 | |
| 		same_arrval,
 | |
| 		HAWK_ARR_SIZER_DEFAULT
 | |
| 	};
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 	int retried = 0;
 | |
| #endif
 | |
| 	hawk_val_arr_t* val;
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| retry:
 | |
| 	val = (hawk_val_arr_t*)gc_calloc_val(rtx, HAWK_SIZEOF(hawk_val_arr_t) + HAWK_SIZEOF(hawk_arr_t) + HAWK_SIZEOF(rtx));
 | |
| #else
 | |
| 	val = (hawk_val_arr_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(hawk_val_arr_t) + HAWK_SIZEOF(hawk_arr_t) + HAWK_SIZEOF(rtx));
 | |
| #endif
 | |
| 	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | |
| 
 | |
| 	val->v_type = HAWK_VAL_ARR;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->arr = (hawk_arr_t*)(val + 1);
 | |
| 
 | |
| 	if (init_capa < 0) init_capa = 64; /* TODO: what is the best initial value? */
 | |
| 	if (HAWK_UNLIKELY(hawk_arr_init(val->arr, hawk_rtx_getgem(rtx), init_capa) <= -1))
 | |
| 	{
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 		gc_free_val (rtx, (hawk_val_t*)val);
 | |
| 		if (HAWK_LIKELY(!retried))
 | |
| 		{
 | |
| 			/* this arr involves non-gc allocatinon, which happens outside gc_calloc_val().
 | |
| 			 * reattempt to allocate after full gc like gc_calloc_val() */
 | |
| 			hawk_rtx_gc (rtx, HAWK_COUNTOF(rtx->gc.g) - 1);
 | |
| 			retried = 1;
 | |
| 			goto retry;
 | |
| 		}
 | |
| #else
 | |
| 		hawk_rtx_freemem (rtx, val);
 | |
| #endif
 | |
| 		return HAWK_NULL;
 | |
| 	}
 | |
| 	*(hawk_rtx_t**)hawk_arr_getxtn(val->arr) = rtx;
 | |
| 	hawk_arr_setstyle (val->arr, &style);
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 	gc_chain_val (&rtx->gc.g[0], (hawk_val_t*)val);
 | |
| 	val->v_gc = 1; /* only array and map are to be garbaged collected as of now */
 | |
| 	#if defined(DEBUG_GC)
 | |
| 	hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] MADE GCH %p VAL(ARR) %p\n", hawk_val_to_gch(val), val);
 | |
| 	#endif
 | |
| #endif
 | |
| 
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| /* --------------------------------------------------------------------- */
 | |
| 
 | |
| static void free_mapval (hawk_map_t* map, void* dptr, hawk_oow_t dlen)
 | |
| {
 | |
| 	hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_map_getxtn(map);
 | |
| 	hawk_val_t* v = (hawk_val_t*)dptr;
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("refdown in map free - [%O]\n"), v);
 | |
| #endif
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 	if (HAWK_VTR_IS_POINTER(v) && v->v_gc && hawk_val_to_gch(v)->gc_refs == GCH_UNREACHABLE)
 | |
| 	{
 | |
| 		/* do nothing if the element is unreachable.
 | |
| 		 * this behavior pairs up with gc_free_unreachables() to
 | |
| 		 * achieve safe disposal of a value */
 | |
| 		return;
 | |
| 	}
 | |
| #endif
 | |
| 
 | |
| 	hawk_rtx_refdownval (rtx, v);
 | |
| }
 | |
| 
 | |
| static void same_mapval (hawk_map_t* map, void* dptr, hawk_oow_t dlen)
 | |
| {
 | |
| 	hawk_rtx_t* rtx = *(hawk_rtx_t**)hawk_map_getxtn(map);
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("refdown nofree in map free - [%O]\n"), dptr);
 | |
| #endif
 | |
| 	hawk_rtx_refdownval_nofree (rtx, dptr);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makemapval (hawk_rtx_t* rtx)
 | |
| {
 | |
| 	static hawk_map_style_t style =
 | |
| 	{
 | |
| 	/* the key is copied inline into a pair and is freed when the pair
 | |
| 	 * is destroyed. not setting copier for a value means that the pointer
 | |
| 	 * to the data allocated somewhere else is remembered in a pair. but
 | |
| 	 * freeing the actual value is handled by free_mapval and same_mapval */
 | |
| 		{
 | |
| 			HAWK_MAP_COPIER_INLINE,
 | |
| 			HAWK_MAP_COPIER_DEFAULT
 | |
| 		},
 | |
| 		{
 | |
| 			HAWK_MAP_FREEER_DEFAULT,
 | |
| 			free_mapval
 | |
| 		},
 | |
| 		HAWK_MAP_COMPER_DEFAULT,
 | |
| 		same_mapval,
 | |
| 	#if defined(HAWK_MAP_IS_HTB)
 | |
| 		HAWK_MAP_SIZER_DEFAULT,
 | |
| 		HAWK_MAP_HASHER_DEFAULT
 | |
| 	#endif
 | |
| 	};
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 	int retried = 0;
 | |
| #endif
 | |
| 	hawk_val_map_t* val;
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| retry:
 | |
| 	val = (hawk_val_map_t*)gc_calloc_val(rtx, HAWK_SIZEOF(hawk_val_map_t) + HAWK_SIZEOF(hawk_map_t) + HAWK_SIZEOF(rtx));
 | |
| #else
 | |
| 	val = (hawk_val_map_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(hawk_val_map_t) + HAWK_SIZEOF(hawk_map_t) + HAWK_SIZEOF(rtx));
 | |
| #endif
 | |
| 	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | |
| 
 | |
| 	val->v_type = HAWK_VAL_MAP;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->map = (hawk_map_t*)(val + 1);
 | |
| 
 | |
| 	if (HAWK_UNLIKELY(hawk_map_init(val->map, hawk_rtx_getgem(rtx), 256, 70, HAWK_SIZEOF(hawk_ooch_t), 1) <= -1))
 | |
| 	{
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 		gc_free_val (rtx, (hawk_val_t*)val);
 | |
| 		if (HAWK_LIKELY(!retried))
 | |
| 		{
 | |
| 			/* this map involves non-gc allocatinon, which happens outside gc_calloc_val().
 | |
| 			 * reattempt to allocate after full gc like gc_calloc_val() */
 | |
| 			hawk_rtx_gc (rtx, HAWK_COUNTOF(rtx->gc.g) - 1);
 | |
| 			retried = 1;
 | |
| 			goto retry;
 | |
| 		}
 | |
| #else
 | |
| 		hawk_rtx_freemem (rtx, val);
 | |
| #endif
 | |
| 		return HAWK_NULL;
 | |
| 	}
 | |
| 	*(hawk_rtx_t**)hawk_map_getxtn(val->map) = rtx;
 | |
| 	hawk_map_setstyle (val->map, &style);
 | |
| 
 | |
| #if defined(HAWK_ENABLE_GC)
 | |
| 	gc_chain_val (&rtx->gc.g[0], (hawk_val_t*)val);
 | |
| 	val->v_gc = 1; /* only array and map are to be garbaged collected as of now */
 | |
| 	#if defined(DEBUG_GC)
 | |
| 	hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] MADE GCH %p VAL(MAP) %p\n", hawk_val_to_gch(val), val);
 | |
| 	#endif
 | |
| #endif
 | |
| 
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makemapvalwithdata (hawk_rtx_t* rtx, hawk_val_map_data_t data[], hawk_oow_t count)
 | |
| {
 | |
| 	hawk_val_t* map, * tmp;
 | |
| 
 | |
| 	hawk_oow_t i;
 | |
| 
 | |
| 	map = hawk_rtx_makemapval(rtx);
 | |
| 	if (HAWK_UNLIKELY(!map)) return HAWK_NULL;
 | |
| 
 | |
| 	hawk_rtx_refupval (rtx, map);
 | |
| 
 | |
| 	for (i = 0; i < count; i++)
 | |
| 	{
 | |
| 		hawk_val_map_data_t* p;
 | |
| 
 | |
| 		p = &data[i];
 | |
| 
 | |
| 		switch (p->type)
 | |
| 		{
 | |
| 			case HAWK_VAL_MAP_DATA_INT:
 | |
| 			{
 | |
| 				hawk_int_t iv = 0;
 | |
| 
 | |
| 				if (p->type_size > 0 && p->type_size <= HAWK_SIZEOF(iv))
 | |
| 				{
 | |
| 				#if defined(HAWK_ENDIAN_LITTLE)
 | |
| 					HAWK_MEMCPY (&iv, p->vptr, p->type_size);
 | |
| 				#else
 | |
| 					HAWK_MEMCPY ((hawk_uint8_t*)&iv + (HAWK_SIZEOF(iv) - p->type_size), p->vptr, p->type_size);
 | |
| 				#endif
 | |
| 				}
 | |
| 				else
 | |
| 				{
 | |
| 					iv = *(hawk_int_t*)p->vptr;
 | |
| 				}
 | |
| 				tmp = hawk_rtx_makeintval(rtx, iv);
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case HAWK_VAL_MAP_DATA_FLT:
 | |
| 				tmp = hawk_rtx_makefltval(rtx, *(hawk_flt_t*)p->vptr);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_MAP_DATA_OOCSTR:
 | |
| 				tmp = hawk_rtx_makestrvalwithoocstr(rtx, (hawk_ooch_t*)p->vptr);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_MAP_DATA_BCSTR:
 | |
| 				tmp = hawk_rtx_makestrvalwithbcstr(rtx, (hawk_bch_t*)p->vptr);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_MAP_DATA_UCSTR:
 | |
| 				tmp = hawk_rtx_makestrvalwithucstr(rtx, (hawk_uch_t*)p->vptr);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_MAP_DATA_OOCS:
 | |
| 				tmp = hawk_rtx_makestrvalwithoocs(rtx, (hawk_oocs_t*)p->vptr);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_MAP_DATA_BCS:
 | |
| 				tmp = hawk_rtx_makestrvalwithbcs(rtx, (hawk_bcs_t*)p->vptr);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_MAP_DATA_UCS:
 | |
| 				tmp = hawk_rtx_makestrvalwithucs(rtx, (hawk_ucs_t*)p->vptr);
 | |
| 				break;
 | |
| 
 | |
| 			default:
 | |
| 				tmp = HAWK_NULL;
 | |
| 				hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 				break;
 | |
| 		}
 | |
| 
 | |
| 		if (tmp == HAWK_NULL || hawk_rtx_setmapvalfld(rtx, map, p->key.ptr, p->key.len, tmp) == HAWK_NULL)
 | |
| 		{
 | |
| 			if (tmp) hawk_rtx_freeval (rtx, tmp, HAWK_RTX_FREEVAL_CACHE);
 | |
| 			hawk_rtx_refdownval (rtx, map);
 | |
| 			return HAWK_NULL;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 
 | |
| 	hawk_rtx_refdownval_nofree (rtx, map);
 | |
| 	return map;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_setmapvalfld (hawk_rtx_t* rtx, hawk_val_t* map, const hawk_ooch_t* kptr, hawk_oow_t klen, hawk_val_t* v)
 | |
| {
 | |
| 	HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, map) == HAWK_VAL_MAP);
 | |
| 
 | |
| 	if (hawk_map_upsert(((hawk_val_map_t*)map)->map, (hawk_ooch_t*)kptr, klen, v, 0) == HAWK_NULL) return HAWK_NULL;
 | |
| 
 | |
| 	/* the value is passed in by an external party. we can't refup()
 | |
| 	 * and refdown() the value if htb_upsert() fails. that way, the value
 | |
| 	 * can be destroyed if it was passed with the reference count of 0.
 | |
| 	 * so we increment the reference count when htb_upsert() is complete */
 | |
| 	hawk_rtx_refupval (rtx, v);
 | |
| 
 | |
| 	return v;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_getmapvalfld (hawk_rtx_t* rtx, hawk_val_t* map, const hawk_ooch_t* kptr, hawk_oow_t klen)
 | |
| {
 | |
| 	hawk_map_pair_t* pair;
 | |
| 
 | |
| 	HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, map) == HAWK_VAL_MAP);
 | |
| 
 | |
| 	pair = hawk_map_search(((hawk_val_map_t*)map)->map, kptr, klen);
 | |
| 	if (!pair)
 | |
| 	{
 | |
| 		/* the given key is not found in the map.
 | |
| 		 * we return NULL here as this function is called by
 | |
| 		 * a user unlike the hawk statement accessing the map key.
 | |
| 		 * so you can easily determine if the key is found by
 | |
| 		 * checking the error number.
 | |
| 		 */
 | |
| 		return HAWK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	return HAWK_MAP_VPTR(pair);
 | |
| }
 | |
| 
 | |
| hawk_val_map_itr_t* hawk_rtx_getfirstmapvalitr (hawk_rtx_t* rtx, hawk_val_t* map, hawk_val_map_itr_t* itr)
 | |
| {
 | |
| 	HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, map) == HAWK_VAL_MAP);
 | |
| 	hawk_init_map_itr (itr, 0); /* override the caller provided direction to 0 */
 | |
| 	itr->pair = hawk_map_getfirstpair(((hawk_val_map_t*)map)->map, itr);
 | |
| 	return itr->pair? itr: HAWK_NULL;
 | |
| }
 | |
| 
 | |
| hawk_val_map_itr_t* hawk_rtx_getnextmapvalitr (hawk_rtx_t* rtx, hawk_val_t* map, hawk_val_map_itr_t* itr)
 | |
| {
 | |
| 	HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, map) == HAWK_VAL_MAP);
 | |
| 	itr->pair = hawk_map_getnextpair(((hawk_val_map_t*)map)->map, itr);
 | |
| 	return itr->pair? itr: HAWK_NULL;
 | |
| }
 | |
| 
 | |
| int hawk_rtx_scalearrval (hawk_rtx_t* rtx, hawk_val_t* arr, hawk_ooi_t capa)
 | |
| {
 | |
| 	HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, arr) == HAWK_VAL_ARR);
 | |
| 	if (!hawk_arr_setcapa(((hawk_val_arr_t*)arr)->arr, capa)) return -1;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_setarrvalfld (hawk_rtx_t* rtx, hawk_val_t* arr, hawk_ooi_t index, hawk_val_t* v)
 | |
| {
 | |
| 	HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, arr) == HAWK_VAL_ARR);
 | |
| 
 | |
| 	if (hawk_arr_upsert(((hawk_val_arr_t*)arr)->arr, index, v, 0) == HAWK_ARR_NIL) return HAWK_NULL;
 | |
| 
 | |
| 	/* the value is passed in by an external party. we can't refup()
 | |
| 	 * and refdown() the value if htb_upsert() fails. that way, the value
 | |
| 	 * can be destroyed if it was passed with the reference count of 0.
 | |
| 	 * so we increment the reference count when htb_upsert() is complete */
 | |
| 	hawk_rtx_refupval (rtx, v);
 | |
| 
 | |
| 	return v;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_getarrvalfld (hawk_rtx_t* rtx, hawk_val_t* arr, hawk_ooi_t index)
 | |
| {
 | |
| 	hawk_arr_t* _arr;
 | |
| 	HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, arr) == HAWK_VAL_ARR);
 | |
| 	_arr = ((hawk_val_arr_t*)arr)->arr;
 | |
| 	if (index < 0 || index >= HAWK_ARR_SIZE(_arr) || !HAWK_ARR_SLOT(_arr, index)) return HAWK_NULL;
 | |
| 	return HAWK_ARR_DPTR(_arr, index);
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makerefval (hawk_rtx_t* rtx, int id, hawk_val_t** adr)
 | |
| {
 | |
| 	hawk_val_ref_t* val;
 | |
| 
 | |
| 	if (rtx->rcache_count > 0)
 | |
| 	{
 | |
| 		val = rtx->rcache[--rtx->rcache_count];
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		val = (hawk_val_ref_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*val));
 | |
| 		if (!val) return HAWK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	HAWK_RTX_INIT_REF_VAL (val, id, adr, 0);
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makefunval (hawk_rtx_t* rtx, const hawk_fun_t* fun)
 | |
| {
 | |
| 	hawk_val_fun_t* val;
 | |
| 
 | |
| 	val = (hawk_val_fun_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(*val));
 | |
| 	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | |
| 
 | |
| 	val->v_type = HAWK_VAL_FUN;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->fun = (hawk_fun_t*)fun;
 | |
| 
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_makebobval (hawk_rtx_t* rtx, const void* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_val_bob_t* val;
 | |
| 
 | |
| 	val = (hawk_val_bob_t*)hawk_rtx_callocmem(rtx, HAWK_SIZEOF(hawk_val_bob_t) + len);
 | |
| 	if (HAWK_UNLIKELY(!val)) return HAWK_NULL;
 | |
| 
 | |
| 	val->v_type = HAWK_VAL_BOB;
 | |
| 	val->v_refs = 0;
 | |
| 	val->v_static = 0;
 | |
| 	val->v_nstr = 0;
 | |
| 	val->v_gc = 0;
 | |
| 	val->val.len = len;
 | |
| 	val->val.ptr = (hawk_bch_t*)(val + 1);
 | |
| 	HAWK_MEMCPY (val + 1, ptr, len);
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 	hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("make_bob_val => %p - [%O]\n"), val, val);
 | |
| #endif
 | |
| 	return (hawk_val_t*)val;
 | |
| }
 | |
| 
 | |
| int HAWK_INLINE hawk_rtx_isstaticval (hawk_rtx_t* rtx, const hawk_val_t* val)
 | |
| {
 | |
| 	return HAWK_VTR_IS_POINTER(val) && HAWK_IS_STATICVAL(val);
 | |
| }
 | |
| 
 | |
| int hawk_rtx_getvaltype (hawk_rtx_t* rtx, const hawk_val_t* val)
 | |
| {
 | |
| 	return HAWK_RTX_GETVALTYPE(rtx, val);
 | |
| }
 | |
| 
 | |
| const hawk_ooch_t* hawk_rtx_getvaltypename(hawk_rtx_t* rtx, const hawk_val_t* val)
 | |
| {
 | |
| 	return val_type_name[HAWK_RTX_GETVALTYPE(rtx, val)];
 | |
| }
 | |
| 
 | |
| int hawk_rtx_getintfromval (hawk_rtx_t* rtx, const hawk_val_t* val)
 | |
| {
 | |
| 	return HAWK_RTX_GETINTFROMVAL(rtx, val);
 | |
| }
 | |
| 
 | |
| void hawk_rtx_freeval (hawk_rtx_t* rtx, hawk_val_t* val, int flags)
 | |
| {
 | |
| 	hawk_val_type_t vtype;
 | |
| 
 | |
| 	if (HAWK_VTR_IS_POINTER(val))
 | |
| 	{
 | |
| 		if (HAWK_IS_STATICVAL(val)) return;
 | |
| 
 | |
| 	#if defined(DEBUG_VAL)
 | |
| 		hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("freeing [cache=%d] - [%O]\n"), cache, val);
 | |
| 	#endif
 | |
| 
 | |
| 		vtype = HAWK_RTX_GETVALTYPE (rtx, val);
 | |
| 		switch (vtype)
 | |
| 		{
 | |
| 			case HAWK_VAL_NIL:
 | |
| 			{
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case HAWK_VAL_BCHR:
 | |
| 			case HAWK_VAL_CHAR:
 | |
| 			{
 | |
| 				/* this never happens */
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case HAWK_VAL_INT:
 | |
| 			{
 | |
| 				((hawk_val_int_t*)val)->nde = (hawk_nde_int_t*)rtx->vmgr.ifree;
 | |
| 				rtx->vmgr.ifree = (hawk_val_int_t*)val;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case HAWK_VAL_FLT:
 | |
| 			{
 | |
| 				((hawk_val_flt_t*)val)->nde = (hawk_nde_flt_t*)rtx->vmgr.rfree;
 | |
| 				rtx->vmgr.rfree = (hawk_val_flt_t*)val;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case HAWK_VAL_STR:
 | |
| 			{
 | |
| 			#if defined(HAWK_ENABLE_STR_CACHE)
 | |
| 				if (flags & HAWK_RTX_FREEVAL_CACHE)
 | |
| 				{
 | |
| 					hawk_val_str_t* v = (hawk_val_str_t*)val;
 | |
| 					hawk_oow_t aligned_len;
 | |
| 					int i;
 | |
| 
 | |
| 					aligned_len = HAWK_ALIGN_POW2((v->val.len + 1), HAWK_STR_CACHE_BLOCK_UNIT);
 | |
| 					i = aligned_len / HAWK_STR_CACHE_BLOCK_UNIT;
 | |
| 					if (i < HAWK_COUNTOF(rtx->str_cache_count) &&
 | |
| 					    rtx->str_cache_count[i] < HAWK_COUNTOF(rtx->str_cache[i]))
 | |
| 					{
 | |
| 						rtx->str_cache[i][rtx->str_cache_count[i]++] = v;
 | |
| 						v->v_nstr = 0;
 | |
| 					}
 | |
| 					else hawk_rtx_freemem (rtx, val);
 | |
| 					break;
 | |
| 				}
 | |
| 			#endif
 | |
| 
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case HAWK_VAL_MBS:
 | |
| 			#if defined(HAWK_ENABLE_MBS_CACHE)
 | |
| 				if (flags & HAWK_RTX_FREEVAL_CACHE)
 | |
| 				{
 | |
| 					hawk_val_mbs_t* v = (hawk_val_mbs_t*)val;
 | |
| 					hawk_oow_t aligned_len;
 | |
| 					int i;
 | |
| 
 | |
| 					aligned_len = HAWK_ALIGN_POW2((v->val.len + 1), HAWK_MBS_CACHE_BLOCK_UNIT);
 | |
| 					i = aligned_len / HAWK_MBS_CACHE_BLOCK_UNIT;
 | |
| 					if (i < HAWK_COUNTOF(rtx->mbs_cache_count) &&
 | |
| 					    rtx->mbs_cache_count[i] < HAWK_COUNTOF(rtx->mbs_cache[i]))
 | |
| 					{
 | |
| 						rtx->mbs_cache[i][rtx->mbs_cache_count[i]++] = v;
 | |
| 					}
 | |
| 					else hawk_rtx_freemem (rtx, val);
 | |
| 					break;
 | |
| 				}
 | |
| 			#endif
 | |
| 
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_REX:
 | |
| 			{
 | |
| 				/* don't free ptr as it is inlined to val
 | |
| 				hawk_rtx_freemem (rtx, ((hawk_val_rex_t*)val)->ptr);
 | |
| 				 */
 | |
| 
 | |
| 				/* code is just a pointer to a regular expression stored
 | |
| 				 * in parse tree nodes. so don't free it.
 | |
| 				hawk_freerex (rtx->hawk, ((hawk_val_rex_t*)val)->code[0], ((hawk_val_rex_t*)val)->code[1]);
 | |
| 				 */
 | |
| 
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			case HAWK_VAL_FUN:
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_MAP:
 | |
| 			#if defined(HAWK_ENABLE_GC)
 | |
| 
 | |
| 				#if defined(DEBUG_GC)
 | |
| 				hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] FREEING GCH %p VAL(MAP) %p - flags %d\n", hawk_val_to_gch(val), val, flags);
 | |
| 				#endif
 | |
| 
 | |
| 				hawk_map_fini (((hawk_val_map_t*)val)->map);
 | |
| 				if (!(flags & HAWK_RTX_FREEVAL_GC_PRESERVE))
 | |
| 				{
 | |
| 					gc_unchain_val (val);
 | |
| 					gc_free_val (rtx, val);
 | |
| 				}
 | |
| 			#else
 | |
| 				hawk_map_fini (((hawk_val_map_t*)val)->map);
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 			#endif
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_ARR:
 | |
| 			#if defined(HAWK_ENABLE_GC)
 | |
| 
 | |
| 				#if defined(DEBUG_GC)
 | |
| 				hawk_logbfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, "[GC] FREEING GCH %p VAL(ARR) %p - flags %d\n", hawk_val_to_gch(val), val, flags);
 | |
| 				#endif
 | |
| 
 | |
| 				hawk_arr_fini (((hawk_val_arr_t*)val)->arr);
 | |
| 				if (!(flags & HAWK_RTX_FREEVAL_GC_PRESERVE))
 | |
| 				{
 | |
| 					gc_unchain_val (val);
 | |
| 					gc_free_val (rtx, val);
 | |
| 				}
 | |
| 			#else
 | |
| 				hawk_arr_fini (((hawk_val_arr_t*)val)->arr);
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 			#endif
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_REF:
 | |
| 				if ((flags & HAWK_RTX_FREEVAL_CACHE) && rtx->rcache_count < HAWK_COUNTOF(rtx->rcache))
 | |
| 				{
 | |
| 					rtx->rcache[rtx->rcache_count++] = (hawk_val_ref_t*)val;
 | |
| 				}
 | |
| 				else hawk_rtx_freemem (rtx, val);
 | |
| 				break;
 | |
| 
 | |
| 			case HAWK_VAL_BOB:
 | |
| 				hawk_rtx_freemem (rtx, val);
 | |
| 				break;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void hawk_rtx_refupval (hawk_rtx_t* rtx, hawk_val_t* val)
 | |
| {
 | |
| 	if (HAWK_VTR_IS_POINTER(val))
 | |
| 	{
 | |
| 		if (HAWK_IS_STATICVAL(val)) return;
 | |
| 
 | |
| 	#if defined(DEBUG_VAL)
 | |
| 		hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("ref up [ptr=%p] [count=%d] - [%O]\n"), val, (int)val->v_refs, val);
 | |
| 	#endif
 | |
| 
 | |
| 	#if defined(USE_ATOMIC_REFCNT) && __has_builtin(__atomic_fetch_add)
 | |
| 		__atomic_fetch_add(&val->v_refs, 1, __ATOMIC_RELAXED);
 | |
| 	#else
 | |
| 		val->v_refs++;
 | |
| 	#endif
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void hawk_rtx_refdownval (hawk_rtx_t* rtx, hawk_val_t* val)
 | |
| {
 | |
| 	if (HAWK_VTR_IS_POINTER(val))
 | |
| 	{
 | |
| 		if (HAWK_IS_STATICVAL(val)) return;
 | |
| 
 | |
| 	#if defined(DEBUG_VAL)
 | |
| 		hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T("ref down [ptr=%p] [count=%d] - [%O]\n"), val, (int)val->v_refs, val);
 | |
| 	#endif
 | |
| 
 | |
| 		/* the reference count of a value should be greater than zero for it to be decremented. check the source code for any bugs */
 | |
| 		HAWK_ASSERT (val->v_refs > 0);
 | |
| 
 | |
| 	#if defined(USE_ATOMIC_REFCNT) && __has_builtin(__atomic_fetch_sub)
 | |
| 		if (__atomic_fetch_sub(&val->v_refs, 1, __ATOMIC_RELAXED) == 1)
 | |
| 		{
 | |
| 			hawk_rtx_freeval (rtx, val, HAWK_RTX_FREEVAL_CACHE);
 | |
| 		}
 | |
| 	#else
 | |
| 		val->v_refs--;
 | |
| 		if (val->v_refs <= 0)
 | |
| 		{
 | |
| 			hawk_rtx_freeval (rtx, val, HAWK_RTX_FREEVAL_CACHE);
 | |
| 		}
 | |
| 	#endif
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void hawk_rtx_refdownval_nofree (hawk_rtx_t* rtx, hawk_val_t* val)
 | |
| {
 | |
| 	if (HAWK_VTR_IS_POINTER(val))
 | |
| 	{
 | |
| 		if (HAWK_IS_STATICVAL(val)) return;
 | |
| 
 | |
| 		/* the reference count of a value should be greater than zero for it to be decremented. check the source code for any bugs */
 | |
| 		HAWK_ASSERT (val->v_refs > 0);
 | |
| 
 | |
| 	#if defined(USE_ATOMIC_REFCNT) && __has_builtin(__atomic_fetch_sub)
 | |
| 		__atomic_fetch_sub(&val->v_refs, 1, __ATOMIC_RELAXED);
 | |
| 	#else
 | |
| 		val->v_refs--;
 | |
| 	#endif
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void hawk_rtx_freevalchunk (hawk_rtx_t* rtx, hawk_val_chunk_t* chunk)
 | |
| {
 | |
| 	while (chunk != HAWK_NULL)
 | |
| 	{
 | |
| 		hawk_val_chunk_t* next = chunk->next;
 | |
| 		hawk_rtx_freemem (rtx, chunk);
 | |
| 		chunk = next;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int val_ref_to_bool (hawk_rtx_t* rtx, const hawk_val_ref_t* ref)
 | |
| {
 | |
| 	switch (ref->id)
 | |
| 	{
 | |
| 		case HAWK_VAL_REF_POS:
 | |
| 		{
 | |
| 			hawk_oow_t idx = (hawk_oow_t)ref->adr;
 | |
| 			if (idx == 0)
 | |
| 			{
 | |
| 				return HAWK_OOECS_LEN(&rtx->inrec.line) > 0;
 | |
| 			}
 | |
| 			else if (idx <= rtx->inrec.nflds)
 | |
| 			{
 | |
| 				return rtx->inrec.flds[idx-1].len > 0;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				/* the index is greater than the number of records.
 | |
| 				 * it's an empty string. so false */
 | |
| 				return 0;
 | |
| 			}
 | |
| 		}
 | |
| 		case HAWK_VAL_REF_GBL:
 | |
| 		{
 | |
| 			hawk_oow_t idx = (hawk_oow_t)ref->adr;
 | |
| 			return hawk_rtx_valtobool(rtx, HAWK_RTX_STACK_GBL(rtx, idx));
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_val_t** xref = (hawk_val_t**)ref->adr;
 | |
| 
 | |
| 			/* A reference value is not able to point to another
 | |
| 			 * refernce value for the way values are represented
 | |
| 			 * in HAWK */
 | |
| 			HAWK_ASSERT (HAWK_RTX_GETVALTYPE (rtx, *xref)!= HAWK_VAL_REF);
 | |
| 
 | |
| 			/* make a recursive call back to the caller */
 | |
| 			return hawk_rtx_valtobool(rtx, *xref);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_rtx_valtobool (hawk_rtx_t* rtx, const hawk_val_t* val)
 | |
| {
 | |
| 	hawk_val_type_t vtype;
 | |
| 
 | |
| 	if (val == HAWK_NULL) return 0;
 | |
| 
 | |
| 	vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 			return 0;
 | |
| 
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 			/* return always true - treat it like a 1-letter string */
 | |
| 			return 1;
 | |
| 
 | |
| 		case HAWK_VAL_INT:
 | |
| 			return HAWK_RTX_GETINTFROMVAL(rtx, val) != 0;
 | |
| 		case HAWK_VAL_FLT:
 | |
| 			return ((hawk_val_flt_t*)val)->val != 0.0;
 | |
| 		case HAWK_VAL_STR:
 | |
| 			return ((hawk_val_str_t*)val)->val.len > 0;
 | |
| 		case HAWK_VAL_MBS:
 | |
| 			return ((hawk_val_mbs_t*)val)->val.len > 0;
 | |
| 		case HAWK_VAL_REX: /* TODO: is this correct? */
 | |
| 			return ((hawk_val_rex_t*)val)->str.len > 0;
 | |
| 		case HAWK_VAL_FUN:
 | |
| 			/* return always true */
 | |
| 			return 1;
 | |
| 		case HAWK_VAL_MAP:
 | |
| 			/* true if the map size is greater than 0. false if not */
 | |
| 			return HAWK_MAP_SIZE(((hawk_val_map_t*)val)->map) > 0;
 | |
| 		case HAWK_VAL_ARR:
 | |
| 			return HAWK_ARR_SIZE(((hawk_val_arr_t*)val)->arr) > 0;
 | |
| 		case HAWK_VAL_REF:
 | |
| 			return val_ref_to_bool(rtx, (hawk_val_ref_t*)val);
 | |
| 		case HAWK_VAL_BOB:
 | |
| 			return ((hawk_val_bob_t*)val)->val.len > 0;
 | |
| 	}
 | |
| 
 | |
| 	/* the type of a value should be one of HAWK_VAL_XXX enumerators defined in hawk-prv.h */
 | |
| 	HAWK_ASSERT (!"should never happen - invalid value type");
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int str_to_str (hawk_rtx_t* rtx, const hawk_ooch_t* str, hawk_oow_t str_len, hawk_rtx_valtostr_out_t* out)
 | |
| {
 | |
| 	int type = out->type & ~HAWK_RTX_VALTOSTR_PRINT;
 | |
| 
 | |
| 	switch (type)
 | |
| 	{
 | |
| 		case HAWK_RTX_VALTOSTR_CPL:
 | |
| 		{
 | |
| 			out->u.cpl.len = str_len;
 | |
| 			out->u.cpl.ptr = (hawk_ooch_t*)str;
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_CPLCPY:
 | |
| 		{
 | |
| 			if (str_len >= out->u.cplcpy.len)
 | |
| 			{
 | |
| 				hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 				/*out->u.cplcpy.len = str_len + 1;*/ /* set the required length */
 | |
| 				return -1;
 | |
| 			}
 | |
| 
 | |
| 			out->u.cplcpy.len = hawk_copy_oochars_to_oocstr_unlimited(out->u.cplcpy.ptr, str, str_len);
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_CPLDUP:
 | |
| 		{
 | |
| 			hawk_ooch_t* tmp;
 | |
| 
 | |
| 			tmp = hawk_rtx_dupoochars(rtx, str, str_len);
 | |
| 			if (!tmp) return -1;
 | |
| 
 | |
| 			out->u.cpldup.ptr = tmp;
 | |
| 			out->u.cpldup.len = str_len;
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRP:
 | |
| 		{
 | |
| 			hawk_oow_t n;
 | |
| 			hawk_ooecs_clear (out->u.strp);
 | |
| 			n = hawk_ooecs_ncat(out->u.strp, str, str_len);
 | |
| 			if (n == (hawk_oow_t)-1) return -1;
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRPCAT:
 | |
| 		{
 | |
| 			hawk_oow_t n;
 | |
| 			n = hawk_ooecs_ncat(out->u.strpcat, str, str_len);
 | |
| 			if (n == (hawk_oow_t)-1) return -1;
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| #if defined(HAWK_OOCH_IS_BCH)
 | |
| #	define mbs_to_str(rtx,str,str_len,out) str_to_str(rtx,str,str_len,out)
 | |
| #else
 | |
| static int mbs_to_str (hawk_rtx_t* rtx, const hawk_bch_t* str, hawk_oow_t str_len, hawk_rtx_valtostr_out_t* out)
 | |
| {
 | |
| 	int type = out->type & ~HAWK_RTX_VALTOSTR_PRINT;
 | |
| 
 | |
| 	switch (type)
 | |
| 	{
 | |
| 		case HAWK_RTX_VALTOSTR_CPL:
 | |
| 			/* conversion is required. i can't simply return it. let CPL
 | |
| 			 * behave like CPLCPY. fall thru */
 | |
| 		case HAWK_RTX_VALTOSTR_CPLCPY:
 | |
| 		{
 | |
| 			hawk_oow_t ucslen;
 | |
| 			if (HAWK_UNLIKELY(out->u.cplcpy.len <= 0))
 | |
| 			{
 | |
| 				hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EBUFFULL);
 | |
| 				return -1;
 | |
| 			}
 | |
| 			/* hawk_rtx_convbtouchars() doesn't null terminate the result. -1 to secure space for '\0' */
 | |
| 			ucslen = out->u.cplcpy.len - 1;
 | |
| 			if (hawk_rtx_convbtouchars(rtx, str, &str_len, out->u.cplcpy.ptr, &ucslen, 1) <= -1) return -1;
 | |
| 
 | |
| 			out->u.cplcpy.ptr[ucslen] = HAWK_T('\0');
 | |
| 			out->u.cplcpy.len = ucslen;
 | |
| 
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_CPLDUP:
 | |
| 		{
 | |
| 			hawk_ooch_t* tmp;
 | |
| 			hawk_oow_t wcslen;
 | |
| 
 | |
| 			tmp = hawk_rtx_dupbtouchars(rtx, str, str_len, &wcslen, 1);
 | |
| 			if (!tmp) return -1;
 | |
| 
 | |
| 			out->u.cpldup.ptr = tmp;
 | |
| 			out->u.cpldup.len = wcslen;
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRP:
 | |
| 			hawk_ooecs_clear (out->u.strp);
 | |
| 			if (hawk_uecs_ncatbchars(out->u.strp, str, str_len, hawk_rtx_getcmgr(rtx), 1) == (hawk_oow_t)-1) return -1;
 | |
| 			return 0;
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRPCAT:
 | |
| 			if (hawk_uecs_ncatbchars(out->u.strpcat, str, str_len, hawk_rtx_getcmgr(rtx), 1) == (hawk_oow_t)-1) return -1;
 | |
| 			return 0;
 | |
| 	}
 | |
| 
 | |
| 	hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 	return -1;
 | |
| }
 | |
| #endif
 | |
| 
 | |
| 
 | |
| static int val_int_to_str (hawk_rtx_t* rtx, const hawk_val_int_t* v, hawk_rtx_valtostr_out_t* out)
 | |
| {
 | |
| 	hawk_ooch_t* tmp;
 | |
| 	hawk_oow_t rlen = 0;
 | |
| 	int type = out->type & ~HAWK_RTX_VALTOSTR_PRINT;
 | |
| 	hawk_int_t orgval = HAWK_RTX_GETINTFROMVAL (rtx, v);
 | |
| 	hawk_uint_t t;
 | |
| 
 | |
| 	if (orgval == 0) rlen++;
 | |
| 	else
 | |
| 	{
 | |
| 		/* non-zero values */
 | |
| 		if (orgval < 0)
 | |
| 		{
 | |
| 			t = orgval * -1; rlen++;
 | |
| 		}
 | |
| 		else t = orgval;
 | |
| 		while (t > 0) { rlen++; t /= 10; }
 | |
| 	}
 | |
| 
 | |
| 	switch (type)
 | |
| 	{
 | |
| 		case HAWK_RTX_VALTOSTR_CPL:
 | |
| 			/* CPL and CPLCP behave the same for int_t.
 | |
| 			 * i just fall through assuming that cplcpy
 | |
| 			 * and cpl are the same type. the following
 | |
| 			 * assertion at least ensure that they have
 | |
| 			 * the same size. */
 | |
| 			HAWK_ASSERT (HAWK_SIZEOF(out->u.cpl) == HAWK_SIZEOF(out->u.cplcpy));
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_CPLCPY:
 | |
| 			if (rlen >= out->u.cplcpy.len)
 | |
| 			{
 | |
| 				hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 				/* store the buffer size needed */
 | |
| 				out->u.cplcpy.len = rlen + 1;
 | |
| 				return -1;
 | |
| 			}
 | |
| 
 | |
| 			tmp = out->u.cplcpy.ptr;
 | |
| 			tmp[rlen] = HAWK_T('\0');
 | |
| 			out->u.cplcpy.len = rlen;
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_CPLDUP:
 | |
| 			tmp = hawk_rtx_allocmem(rtx, (rlen + 1) * HAWK_SIZEOF(hawk_ooch_t));
 | |
| 			if (!tmp) return -1;
 | |
| 
 | |
| 			tmp[rlen] = HAWK_T('\0');
 | |
| 			out->u.cpldup.ptr = tmp;
 | |
| 			out->u.cpldup.len = rlen;
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRP:
 | |
| 		{
 | |
| 			hawk_oow_t n;
 | |
| 
 | |
| 			hawk_ooecs_clear (out->u.strp);
 | |
| 			HAWK_ASSERT (HAWK_OOECS_LEN(out->u.strp) == 0);
 | |
| 
 | |
| 			/* point to the beginning of the buffer */
 | |
| 			tmp = HAWK_OOECS_PTR(out->u.strp);
 | |
| 
 | |
| 			/* extend the buffer */
 | |
| 			n = hawk_ooecs_nccat(out->u.strp, HAWK_T(' '), rlen);
 | |
| 			if (n == (hawk_oow_t)-1) return -1;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRPCAT:
 | |
| 		{
 | |
| 			hawk_oow_t n;
 | |
| 
 | |
| 			/* point to the insertion point */
 | |
| 			tmp = HAWK_OOECS_PTR(out->u.strpcat) + HAWK_OOECS_LEN(out->u.strpcat);
 | |
| 
 | |
| 			/* extend the buffer */
 | |
| 			n = hawk_ooecs_nccat(out->u.strpcat, HAWK_T(' '), rlen);
 | |
| 			if (n == (hawk_oow_t)-1) return -1;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 			return -1;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (orgval == 0) tmp[0] = HAWK_T('0');
 | |
| 	else
 | |
| 	{
 | |
| 		t = (orgval < 0)? (orgval * -1): orgval;
 | |
| 
 | |
| 		/* fill in the buffer with digits */
 | |
| 		while (t > 0)
 | |
| 		{
 | |
| 			tmp[--rlen] = (hawk_ooch_t)(t % 10) + HAWK_T('0');
 | |
| 			t /= 10;
 | |
| 		}
 | |
| 
 | |
| 		/* insert the negative sign if necessary */
 | |
| 		if (orgval < 0) tmp[--rlen] = HAWK_T('-');
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int val_flt_to_str (hawk_rtx_t* rtx, const hawk_val_flt_t* v, hawk_rtx_valtostr_out_t* out)
 | |
| {
 | |
| 	hawk_ooch_t* tmp;
 | |
| 	hawk_oow_t tmp_len;
 | |
| 	hawk_ooecs_t buf, fbu;
 | |
| 	int buf_inited = 0, fbu_inited = 0;
 | |
| 	int type = out->type & ~HAWK_RTX_VALTOSTR_PRINT;
 | |
| 
 | |
| 	if (out->type & HAWK_RTX_VALTOSTR_PRINT)
 | |
| 	{
 | |
| 		tmp = rtx->gbl.ofmt.ptr;
 | |
| 		tmp_len = rtx->gbl.ofmt.len;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		tmp = rtx->gbl.convfmt.ptr;
 | |
| 		tmp_len = rtx->gbl.convfmt.len;
 | |
| 	}
 | |
| 
 | |
| 	if (hawk_ooecs_init(&buf, hawk_rtx_getgem(rtx), 256) <= -1) return -1;
 | |
| 	buf_inited = 1;
 | |
| 
 | |
| 	if (hawk_ooecs_init(&fbu, hawk_rtx_getgem(rtx), 256) <= -1)
 | |
| 	{
 | |
| 		hawk_ooecs_fini (&buf);
 | |
| 		return -1;
 | |
| 	}
 | |
| 	fbu_inited = 1;
 | |
| 
 | |
| 	tmp = hawk_rtx_format(rtx, &buf, &fbu, tmp, tmp_len, (hawk_oow_t)-1, (hawk_nde_t*)v, &tmp_len);
 | |
| 	if (HAWK_UNLIKELY(!tmp)) goto oops;
 | |
| 
 | |
| 	switch (type)
 | |
| 	{
 | |
| 		case HAWK_RTX_VALTOSTR_CPL:
 | |
| 			/* CPL and CPLCP behave the same for flt_t.
 | |
| 			 * i just fall through assuming that cplcpy
 | |
| 			 * and cpl are the same type. the following
 | |
| 			 * assertion at least ensure that they have
 | |
| 			 * the same size. */
 | |
| 			HAWK_ASSERT (HAWK_SIZEOF(out->u.cpl) == HAWK_SIZEOF(out->u.cplcpy));
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_CPLCPY:
 | |
| 			if (out->u.cplcpy.len <= tmp_len)
 | |
| 			{
 | |
| 				hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 				/* store the buffer size required */
 | |
| 				out->u.cplcpy.len = tmp_len + 1;
 | |
| 				goto oops;
 | |
| 			}
 | |
| 
 | |
| 			hawk_copy_oochars_to_oocstr_unlimited (out->u.cplcpy.ptr, tmp, tmp_len);
 | |
| 			out->u.cplcpy.len = tmp_len;
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_CPLDUP:
 | |
| 		{
 | |
| 			hawk_ooecs_yield (&buf, HAWK_NULL, 0);
 | |
| 			out->u.cpldup.ptr = tmp;
 | |
| 			out->u.cpldup.len = tmp_len;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRP:
 | |
| 		{
 | |
| 			hawk_oow_t n;
 | |
| 			hawk_ooecs_clear (out->u.strp);
 | |
| 			n = hawk_ooecs_ncat(out->u.strp, tmp, tmp_len);
 | |
| 			if (n == (hawk_oow_t)-1) goto oops;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_RTX_VALTOSTR_STRPCAT:
 | |
| 		{
 | |
| 			hawk_oow_t n;
 | |
| 			n = hawk_ooecs_ncat(out->u.strpcat, tmp, tmp_len);
 | |
| 			if (n == (hawk_oow_t)-1) goto oops;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 			goto oops;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	hawk_ooecs_fini (&fbu);
 | |
| 	hawk_ooecs_fini (&buf);
 | |
| 	return 0;
 | |
| 
 | |
| oops:
 | |
| 	if (fbu_inited) hawk_ooecs_fini (&fbu);
 | |
| 	if (buf_inited) hawk_ooecs_fini (&buf);
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| static int val_ref_to_str (hawk_rtx_t* rtx, const hawk_val_ref_t* ref, hawk_rtx_valtostr_out_t* out)
 | |
| {
 | |
| 	switch (ref->id)
 | |
| 	{
 | |
| 		case HAWK_VAL_REF_POS:
 | |
| 		{
 | |
| 			hawk_oow_t idx;
 | |
| 
 | |
| 			/* special case when the reference value is
 | |
| 			 * pointing to the positional */
 | |
| 
 | |
| 			idx = (hawk_oow_t)ref->adr;
 | |
| 			if (idx == 0)
 | |
| 			{
 | |
| 				return str_to_str(
 | |
| 					rtx,
 | |
| 					HAWK_OOECS_PTR(&rtx->inrec.line),
 | |
| 					HAWK_OOECS_LEN(&rtx->inrec.line),
 | |
| 					out
 | |
| 				);
 | |
| 			}
 | |
| 			else if (idx <= rtx->inrec.nflds)
 | |
| 			{
 | |
| 				return str_to_str(
 | |
| 					rtx,
 | |
| 					rtx->inrec.flds[idx-1].ptr,
 | |
| 					rtx->inrec.flds[idx-1].len,
 | |
| 					out
 | |
| 				);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				return str_to_str(rtx, HAWK_T(""), 0, out);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_REF_GBL:
 | |
| 		{
 | |
| 			hawk_oow_t idx = (hawk_oow_t)ref->adr;
 | |
| 			return hawk_rtx_valtostr(rtx, HAWK_RTX_STACK_GBL(rtx, idx), out);
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_val_t** xref = (hawk_val_t**)ref->adr;
 | |
| 
 | |
| 			/* A reference value is not able to point to another
 | |
| 			 * refernce value for the way values are represented
 | |
| 			 * in HAWK */
 | |
| 			HAWK_ASSERT (HAWK_RTX_GETVALTYPE (rtx, *xref) != HAWK_VAL_REF);
 | |
| 
 | |
| 			/* make a recursive call back to the caller */
 | |
| 			return hawk_rtx_valtostr(rtx, *xref, out);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_rtx_valtostr (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_rtx_valtostr_out_t* out)
 | |
| {
 | |
| 	hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | |
| 
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 			return str_to_str(rtx, HAWK_T(""), 0, out);
 | |
| 
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		{
 | |
| 			hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			return str_to_str(rtx, &tmp, 1, out);
 | |
| 		#else
 | |
| 			return mbs_to_str(rtx, &tmp, 1, out);
 | |
| 		#endif
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		{
 | |
| 			hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | |
| 			return str_to_str(rtx, &tmp, 1, out);
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_INT:
 | |
| 			return val_int_to_str(rtx, (hawk_val_int_t*)v, out);
 | |
| 
 | |
| 		case HAWK_VAL_FLT:
 | |
| 			return val_flt_to_str(rtx, (hawk_val_flt_t*)v, out);
 | |
| 
 | |
| 		case HAWK_VAL_STR:
 | |
| 		{
 | |
| 			hawk_val_str_t* vs = (hawk_val_str_t*)v;
 | |
| 			return str_to_str(rtx, vs->val.ptr, vs->val.len, out);
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_MBS:
 | |
| 		{
 | |
| 			hawk_val_mbs_t* vs = (hawk_val_mbs_t*)v;
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			return str_to_str(rtx, vs->val.ptr, vs->val.len, out);
 | |
| 		#else
 | |
| 			return mbs_to_str(rtx, vs->val.ptr, vs->val.len, out);
 | |
| 		#endif
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_FUN:
 | |
| 			return str_to_str(rtx, ((hawk_val_fun_t*)v)->fun->name.ptr, ((hawk_val_fun_t*)v)->fun->name.len, out);
 | |
| 
 | |
| 		case HAWK_VAL_MAP:
 | |
| 			if (rtx->hawk->opt.trait & HAWK_FLEXMAP)
 | |
| 			{
 | |
| 				return str_to_str(rtx, HAWK_T("#MAP"), 4, out);
 | |
| 			}
 | |
| 			goto invalid;
 | |
| 
 | |
| 		case HAWK_VAL_ARR:
 | |
| 			if (rtx->hawk->opt.trait & HAWK_FLEXMAP)
 | |
| 			{
 | |
| 				return str_to_str(rtx, HAWK_T("#ARRAY"), 4, out);
 | |
| 			}
 | |
| 			goto invalid;
 | |
| 
 | |
| 		case HAWK_VAL_REF:
 | |
| 			return val_ref_to_str(rtx, (hawk_val_ref_t*)v, out);
 | |
| 
 | |
| 		case HAWK_VAL_REX:
 | |
| 		default:
 | |
| 		invalid:
 | |
| 		#if defined(DEBUG_VAL)
 | |
| 			hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T(">>WRONG VALUE TYPE [%d] in hawk_rtx_valtostr\n"), v->type);
 | |
| 		#endif
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EVALTOSTR);
 | |
| 			return -1;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_rtx_valtobcstrdupwithcmgr (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_oow_t* len, hawk_cmgr_t* cmgr)
 | |
| {
 | |
| 	hawk_bch_t* mbs;
 | |
| 	hawk_val_type_t vtype;
 | |
| 
 | |
| 	vtype = HAWK_RTX_GETVALTYPE(rtx,v);
 | |
| 
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		{
 | |
| 			hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | |
| 			mbs = hawk_rtx_dupbchars(rtx, &tmp, 1);
 | |
| 			if (HAWK_UNLIKELY(!mbs)) return HAWK_NULL;
 | |
| 			if (len) *len = 1;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_MBS:
 | |
| 			mbs = hawk_rtx_dupbchars(rtx, ((hawk_val_mbs_t*)v)->val.ptr, ((hawk_val_mbs_t*)v)->val.len);
 | |
| 			if (HAWK_UNLIKELY(!mbs)) return HAWK_NULL;
 | |
| 			if (len) *len = ((hawk_val_mbs_t*)v)->val.len;
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_BOB:
 | |
| 			mbs = hawk_rtx_dupbchars(rtx, (hawk_bch_t*)((hawk_val_bob_t*)v)->val.ptr, ((hawk_val_bob_t*)v)->val.len);
 | |
| 			if (HAWK_UNLIKELY(!mbs)) return HAWK_NULL;
 | |
| 			if (len) *len = ((hawk_val_mbs_t*)v)->val.len;
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		case HAWK_VAL_STR:
 | |
| 		{
 | |
| 			const hawk_ooch_t* ptr;
 | |
| 			hawk_oow_t slen;
 | |
| 			hawk_ooch_t tmp;
 | |
| 
 | |
| 			if (vtype == HAWK_VAL_CHAR)
 | |
| 			{
 | |
| 				tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | |
| 				ptr = &tmp;
 | |
| 				slen = 1;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				ptr = ((hawk_val_str_t*)v)->val.ptr;
 | |
| 				slen = ((hawk_val_str_t*)v)->val.len;
 | |
| 			}
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			mbs = hawk_rtx_dupbchars(rtx, ptr, slen);
 | |
| 			if (HAWK_UNLIKELY(!mbs)) return HAWK_NULL;
 | |
| 			if (len) *len = slen;
 | |
| 		#else
 | |
| 			{
 | |
| 				hawk_oow_t mbslen, wcslen;
 | |
| 				wcslen = slen;
 | |
| 				mbs = hawk_rtx_duputobcharswithcmgr(rtx, ptr, wcslen, &mbslen, cmgr);
 | |
| 				if (HAWK_UNLIKELY(!mbs)) return HAWK_NULL;
 | |
| 				if (len) *len = mbslen;
 | |
| 			}
 | |
| 		#endif
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			hawk_rtx_valtostr_out_t out;
 | |
| 
 | |
| 			out.type = HAWK_RTX_VALTOSTR_CPLDUP;
 | |
| 			if (hawk_rtx_valtostr(rtx, v, &out) <= -1) return HAWK_NULL;
 | |
| 
 | |
| 			mbs = out.u.cpldup.ptr;
 | |
| 			if (len) *len = out.u.cpldup.len;
 | |
| 		#else
 | |
| 			hawk_oow_t mbslen;
 | |
| 			hawk_rtx_valtostr_out_t out;
 | |
| 
 | |
| 			out.type = HAWK_RTX_VALTOSTR_CPLDUP;
 | |
| 			if (hawk_rtx_valtostr(rtx, v, &out) <= -1) return HAWK_NULL;
 | |
| /* TODO IMPLEMENT hawk_rtx_valtobcs()... and use it */
 | |
| 
 | |
| 			mbs = hawk_rtx_duputobcharswithcmgr(rtx, out.u.cpldup.ptr, out.u.cpldup.len, &mbslen, cmgr);
 | |
| 			hawk_rtx_freemem (rtx, out.u.cpldup.ptr);
 | |
| 			if (HAWK_UNLIKELY(!mbs)) return HAWK_NULL;
 | |
| 			if (len) *len = mbslen;
 | |
| 		#endif
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return mbs;
 | |
| }
 | |
| 
 | |
| hawk_uch_t* hawk_rtx_valtoucstrdupwithcmgr (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_oow_t* len, hawk_cmgr_t* cmgr)
 | |
| {
 | |
| 	hawk_uch_t* wcs;
 | |
| 	hawk_val_type_t vtype;
 | |
| 
 | |
| 	vtype = HAWK_RTX_GETVALTYPE(rtx,v);
 | |
| 
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		{
 | |
| 			hawk_bch_t tmp;
 | |
| 			hawk_oow_t mbslen, wcslen;
 | |
| 
 | |
| 			tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | |
| 			mbslen = 1;
 | |
| 			wcs = hawk_rtx_dupbtoucharswithcmgr(rtx, &tmp, mbslen, &wcslen, cmgr, 1);
 | |
| 			if (!wcs) return HAWK_NULL;
 | |
| 			if (len) *len = wcslen;
 | |
| 			break;
 | |
| 		}
 | |
| 		case HAWK_VAL_MBS:
 | |
| 		{
 | |
| 			hawk_oow_t mbslen, wcslen;
 | |
| 			mbslen = ((hawk_val_mbs_t*)v)->val.len;
 | |
| 			wcs = hawk_rtx_dupbtoucharswithcmgr(rtx, ((hawk_val_mbs_t*)v)->val.ptr, mbslen, &wcslen, cmgr, 1);
 | |
| 			if (!wcs) return HAWK_NULL;
 | |
| 			if (len) *len = wcslen;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		{
 | |
| 			hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			hawk_oow_t wcslen, mbslen;
 | |
| 			mbslen = 1;
 | |
| 			wcs = hawk_rtx_dupbtoucharswithcmgr(rtx, &tmp, mbslen, &wcslen, cmgr, 1);
 | |
| 		#else
 | |
| 			wcs = hawk_rtx_dupuchars(rtx, &tmp, 1);
 | |
| 		#endif
 | |
| 			if (!wcs) return HAWK_NULL;
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			if (len) *len = wcslen;
 | |
| 		#else
 | |
| 			if (len) *len = 1;
 | |
| 		#endif
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_STR:
 | |
| 		{
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			hawk_oow_t wcslen, mbslen;
 | |
| 			mbslen = ((hawk_val_str_t*)v)->val.len;
 | |
| 			wcs = hawk_rtx_dupbtoucharswithcmgr(rtx, ((hawk_val_str_t*)v)->val.ptr, mbslen, &wcslen, cmgr, 1);
 | |
| 		#else
 | |
| 			wcs = hawk_rtx_dupuchars(rtx, ((hawk_val_str_t*)v)->val.ptr, ((hawk_val_str_t*)v)->val.len);
 | |
| 		#endif
 | |
| 			if (!wcs) return HAWK_NULL;
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			if (len) *len = wcslen;
 | |
| 		#else
 | |
| 			if (len) *len = ((hawk_val_str_t*)v)->val.len;
 | |
| 		#endif
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 		#if defined(HAWK_OOCH_IS_BCH)
 | |
| 			hawk_oow_t wcslen;
 | |
| 			hawk_rtx_valtostr_out_t out;
 | |
| 
 | |
| 			out.type = HAWK_RTX_VALTOSTR_CPLDUP;
 | |
| 			if (hawk_rtx_valtostr(rtx, v, &out) <= -1) return HAWK_NULL;
 | |
| 
 | |
| 			wcs = hawk_rtx_dupbtoucharswithcmgr(rtx, out.u.cpldup.ptr, out.u.cpldup.len, &wcslen, cmgr, 1);
 | |
| 			hawk_rtx_freemem (rtx, out.u.cpldup.ptr);
 | |
| 			if (!wcs) return HAWK_NULL;
 | |
| 
 | |
| 			if (len) *len = wcslen;
 | |
| 		#else
 | |
| 			hawk_rtx_valtostr_out_t out;
 | |
| 
 | |
| 			out.type = HAWK_RTX_VALTOSTR_CPLDUP;
 | |
| 			if (hawk_rtx_valtostr(rtx, v, &out) <= -1) return HAWK_NULL;
 | |
| 
 | |
| 			wcs = out.u.cpldup.ptr;
 | |
| 			if (len) *len = out.u.cpldup.len;
 | |
| 		#endif
 | |
| 			break;
 | |
| 		}
 | |
| 	}
 | |
| 	return wcs;
 | |
| }
 | |
| 
 | |
| hawk_ooch_t* hawk_rtx_getvaloocstrwithcmgr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_oow_t* len, hawk_cmgr_t* cmgr)
 | |
| {
 | |
| 	hawk_ooch_t c;
 | |
| 	hawk_oow_t l;
 | |
| 
 | |
| 	switch (HAWK_RTX_GETVALTYPE(rtx, v))
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 			c = '\0';
 | |
| 			l = 0;
 | |
| 			goto ctos;
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 			c = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | |
| 			l = 1;
 | |
| 		ctos:
 | |
| 			if (rtx->ctos.fi) /* free slot available */
 | |
| 			{
 | |
| 				/* use a ctos slot to avoid duplication */
 | |
| 				hawk_oow_t fi;
 | |
| 				fi = rtx->ctos.fi;
 | |
| 				rtx->ctos.fi = rtx->ctos.b[rtx->ctos.fi].c[0];
 | |
| 				rtx->ctos.b[fi].c[0] = c;
 | |
| 				rtx->ctos.b[fi].c[1] = '\0';
 | |
| 				if (len) *len = l;
 | |
| 				HAWK_ASSERT ((void*)&rtx->ctos.b[fi] == (void*)rtx->ctos.b[fi].c);
 | |
| 				return rtx->ctos.b[fi].c;
 | |
| 			}
 | |
| 			goto duplicate;
 | |
| 
 | |
| 		case HAWK_VAL_STR:
 | |
| #if 0
 | |
| 		plain_str:
 | |
| #endif
 | |
| 			if (len) *len = ((hawk_val_str_t*)v)->val.len;
 | |
| 			return ((hawk_val_str_t*)v)->val.ptr;
 | |
| 
 | |
| #if 0
 | |
| /* i'm commenting out this part because hawk_rtx_setrefval() changes v->adr
 | |
|  * and leads hawk_rtx_freevaloocstr() to check a wrong value obejct.
 | |
|  * if you know that a value is a reference, you can get the referenced value
 | |
|  * with hawk_rtx_getrefval() and call this function over it */
 | |
| 		case HAWK_VAL_REF:
 | |
| 			v = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)v);
 | |
| 			if (HAWK_RTX_GETVALTYPE(rtx, v1) == HAWK_VAL_STR) goto plain_str;
 | |
| 			/* fall through */
 | |
| #endif
 | |
| 
 | |
| 		default:
 | |
| 		duplicate:
 | |
| 			return hawk_rtx_valtooocstrdupwithcmgr(rtx, v, len, cmgr);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void hawk_rtx_freevaloocstr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_ooch_t* str)
 | |
| {
 | |
| 	switch (HAWK_RTX_GETVALTYPE(rtx, v))
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		{
 | |
| 			hawk_ctos_b_t* b = (hawk_ctos_b_t*)str;
 | |
| 			if (b >= &rtx->ctos.b[0] && b < &rtx->ctos.b[HAWK_COUNTOF(rtx->ctos.b)])
 | |
| 			{
 | |
| 				hawk_oow_t fi;
 | |
| 				fi = b - &rtx->ctos.b[0];
 | |
| 				rtx->ctos.b[fi].c[0] = rtx->ctos.fi;
 | |
| 				rtx->ctos.fi = fi;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			goto freemem;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_STR:
 | |
| #if 0
 | |
| 		plain_str:
 | |
| #endif
 | |
| 			if (str != ((hawk_val_str_t*)v)->val.ptr) hawk_rtx_freemem (rtx, str);
 | |
| 			break;
 | |
| 
 | |
| #if 0
 | |
| 		case HAWK_VAL_REF:
 | |
| 			v = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)v);
 | |
| 			if (v && HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_STR) goto plain_str;
 | |
| 			/* fall through */
 | |
| #endif
 | |
| 
 | |
| 		default:
 | |
| 		freemem:
 | |
| 			hawk_rtx_freemem (rtx, str);
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| hawk_bch_t* hawk_rtx_getvalbcstrwithcmgr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_oow_t* len, hawk_cmgr_t* cmgr)
 | |
| {
 | |
| 	hawk_bch_t c;
 | |
| 	hawk_oow_t l;
 | |
| 
 | |
| 	switch (HAWK_RTX_GETVALTYPE(rtx, v))
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 			c = '\0';
 | |
| 			l = 0;
 | |
| 			goto bctos;
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 			c = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | |
| 			l = 1;
 | |
| 		bctos:
 | |
| 			if (rtx->bctos.fi) /* free slot available */
 | |
| 			{
 | |
| 				/* use a bctos slot to avoid duplication */
 | |
| 				hawk_oow_t fi;
 | |
| 				fi = rtx->bctos.fi;
 | |
| 				rtx->bctos.fi = rtx->bctos.b[rtx->bctos.fi].c[0];
 | |
| 				rtx->bctos.b[fi].c[0] = c;
 | |
| 				rtx->bctos.b[fi].c[1] = '\0';
 | |
| 				if (len) *len = l;
 | |
| 				HAWK_ASSERT ((void*)&rtx->bctos.b[fi] == (void*)rtx->bctos.b[fi].c);
 | |
| 				return (hawk_bch_t*)rtx->bctos.b[fi].c; /* type-cast hawk_bchu_t* to hawk_bch_t* */
 | |
| 			}
 | |
| 			goto duplicate;
 | |
| 
 | |
| 		case HAWK_VAL_MBS:
 | |
| #if 0
 | |
| 		plain_mbs:
 | |
| #endif
 | |
| 			if (len) *len = ((hawk_val_mbs_t*)v)->val.len;
 | |
| 			return ((hawk_val_mbs_t*)v)->val.ptr;
 | |
| 
 | |
| #if 0
 | |
| /* i'm commenting out this part because hawk_rtx_setrefval() changes v->adr
 | |
|  * and leads hawk_rtx_freevalbcstr() to check a wrong value obejct.
 | |
|  * if you know that a value is a reference, you can get the referenced value
 | |
|  * with hawk_rtx_getrefval() and call this function over it */
 | |
| 		case HAWK_VAL_REF:
 | |
| 			v1 = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)v);
 | |
| 			if (v1 && HAWK_RTX_GETVALTYPE(rtx, v1) == HAWK_VAL_MBS) goto plain_mbs;
 | |
| 			/* fall through */
 | |
| #endif
 | |
| 
 | |
| 		case HAWK_VAL_BOB: /* BOB must be duplicated */
 | |
| 		default:
 | |
| 		duplicate:
 | |
| 			return hawk_rtx_valtobcstrdupwithcmgr(rtx, v, len, cmgr);
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void hawk_rtx_freevalbcstr (hawk_rtx_t* rtx, hawk_val_t* v, hawk_bch_t* str)
 | |
| {
 | |
| 	switch (HAWK_RTX_GETVALTYPE(rtx, v))
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		{
 | |
| 			hawk_bctos_b_t* b = (hawk_bctos_b_t*)str;
 | |
| 			if (b >= &rtx->bctos.b[0] && b < &rtx->bctos.b[HAWK_COUNTOF(rtx->bctos.b)])
 | |
| 			{
 | |
| 				hawk_oow_t fi;
 | |
| 				fi = b - &rtx->bctos.b[0];
 | |
| 				rtx->bctos.b[fi].c[0] = rtx->bctos.fi;
 | |
| 				rtx->bctos.fi = fi;
 | |
| 				break;
 | |
| 			}
 | |
| 
 | |
| 			goto freemem;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_MBS:
 | |
| #if 0
 | |
| 		plain_mbs:
 | |
| #endif
 | |
| 			if (str != ((hawk_val_mbs_t*)v)->val.ptr) hawk_rtx_freemem (rtx, str);
 | |
| 			break;
 | |
| 
 | |
| #if 0
 | |
| 		case HAWK_VAL_REF:
 | |
| 			v = hawk_rtx_getrefval(rtx, (hawk_val_ref_t*)v);
 | |
| 			if (v && HAWK_RTX_GETVALTYPE(rtx, v) == HAWK_VAL_MBS) goto plain_mbs;
 | |
| 			/* fall through */
 | |
| #endif
 | |
| 
 | |
| 		case HAWK_VAL_BOB: /* BOB to MBS is always duplication */
 | |
| 		default:
 | |
| 		freemem:
 | |
| 			hawk_rtx_freemem (rtx, str);
 | |
| 			break;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static int val_ref_to_num (hawk_rtx_t* rtx, const hawk_val_ref_t* ref, hawk_int_t* l, hawk_flt_t* r)
 | |
| {
 | |
| 	switch (ref->id)
 | |
| 	{
 | |
| 		case HAWK_VAL_REF_POS:
 | |
| 		{
 | |
| 			hawk_oow_t idx;
 | |
| 
 | |
| 			idx = (hawk_oow_t)ref->adr;
 | |
| 			if (idx == 0)
 | |
| 			{
 | |
| 				return hawk_oochars_to_num(
 | |
| 					HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | |
| 					HAWK_OOECS_PTR(&rtx->inrec.line),
 | |
| 					HAWK_OOECS_LEN(&rtx->inrec.line),
 | |
| 					l, r
 | |
| 				);
 | |
| 			}
 | |
| 			else if (idx <= rtx->inrec.nflds)
 | |
| 			{
 | |
| 				return hawk_oochars_to_num(
 | |
| 					HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | |
| 					rtx->inrec.flds[idx-1].ptr,
 | |
| 					rtx->inrec.flds[idx-1].len,
 | |
| 					l, r
 | |
| 				);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				return hawk_oochars_to_num(HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0), HAWK_T(""), 0, l, r);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_REF_GBL:
 | |
| 		{
 | |
| 			hawk_oow_t idx = (hawk_oow_t)ref->adr;
 | |
| 			return hawk_rtx_valtonum(rtx, HAWK_RTX_STACK_GBL(rtx, idx), l, r);
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_val_t** xref = (hawk_val_t**)ref->adr;
 | |
| 
 | |
| 			/* A reference value is not able to point to another
 | |
| 			 * refernce value for the way values are represented
 | |
| 			 * in HAWK */
 | |
| 			HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, *xref) != HAWK_VAL_REF);
 | |
| 
 | |
| 			/* make a recursive call back to the caller */
 | |
| 			return hawk_rtx_valtonum(rtx, *xref, l, r);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| int hawk_rtx_valtonum (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_int_t* l, hawk_flt_t* r)
 | |
| {
 | |
| 	hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | |
| 
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 			*l = 0;
 | |
| 			return 0;
 | |
| 
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		{
 | |
| 			hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | |
| 			return hawk_bchars_to_num(
 | |
| 				HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | |
| 				&tmp, 1, l, r
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		{
 | |
| 			/* treat it as if it is a 1-letter string */
 | |
| 			hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | |
| 			return hawk_oochars_to_num(
 | |
| 				HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | |
| 				&tmp, 1, l, r
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_INT:
 | |
| 			*l = HAWK_RTX_GETINTFROMVAL(rtx, v);
 | |
| 			return 0; /* long */
 | |
| 
 | |
| 		case HAWK_VAL_FLT:
 | |
| 			*r = ((hawk_val_flt_t*)v)->val;
 | |
| 			return 1; /* real */
 | |
| 
 | |
| 		case HAWK_VAL_STR:
 | |
| 			return hawk_oochars_to_num(
 | |
| 				HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | |
| 				((hawk_val_str_t*)v)->val.ptr,
 | |
| 				((hawk_val_str_t*)v)->val.len,
 | |
| 				l, r
 | |
| 			);
 | |
| 
 | |
| 		case HAWK_VAL_MBS:
 | |
| 			return hawk_bchars_to_num(
 | |
| 				HAWK_OOCHARS_TO_NUM_MAKE_OPTION(0, 0, HAWK_RTX_IS_STRIPSTRSPC_ON(rtx), 0),
 | |
| 				((hawk_val_mbs_t*)v)->val.ptr,
 | |
| 				((hawk_val_mbs_t*)v)->val.len,
 | |
| 				l, r
 | |
| 			);
 | |
| 
 | |
| 		case HAWK_VAL_FUN:
 | |
| 			/* unable to convert a function to a number */
 | |
| 			goto invalid;
 | |
| 
 | |
| 		case HAWK_VAL_MAP:
 | |
| 			if (rtx->hawk->opt.trait & HAWK_FLEXMAP)
 | |
| 			{
 | |
| 				*l = HAWK_MAP_SIZE(((hawk_val_map_t*)v)->map);
 | |
| 				return 0; /* long */
 | |
| 			}
 | |
| 			goto invalid;
 | |
| 
 | |
| 		case HAWK_VAL_ARR:
 | |
| 			if (rtx->hawk->opt.trait & HAWK_FLEXMAP)
 | |
| 			{
 | |
| 				*l = HAWK_ARR_SIZE(((hawk_val_arr_t*)v)->arr);
 | |
| 				return 0; /* long */
 | |
| 			}
 | |
| 			goto invalid;
 | |
| 
 | |
| 		case HAWK_VAL_REF:
 | |
| 			return val_ref_to_num(rtx, (hawk_val_ref_t*)v, l, r);
 | |
| 
 | |
| 		case HAWK_VAL_REX:
 | |
| 		case HAWK_VAL_BOB: /* never allow reference */
 | |
| 		default:
 | |
| 		invalid:
 | |
| 		#if defined(DEBUG_VAL)
 | |
| 			hawk_logfmt(hawk, HAWK_T(">>WRONG VALUE TYPE [%d] in hawk_rtx_valtonum()\n"), v->type);
 | |
| 		#endif
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EVALTONUM);
 | |
| 			return -1; /* error */
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_rtx_valtoint (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_int_t* l)
 | |
| {
 | |
| 	int n;
 | |
| 	hawk_flt_t r;
 | |
| 
 | |
| 	n = hawk_rtx_valtonum(rtx, v, l, &r);
 | |
| 	if (n == 1)
 | |
| 	{
 | |
| 		*l = (hawk_int_t)r;
 | |
| 		n = 0;
 | |
| 	}
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| int hawk_rtx_valtoflt (hawk_rtx_t* rtx, const hawk_val_t* v, hawk_flt_t* r)
 | |
| {
 | |
| 	int n;
 | |
| 	hawk_int_t l;
 | |
| 
 | |
| 	n = hawk_rtx_valtonum(rtx, v, &l, r);
 | |
| 	if (n == 0) *r = (hawk_flt_t)l;
 | |
| 	else if (n == 1) n = 0;
 | |
| 
 | |
| 	return n;
 | |
| }
 | |
| 
 | |
| 
 | |
| hawk_fun_t* hawk_rtx_valtofun (hawk_rtx_t* rtx, hawk_val_t* v)
 | |
| {
 | |
| 	hawk_fun_t* fun;
 | |
| 	hawk_val_type_t vtype;
 | |
| 
 | |
| 	vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | |
| 
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_FUN:
 | |
| 			fun = ((hawk_val_fun_t*)v)->fun;
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		case HAWK_VAL_MBS:
 | |
| 		case HAWK_VAL_BOB:
 | |
| 		{
 | |
| 			hawk_bcs_t x;
 | |
| 			x.ptr = hawk_rtx_getvalbcstr(rtx, v, &x.len);
 | |
| 			if (HAWK_UNLIKELY(!x.ptr)) return HAWK_NULL;
 | |
| 			if (hawk_count_bcstr(x.ptr) != x.len)
 | |
| 			{
 | |
| 				hawk_rtx_freevalbcstr (rtx, v, x.ptr);
 | |
| 				goto error_inval;
 | |
| 			}
 | |
| 			fun = hawk_rtx_findfunwithbcstr(rtx, x.ptr);
 | |
| 			hawk_rtx_freevalbcstr (rtx, v, x.ptr);
 | |
| 			if (!fun) return HAWK_NULL;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		case HAWK_VAL_STR:
 | |
| 		{
 | |
| 			hawk_oocs_t x;
 | |
| 			x.ptr = hawk_rtx_getvaloocstr(rtx, v, &x.len);
 | |
| 			if (HAWK_UNLIKELY(!x.ptr)) return HAWK_NULL;
 | |
| 			if (hawk_count_oocstr(x.ptr) != x.len)
 | |
| 			{
 | |
| 				hawk_rtx_freevaloocstr (rtx, v, x.ptr);
 | |
| 				goto error_inval;
 | |
| 			}
 | |
| 			fun = hawk_rtx_findfunwithoocstr(rtx, x.ptr);
 | |
| 			hawk_rtx_freevaloocstr (rtx, v, x.ptr);
 | |
| 			if (!fun) return HAWK_NULL;
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		error_inval:
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 			return HAWK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	return fun;
 | |
| }
 | |
| 
 | |
| hawk_fnc_t* hawk_rtx_valtofnc (hawk_rtx_t* rtx, hawk_val_t* v, hawk_fnc_t* rfnc)
 | |
| {
 | |
| 	/* this function looks for intrinsic functions as well as module functions.
 | |
| 	 * it combines the functionality of the following two functions.
 | |
| 	 *   hawk_findfncwithoocs() - finds an intrisic function
 | |
| 	 *   hawk_querymodulewithname() - finds a function defined in a module
 | |
| 	 */
 | |
| 
 | |
| 	hawk_t* hawk = hawk_rtx_gethawk(rtx);
 | |
| 	hawk_val_type_t vtype;
 | |
| 
 | |
| 	vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | |
| 
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		case HAWK_VAL_MBS:
 | |
| 		case HAWK_VAL_BOB:
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		case HAWK_VAL_STR:
 | |
| 		{
 | |
| 			hawk_oocs_t x;
 | |
| 			hawk_fnc_t* fnc;
 | |
| 
 | |
| 			x.ptr = hawk_rtx_getvaloocstr(rtx, v, &x.len);
 | |
| 			if (HAWK_UNLIKELY(!x.ptr)) return HAWK_NULL;
 | |
| 			if (hawk_count_oocstr(x.ptr) != x.len)
 | |
| 			{
 | |
| 				hawk_rtx_freevaloocstr (rtx, v, x.ptr);
 | |
| 				goto error_inval;
 | |
| 			}
 | |
| 
 | |
| 			fnc = hawk_findfncwithoocs(hawk, &x);
 | |
| 			if (fnc)
 | |
| 			{
 | |
| 				hawk_rtx_freevaloocstr (rtx, v, x.ptr);
 | |
| 				*rfnc = *fnc;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				hawk_mod_t* mod;
 | |
| 				hawk_mod_sym_t sym;
 | |
| 
 | |
| 				mod = hawk_querymodulewithname(hawk, x.ptr, &sym);
 | |
| 				hawk_rtx_freevaloocstr (rtx, v, x.ptr);
 | |
| 				if (!mod) return HAWK_NULL;
 | |
| 
 | |
| 				if (sym.type != HAWK_MOD_FNC || (hawk->opt.trait & sym.u.fnc_.trait) != sym.u.fnc_.trait)
 | |
| 				{
 | |
| 					hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ENOENT);
 | |
| 					return HAWK_NULL;
 | |
| 				}
 | |
| 
 | |
| 				HAWK_MEMSET (rfnc, 0, HAWK_SIZEOF(*rfnc));
 | |
| 				rfnc->name.ptr = sym.name;
 | |
| 				rfnc->name.len = hawk_count_oocstr(sym.name);
 | |
| 				rfnc->spec = sym.u.fnc_;
 | |
| 				/* TODO: FIX THIS - set the owner name */
 | |
| 				/*rfnc->owner = name of the module?*/
 | |
| 				rfnc->mod = mod;
 | |
| 			}
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		error_inval:
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 			return HAWK_NULL;
 | |
| 	}
 | |
| 
 | |
| 	return rfnc;
 | |
| }
 | |
| 
 | |
| /* ========================================================================== */
 | |
| 
 | |
| static HAWK_INLINE hawk_uint_t hash (hawk_uint8_t* ptr, hawk_oow_t len)
 | |
| {
 | |
| 	hawk_uint_t h;
 | |
| 	HAWK_HASH_BYTES (h, ptr, len);
 | |
| 	return h;
 | |
| }
 | |
| 
 | |
| hawk_int_t hawk_rtx_hashval (hawk_rtx_t* rtx, hawk_val_t* v)
 | |
| {
 | |
| 	hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, v);
 | |
| 	hawk_int_t hv;
 | |
| 
 | |
| 	switch (vtype)
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 			hv = 0;
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 		{
 | |
| 			hawk_bch_t tmp = HAWK_RTX_GETBCHRFROMVAL(rtx, v);
 | |
| 			hv = (hawk_int_t)hash((hawk_uint8_t*)&tmp, HAWK_SIZEOF(tmp));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 		{
 | |
| 			hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, v);
 | |
| 			hv = (hawk_int_t)hash((hawk_uint8_t*)&tmp, HAWK_SIZEOF(tmp));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_INT:
 | |
| 		{
 | |
| 			hawk_int_t tmp = HAWK_RTX_GETINTFROMVAL(rtx, v);
 | |
| 			/*hv = ((hawk_val_int_t*)v)->val;*/
 | |
| 			hv = (hawk_int_t)hash((hawk_uint8_t*)&tmp, HAWK_SIZEOF(tmp));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_FLT:
 | |
| 		{
 | |
| 			hawk_val_flt_t* dv = (hawk_val_flt_t*)v;
 | |
| 			hv = (hawk_int_t)hash((hawk_uint8_t*)&dv->val, HAWK_SIZEOF(dv->val));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_STR:
 | |
| 		{
 | |
| 			hawk_val_str_t* dv = (hawk_val_str_t*)v;
 | |
| 			hv = (hawk_int_t)hash((hawk_uint8_t*)dv->val.ptr, dv->val.len * HAWK_SIZEOF(*dv->val.ptr));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_MBS:
 | |
| 		{
 | |
| 			hawk_val_mbs_t* dv = (hawk_val_mbs_t*)v;
 | |
| 			hv = (hawk_int_t)hash((hawk_uint8_t*)dv->val.ptr, dv->val.len * HAWK_SIZEOF(*dv->val.ptr));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_BOB:
 | |
| 		{
 | |
| 			hawk_val_bob_t* dv = (hawk_val_bob_t*)v;
 | |
| 			hv = (hawk_int_t)hash((hawk_uint8_t*)dv->val.ptr, dv->val.len * HAWK_SIZEOF(*dv->val.ptr));
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 
 | |
| #if defined(DEBUG_VAL)
 | |
| 			hawk_logfmt (hawk_rtx_gethawk(rtx), HAWK_LOG_STDERR, HAWK_T(">>WRONG VALUE TYPE [%d] in hawk_rtx_hashval()\n"), v->type);
 | |
| #endif
 | |
| 			hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EHASHVAL);
 | |
| 			return -1;
 | |
| 	}
 | |
| 
 | |
| 	/* turn off the sign bit */
 | |
| 	return hv  & ~(((hawk_uint_t)1) << ((HAWK_SIZEOF(hawk_uint_t) * 8) - 1));
 | |
| }
 | |
| 
 | |
| hawk_val_type_t hawk_rtx_getrefvaltype (hawk_rtx_t* rtx, hawk_val_ref_t* ref)
 | |
| {
 | |
| 	/* return the type of the value that the reference points to */
 | |
| 	switch (ref->id)
 | |
| 	{
 | |
| 		case HAWK_VAL_REF_POS:
 | |
| 		{
 | |
| 			hawk_oow_t idx;
 | |
| 
 | |
| 			idx = (hawk_oow_t)ref->adr;
 | |
| 			if (idx == 0)
 | |
| 			{
 | |
| 				return HAWK_RTX_GETVALTYPE(rtx, rtx->inrec.d0);
 | |
| 			}
 | |
| 			else if (idx <= rtx->inrec.nflds)
 | |
| 			{
 | |
| 				return HAWK_RTX_GETVALTYPE(rtx, rtx->inrec.flds[idx-1].val);
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				return HAWK_RTX_GETVALTYPE(rtx, hawk_val_nil);
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_REF_GBL:
 | |
| 		{
 | |
| 			hawk_oow_t idx;
 | |
| 			hawk_val_t* v;
 | |
| 			idx = (hawk_oow_t)ref->adr;
 | |
| 			v = HAWK_RTX_STACK_GBL(rtx, idx);
 | |
| 			return HAWK_RTX_GETVALTYPE(rtx, v);
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_val_t** xref = (hawk_val_t**)ref->adr;
 | |
| 			hawk_val_t* v;
 | |
| 
 | |
| 			/* A reference value is not able to point to another
 | |
| 			 * refernce value for the way values are represented
 | |
| 			 * in HAWK */
 | |
| 			v = *xref;
 | |
| 			HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, v) != HAWK_VAL_REF);
 | |
| 			return HAWK_RTX_GETVALTYPE(rtx, v);
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| hawk_val_t* hawk_rtx_getrefval (hawk_rtx_t* rtx, hawk_val_ref_t* ref)
 | |
| {
 | |
| 	switch (ref->id)
 | |
| 	{
 | |
| 		case HAWK_VAL_REF_POS:
 | |
| 		{
 | |
| 			hawk_oow_t idx;
 | |
| 
 | |
| 			idx = (hawk_oow_t)ref->adr;
 | |
| 			if (idx == 0)
 | |
| 			{
 | |
| 				return rtx->inrec.d0;
 | |
| 			}
 | |
| 			else if (idx <= rtx->inrec.nflds)
 | |
| 			{
 | |
| 				return rtx->inrec.flds[idx-1].val;
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				return hawk_val_nil;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_REF_GBL:
 | |
| 		{
 | |
| 			hawk_oow_t idx;
 | |
| 			idx = (hawk_oow_t)ref->adr;
 | |
| 			return HAWK_RTX_STACK_GBL(rtx, idx);
 | |
| 		}
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_val_t** xref = (hawk_val_t**)ref->adr;
 | |
| 			/* A reference value is not able to point to another
 | |
| 			 * refernce value for the way values are represented
 | |
| 			 * in HAWK */
 | |
| 			HAWK_ASSERT (HAWK_RTX_GETVALTYPE(rtx, *xref) != HAWK_VAL_REF);
 | |
| 			return *xref;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int hawk_rtx_setrefval (hawk_rtx_t* rtx, hawk_val_ref_t* ref, hawk_val_t* val)
 | |
| {
 | |
| 	hawk_val_type_t vtype = HAWK_RTX_GETVALTYPE(rtx, val);
 | |
| 
 | |
| 	if (vtype == HAWK_VAL_REX || vtype == HAWK_VAL_REF)
 | |
| 	{
 | |
| 		/* though it is possible that an intrinsic function handler
 | |
| 		 * can accept a regular expression withtout evaluation when 'x'
 | |
| 		 * is specified for the parameter, this function doesn't allow
 | |
| 		 * regular expression to be set to a reference variable to
 | |
| 		 * avoid potential chaos. the nature of performing '/rex/ ~ $0'
 | |
| 		 * for a regular expression without the match operator
 | |
| 		 * makes it difficult to be implemented. */
 | |
| 		hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_EINVAL);
 | |
| 		return -1;
 | |
| 	}
 | |
| 
 | |
| 	switch (ref->id)
 | |
| 	{
 | |
| 		case HAWK_VAL_REF_POS:
 | |
| 		{
 | |
| 			switch (vtype)
 | |
| 			{
 | |
| 				case HAWK_VAL_MAP:
 | |
| 				case HAWK_VAL_ARR:
 | |
| 					/* a map is assigned to a positional. this is disallowed. */
 | |
| 					hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ENONSCATOPOS);
 | |
| 					return -1;
 | |
| 
 | |
| 				default:
 | |
| 				{
 | |
| 					hawk_oocs_t str;
 | |
| 					int x;
 | |
| 
 | |
| 					hawk_rtx_refupval (rtx, val);
 | |
| 					str.ptr = hawk_rtx_getvaloocstr(rtx, val, &str.len);
 | |
| 					if (HAWK_UNLIKELY(!str.ptr))
 | |
| 					{
 | |
| 						hawk_rtx_refdownval (rtx, val);
 | |
| 						return -1;
 | |
| 					}
 | |
| 					x = hawk_rtx_setrec(rtx, (hawk_oow_t)ref->adr, &str, 0);
 | |
| 					hawk_rtx_freevaloocstr (rtx, val, str.ptr);
 | |
| 					hawk_rtx_refdownval (rtx, val);
 | |
| 					return x;
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_REF_GBL:
 | |
| 			/* ref->adr is the index to the global variables, not a real pointer address for HAWK_VAL_REF_GBL */
 | |
| 			return hawk_rtx_setgbl(rtx, (int)ref->adr, val);
 | |
| 
 | |
| 		case HAWK_VAL_REF_NAMEDIDX:
 | |
| 		case HAWK_VAL_REF_GBLIDX:
 | |
| 		case HAWK_VAL_REF_LCLIDX:
 | |
| 		case HAWK_VAL_REF_ARGIDX:
 | |
| 		#if !defined(HAWK_ENABLE_GC)
 | |
| 			if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | |
| 			{
 | |
| 				/* an indexed variable cannot be assigned a map.
 | |
| 				 * in other cases, it falls down to the default case. */
 | |
| 				hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ENONSCATOIDX);
 | |
| 				return -1;
 | |
| 			}
 | |
| 		#endif
 | |
| 			/* fall through */
 | |
| 
 | |
| 		default:
 | |
| 		{
 | |
| 			hawk_val_t** rref;
 | |
| 			hawk_val_type_t rref_vtype;
 | |
| 
 | |
| 			rref = (hawk_val_t**)ref->adr; /* old value pointer */
 | |
| 			rref_vtype = HAWK_RTX_GETVALTYPE(rtx, *rref); /* old value type */
 | |
| 			if (vtype == HAWK_VAL_MAP || vtype == HAWK_VAL_ARR)
 | |
| 			{
 | |
| 				/* new value: map, old value: nil or map => ok */
 | |
| 				if (rref_vtype != HAWK_VAL_NIL && rref_vtype != vtype)
 | |
| 				{
 | |
| 					if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | |
| 					{
 | |
| 						/* cannot change a scalar value to a map */
 | |
| 						hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ESCALARTONONSCA);
 | |
| 						return -1;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 			else
 | |
| 			{
 | |
| 				/* new value: scalar, old value: nil or scalar => ok */
 | |
| 				if (rref_vtype == HAWK_VAL_MAP || rref_vtype == HAWK_VAL_ARR)
 | |
| 				{
 | |
| 					if (!(rtx->hawk->opt.trait & HAWK_FLEXMAP))
 | |
| 					{
 | |
| 						hawk_rtx_seterrnum (rtx, HAWK_NULL, HAWK_ENONSCATOSCALAR);
 | |
| 						return -1;
 | |
| 					}
 | |
| 				}
 | |
| 			}
 | |
| 
 | |
| 			if (*rref != val)
 | |
| 			{
 | |
| 				/* if the new value is not the same as the old value */
 | |
| 				hawk_rtx_refdownval (rtx, *rref);
 | |
| 				*rref = val;
 | |
| 				hawk_rtx_refupval (rtx, *rref);
 | |
| 			}
 | |
| 			return 0;
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| 
 | |
| #define hawk_errputstrf hawk_errputstrf
 | |
| 
 | |
| static hawk_map_walk_t print_pair (hawk_map_t* map, hawk_map_pair_t* pair, void* arg)
 | |
| {
 | |
| 	hawk_rtx_t* rtx = (hawk_rtx_t*)arg;
 | |
| 
 | |
| 	HAWK_ASSERT (rtx == *(hawk_rtx_t**)hawk_map_getxtn(map));
 | |
| 
 | |
| 	hawk_errputstrf (HAWK_T(" %.*s=>"), HAWK_MAP_KLEN(pair), HAWK_MAP_KPTR(pair));
 | |
| 	hawk_dprintval ((hawk_rtx_t*)arg, HAWK_MAP_VPTR(pair));
 | |
| 	hawk_errputstrf (HAWK_T(" "));
 | |
| 
 | |
| 	return HAWK_MAP_WALK_FORWARD;
 | |
| }
 | |
| 
 | |
| 
 | |
| static hawk_arr_walk_t print_pair (hawk_arr_t* arr, hawk_oow_t index, void* arg)
 | |
| {
 | |
| 	hawk_rtx_t* rtx = (hawk_rtx_t*)arg;
 | |
| 
 | |
| 	HAWK_ASSERT (rtx == *(hawk_rtx_t**)hawk_arr_getxtn(arr));
 | |
| 
 | |
| 	hawk_errputstrf (HAWK_T(" %lu=>"), (unsigned long int)index);
 | |
| 	hawk_dprintval ((hawk_rtx_t*)arg, (HAWK_ARR_SLOT(arr,index)? HAWK_ARR_DPTR(arr, index): hawk_val_nil));
 | |
| 	hawk_errputstrf (HAWK_T(" "));
 | |
| 
 | |
| 	return HAWK_ARR_WALK_FORWARD;
 | |
| }
 | |
| 
 | |
| 
 | |
| void hawk_dprintval (hawk_rtx_t* run, hawk_val_t* val)
 | |
| {
 | |
| 	/* TODO: better value printing ... */
 | |
| 
 | |
| 	switch (val->type)
 | |
| 	{
 | |
| 		case HAWK_VAL_NIL:
 | |
| 			hawk_errputstrf (HAWK_T("@nil"));
 | |
| 		       	break;
 | |
| 
 | |
| 		case HAWK_VAL_NIL:
 | |
| 		{
 | |
| 			hawk_ooch_t tmp = HAWK_RTX_GETCHARFROMVAL(rtx, val);
 | |
| 			if (tmp == '\'')
 | |
| 				hawk_errputstrf (HAWK_T("'\\%c'"), tmp);
 | |
| 			else if (tmp == '\0')
 | |
| 				hawk_errputstrf (HAWK_T("'\\0'"));
 | |
| 			else if (hawk_is_ooch_print(tmp))
 | |
| 				hawk_errputstrf (HAWK_T("'%jc'"), tmp);
 | |
| 		#if defined(HAWK_OOCH_IS_UCH)
 | |
| 			else if (tmp <= 0xFFFF)
 | |
| 				hawk_errputstrf (HAWK_T("'\\u%04x'"), tmp);
 | |
| 			else
 | |
| 				hawk_errputstrf (HAWK_T("'\\U%08x'"), tmp);
 | |
| 		#else
 | |
| 			else
 | |
| 				hawk_errputstrf (HAWK_T("'\\x%02x'"), tmp);
 | |
| 		#endif
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		case HAWK_VAL_BCHR:
 | |
| 			hawk_errputstrf (HAWK_T("%hc"), HAWK_GETBCHRFROMVAL(val));
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_CHAR:
 | |
| 			hawk_errputstrf (HAWK_T("%jc"), HAWK_GETCHARFROMVAL(val));
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_INT:
 | |
| 			hawk_errputstrf (HAWK_T("%jd"), (hawk_intmax_t)HAWK_GETINTFROMVAL(val));
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_FLT:
 | |
| 		#if defined(HAWK_USE_FLTMAX)
 | |
| 			/*hawk_errputstrf (HAWK_T("%jf"), ((hawk_val_flt_t*)val)->val);*/
 | |
| 			hawk_errputstrf (HAWK_T("%jjf"), &((hawk_val_flt_t*)val)->val);
 | |
| 		#else
 | |
| 			hawk_errputstrf (HAWK_T("%zf"), ((hawk_val_flt_t*)val)->val);
 | |
| 		#endif
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_STR:
 | |
| 			hawk_errputstrf (HAWK_T("%.*s"), ((hawk_val_str_t*)val)->len, ((hawk_val_str_t*)val)->ptr);
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_MBS:
 | |
| 			hawk_errputstrf (HAWK_T("%.*hs"), ((hawk_val_mbs_t*)val)->len, ((hawk_val_mbs_t*)val)->ptr);
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_REX:
 | |
| 			hawk_errputstrf (HAWK_T("/%s/"), ((hawk_val_rex_t*)val)->ptr);
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_FUN:
 | |
| 			hawk_errputstrf (HAWK_T("%.*s"), ((hawk_val_fun_t*)val)->fun->name.len, ((hawk_val_fun_t*)val)->fun->name.ptr);
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_MAP:
 | |
| 			hawk_errputstrf (HAWK_T("MAP["));
 | |
| 			hawk_map_walk (((hawk_val_map_t*)val)->map, print_pair, run);
 | |
| 			hawk_errputstrf (HAWK_T("]"));
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_ARR:
 | |
| 			hawk_errputstrf (HAWK_T("ARR["));
 | |
| 			hawk_arr_walk (((hawk_val_arr_t*)val)->arr, print_elem, run);
 | |
| 			hawk_errputstrf (HAWK_T("]"));
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_REF:
 | |
| 			hawk_errputstrf (HAWK_T("REF[id=%d,val="), ((hawk_val_ref_t*)val)->id);
 | |
| 			hawk_dprintval (run, *((hawk_val_ref_t*)val)->adr);
 | |
| 			hawk_errputstrf (HAWK_T("]"));
 | |
| 			break;
 | |
| 
 | |
| 		case HAWK_VAL_BOB:
 | |
| 			hawk_errputstrf (HAWK_T("%.*k"), ((hawk_val_bob_t*)val)->len, ((hawk_val_bob_t*)val)->ptr);
 | |
| 			break;
 | |
| 
 | |
| 		default:
 | |
| 			hawk_errputstrf (HAWK_T("**** INTERNAL ERROR - INVALID VALUE TYPE ****\n"));
 | |
| 	}
 | |
| }
 | |
| 
 | |
| #endif
 |