diff options
-rw-r--r-- | cgen.c | 8 | ||||
-rw-r--r-- | decls_cgen.c | 68 | ||||
-rw-r--r-- | main.c | 1 | ||||
-rw-r--r-- | parse.c | 36 | ||||
-rw-r--r-- | test.toc | 4 | ||||
-rw-r--r-- | types.c | 113 | ||||
-rw-r--r-- | types.h | 21 |
7 files changed, 142 insertions, 109 deletions
@@ -406,7 +406,9 @@ static inline void cgen_fn_instance_number(CGenerator *g, U64 instance) { /* should we generate this function? (or is it just meant for compile time) */ static bool cgen_should_gen_fn(FnExpr *f) { - if (f->ret_decls) { + if (f->flags & FN_EXPR_FOREIGN) + return true; + else if (f->ret_decls) { arr_foreach(f->ret_decls, Declaration, decl) if (type_is_compileonly(&decl->type)) return false; @@ -499,6 +501,8 @@ static inline void cgen_arg(CGenerator *g, Expression *arg) { /* unless f has const/semi-const args, instance and which_are_const can be set to 0 */ static void cgen_fn_header(CGenerator *g, FnExpr *f, U64 instance, U64 which_are_const) { + assert(!(f->flags & FN_EXPR_FOREIGN)); + bool out_param = cgen_uses_ptr(&f->ret_type); assert(cgen_should_gen_fn(f)); if (!(f->flags & FN_EXPR_EXPORT)) @@ -1562,6 +1566,8 @@ static void cgen_zero_value(CGenerator *g, Type *t) { /* pass 0 for instance and NULL for compile_time_args if there are no compile time arguments. */ static void cgen_fn(CGenerator *g, FnExpr *f, U64 instance, Value *compile_time_args) { + if (f->flags & FN_EXPR_FOREIGN) + return; /* handled by decls_cgen */ /* see also cgen_defs_expr */ FnExpr *prev_fn = g->fn; U64 which_are_const = compile_time_args ? compile_time_args->u64 : 0; diff --git a/decls_cgen.c b/decls_cgen.c index 44fa436..0753616 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -3,44 +3,6 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see <https://www.gnu.org/licenses/>. */ - -/* TODO */ -#if 0 - if (d->flags & DECL_FOREIGN) { - cgen_write(g, "extern "); - if ((d->flags & DECL_IS_CONST) && (d->type.kind == TYPE_FN) && arr_len(d->idents) == 1) { - /* foreign function declaration */ - Type *fn_types = d->type.fn.types; - const char *foreign_name = (d->flags & DECL_FOUND_VAL) - ? d->val.fn->foreign.name - : d->foreign.name_str; - cgen_type_pre(g, &fn_types[0], d->where); - cgen_write(g, " %s", foreign_name); - cgen_write(g, "("); - arr_foreach(fn_types, Type, t) { - if (t == fn_types) continue; - if (t != fn_types+1) - cgen_write(g, ", "); - cgen_type_pre(g, t, d->where); - cgen_type_post(g, t, d->where); - } - cgen_write(g, ")"); - cgen_type_post(g, &fn_types[0], d->where); - cgen_write(g, ";"); - if (!ident_eq_str(d->idents[0], foreign_name)) { - cgen_write(g, "static "); - cgen_type_pre(g, &d->type, d->where); - cgen_write(g, " const "); - cgen_ident(g, d->idents[0]); - cgen_type_post(g, &d->type, d->where); - cgen_write(g, " = %s;", foreign_name); - } - cgen_nl(g); - if (d->flags & DECL_FOUND_VAL) - d->val.fn->c.name = d->idents[0]; - return; - -#endif static void cgen_decls_stmt(CGenerator *g, Statement *s); static void cgen_decls_block(CGenerator *g, Block *b); @@ -101,6 +63,36 @@ static void cgen_decls_fn_instances(CGenerator *g, FnExpr *f) { } static void cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) { + if (f->flags & FN_EXPR_FOREIGN) { + + /* foreign function declaration */ + 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); + 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) + cgen_write(g, ", "); + cgen_type_pre(g, t, f->where); + cgen_type_post(g, t, f->where); + } + cgen_write(g, ")"); + 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 "); + cgen_type_pre(g, t, f->where); + cgen_write(g, " const "); + cgen_fn_name(g, f); + cgen_type_post(g, t, f->where); + cgen_write(g, " = %s;", foreign_name); + } + cgen_nl(g); + return; + } FnType *fn_type = &t->fn; if (fn_type->constness) { cgen_decls_fn_instances(g, f); @@ -9,6 +9,7 @@ /* TODO: better #foreign system- something like f := #foreign fn (int,float, #C int, #C longlong); +make err_print and tokr_err return Status --- constants in structs #if @@ -1770,15 +1770,45 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) { single_arg = e->unary.of = parser_new_expr(p); break; case DIRECT_FOREIGN: { - /* foreign function */ + ++t->token; + if (!token_is_kw(t->token, KW_LPAREN)) { + tokr_err(t, "Expected ( following #foreign."); + return false; + } + ++t->token; + e->kind = EXPR_FN; - e->type.kind = TYPE_FN; FnExpr *fn = e->fn = parser_calloc(p, 1, sizeof *e->fn); fn->flags |= FN_EXPR_FOREIGN; - FnType *fn_type = &e->type.fn; + 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; + Expression *name = fn->foreign.name_expr = parser_new_expr(p); + + if (!parse_expr(p, name, expr_find_end(p, EXPR_CAN_END_WITH_COMMA))) + return false; + if (token_is_kw(t->token, KW_RPAREN)) { + fn->foreign.lib_expr = NULL; + } else { + if (!token_is_kw(t->token, KW_COMMA)) { + tokr_err(t, "Expected , to follow #foreign name."); + return false; + } + ++t->token; + Expression *lib = fn->foreign.lib_expr = parser_new_expr(p); + if (!parse_expr(p, lib, expr_find_end(p, 0))) + return false; + if (!token_is_kw(t->token, KW_RPAREN)) { + tokr_err(t, "Expected ) to follow #foreign lib."); + return false; + } + } ++t->token; + + if (!token_is_kw(t->token, KW_FN)) { tokr_err(t, "Expected fn to follow #foreign."); return false; @@ -1,6 +1,6 @@ -puts ::= #foreign fn (#C int); +puts ::= #foreign("puts", "libc.so.6") fn (#C int); main ::= fn() { - + puts("Hello!"); };
\ No newline at end of file @@ -354,12 +354,57 @@ static bool type_is_compileonly(Type *t) { return false; } +/* returns NULL if an error occured */ +static char *eval_expr_as_cstr(Typer *tr, Expression *e, const char *what_is_this) { + Value e_val; + if (!types_expr(tr, e)) + return NULL; + if (!type_is_slicechar(&e->type)) { + char *got = type_to_str(&e->type); + err_print(e->where, "Expected []char for %s, but got %s.", what_is_this, got); + free(got); + return NULL; + } + if (!eval_expr(tr->evalr, e, &e_val)) + return NULL; + Slice e_slice = e_val.slice; + char *str = typer_malloc(tr, (size_t)e_slice.n + 1); + str[e_slice.n] = 0; + memcpy(str, e_slice.data, (size_t)e_slice.n); + return str; +} + enum { /* is f an instance? (changes behaviour a bit) */ TYPE_OF_FN_IS_INSTANCE = 0x01 }; -static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { +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; + + + 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)) + return false; + *t = f->foreign.type; + char *name_cstr = eval_expr_as_cstr(tr, f->foreign.name_expr, "foreign name"); + if (!name_cstr) + return false; + f->foreign.name = name_cstr; + if (f->foreign.lib_expr) { + char *lib_cstr = eval_expr_as_cstr(tr, f->foreign.lib_expr, "foreign library name"); + if (!lib_cstr) + return false; + f->foreign.lib = lib_cstr; + } else { + f->foreign.lib = NULL; + } + return true; + } + t->kind = TYPE_FN; t->fn.types = NULL; t->fn.constness = NULL; /* OPTIM: constness doesn't need to be a dynamic array */ @@ -370,40 +415,6 @@ static Status type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { FnExpr *prev_fn = tr->fn; FnExpr fn_copy = {0}; -#if 0 - /* TODO */ - if (!type_resolve(tr, &d->type, d->where)) { - success = false; - goto ret; - } - char *name_cstr = eval_expr_as_cstr(tr, d->foreign.name, "foreign name"); - if (!name_cstr) { - success = false; - goto ret; - } - if (d->foreign.lib) { - char *lib_cstr = eval_expr_as_cstr(tr, d->foreign.lib, "foreign library name"); - if (!lib_cstr) { - success = false; - goto ret; - } - /* make sure no one tries to use these */ - d->foreign.name = NULL; - d->foreign.lib = NULL; - - FnExpr *f = d->val.fn = typer_calloc(tr, 1, sizeof *d->expr.fn); - f->flags = FN_EXPR_FOREIGN; - f->where = d->expr.where = d->where; - f->foreign.name = name_cstr; - f->foreign.lib = lib_cstr; - f->foreign.fn_ptr = NULL; - - d->flags |= DECL_FOUND_VAL; - } else { - d->foreign.name_str = name_cstr; - } -#endif - /* f has compile time params, but it's not an instance! */ bool generic = !(flags & TYPE_OF_FN_IS_INSTANCE) && fn_has_any_const_params(f); if (generic) { @@ -639,7 +650,8 @@ 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.fn, t, 0)) return false; + if (!type_of_fn(tr, &d->expr, 0)) return false; + *t = d->expr.type; return true; } else { if (where.start <= d->where.end) { @@ -978,9 +990,9 @@ static bool arg_is_const(Expression *arg, Constness constness) { } -/* MUST be called after type_of_fn. */ /* pass NULL for instance if this isn't an instance */ static Status types_fn(Typer *tr, FnExpr *f, Type *t, Instance *instance) { + if (f->flags & FN_EXPR_FOREIGN) return true; FnExpr *prev_fn = tr->fn; bool success = true; Expression *ret_expr; @@ -1348,26 +1360,6 @@ static void get_builtin_val_type(Allocator *a, BuiltinVal val, Type *t) { } } -/* returns NULL if an error occured */ -static char *eval_expr_as_cstr(Typer *tr, Expression *e, const char *what_is_this) { - Value e_val; - if (!types_expr(tr, e)) - return NULL; - if (!type_is_slicechar(&e->type)) { - char *got = type_to_str(&e->type); - err_print(e->where, "Expected []char for %s, but got %s.", what_is_this, got); - free(got); - return NULL; - } - if (!eval_expr(tr->evalr, e, &e_val)) - return NULL; - Slice e_slice = e_val.slice; - char *str = typer_malloc(tr, (size_t)e_slice.n + 1); - str[e_slice.n] = 0; - memcpy(str, e_slice.data, (size_t)e_slice.n); - return str; -} - static Status types_expr(Typer *tr, Expression *e) { if (e->flags & EXPR_FOUND_TYPE) return true; @@ -1378,7 +1370,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->fn, &e->type, 0)) { + if (!type_of_fn(tr, e, 0)) { return false; } if (fn_has_any_const_params(e->fn)) { @@ -2039,8 +2031,11 @@ static Status types_expr(Typer *tr, Expression *e) { } } /* type params, return declarations, etc */ - if (!type_of_fn(tr, fn_copy, &f->type, TYPE_OF_FN_IS_INSTANCE)) + FnExpr *prev = f->fn; + f->fn = fn_copy; + if (!type_of_fn(tr, f, TYPE_OF_FN_IS_INSTANCE)) return false; + f->fn = prev; /* deal with default arguments */ i = 0; @@ -662,16 +662,25 @@ typedef struct { } CType; typedef struct FnExpr { - struct Declaration *params; /* declarations of the parameters to this function */ - struct Declaration *ret_decls; /* array of decls, if this has named return values. otherwise, NULL */ Location where; - Type ret_type; union { - Block body; struct { + struct Declaration *params; /* declarations of the parameters to this function */ + struct Declaration *ret_decls; /* array of decls, if this has named return values. otherwise, NULL */ + Type ret_type; + Block body; + }; + struct { + Type type; /* type of this function */ CType *ctypes; /* ctypes[i] = CTYPE_NONE if this isn't a ctype, or the specified CType. don't use this as a dynamic array. */ - const char *name; - const char *lib; + union { + const char *name; + struct Expression *name_expr; /* before typing */ + }; + union { + const char *lib; + struct Expression *lib_expr; + }; void (*fn_ptr)(); } foreign; }; |