// New draft of exception tests.


#include <stdlib>
#include "except-mac.h"

TRIVIAL_EXCEPTION(yin)
TRIVIAL_EXCEPTION(yang)

struct num_error;
struct num_error_vtable {
	struct TABLE(BASE_EXCEPT) const * parent;
	size_t size;
	void (*copy)(num_error *this, num_error * other);
	void (*free)(num_error *this);
	const char * (*msg)(num_error *this);
	int (*code)(num_error *this);
};
extern num_error_vtable INSTANCE(num_error);

struct num_error {
	struct num_error_vtable const * virtual_table;
	char * msg;
	int num;
};

void num_error_msg(num_error * this) {
	if ( ! this->msg ) {
		static const char * base = "Num Error with code: X";
		this->msg = malloc(22);
		for (int i = 0 ; (this->msg[i] = base[i]) ; ++i);
	}
	this->msg[21] = '0' + this->num;
	return this->msg;
}
void ?{}(num_error * this, int num) {
	this->virtual_table = &INSTANCE(num_error);
	this->msg = 0;
	this->num = num;
}
void ?{}(num_error * this, num_error * other) {
	this->virtual_table = other->virtual_table;
	this->msg = 0;
	this->num = other->num;
}
void ^?{}(num_error * this) {
	if( this->msg ) free( this->msg );
}
int num_error_code( num_error * this ) {
	return this->num;
}
num_error_vtable _num_error_vtable_instance @= {
	&INSTANCE(BASE_EXCEPT),
	sizeof(num_error), ?{}, ^?{},
	num_error_msg, num_error_code
};


// Test simple throwing, matching and catching.
void throw_catch() {
	try {
		yin black;
		THROW(&black);
	} catch ( yin * error ) {
		printf("throw yin caught.\n");
	}

	try {
		yang white;
		THROW_RESUME(&white);
		printf("> throwResume returned.\n");
	} catchResume ( yang * error ) {
		printf("throwResume yang caught <");
	}

	try {
		num_error x = { 2 };
		THROW(&x);
	}
	catch (num_error * error ; 3 == error->virtual_table->code( error ) ) {
		printf("exception at %p\n", error );
		printf("Should not be printed.\n");
	}
	catch (num_error * error ; 2 == error->virtual_table->code( error ) ) {
		printf("Should be printed.\n");
	}
}

int main (int argc, char * argv[]) {
	throw_catch();
	return 0;
}
