// Debugging support for dynamic typing.

// General includes.
#include "cl_sysdep.h"

// Specification.
#include "cl_object.h"


// Implementation.

#include "cl_io.h"
#include "cl_abort.h"

// The default printer function.
void cl_dprint_unknown (cl_heap* pointer)
{
	fprint(cl_debugout, "<unknown @0x");
	fprinthexadecimal(cl_debugout, (unsigned long) pointer);
	fprint(cl_debugout, " refcount=");
	fprintdecimal(cl_debugout, pointer->refcount);
	fprint(cl_debugout, " typetag=");
	fprintdecimal(cl_debugout, pointer->typetag);
	fprint(cl_debugout, ">");
}

static void cl_dprint_unknown_immediate (cl_heap* pointer)
{
	fprint(cl_debugout, "<unknown @0x");
	fprinthexadecimal(cl_debugout, (unsigned long) pointer);
	fprint(cl_debugout, ">");
}

// Global table of printer functions.
static cl_heap_dprint_function printer_table [(int)cl_typetag_dynamic_end];
AT_INITIALIZATION(ini_printer_table)
{
	var unsigned int i;
	i = cl_typetag_fixnum;
		if (!printer_table[i])
			printer_table[i] = cl_dprint_unknown_immediate;
	i = cl_typetag_sfloat;
		if (!printer_table[i])
			printer_table[i] = cl_dprint_unknown_immediate;
	#ifdef CL_WIDE_POINTERS
	i = cl_typetag_ffloat;
		if (!printer_table[i])
			printer_table[i] = cl_dprint_unknown_immediate;
	#endif
	for (i = 0; i < sizeof(printer_table)/sizeof(printer_table[0]); i++)
		if (!printer_table[i])
			printer_table[i] = cl_dprint_unknown;
}

// Register a printer function.
void cl_register_typetag_printer (int typetag, cl_heap_dprint_function printer)
{
	var unsigned int index = typetag;
	if (!(index < (int)cl_typetag_dynamic_end))
		cl_abort();
	printer_table[index] = printer;
}

// Print an object. This function is callable from the debugger.
extern "C" void* cl_print (cl_uint word);
void* cl_print (cl_uint word)
{
	var cl_heap* pointer = (cl_heap*)word;
	if (cl_pointer_p(word)) {
		var unsigned int index = pointer->typetag;
		if (index < (int)cl_typetag_dynamic_end)
			printer_table[index](pointer);
		else
			cl_dprint_unknown(pointer);
	} else {
		switch (cl_tag(word)) {
			case cl_FN_tag:
				printer_table[cl_typetag_fixnum](pointer);
				break;
			case cl_SF_tag:
				printer_table[cl_typetag_sfloat](pointer);
				break;
			#ifdef CL_WIDE_POINTERS
			case cl_FF_tag:
				printer_table[cl_typetag_ffloat](pointer);
				break;
			#endif
			default:
				cl_dprint_unknown_immediate(pointer);
				break;
		}
	}
	#ifdef CL_IO_IOSTREAM
	cl_debugout << endl; // newline and flush output
	#else
	fprint(cl_debugout, "\n");
	#endif
	return pointer;
}

void cl_gcobject::debug_print () const
{
	cl_print(word);
}

void cl_gcpointer::debug_print () const
{
	cl_print(word);
}

void cl_rcobject::debug_print () const
{
	cl_print(word);
}

void cl_rcpointer::debug_print () const
{
	cl_print(word);
}
