From 7cced2c313c94d1fb8736581840dff00708aabf1 Mon Sep 17 00:00:00 2001
From: Leo Tenenbaum <pommicket@gmail.com>
Date: Sat, 29 Feb 2020 11:32:42 -0500
Subject: new foreign system working like old one did now

---
 allocator.c  |   2 +-
 decls_cgen.c |   4 +-
 foreign.c    |   5 ++
 parse.c      | 151 ++++++++++++++++++++++++++++++++++-------------------------
 test.toc     |   9 ++--
 toc.c        |   1 +
 types.c      |   2 +-
 7 files changed, 102 insertions(+), 72 deletions(-)

diff --git a/allocator.c b/allocator.c
index cf747ab..fae828a 100644
--- a/allocator.c
+++ b/allocator.c
@@ -25,7 +25,7 @@ static void *err_malloc(size_t bytes);
 static void *err_calloc(size_t n, size_t sz);
 static void *err_realloc(void *prev, size_t new_size);
 #ifdef TOC_DEBUG
-/* #define NO_ALLOCATOR 1 /\* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator *\/ */
+#define NO_ALLOCATOR 1 /* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator */
 #endif
 /* number of bytes a page hold, not including the header */
 #define PAGE_BYTES (16384 - sizeof(Page))
diff --git a/decls_cgen.c b/decls_cgen.c
index 0753616..8d56444 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -76,8 +76,8 @@ static void cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) {
 			if (sub == fn_types) continue;
 			if (sub != fn_types+1)
 				cgen_write(g, ", ");
-			cgen_type_pre(g, t, f->where);
-			cgen_type_post(g, t, f->where);
+			cgen_type_pre(g, sub, f->where);
+			cgen_type_post(g, sub, f->where);
 		}
 		cgen_write(g, ")");
 		cgen_type_post(g, &fn_types[0], f->where);
diff --git a/foreign.c b/foreign.c
index 2a61aca..cbceba4 100644
--- a/foreign.c
+++ b/foreign.c
@@ -273,6 +273,11 @@ static bool foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *fn_type, Val
 	if (!fn_ptr) {
 		assert(fn->flags & FN_EXPR_FOREIGN);
 		const char *libname = fn->foreign.lib;
+		if (!libname) {
+			err_print(call_where, "Attempt to call function at compile time which does not have an associated library.");
+			info_print(fn->where, "Function was declared here.");
+			return false;
+		}
 		Library *lib = str_hash_table_get(&ffmgr->libs_loaded, libname, strlen(libname));
 		if (!lib) {
 			void *handle = dlopen(libname, RTLD_LAZY);
diff --git a/parse.c b/parse.c
index f2d5540..2aa3da0 100644
--- a/parse.c
+++ b/parse.c
@@ -1122,6 +1122,68 @@ static Status ctype_to_type(Allocator *a, CType *ctype, Type *type, Location whe
 	return true;
 }
 
+static Status parse_c_type(Parser *p, CType *ctype, Type *type) {
+	Tokenizer *t = p->tokr;
+	if (token_is_direct(t->token, DIRECT_C)) {
+		++t->token;
+		ctype->kind = CTYPE_NONE;
+		if (token_is_kw(t->token, KW_INT)) {
+			ctype->kind = CTYPE_INT;
+			++t->token;
+		} else if (token_is_kw(t->token, KW_AMPERSAND)) {
+			ctype->kind = CTYPE_PTR;
+			++t->token;
+			if (t->token->kind != TOKEN_IDENT) {
+				tokr_err(t, "Expected type to follow &");
+				return false;
+			}
+			ctype->points_to = t->token->ident;
+			++t->token;
+		} else if (t->token->kind == TOKEN_IDENT) {
+			char *id = t->token->ident;
+			CTypeKind kind = 0;
+			if (ident_str_len(id) > 9 && strncmp(id, "unsigned_", 9)) {
+				kind |= CTYPE_UNSIGNED;
+				id += 9;
+			}
+			if (ident_str_eq_str(id, "char"))
+				ctype->kind |= CTYPE_CHAR;
+			else if (ident_str_eq_str(id, "signed_char"))
+				ctype->kind = CTYPE_SIGNED_CHAR;
+			else if (ident_str_eq_str(id, "short"))
+				ctype->kind |= CTYPE_SHORT;
+			else if (ident_str_eq_str(id, "int"))
+				ctype->kind |= CTYPE_INT;
+			else if (ident_str_eq_str(id, "long"))
+				ctype->kind |= CTYPE_LONG;
+			else if (ident_str_eq_str(id, "long_long"))
+				ctype->kind |= CTYPE_CHAR;
+			else if (ident_str_eq_str(id, "float"))
+				ctype->kind = CTYPE_FLOAT;
+			else if (ident_str_eq_str(id, "double"))
+				ctype->kind = CTYPE_DOUBLE;
+			else if (ident_str_eq_str(id, "long_double")) {
+				tokr_err(t, "long double is not supported for #foreign functions.");
+				return false;
+			} else {
+				tokr_err(t, "Unrecognized C type.");
+				return false;
+			}
+			++t->token;
+		} else {
+			tokr_err(t, "Unrecognized C type.");
+			return false;
+		}
+		if (!ctype_to_type(p->allocr, ctype, type, token_location(p->file, t->token)))
+			return false;
+	} else {
+		ctype->kind = CTYPE_NONE;
+		if (!parse_type(p, type))
+			return false;
+	}
+	return true;
+}
+
 static Status parse_expr(Parser *p, Expression *e, Token *end) {
 	Tokenizer *t = p->tokr;
 
@@ -1770,22 +1832,26 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
 					single_arg = e->unary.of = parser_new_expr(p);
 					break;
 				case DIRECT_FOREIGN: {
+					
+					e->kind = EXPR_FN;
+					FnExpr *fn = e->fn = parser_calloc(p, 1, sizeof *e->fn);
+					fn->flags |= FN_EXPR_FOREIGN;
+					fn->foreign.fn_ptr = 0;
+					fn->where.start = t->token;
+					fn->where.file = p->file;
 					++t->token;
 					if (!token_is_kw(t->token, KW_LPAREN)) {
 						tokr_err(t, "Expected ( following #foreign.");
 						return false;
 					}
 					++t->token;
-					
-					e->kind = EXPR_FN;
-					FnExpr *fn = e->fn = parser_calloc(p, 1, sizeof *e->fn);
-					fn->flags |= FN_EXPR_FOREIGN;
-					fn->foreign.fn_ptr = 0;
 					Type *fn_t = &fn->foreign.type;
 					fn_t->kind = TYPE_FN;
 					FnType *fn_type = &fn_t->fn;
 				    fn_type->constness = NULL;
 					fn_type->types = NULL;
+					Type *ret_type = parser_arr_add(p, &fn_type->types);
+					CType *ret_ctype = parser_arr_add(p, &fn->foreign.ctypes);
 					Expression *name = fn->foreign.name_expr = parser_new_expr(p);
 					
 					if (!parse_expr(p, name, expr_find_end(p, EXPR_CAN_END_WITH_COMMA)))
@@ -1819,66 +1885,10 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
 					}
 					++t->token;
 					while (!token_is_kw(t->token, KW_RPAREN)) {
-						if (token_is_direct(t->token, DIRECT_C)) {
-							CType ctype = {0};
-							++t->token;
-							if (token_is_kw(t->token, KW_INT)) {
-								ctype.kind = CTYPE_INT;
-								++t->token;
-							} else if (token_is_kw(t->token, KW_AMPERSAND)) {
-								ctype.kind = CTYPE_PTR;
-								++t->token;
-								if (t->token->kind != TOKEN_IDENT) {
-									tokr_err(t, "Expected type to follow &");
-									return false;
-								}
-								ctype.points_to = t->token->ident;
-								++t->token;
-							} else if (t->token->kind == TOKEN_IDENT) {
-								char *id = t->token->ident;
-								CTypeKind kind = 0;
-								if (ident_str_len(id) > 9 && strncmp(id, "unsigned_", 9)) {
-									kind |= CTYPE_UNSIGNED;
-									id += 9;
-								}
-								if (ident_str_eq_str(id, "char"))
-									ctype.kind |= CTYPE_CHAR;
-								else if (ident_str_eq_str(id, "signed_char"))
-									ctype.kind = CTYPE_SIGNED_CHAR;
-								else if (ident_str_eq_str(id, "short"))
-									ctype.kind |= CTYPE_SHORT;
-								else if (ident_str_eq_str(id, "int"))
-									ctype.kind |= CTYPE_INT;
-								else if (ident_str_eq_str(id, "long"))
-									ctype.kind |= CTYPE_LONG;
-								else if (ident_str_eq_str(id, "long_long"))
-									ctype.kind |= CTYPE_CHAR;
-								else if (ident_str_eq_str(id, "float"))
-									ctype.kind = CTYPE_FLOAT;
-								else if (ident_str_eq_str(id, "double"))
-									ctype.kind = CTYPE_DOUBLE;
-								else if (ident_str_eq_str(id, "long_double")) {
-								    tokr_err(t, "long double is not supported for #foreign functions.");
-									return false;
-								} else {
-									tokr_err(t, "Unrecognized C type.");
-									return false;
-								}
-								++t->token;
-							} else {
-								tokr_err(t, "Unrecognized C type.");
-								return false;
-							}
-							*(CType *)parser_arr_add(p, &fn->foreign.ctypes) = ctype;
-							Type *type = parser_arr_add(p, &fn_type->types);
-							if (!ctype_to_type(p->allocr, &ctype, type, token_location(p->file, t->token)))
-								return false;
-						} else {
-							CType *ctype = parser_arr_add(p, &fn->foreign.ctypes);
-							ctype->kind = CTYPE_NONE;
-							Type *type = parser_arr_add(p, &fn_type->types);
-							if (!parse_type(p, type))
-								return false;
+						Type *type = parser_arr_add(p, &fn_type->types);
+						CType *ctype = parser_arr_add(p, &fn->foreign.ctypes);
+						if (!parse_c_type(p, ctype, type)) {
+							return false;
 						}
 						if (token_is_kw(t->token, KW_COMMA)) {
 							++t->token;
@@ -1890,6 +1900,17 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
 							return false;
 						}
 					}
+					if (t->token == end) {
+						/* void */
+						ret_ctype->kind = CTYPE_NONE;
+						ret_type->kind = TYPE_VOID;
+						ret_type->flags = 0;
+						ret_type->was_expr = NULL;
+					} else {
+						if (!parse_c_type(p, ret_ctype, ret_type))
+							return false;
+					}
+					fn->where.end = t->token;
 					return true;
 				}
 				case DIRECT_EXPORT:
diff --git a/test.toc b/test.toc
index 825da51..66560f8 100644
--- a/test.toc
+++ b/test.toc
@@ -1,6 +1,9 @@
 
-puts ::= #foreign("puts", "libc.so.6") fn (#C int);
+putchar ::= #foreign("putchar", "libc.so.6") fn (#C int) #C int;
+
 
 main ::= fn() {
-	 puts("Hello!");
-};
\ No newline at end of file
+	 putchar(97);
+	 putchar('\n' as i32);
+};
+main();
\ No newline at end of file
diff --git a/toc.c b/toc.c
index ac52363..4033181 100644
--- a/toc.c
+++ b/toc.c
@@ -91,6 +91,7 @@
 /* forward declarations for debugging */
 static void print_val(Value v, Type *t);
 static void print_token(Token *t);
+static void print_type(Type *t);
 static void print_block(Block *b);
 static void print_decl(Declaration *d);
 static void print_block_location(Block *b);
diff --git a/types.c b/types.c
index fa5d60b..54a28ae 100644
--- a/types.c
+++ b/types.c
@@ -1832,7 +1832,7 @@ static Status types_expr(Typer *tr, Expression *e) {
 		arr_set_lena(&arg_exprs, nparams, tr->allocr);
 
 		I16 *order = NULL;
-		if (fn_decl) {
+		if (fn_decl && !(fn_decl->flags & FN_EXPR_FOREIGN)) {
 			if (!call_arg_param_order(fn_decl, &f->type, c->args, e->where, &order)) {
 				free(order);
 				return false;
-- 
cgit v1.2.3