#include "mk.h"
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
#include <sys/malloc.h>
#else 
#include <malloc.h>
#endif

#define free_if_not_memory_pool( p )				\
{													\
	if( mk_is_ptr_in_memory_pool(p,top) == 0 )		\
		free( p );									\
}

int mk_is_ptr_in_memory_pool ( const void *ptr, MK_MEMORY_POOL *memoryPool )
{
	while( memoryPool != NULL )
	{
		if( (unsigned char*)ptr >= memoryPool->memory &&
			(unsigned char*)ptr < memoryPool->memory + sizeof( memoryPool->memory ) )
			return 1;
		memoryPool = memoryPool->previous;
	}
	return 0;
}

MK_CHAR *mk_get_symbol_name_ptr( MK_VM_STRUCT *vm, const MK_CHAR *target )
{
	MK_CHAR *result = NULL;
	MK_CHAR *keyPtr = NULL;
	if( mk_find_item_hashtable(vm->hashSymbolName, target, (void**)&keyPtr ) == 0 )
	{
		result = mk_allocate_memory_pool( &vm->memoryPool,
			target, 
			sizeof( MK_CHAR ) * ( strlen( target ) + 1 ) );
		mk_insert_item_hashtable( vm->hashSymbolName, result, result );
	}
	else
	{
		result = (MK_CHAR*)keyPtr;
	}
	return result;
}

void *mk_allocate_memory_pool( MK_MEMORY_POOL **target, const void *ptr, unsigned int size )
{
	void *result = NULL;
	
	if( target == NULL || 
		size == 0 || 
		size > sizeof( (*target)->memory ) )
		return NULL;
	while( *target != NULL )
	{
		if( (*target)->next + size <= (*target)->memory + MK_SIZEOF_MEMORY_POOL_BLOCK )
			break;
		*target = (*target)->previous;
	}
	if( *target == NULL )
	{
		MK_MEMORY_POOL *newMemoryPool = NULL;
		newMemoryPool = malloc( sizeof(MK_MEMORY_POOL) );
		memset( newMemoryPool, 0x00, sizeof(MK_MEMORY_POOL) );
		newMemoryPool->next = newMemoryPool->memory;
		newMemoryPool->previous = *target;
		*target = newMemoryPool;
	}
	result = (*target)->next;
	memcpy( (*target)->next, ptr, size );
	(*target)->next += ( ( size + 3 ) >> 2 ) << 2;
	return result;
}

void mk_copy_string( MK_CHAR **dest, const MK_CHAR *target )
{
	if( dest && target )
	{
		int length = strlen( target );
		*dest = malloc( length + 1 );
		strcpy( *dest, target );
	}
}

static
MK_MANAGED_VM_FRAME_ITEM_TABLE *mk_create_new_frame_item_table( )
{
	MK_MANAGED_VM_FRAME_ITEM_TABLE *result = 
		(MK_MANAGED_VM_FRAME_ITEM_TABLE *)malloc( sizeof(MK_MANAGED_VM_FRAME_ITEM_TABLE) );
	memset( result, 0x00, sizeof(MK_MANAGED_VM_FRAME_ITEM_TABLE) );
	result->freeSpace = MK_SIZEOF_MANAGED_TABLE;
	return result;
}

MK_VM_FRAME_ITEM *mk_create_vm_frame_item_object( MK_MANAGED_VM_FRAME_ITEM_TABLE **itemTable )
{
	MK_MANAGED_VM_FRAME_ITEM_TABLE *current = *itemTable;
	MK_VM_FRAME_ITEM *ptr = NULL;

	while( current != NULL )
	{
		if( current->freeSpace > 0 )
			break;
		current = current->previous;
	}
	if( current == NULL )
	{
		current = mk_create_new_frame_item_table( );
		current->previous = *itemTable;
		*itemTable = current;
	}
	ptr = current->table + current->nextIndex;
	while( ptr < current->table + MK_SIZEOF_MANAGED_TABLE )
	{
		if( MK_GC_IS_ALLOCATED_OBJECT( ptr->flags ) == 0 )
			break;
		ptr ++;
	}
	if( ptr >= current->table + MK_SIZEOF_MANAGED_TABLE )
	{
		ptr = current->table;
		while( ptr != current->table + current->nextIndex )
		{
			if( MK_GC_IS_ALLOCATED_OBJECT( ptr->flags ) == 0 )
				break;
			ptr ++;
		}
	}
	ptr->flags = MK_TYPE_SET_ATTRIBUTE( MK_OBJECT_TYPE_VM_FRAME_ITEM, MK_VM_FRAME_ITEM_TYPE_NIL );
	MK_GC_SET_MANAGED_BIT( &ptr->flags );
	MK_GC_ALLOCATE_OBJECT( &ptr->flags );
	MK_GC_SET_CN_BIT( &ptr->flags );
	current->freeSpace --;
	current->nextIndex = ptr - current->table + 1;

	return ptr;
}

static
MK_MANAGED_VM_FRAME_TABLE *mk_create_new_frame_table( )
{
	MK_MANAGED_VM_FRAME_TABLE *result = 
		(MK_MANAGED_VM_FRAME_TABLE *)malloc( sizeof(MK_MANAGED_VM_FRAME_TABLE) );
	memset( result, 0x00, sizeof(MK_MANAGED_VM_FRAME_TABLE) );
	result->freeSpace = MK_SIZEOF_MANAGED_TABLE;
	return result;
}

MK_VM_FRAME *mk_create_vm_frame_object( MK_MANAGED_VM_FRAME_TABLE **frameTable )
{
	MK_MANAGED_VM_FRAME_TABLE *current = *frameTable;
	MK_VM_FRAME *ptr = NULL;

	while( current != NULL )
	{
		if( current->freeSpace > 0 )
			break;
		current = current->previous;
	}
	if( current == NULL )
	{
		current = mk_create_new_frame_table( );
		current->previous = *frameTable;
		*frameTable = current;
	}
	ptr = current->table + current->nextIndex;
	while( ptr != current->table + MK_SIZEOF_MANAGED_TABLE )
	{
		if( MK_GC_IS_ALLOCATED_OBJECT( ptr->flags ) == 0 )
			break;
		ptr ++;
	}
	if( ptr == current->table + MK_SIZEOF_MANAGED_TABLE )
	{
		ptr = current->table;
		while( ptr != current->table + current->nextIndex )
		{
			if( MK_GC_IS_ALLOCATED_OBJECT( ptr->flags ) == 0 )
				break;
			ptr ++;
		}
	}
	ptr->flags = MK_OBJECT_TYPE_VM_FRAME;
	MK_GC_SET_MANAGED_BIT( &ptr->flags );
	MK_GC_ALLOCATE_OBJECT( &ptr->flags );
	MK_GC_SET_CN_BIT( &ptr->flags );
	// initialize after this function ptr->previous, ptr->pMethod, ptr->pThis
	current->freeSpace --;
	current->nextIndex = ptr - current->table;

	return ptr;
}

void *mk_create_object( unsigned int nsType )
{
	void *result = NULL;
	unsigned int size = 0;

	switch( MK_OBJECT_TYPE( nsType ) )
	{
	case MK_OBJECT_TYPE_VM_STRUCT:
		size = sizeof( MK_VM_STRUCT );
		break;
	case MK_OBJECT_TYPE_VM_FRAME:
		size = sizeof( MK_VM_FRAME );			// use mk_create_vm_frame_object insted of mk_create_object.
		break;
	case MK_OBJECT_TYPE_OBJECTCODE:
		size = sizeof( MK_OBJECTCODE );
		break;
	case MK_OBJECT_TYPE_VM_FRAME_ITEM:
		size = sizeof( MK_VM_FRAME_ITEM );	// use mk_create_vm_frame_item_object insted of mk_create_object.
		break;
	case MK_TYPE_CLASS:
		size = sizeof( MK_CLASS );
		break;
	case MK_TYPE_VARIABLE:
		size = sizeof( MK_VARIABLE );
		break;
	case MK_TYPE_NODE_BLOCK:
		size = sizeof( MK_NODE_BLOCK );
		break;
	case MK_TYPE_NODE_EXPR:
		size = sizeof( MK_NODE_EXPR );
		break;
	case MK_TYPE_NODE_IF:
		size = sizeof( MK_NODE_IF );
		break;
	case MK_TYPE_NODE_WHILE:
		size = sizeof( MK_NODE_WHILE );
		break;
	case MK_TYPE_TRY_BLOCK:
		size = sizeof( MK_TRY_BLOCK );
		break;
	case MK_TYPE_CATCH_BLOCK:
		size = sizeof( MK_CATCH_BLOCK );
		break;
	default:
		size = 0;
		break;
	}
	if( size > 0 )
	{
		result = 
			malloc( size );
		memset( result, 0x00, size );
		*((unsigned int *)result) = nsType;
	}
	return result;
}

MK_VM_FRAME_ITEM *mk_vm_create_bool_frame_item( int isTrue )
{
	return ( MK_VM_FRAME_ITEM * )
		( ( isTrue ) ? 
			MK_VM_FRAME_ITEM_TYPE_DIRECT_VALUE | MK_VM_FRAME_ITEM_TYPE_DIRECT_BOOL | 0x00000010:
			MK_VM_FRAME_ITEM_TYPE_DIRECT_VALUE | MK_VM_FRAME_ITEM_TYPE_DIRECT_BOOL );
}

int mk_vm_frame_item_is_true( MK_VM_FRAME_ITEM *target )
{
	if( (INT_PTR)target & MK_VM_FRAME_ITEM_TYPE_DIRECT_VALUE )
	{
		return ( (INT_PTR)target & MK_VM_FRAME_ITEM_DIRECT_INT_VALUE_MASK );
	}
	else
	{
		switch( MK_TYPE_ATTRIBUTE( target->flags ) )
		{
		case MK_VM_FRAME_ITEM_TYPE_NIL:
			return 0;

		case MK_VM_FRAME_ITEM_TYPE_INT_VALUE:
		case MK_VM_FRAME_ITEM_TYPE_BOOL_VALUE:
			return target->int32TypeValue != 0;

		case MK_VM_FRAME_ITEM_TYPE_FLOAT_VALUE:
			return target->floatTypeValue != 0;
		
		default:
			return 1;
		}
	}
}

MK_VM_FRAME_ITEM *mk_vm_create_float_frame_item( MK_VM_STRUCT *vm, MK_FLOAT value )
{
	MK_VM_FRAME_ITEM *result = NULL;
	result = mk_create_vm_frame_item_object( &vm->pFrameItemTable );
	result->flags = 
		MK_TYPE_SET_ATTRIBUTE( result->flags, MK_VM_FRAME_ITEM_TYPE_FLOAT_VALUE );
	result->floatTypeValue = value;
	return result;
}

MK_VM_FRAME_ITEM *mk_vm_create_int32_frame_item( MK_VM_STRUCT *vm, int value )
{
	MK_VM_FRAME_ITEM *result = NULL;
	if( abs( value ) < 0x01000000 )
	{
		unsigned int intResult = 0;
		intResult = 
			MK_VM_FRAME_ITEM_TYPE_DIRECT_VALUE | MK_VM_FRAME_ITEM_TYPE_DIRECT_INT | ( abs( value ) << 4 );
		if( value < 0 )
			intResult |= MK_VM_FRAME_ITEM_TYPE_INT_MINUS_VALUE;
		result = ( MK_VM_FRAME_ITEM* )intResult;
	}
	else
	{
		result = mk_create_vm_frame_item_object( &vm->pFrameItemTable );
		result->flags = 
			MK_TYPE_SET_ATTRIBUTE( result->flags, MK_VM_FRAME_ITEM_TYPE_INT_VALUE );
		result->int32TypeValue = value;
	}
	return result;
}

MK_FLOAT mk_vm_frame_item_to_float( MK_VM_FRAME_ITEM *target )
{
	MK_FLOAT num = 0.0;
	if( (INT_PTR)target & MK_VM_FRAME_ITEM_TYPE_DIRECT_VALUE )
	{
		num = ( MK_FLOAT )( ( (INT_PTR)target & MK_VM_FRAME_ITEM_DIRECT_INT_VALUE_MASK ) >> 4 );
		if( (INT_PTR)target & MK_VM_FRAME_ITEM_TYPE_INT_MINUS_VALUE )
			num *= -1.0;
	}
	else
	{
		switch( MK_TYPE_ATTRIBUTE( target->flags ) )
		{
		case MK_VM_FRAME_ITEM_TYPE_INT_VALUE:
			num = (MK_FLOAT)target->int32TypeValue;
			break;

		case MK_VM_FRAME_ITEM_TYPE_FLOAT_VALUE:
			num = target->floatTypeValue;
			break;
		}
	}
	return num;
}

int mk_vm_frame_item_to_int32( MK_VM_FRAME_ITEM *target )
{
	int result = 0;
	if( (INT_PTR)target & MK_VM_FRAME_ITEM_TYPE_DIRECT_VALUE )
	{
		result = ( (INT_PTR)target & MK_VM_FRAME_ITEM_DIRECT_INT_VALUE_MASK ) >> 4;
		if( (INT_PTR)target & MK_VM_FRAME_ITEM_TYPE_INT_MINUS_VALUE )
			result *= -1;
	}
	else
	{
		switch( MK_TYPE_ATTRIBUTE( target->flags ) )
		{
		case MK_VM_FRAME_ITEM_TYPE_INT_VALUE:
			result = target->int32TypeValue;
			break;

		case MK_VM_FRAME_ITEM_TYPE_FLOAT_VALUE:
			result = (int)target->floatTypeValue;
			break;
		}
	}
	return result;
}

void mk_destroy_vector_node( MK_MEMORY_POOL *top, MK_VECTOR *target )
{
	if( target != NULL )
	{
		unsigned int size = 0;
		unsigned int index = 0;
		size = target->used;
		if( MK_TYPE_ATTRIBUTE_VECTOR_STYLE(target->flags) == MK_TYPE_VECTOR_ARRAY_MANAGED_PTR )
		{
			for( index = 0; index < size; index ++ )
				mk_destroy_node( top, (void*)target->items[index] );
		}
		if( ( target->flags & MK_TYPE_VECTOR_POINT_MEMORY_DIRECT ) == 0 )
			free_if_not_memory_pool( target->items );
		free_if_not_memory_pool( target );
	}
}

void mk_destroy_map_item( MK_MEMORY_POOL *top, MK_MAP_ITEM *items, unsigned int size, int isDeleteValue )
{
	if( items != NULL )
	{
		unsigned int index = 0;
		for( index = 0; index < size; index ++ )
		{
			free_if_not_memory_pool( items[index].key );
			if( isDeleteValue )
				mk_destroy_node( top, items[index].value );
		}
	}
}

void mk_destroy_hashtable_node( MK_MEMORY_POOL *top, MK_HASHTABLE *target, int isDeleteValue )
{
	if( target != NULL )
	{
		if( MK_GC_IS_MANAGED_BIT( target->flags ) == 0 )
		{
			mk_destroy_map_item( top, target->elems, target->used, isDeleteValue );
			free_if_not_memory_pool( target->elems );
				free_if_not_memory_pool( target );
		}
	}
}

void mk_destroy_vm_frame_item( MK_MEMORY_POOL *top, MK_VM_FRAME_ITEM *target )
{
	switch( MK_TYPE_ATTRIBUTE( target->flags ) )
	{
	case MK_VM_FRAME_ITEM_TYPE_STRING_VALUE:
		free_if_not_memory_pool( target->stringTypeValue );
		break;

	case MK_VM_FRAME_ITEM_TYPE_CLASS:
		free_if_not_memory_pool( target->classTypeValue.typeName );
		break;
	}
	target->flags = 0;
}

static
void mk_destroy_expr( MK_MEMORY_POOL *top, MK_NODE_EXPR *target )
{
	unsigned int attribute = 0;
	if( target == NULL )
		return;

	attribute = MK_TYPE_ATTRIBUTE_MASK & target->flags;
	switch( MK_OBJECT_TYPE( target->flags ) )
	{
	case MK_TYPE_NODE_EXPR:
		switch( attribute )
		{
		case MK_TYPE_NODE_EXPR_FUNCTION_CALL:
		case MK_TYPE_NODE_EXPR_NEW:
		case MK_TYPE_NODE_EXPR_SUPER_CALL:
			free_if_not_memory_pool( target->u1.symbolName );
			mk_destroy_vector_node( top, target->u2.args );
			break;

		case MK_TYPE_NODE_EXPR_NODE_WITH_PARAM:
			mk_destroy_node( top, target->u1.node );
			break;

		case MK_TYPE_NODE_EXPR_SYMBOL:
		case MK_TYPE_NODE_EXPR_ATSYMBOL:
		case MK_TYPE_NODE_EXPR_DBLATSYMBOL:
			free_if_not_memory_pool( target->u1.symbolName );
			break;
		case MK_TYPE_NODE_EXPR_MULTIPLESYMBOL:
			mk_destroy_vector_node( top, target->u1.multipleSymbols );
			break;

		case MK_TYPE_NODE_EXPR_OPERATION:
			mk_destroy_node( top, target->u1.left );
			mk_destroy_node( top, target->u2.right );
			break;

		case MK_TYPE_NODE_EXPR_RETURN:
			mk_destroy_node( top, target->u1.left );
			break;

		case MK_TYPE_NODE_EXPR_RAISE:
			mk_destroy_node( top, target->u1.left );
			break;

		case MK_TYPE_NODE_EXPR_BREAK:
			break;

		case MK_TYPE_NODE_EXPR_CONTINUE:
			break;

		case MK_TYPE_NODE_EXPR_SYMBOL_THIS:
			break;

		case MK_TYPE_NODE_EXPR_SYMBOL_SUPER:
			break;

		case MK_TYPE_NODE_EXPR_SYMBOL_NIL:
			break;

		case MK_TYPE_NODE_EXPR_SYMBOL_TRUE:
			break;

		case MK_TYPE_NODE_EXPR_SYMBOL_FALSE:
			break;

		case MK_TYPE_NODE_EXPR_STRING:
			free_if_not_memory_pool( target->u2.value );
			break;

		case MK_TYPE_NODE_EXPR_INT8:
		case MK_TYPE_NODE_EXPR_INT16:
		case MK_TYPE_NODE_EXPR_INT32:
		case MK_TYPE_NODE_EXPR_INT64:
		case MK_TYPE_NODE_EXPR_FLOAT:
		case MK_TYPE_NODE_EXPR_CHAR:
			break;
		
		case MK_TYPE_NODE_EXPR_ARRAY_DEFINITION:
			mk_destroy_vector_node( top, target->u1.arrayDefinition );
			break;
		}
		break;
	}
}

void mk_destroy_node( MK_MEMORY_POOL *top, void *target )
{

	unsigned int flags = 0;
	unsigned int switchFlag = 0;
	int isFail = 0;

	if( target == NULL )
		return;
	if( (INT_PTR)target & MK_VM_FRAME_ITEM_TYPE_DIRECT_VALUE )
		return;

	flags =	*( (unsigned int*)target );
	switchFlag = MK_OBJECT_TYPE( flags );
	switch( switchFlag )
	{
	case MK_OBJECT_TYPE_VM_STRUCT:
		{
			MK_VM_STRUCT *vm = 
				(MK_VM_STRUCT*)target;
			MK_MANAGED_VM_FRAME_TABLE *pFrameTable = vm->pFrameTable;
			MK_MANAGED_VM_FRAME_ITEM_TABLE *pTable = vm->pFrameItemTable;
			MK_MANAGED_HASH_TABLE *pHash = vm->pHashTable;
			MK_MANAGED_VECTOR_TABLE *pVector = vm->pVectorTable;
			MK_MEMORY_POOL *memoryPool = vm->memoryPool;
			mk_destroy_node( top, vm->code );
			free_if_not_memory_pool( vm->cache );
			mk_destroy_hashtable_node( top, vm->hashSymbolName, 0 );
			mk_destroy_vector_node( top, vm->localStack );
			while( pTable )
			{
				int index = 0;
				MK_MANAGED_VM_FRAME_ITEM_TABLE *pNext = NULL;
				for( index = 0; index < MK_SIZEOF_MANAGED_TABLE; index ++ )
				{
					if( MK_GC_IS_ALLOCATED_OBJECT( pTable->table[index].flags ) )
						mk_destroy_vm_frame_item( top, &pTable->table[index] );
				}
				pNext = pTable->previous;
				free_if_not_memory_pool( pTable );
				pTable = pNext;
			}
			while( pFrameTable )
			{
				MK_MANAGED_VM_FRAME_TABLE *pNext = pFrameTable->previous;
				free_if_not_memory_pool( pFrameTable );
				pFrameTable = pNext;
			}
			while( pHash )
			{
				int index = 0;
				MK_MANAGED_HASH_TABLE *pNext = NULL;
				for( index = 0; index < MK_SIZEOF_MANAGED_TABLE; index ++ )
				{
					MK_HASHTABLE *pTarget = 
						&pHash->hashTables[index];
					if( MK_GC_IS_ALLOCATED_OBJECT( pTarget->flags ) )
					{
						if( MK_TYPE_ATTRIBUTE_HASHKEY_STYLE( pTarget->flags ) == 
							MK_TYPE_ATTRIBUTE_HASHKEY_STRING )
							mk_destroy_map_item( top, pTarget->elems, pTarget->used, 0 );
						free_if_not_memory_pool( pTarget->elems );
					}
				}
				pNext = pHash->previous;
				free_if_not_memory_pool( pHash );
				pHash = pNext;
			}
			while( pVector )
			{
				int index = 0;
				MK_MANAGED_VECTOR_TABLE *pNext = NULL;
				for( index = 0; index < MK_SIZEOF_MANAGED_TABLE; index ++ )
				{
					MK_VECTOR *pTarget = 
						&pVector->vectors[index];
					if( MK_GC_IS_ALLOCATED_OBJECT( pTarget->flags ) )
						free_if_not_memory_pool( pTarget->items );
				}
				pNext = pVector->previous;
				free_if_not_memory_pool( pVector );
				pVector = pNext;
			}
			while( memoryPool )
			{
				MK_MEMORY_POOL *previous = memoryPool->previous;
				free( memoryPool );
				memoryPool = previous;
			}
			vm->memoryPool = NULL;
			top = NULL;
		}
		break;

	case MK_OBJECT_TYPE_OBJECTCODE:
		{
			MK_OBJECTCODE *objectCode = 
				( MK_OBJECTCODE * )target;
			mk_destroy_hashtable_node( top, objectCode->classes, 1 );
		}
		break;

	case MK_OBJECT_TYPE_VM_FRAME:
		break;
	
	case MK_OBJECT_TYPE_VM_FRAME_ITEM:
		isFail = 1;		// managed object.
		break;

	case MK_TYPE_CLASS:
		{
			MK_CLASS *classTarget = 
				( MK_CLASS * )target;
			mk_destroy_hashtable_node( top, classTarget->variables, 1 );
			if( classTarget->operatorMethod != NULL )
			{
				int index = 0;
				for( index = 0; index < MK_SIZEOF_ENABELD_OPELATORS; index ++ )
					mk_destroy_node( top, (void*)classTarget->operatorMethod[index] );
				free_if_not_memory_pool( classTarget->operatorMethod );
			}
			free_if_not_memory_pool( classTarget->nameThis );
			free_if_not_memory_pool( classTarget->nameSuper );
		}
		break;
	
	case MK_TYPE_VARIABLE:
		{
			MK_VARIABLE *variableTarget = 
				( MK_VARIABLE * )target;
			if( variableTarget->flags & MK_TYPE_ATTRIBUTE_VARIABLE_METHOD )
			{	// method
				if( !( variableTarget->flags & MK_TYPE_ATTRIBUTE_VARIABLE_METHOD_NATIVE ) &&
					variableTarget->impl != NULL )
				{
					mk_destroy_vector_node( top, variableTarget->args );
					mk_destroy_node( top, variableTarget->impl );
				}
			}
			else
			{	// value
				mk_destroy_node( top, variableTarget->defaultValue );
				free_if_not_memory_pool( variableTarget->name );
			}
		}
		break;
	
	case MK_TYPE_NODE_BLOCK:
		{
			MK_NODE_BLOCK *blockTarget =
				( MK_NODE_BLOCK * )target;
			mk_destroy_vector_node( top, blockTarget->exprs );
		}
		break;

	case MK_TYPE_NODE_IF:
		{
			MK_NODE_IF *ifTarget =
				( MK_NODE_IF * )target;
			MK_NODE_IF *previous = NULL;
			while( ifTarget != NULL )
			{
				mk_destroy_node( top, ifTarget->expr );
				mk_destroy_node( top, ifTarget->block );
				previous = ifTarget;
				ifTarget = ifTarget->next;
				if( previous != target )
					free( previous );
			}
		}
		break;

	case MK_TYPE_NODE_WHILE:
		{
			MK_NODE_WHILE *whileTarget =
				( MK_NODE_WHILE * )target;
			mk_destroy_node( top, whileTarget->block );
			mk_destroy_node( top, whileTarget->expr );
		}
		break;

	case MK_TYPE_NODE_EXPR:
		mk_destroy_expr( top, target );
		break;

	case MK_TYPE_TRY_BLOCK:
		{
			MK_TRY_BLOCK *tryBlock = 
				( MK_TRY_BLOCK *) target;
			mk_destroy_node( top, tryBlock->blockTry );
			mk_destroy_vector_node( top, tryBlock->blockCatch );
			mk_destroy_node( top, tryBlock->blockNoException );
			mk_destroy_node( top, tryBlock->blockFinally );
		}
		break;
	
	case MK_TYPE_CATCH_BLOCK:
		{
			MK_CATCH_BLOCK *catchBlock = 
				(MK_CATCH_BLOCK*) target;
			mk_destroy_node( top, catchBlock->paramCatch );
			mk_destroy_node( top, catchBlock->blockCatch );
		}
		break;

	case MK_TYPE_HASHTABLE:	// call	mk_destroy_hashtable_node, mk_destroy_map_item
	case MK_TYPE_VECTOR:	// call mk_destroy_vector_node
	default:
		isFail = 1;
		break;
	}
	if( isFail == 0 )
		free_if_not_memory_pool( target );
}
