From 673e411c86c6d9903c71f4eba1b54b69a22b2fa6 Mon Sep 17 00:00:00 2001
From: overflowerror <mail@overflowerror.com>
Date: Fri, 10 Mar 2017 18:43:56 +0100
Subject: [PATCH] we now have a stackstrace \o/

---
 try/Makefile                | 13 ++++++---
 try/example.c               | 54 ++++++++----------------------------
 try/exceptions/exceptions.c | 22 +++++++++++++++
 try/exceptions/exceptions.h | 32 +++++++++++++++++++++
 try/try.c                   | 55 ++++++++++++++++++++++++++++++++++---
 try/try.h                   | 29 +++++++++++++++----
 6 files changed, 149 insertions(+), 56 deletions(-)
 create mode 100644 try/exceptions/exceptions.c
 create mode 100644 try/exceptions/exceptions.h

diff --git a/try/Makefile b/try/Makefile
index 1ece937..63fc375 100644
--- a/try/Makefile
+++ b/try/Makefile
@@ -5,9 +5,9 @@
 #
 
 CC = gcc
-DEFS = -D_XOPEN_SOURCE=500 -D_BSD_SOURCE
+DEFS = -D_XOPEN_SOURCE=500 -D_BSD_SOURCE -B "../oop/"
 CFLAGS = -Wall -Wextra -g -std=c99 -DENDEBUG $(DEFS) -fPIC
-LDFLAGS = $(DEFS)
+LDFLAGS = $(DEFS) -rdynamic
 LIBFLAGS = -shared $(DEFS)
 
 .PHONY: all clean
@@ -17,14 +17,19 @@ all: example libtry.so
 %.o: %.c
 	$(CC) $(CFLAGS) -c -o $@ $<
 
-example: example.o try.o 
+example: example.o try.o exceptions/exceptions.o ../oop/liboop.so
 	$(CC) $(LDFLAGS) -o $@ $^
 
-libtry.so: try.o
+libtry.so: try.o exceptions/exceptions.o ../oop/liboop.so
 	$(CC) $(LIBFLAGS) -o $@ $^
 
 try.o: try.c try.h
 example.o: example.c try.h 
+exceptions/exceptions.o: exceptions/exceptions.c exceptions/exceptions.h
+
+../oop/liboop.so:
+	cd ../oop/ && $(MAKE) liboop.so
 
 clean: 
 	rm -f *.o example libtry.so
+	cd ../oop/ && $(MAKE) clean
diff --git a/try/example.c b/try/example.c
index cb7ddc2..39794cc 100644
--- a/try/example.c
+++ b/try/example.c
@@ -1,54 +1,24 @@
 #include "try.h"
 
+#include "../oop/oop.h"
+#include "exceptions/exceptions.h"
+
 #include <stdio.h>
 
-void function_with_throw(const char* e) {
-	subtry();
-	
-	throw(e);
+void function(void) { throws(exception_class)
+
+	throw(new exception("This is an uncaught exception."));
 }
 
 int main(void) {
-	// simple try-catch
 	try {
-		throw("Hello World 1");
-	} catch(const char* e) {
-		printf("Catch 1: %s\n", e);
-	} endtry;
-
-	// try-catch from function
-	try {
-		trycall function_with_throw("Hello World 2");
-	} catch(const char* e) {
-		printf("Catch 2: %s\n", e);
-	} endtry;
-
-	// nested try-catch
-	try {
-		const char* string;
-
-		try {
-			throw("Hello World 3");
-		} catch(const char* e) {
-			string = e;
-		} endtry;
-
-		throw(string);
-	} catch(const char* e) {
-		printf("Catch 3: %s\n", e);
-	} endtry;
-
-	// nested try-catch with throw in catch-clause
-	try {
-		tpush();
-		try {
-			throw("Hello World 4");
-		} catch(const char* e) {
-			cthrow(e);
-		} endtry;
-	} catch(const char* e) {
-		printf("Catch 4: %s\n", e);
+		throw(new exception("This is a caught exception."));
+	} catch(exception_class, exception_t* e) {
+		printf("Caught: %s\n", e->msg);
+		e->destruct(e);
 	} endtry;
+	
+	function();
 
 	return 0;
 }
diff --git a/try/exceptions/exceptions.c b/try/exceptions/exceptions.c
new file mode 100644
index 0000000..8c8ad2b
--- /dev/null
+++ b/try/exceptions/exceptions.c
@@ -0,0 +1,22 @@
+#include "exceptions.h"
+
+#include <stdlib.h>
+
+void method(exception, destruct)(exception_t* this) {
+	this->super.destruct((object_t*) this);
+}
+
+void method(exception, populate)(exception_t* obj, class_t c) {
+	populate(object)((object_t*) obj, c);
+
+	add_method(obj, exception, destruct);
+}
+
+exception_t* method(exception, construct)(const char* msg) {
+	exception_t* obj = malloc(sizeof(exception_t));
+	populate(exception)(obj, exception_class);
+
+	obj->msg = msg;
+
+	return obj;
+}
diff --git a/try/exceptions/exceptions.h b/try/exceptions/exceptions.h
new file mode 100644
index 0000000..eea064d
--- /dev/null
+++ b/try/exceptions/exceptions.h
@@ -0,0 +1,32 @@
+#ifndef EXCEPTIONS_H
+#define EXCEPTIONS_H
+
+#include "../../oop/oop.h"
+
+#define exception construct(exception)
+class_t exception_class;
+class(exception, exception_class, object_class, true) {
+	extends(object_t);	
+
+	const char* msg;
+
+	void (*destruct)(defclass exception*);
+} exception_t;
+
+void method(exception, populate)(exception_t*);
+exception_t* method(exception, construct)(const char*);
+
+#define exception construct(exception)
+class_t exception_class;
+class(exception, exception_class, object_class, true) {
+	extends(object_t);	
+
+	const char* msg;
+
+	void (*destruct)(defclass exception*);
+} exception_t;
+
+void method(exception, populate)(exception_t*);
+exception_t* method(exception, construct)(const char*);
+
+#endif
diff --git a/try/try.c b/try/try.c
index 0b9238f..ff7a91c 100644
--- a/try/try.c
+++ b/try/try.c
@@ -1,6 +1,11 @@
 #include "try.h"
+#include "exceptions/exceptions.h"
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <execinfo.h>
+#include <string.h>
+#include <errno.h>
 
 struct tryc {
 	bool used;
@@ -43,11 +48,15 @@ void* try_catch(try_t id) {
 
 
 void try_remove(try_t id) {
-	trys[id].used = false;
-	trynr--;
+	if (trys[id].used) {
+		trys[id].used = false;
+		trynr--;
+	}
 }
 
 try_t try_pop(void) {
+	if (stack_position < 0)
+		return NO_TRY_BODY;
 	return stack[stack_position--];
 }
 
@@ -55,6 +64,44 @@ void try_push(try_t id) {
 	stack[++stack_position] = id;
 }
 
-void try_throw(try_t id, void* exception) {
-	trys[id].exception = exception;
+#define BACKTRACE_BUFFER_SIZE 16
+#define EXIT_BACKTRACE_FAILED 3
+#define EXIT_UNCAUGHT 4
+void print_backtrace(FILE* file) {
+	void* buffer[BACKTRACE_BUFFER_SIZE];
+	char** strings;
+	int entries = backtrace(buffer, BACKTRACE_BUFFER_SIZE);
+	strings = backtrace_symbols(buffer, entries);
+	
+	if (strings == NULL) {
+		fprintf(file, "  Error while backtracing: %s\n", strerror(errno));
+		exit(EXIT_BACKTRACE_FAILED);
+	}
+
+	int tmp = (entries < BACKTRACE_BUFFER_SIZE) ? entries : entries - 1;
+
+	// from 2, because of print_backtrace and try_throw
+	for (int i = 2; i < tmp; i++) {
+		fprintf(file, "  at %s\n", strings[i]);
+	}
+	if (tmp < entries) {
+		fprintf(file, "  ...\n");
+	}
+	exit(EXIT_UNCAUGHT);
+}
+
+void try_throw(try_t id, void* exception) {
+	if (id == NO_TRY_BODY) {
+		exception_t* e = exception;
+		fprintf(stderr, "\nUncaught exception '%s_t' (\"%s\")\n", 
+			oop_get_class_name(oop_get_class_from_obj((void*) e)),
+			e->msg);
+		print_backtrace(stderr);
+	} else {
+		trys[id].exception = exception;
+	}
+}
+
+void try_reset(try_t id) {
+	trys[id].exception = NULL;
 }
diff --git a/try/try.h b/try/try.h
index 5d211a2..c818d76 100644
--- a/try/try.h
+++ b/try/try.h
@@ -3,17 +3,33 @@
 
 #include <stdbool.h>
 
+#include "../oop/oop.h"
+#include "../misc/unused.h"
+
 typedef int try_t;
 
-#define try do { try_t _try_id = try_new(); void _try_f(void)
-#define catch(e) ; _try_f(); if (try_has_catch(_try_id)) { e = try_catch(_try_id); try_remove(_try_id); do 
-#define endtry while(false); } } while(false);
-#define throw(e) try_throw(_try_id, (void*) e); return;
+#define throws(...) subtry();
+
+#define try { bool _try_catch = false, _try_body = false; void* _try_data = NULL; try_t _try_id = try_new(); void _try_f(void)
+#define pcatch(e) ; _try_f(); if (try_has_catch(_try_id)) { e = try_catch(_try_id); try_remove(_try_id); do 
+
+#define catch(c, ex) ; if (!_try_body) { _try_f(); _try_body = true; _try_data = try_catch(_try_id); _try_catch = try_has_catch(_try_id); try_remove(_try_id); } if (_try_catch && instanceof(_try_data, c)) { _try_catch = false; ex = _try_data; do  
+
+#define endtry while(false); } if (_try_catch) { UNUSED(_try_body); UNUSED(_try_data); }};
+#define throw(e) { try_throw(_try_id, (void*) e); return; }
+
+#define until(condition) ; do { try_reset(_try_id); _try_f(); } while(try_has_catch(_try_id) == condition); void* _try_result = try_catch(_try_id); try_remove(_try_id); if(true) { do
+#define get_thrown() (_try_result)
+#define failed false
+#define succeeded true
+
 #define subtry() try_t _try_id = try_pop();
-#define tpush() try_push(_try_id)
-#define cthrow(e) _try_id = try_pop(); throw(e);
 #define trycall try_push(_try_id);
 
+#define tpush() try_push(_try_id)
+#define cthrow(e) _try_id = try_pop(); throw(e);
+
+#define NO_TRY_BODY -1
 
 try_t try_new(void);
 bool try_has_catch(try_t);
@@ -22,5 +38,6 @@ void try_remove(try_t);
 void try_throw(try_t, void*);
 try_t try_pop(void);
 void try_push(try_t);
+void try_reset(try_t);
 
 #endif