// Draft of tests for exception handling.

// ERROR: exceptions do not interact with ^?{} properly.

#include <stdio.h>
#include <stdbool.h>

struct signal_exit {
	const char * area;
};

void ?{}(signal_exit * this, const char * area) {
	this->area = area;
}

void ^?{}(signal_exit * this) {
	printf("Exiting: %s\n", this->area);
//	sout | "Exiting:" | this->area | endl;
}

void terminate(int except_value) {
	signal_exit a = {"terminate function"};
	throw except_value;
	printf("terminate returned\n");
}

void resume(int except_value) {
	signal_exit a = {"resume function"};
	throwResume except_value;
	printf("resume returned\n");
}

// Termination Test: Two handlers: no catch, catch
void bar() {
	signal_exit a = {"bar function"};
	try {
		terminate(4);
	} catch (3) {
		printf("bar caught exception 3.\n");
	}
}

void foo() {
	signal_exit a = {"foo function"};
	try {
		bar();
	} catch (4) {
		printf("foo caught exception 4.\n");
	} catch (2) {
		printf("foo caught exception 2.\n");
	}
}

// Resumption Two Handler Test: no catch, catch.
void beta() {
	signal_exit a = {"beta function"};
	try {
		resume(4);
	} catchResume (3) {
		printf("beta caught exception 3\n");
	}
}

void alpha() {
	signal_exit a = {"alpha function"};
	try {
		beta();
	} catchResume (2) {
		printf("alpha caught exception 2\n");
	} catchResume (4) {
		printf("alpha caught exception 4\n");
	}
}

// Finally Test:
void farewell(bool jump) {
	try {
		if (jump) {
			printf("jump out of farewell\n");
			goto endoffunction;
		} else {
			printf("walk out of farewell\n");
		}
	} finally {
		printf("See you next time\n");
	}
	endoffunction:
	printf("leaving farewell\n");
}

// Resume-to-Terminate Test:
void fallback() {
	try {
		resume(2);
	} catch (2) {
		printf("fallback caught termination 2\n");
	}
}

// Terminate Throw New Exception:
void terminate_swap() {
	signal_exit a = {"terminate_swap"};
	try {
		terminate(2);
	} catch (2) {
		terminate(3);
	}
}

void terminate_swapped() {
	signal_exit a = {"terminate_swapped"};
	try {
		terminate_swap();
	} catch (3) {
		printf("terminate_swapped caught exception 3\n");
	}
}

// Resume Throw New Exception:
void resume_swap() {
	signal_exit a = {"resume_swap"};
	try {
		resume(2);
	} catchResume (2) {
		resume(3);
	}
}

void resume_swapped() {
	try {
		resume_swap();
	} catchResume (3) {
		printf("resume_swapped caught exception 3\n");
	}
}

// Terminate Rethrow:
void reterminate() {
	try {
		try {
			terminate(2);
		} catch (2) {
			printf("reterminate 2 caught and "
			       "will rethrow exception 2\n");
			throw;
		}
	} catch (2) {
		printf("reterminate 1 caught exception 2\n");
	}
}

// Resume Rethrow:
void reresume() {
	try {
		try {
			resume(2);
		} catchResume (2) {
			printf("reresume 2 caught and rethrows exception 2\n");
			throwResume;
		}
	} catchResume (2) {
		printf("reresume 1 caught exception 2\n");
	}
}

// Terminate-Resume interaction:
void fum() {
	// terminate block, call resume
	try {
		resume(3);
	} catch (3) {
		printf("fum caught exception 3\n");
	}
}

void foe() {
	// resume block, call terminate
	try {
		terminate(3);
	} catchResume (3) {
		printf("foe caught exception 3\n");
	}
}

void fy() {
	// terminate block calls fum, call foe
	try {
		foe();
	} catch (3) {
		printf("fy caught exception 3\n");
		fum();
	}
}

void fee() {
	// resume block, call fy
	try {
		fy();
	} catchResume (3) {
		printf("fee caught exception 3\n");
	}
}


// main: choose which tests to run
int main(int argc, char * argv[]) {
	signal_exit a = {"main function"};

	foo(); printf("\n");
	alpha(); printf("\n");
	farewell(false); printf("\n");
	farewell(true); printf("\n");
	fallback(); printf("\n");
	terminate_swapped(); printf("\n");
	resume_swapped(); printf("\n");
	reterminate(); printf("\n");
	reresume(); printf("\n");
	fee(); printf("\n");
	// Uncaught termination test.
	terminate(7);
}
