summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-03-01 12:08:28 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-03-01 12:08:28 -0500
commitda748748c0239c21b9d62c77b51e269ad1d7de9f (patch)
tree2e546d3d370cb0aeea7fe24e653c9a456ec614b7
parent7cced2c313c94d1fb8736581840dff00708aabf1 (diff)
better #foreign system
-rw-r--r--decls_cgen.c68
-rw-r--r--main.c2
-rw-r--r--parse.c45
-rw-r--r--std/io.toc4
-rw-r--r--test.toc8
-rw-r--r--tests/arr3/io.toc4
-rw-r--r--tests/foreign/foreign.toc15
-rw-r--r--tests/nms/io.toc28
-rw-r--r--types.c18
-rw-r--r--types.h3
10 files changed, 127 insertions, 68 deletions
diff --git a/decls_cgen.c b/decls_cgen.c
index 8d56444..b5dbec0 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -62,6 +62,48 @@ static void cgen_decls_fn_instances(CGenerator *g, FnExpr *f) {
}
}
+static void cgen_ctype(CGenerator *g, CType *c) {
+ if (c->kind & CTYPE_UNSIGNED) {
+ c->kind &= (CTypeKind)~(CTypeKind)CTYPE_UNSIGNED;
+ cgen_write(g, "unsigned ");
+ }
+ switch (c->kind) {
+ case CTYPE_CHAR:
+ cgen_write(g, "char");
+ break;
+ case CTYPE_SIGNED_CHAR:
+ cgen_write(g, "signed char");
+ break;
+ case CTYPE_SHORT:
+ cgen_write(g, "short");
+ break;
+ case CTYPE_INT:
+ cgen_write(g, "int");
+ break;
+ case CTYPE_LONG:
+ cgen_write(g, "long");
+ break;
+ case CTYPE_LONGLONG:
+ cgen_write(g, "long long");
+ break;
+ case CTYPE_PTR:
+ cgen_write(g, "%s *", c->points_to);
+ break;
+ case CTYPE_FLOAT:
+ cgen_write(g, "float");
+ break;
+ case CTYPE_DOUBLE:
+ cgen_write(g, "double");
+ break;
+ case CTYPE_SIZE_T:
+ cgen_write(g, "size_t");
+ break;
+ default:
+ assert(0);
+ break;
+ }
+}
+
static void cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) {
if (f->flags & FN_EXPR_FOREIGN) {
@@ -69,18 +111,30 @@ static void cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) {
cgen_write(g, "extern ");
Type *fn_types = t->fn.types;
const char *foreign_name = f->foreign.name;
- cgen_type_pre(g, &fn_types[0], f->where);
+ CType *ctypes = f->foreign.ctypes;
+ if (ctypes[0].kind == CTYPE_NONE) {
+ cgen_type_pre(g, &fn_types[0], f->where);
+ } else {
+ cgen_ctype(g, &ctypes[0]);
+ }
cgen_write(g, " %s", foreign_name);
cgen_write(g, "(");
- arr_foreach(fn_types, Type, sub) {
- if (sub == fn_types) continue;
- if (sub != fn_types+1)
+
+ for (size_t i = 1; i < arr_len(fn_types); ++i) {
+ if (i > 1)
cgen_write(g, ", ");
- cgen_type_pre(g, sub, f->where);
- cgen_type_post(g, sub, f->where);
+ CType *csub = &ctypes[i];
+ if (csub->kind == CTYPE_NONE) {
+ Type *sub = &fn_types[i];
+ cgen_type_pre(g, sub, f->where);
+ cgen_type_post(g, sub, f->where);
+ } else {
+ cgen_ctype(g, csub);
+ }
}
cgen_write(g, ")");
- cgen_type_post(g, &fn_types[0], f->where);
+ if (ctypes[0].kind == CTYPE_NONE)
+ cgen_type_post(g, &fn_types[0], f->where);
cgen_write(g, ";");
if (!f->c.name || !ident_eq_str(f->c.name, foreign_name)) {
cgen_write(g, "static ");
diff --git a/main.c b/main.c
index e1af365..15bd387 100644
--- a/main.c
+++ b/main.c
@@ -8,7 +8,7 @@
/*
TODO:
-better #foreign system- something like f := #foreign fn (int,float, #C int, #C longlong);
+as #C int
make err_print and tokr_err return Status
---
constants in structs
diff --git a/parse.c b/parse.c
index 2aa3da0..f49d9a0 100644
--- a/parse.c
+++ b/parse.c
@@ -1090,6 +1090,9 @@ static Status ctype_to_type(Allocator *a, CType *ctype, Type *type, Location whe
case CTYPE_UNSIGNED_LONG:
size = sizeof(long);
break;
+ case CTYPE_SIZE_T:
+ size = sizeof(size_t);
+ break;
case CTYPE_LONGLONG:
case CTYPE_UNSIGNED_LONGLONG:
#if HAVE_LONGLONG
@@ -1113,7 +1116,7 @@ static Status ctype_to_type(Allocator *a, CType *ctype, Type *type, Location whe
case CTYPE_UNSIGNED: assert(0); break;
}
if (size != 0) {
- type->builtin = ((ctype->kind & CTYPE_UNSIGNED) ? uint_with_size : int_with_size)(size);
+ type->builtin = (((ctype->kind & CTYPE_UNSIGNED) || ctype->kind == CTYPE_SIZE_T) ? uint_with_size : int_with_size)(size);
if (type->builtin == BUILTIN_F32) {
err_print(where, "This C type is not representable by a toc type, because it is %lu bytes (not 1, 2, 4, or 8).", size);
return false;
@@ -1130,38 +1133,50 @@ static Status parse_c_type(Parser *p, CType *ctype, Type *type) {
if (token_is_kw(t->token, KW_INT)) {
ctype->kind = CTYPE_INT;
++t->token;
+ } else if (token_is_kw(t->token, KW_FLOAT)) {
+ ctype->kind = CTYPE_FLOAT;
+ ++t->token;
+ } else if (token_is_kw(t->token, KW_CHAR)) {
+ ctype->kind = CTYPE_CHAR;
+ ++t->token;
} else if (token_is_kw(t->token, KW_AMPERSAND)) {
ctype->kind = CTYPE_PTR;
++t->token;
- if (t->token->kind != TOKEN_IDENT) {
+ if (t->token->kind == TOKEN_IDENT) {
+ size_t n = ident_str_len(t->token->ident);
+ ctype->points_to = parser_malloc(p, n+1);
+ memcpy(ctype->points_to, t->token->ident, n);
+ ctype->points_to[n] = 0;
+ } else if (t->token->kind == TOKEN_LITERAL_STR) {
+ size_t n = t->token->str.len;
+ ctype->points_to = parser_malloc(p, n+1);
+ memcpy(ctype->points_to, t->token->str.str, n);
+ ctype->points_to[n] = 0;
+ } else {
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;
+ ctype->kind = 0;
+ if (ident_str_len(id) > 9 && strncmp(id, "unsigned_", 9) == 0) {
+ ctype->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"))
+ 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;
+ ctype->kind |= CTYPE_LONGLONG;
else if (ident_str_eq_str(id, "double"))
ctype->kind = CTYPE_DOUBLE;
+ else if (ident_str_eq_str(id, "size_t"))
+ ctype->kind = CTYPE_SIZE_T;
else if (ident_str_eq_str(id, "long_double")) {
tokr_err(t, "long double is not supported for #foreign functions.");
return false;
@@ -1174,6 +1189,7 @@ static Status parse_c_type(Parser *p, CType *ctype, Type *type) {
tokr_err(t, "Unrecognized C type.");
return false;
}
+ assert(ctype->kind != CTYPE_NONE && ctype->kind != CTYPE_UNSIGNED);
if (!ctype_to_type(p->allocr, ctype, type, token_location(p->file, t->token)))
return false;
} else {
@@ -1882,6 +1898,7 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
++t->token;
if (!token_is_kw(t->token, KW_LPAREN)) {
tokr_err(t, "Expected ( after #foreign fn");
+ return false;
}
++t->token;
while (!token_is_kw(t->token, KW_RPAREN)) {
diff --git a/std/io.toc b/std/io.toc
index fac4921..5a69269 100644
--- a/std/io.toc
+++ b/std/io.toc
@@ -17,12 +17,12 @@ get_utype_with_size ::= fn(size :: i64) Type {
c_int ::= get_type_with_size(#builtin("sizeof int"));
c_size_t ::= get_utype_with_size(#builtin("sizeof size_t"));
-c_putchar :: fn(c_int) c_int = #foreign "putchar", "libc.so.6";
+c_putchar ::= #foreign("putchar", "libc.so.6") fn(#C int) #C int;
toc_putchar ::= fn(x: char) {
c_putchar(x as c_int);
};
-c_fwrite :: fn(&u8, c_size_t, c_size_t, &u8) = #foreign "fwrite", "libc.so.6";
+c_fwrite ::= #foreign("fwrite", "libc.so.6") fn(&u8, #C size_t, #C size_t, &u8) #C size_t;
stdout_fwrite ::= fn(data: &u8, size: u64, nmemb: u64) {
c_fwrite(data, size as c_size_t, nmemb as c_size_t, #builtin("stdout"));
diff --git a/test.toc b/test.toc
index 66560f8..2a3a68a 100644
--- a/test.toc
+++ b/test.toc
@@ -1,9 +1,7 @@
-
-putchar ::= #foreign("putchar", "libc.so.6") fn (#C int) #C int;
-
+#include "std/io.toc", io;
main ::= fn() {
- putchar(97);
- putchar('\n' as i32);
+ io.puts("Hello!");
+ io.puti(17);
};
main(); \ No newline at end of file
diff --git a/tests/arr3/io.toc b/tests/arr3/io.toc
index fac4921..5a69269 100644
--- a/tests/arr3/io.toc
+++ b/tests/arr3/io.toc
@@ -17,12 +17,12 @@ get_utype_with_size ::= fn(size :: i64) Type {
c_int ::= get_type_with_size(#builtin("sizeof int"));
c_size_t ::= get_utype_with_size(#builtin("sizeof size_t"));
-c_putchar :: fn(c_int) c_int = #foreign "putchar", "libc.so.6";
+c_putchar ::= #foreign("putchar", "libc.so.6") fn(#C int) #C int;
toc_putchar ::= fn(x: char) {
c_putchar(x as c_int);
};
-c_fwrite :: fn(&u8, c_size_t, c_size_t, &u8) = #foreign "fwrite", "libc.so.6";
+c_fwrite ::= #foreign("fwrite", "libc.so.6") fn(&u8, #C size_t, #C size_t, &u8) #C size_t;
stdout_fwrite ::= fn(data: &u8, size: u64, nmemb: u64) {
c_fwrite(data, size as c_size_t, nmemb as c_size_t, #builtin("stdout"));
diff --git a/tests/foreign/foreign.toc b/tests/foreign/foreign.toc
index beaa822..d88a223 100644
--- a/tests/foreign/foreign.toc
+++ b/tests/foreign/foreign.toc
@@ -1,20 +1,13 @@
-voidptr ::= &u8;
-
-getstdout ::= fn() voidptr {
- #builtin("stdout")
-};
-
-
-fwrite :: fn(voidptr, u64, u64, voidptr) u64 = #foreign "fwrite", "libc.so.6";
-fputc :: fn(i32, voidptr) i32 = #foreign "fputc", "libc.so.6";
+fwrite ::= #foreign("fwrite", "libc.so.6") fn (#C &"void const", #C size_t, #C size_t, &u8) #C size_t;
+fputc ::= #foreign("fputc", "libc.so.6") fn (#C int, &u8) #C int;
writes ::= fn(x : []char) {
- fwrite(&x[0] as voidptr, 1, x.len as u64, getstdout());
+ fwrite(&x[0], 1, x.len as u64, #builtin("stdout"));
};
puts ::= fn(x : []char) {
writes(x);
- fputc('\n' as i32, getstdout());
+ fputc('\n' as i32, #builtin("stdout"));
};
hw ::= fn() int {
diff --git a/tests/nms/io.toc b/tests/nms/io.toc
index 51cfd76..5a69269 100644
--- a/tests/nms/io.toc
+++ b/tests/nms/io.toc
@@ -17,12 +17,12 @@ get_utype_with_size ::= fn(size :: i64) Type {
c_int ::= get_type_with_size(#builtin("sizeof int"));
c_size_t ::= get_utype_with_size(#builtin("sizeof size_t"));
-c_putchar :: fn(c_int) c_int = #foreign "putchar", "libc.so.6";
+c_putchar ::= #foreign("putchar", "libc.so.6") fn(#C int) #C int;
toc_putchar ::= fn(x: char) {
c_putchar(x as c_int);
};
-c_fwrite :: fn(&u8, c_size_t, c_size_t, &u8) = #foreign "fwrite", "libc.so.6";
+c_fwrite ::= #foreign("fwrite", "libc.so.6") fn(&u8, #C size_t, #C size_t, &u8) #C size_t;
stdout_fwrite ::= fn(data: &u8, size: u64, nmemb: u64) {
c_fwrite(data, size as c_size_t, nmemb as c_size_t, #builtin("stdout"));
@@ -38,16 +38,20 @@ puti ::= fn(x: int) {
toc_putchar('-');
// NOTE: don't do x = -x; here to make sure I64_MIN works
}
- abs ::= fn(x: int) int { if x < 0 { -x } else { x } };
- scan_digit := 1000000000000000000;
- started := false;
- while scan_digit > 0 {
- digit := abs((x / scan_digit) % 10);
- if digit > 0 { started = true; }
- if started {
- toc_putchar((('0' as int) + digit) as char);
+ if x == 0 {
+ toc_putchar('0');
+ } else {
+ abs ::= fn(x: int) int { if x < 0 { -x } else { x } };
+ scan_digit := 1000000000000000000;
+ started := false;
+ while scan_digit > 0 {
+ digit := abs((x / scan_digit) % 10);
+ if digit > 0 { started = true; }
+ if started {
+ toc_putchar((('0' as int) + digit) as char);
+ }
+ scan_digit /= 10;
}
- scan_digit /= 10;
}
toc_putchar('\n');
-}; \ No newline at end of file
+};
diff --git a/types.c b/types.c
index 54a28ae..722fbc3 100644
--- a/types.c
+++ b/types.c
@@ -379,15 +379,11 @@ enum {
TYPE_OF_FN_IS_INSTANCE = 0x01
};
-static Status type_of_fn(Typer *tr, Expression *f_expr, U16 flags) {
- assert(f_expr->kind == EXPR_FN);
- FnExpr *f = f_expr->fn;
- Type *t = &f_expr->type;
-
+static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) {
if (f->flags & FN_EXPR_FOREIGN) {
/* we've already mostly determined the type in parse_expr */
- if (!type_resolve(tr, &f->foreign.type, f_expr->where))
+ if (!type_resolve(tr, &f->foreign.type, f->where))
return false;
*t = f->foreign.type;
char *name_cstr = eval_expr_as_cstr(tr, f->foreign.name_expr, "foreign name");
@@ -650,7 +646,7 @@ static Status type_of_ident(Typer *tr, Location where, Identifier *ident, Type *
} else {
if ((d->flags & DECL_HAS_EXPR) && (d->expr.kind == EXPR_FN)) {
/* allow using a function before declaring it */
- if (!type_of_fn(tr, &d->expr, 0)) return false;
+ if (!type_of_fn(tr, d->expr.fn, &d->expr.type, 0)) return false;
*t = d->expr.type;
return true;
} else {
@@ -1370,7 +1366,7 @@ static Status types_expr(Typer *tr, Expression *e) {
e->flags |= EXPR_FOUND_TYPE; /* even if failed, pretend we found the type */
switch (e->kind) {
case EXPR_FN: {
- if (!type_of_fn(tr, e, 0)) {
+ if (!type_of_fn(tr, e->fn, &e->type, 0)) {
return false;
}
if (fn_has_any_const_params(e->fn)) {
@@ -2031,11 +2027,8 @@ static Status types_expr(Typer *tr, Expression *e) {
}
}
/* type params, return declarations, etc */
- FnExpr *prev = f->fn;
- f->fn = fn_copy;
- if (!type_of_fn(tr, f, TYPE_OF_FN_IS_INSTANCE))
+ if (!type_of_fn(tr, fn_copy, &f->type, TYPE_OF_FN_IS_INSTANCE))
return false;
- f->fn = prev;
/* deal with default arguments */
i = 0;
@@ -2107,7 +2100,6 @@ static Status types_expr(Typer *tr, Expression *e) {
}
}
free(order);
-
*t = *ret_type;
} break;
case EXPR_BLOCK: {
diff --git a/types.h b/types.h
index ff9d2c1..b7c1b0b 100644
--- a/types.h
+++ b/types.h
@@ -654,7 +654,8 @@ typedef enum {
CTYPE_UNSIGNED_LONGLONG = CTYPE_UNSIGNED|CTYPE_LONGLONG,
CTYPE_PTR = 0x10,
CTYPE_FLOAT = 0x11,
- CTYPE_DOUBLE = 0x12
+ CTYPE_DOUBLE = 0x12,
+ CTYPE_SIZE_T = 0x13
} CTypeKind;
typedef struct {
CTypeKind kind;