diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-03-01 12:08:28 -0500 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-03-01 12:08:28 -0500 |
commit | da748748c0239c21b9d62c77b51e269ad1d7de9f (patch) | |
tree | 2e546d3d370cb0aeea7fe24e653c9a456ec614b7 | |
parent | 7cced2c313c94d1fb8736581840dff00708aabf1 (diff) |
better #foreign system
-rw-r--r-- | decls_cgen.c | 68 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | parse.c | 45 | ||||
-rw-r--r-- | std/io.toc | 4 | ||||
-rw-r--r-- | test.toc | 8 | ||||
-rw-r--r-- | tests/arr3/io.toc | 4 | ||||
-rw-r--r-- | tests/foreign/foreign.toc | 15 | ||||
-rw-r--r-- | tests/nms/io.toc | 28 | ||||
-rw-r--r-- | types.c | 18 | ||||
-rw-r--r-- | types.h | 3 |
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 "); @@ -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 @@ -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)) { @@ -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")); @@ -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 +}; @@ -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: { @@ -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; |