From c169e55a4bf4e278b712176ae7a9787f3db8d610 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Wed, 22 Jan 2020 13:45:47 -0500 Subject: runtime foreign --- cgen.c | 30 ++++++++++++++++-------------- decls_cgen.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- foreign.c | 1 + parse.c | 13 ++++++++++++- runv | 2 +- test.toc | 15 +++++++++++---- toc.c | 4 ++++ types.c | 2 ++ types.h | 12 +++++++++--- 9 files changed, 104 insertions(+), 24 deletions(-) diff --git a/cgen.c b/cgen.c index 250ddda..f9ebce1 100644 --- a/cgen.c +++ b/cgen.c @@ -1203,20 +1203,22 @@ static bool cgen_expr(CGenerator *g, Expression *e) { if (idecl && idecl->kind == IDECL_DECL) { Declaration *d = idecl->decl; if (d->flags & DECL_IS_CONST) { - int index = decl_ident_index(d, e->ident); - Value fn_val = *decl_val_at_index(d, index); - FnExpr *fn = fn_val.fn; - Expression fn_expr; + if (!(d->flags & DECL_FOREIGN) || d->foreign.lib) { + int index = decl_ident_index(d, e->ident); + Value fn_val = *decl_val_at_index(d, index); + FnExpr *fn = fn_val.fn; + Expression fn_expr; - fn_expr.kind = EXPR_FN; - fn_expr.fn = allocr_malloc(g->allocr, sizeof *fn_expr.fn); - *fn_expr.fn = *fn; - fn_expr.flags = EXPR_FOUND_TYPE; - fn_expr.type = *decl_type_at_index(d, index); + fn_expr.kind = EXPR_FN; + fn_expr.fn = allocr_malloc(g->allocr, sizeof *fn_expr.fn); + *fn_expr.fn = *fn; + fn_expr.flags = EXPR_FOUND_TYPE; + fn_expr.type = *decl_type_at_index(d, index); - if (!cgen_expr(g, &fn_expr)) - return false; - handled = true; + if (!cgen_expr(g, &fn_expr)) + return false; + handled = true; + } } } } @@ -2018,7 +2020,7 @@ static bool cgen_file(CGenerator *g, ParsedFile *f) { TODO: don't include stdio.h with posix file descriptors */ cgen_write(g, "#include \n" - "#include \n" + "#include \n" "typedef int8_t i8;\n" "typedef int16_t i16;\n" "typedef int32_t i32;\n" @@ -2035,7 +2037,7 @@ static bool cgen_file(CGenerator *g, ParsedFile *f) { "#define true ((bool)1)\n" "static slice_ mkslice_(void *data, i64 n) { slice_ ret; ret.data = data; ret.n = n; return ret; }\n" "static void free_(void *data) { extern void free(void *data); free(data); }\n" /* don't introduce free to global namespace */ - "static void *e__calloc(size_t n, size_t sz) { extern void *calloc(size_t n, size_t size); extern void abort(void); void *ret = calloc(n, sz); if (n && sz && !ret) { fprintf(stderr, \"Out of memory.\\n\"); abort(); } return ret; }\n\n\n"); + "static void *e__calloc(size_t n, size_t sz) { extern void *calloc(size_t n, size_t size); extern void abort(void); extern int printf(const char *fmt, ...); void *ret = calloc(n, sz); if (n && sz && !ret) { printf(\"Out of memory.\\n\"); abort(); } return ret; }\n\n\n"); if (!cgen_sdecls_file(g, f)) return false; diff --git a/decls_cgen.c b/decls_cgen.c index 7e91e2a..3c761ac 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -189,7 +189,54 @@ static bool cgen_decls_block(CGenerator *g, Block *b) { static bool cgen_decls_decl(CGenerator *g, Declaration *d) { if (d->flags & DECL_FOREIGN) { - /* TODO */ + 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; + if (!cgen_type_pre(g, &fn_types[0], d->where)) + return false; + 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, ", "); + if (!cgen_type_pre(g, t, d->where)) + return false; + if (!cgen_type_post(g, t, d->where)) + return false; + } + cgen_write(g, ")"); + if (!cgen_type_post(g, &fn_types[0], d->where)) + return false; + cgen_write(g, ";"); + if (!ident_eq_str(d->idents[0], foreign_name)) { + cgen_write(g, "static "); + if (!cgen_type_pre(g, &d->type, d->where)) + return false; + cgen_write(g, " "); + cgen_ident(g, d->idents[0]); + if (!cgen_type_post(g, &d->type, d->where)) + return false; + cgen_write(g, " = %s;", foreign_name); + } + cgen_nl(g); + if (d->flags & DECL_FOUND_VAL) + d->val.fn->c.name = d->idents[0]; + return true; + } else { + const char *foreign_name = d->foreign.name_str; + if (!cgen_type_pre(g, &d->type, d->where)) + return false; + cgen_write(g, " %s", foreign_name); + if (!cgen_type_post(g, &d->type, d->where)) + return false; + cgen_write(g, ";"); + cgen_nl(g); + } return true; } if (!cgen_decls_type(g, &d->type)) diff --git a/foreign.c b/foreign.c index ff8ab03..e669f8a 100644 --- a/foreign.c +++ b/foreign.c @@ -300,3 +300,4 @@ static void ffmgr_free(ForeignFnManager *ffmgr) { (void)ffmgr; } #endif + diff --git a/parse.c b/parse.c index f969793..eea5de5 100644 --- a/parse.c +++ b/parse.c @@ -1842,6 +1842,7 @@ static bool parse_decl(Parser *p, Declaration *d, DeclEndKind ends_with, U16 fla if (!parse_expr(p, d->foreign.name, expr_find_end(p, EXPR_CAN_END_WITH_COMMA))) { goto ret_false; } + d->foreign.lib = NULL; if (!ends_decl(t->token, ends_with)) { if (!token_is_kw(t->token, KW_COMMA)) { tokr_err(t, "Expected comma, followed by foreign library."); @@ -2372,7 +2373,17 @@ static inline Type *decl_type_at_index(Declaration *d, int i) { static bool ident_is_definitely_const(Identifier i) { IdentDecl *idecl = ident_decl(i); assert(idecl); - return idecl->kind == IDECL_DECL && (idecl->decl->flags & DECL_IS_CONST); + Declaration *decl = idecl->decl; + if (idecl->kind != IDECL_DECL || !(decl->flags & DECL_IS_CONST)) + return false; + if (decl->flags & DECL_FOREIGN) { + if (decl->foreign.lib && COMPILE_TIME_FOREIGN_FN_SUPPORT) + return true; + else + return false; + } else { + return true; + } } diff --git a/runv b/runv index 7f621fe..4134417 100755 --- a/runv +++ b/runv @@ -12,7 +12,7 @@ fi valgrind $FLAGS --track-origins=yes --exit-on-first-error=yes --error-exitcode=1 --malloc-fill=0xcd --free-fill=0xef --num-callers=100 ./toc $tocf || exit 1 if [ "$1" = "c" ]; then - gcc out.c -g && ./a.out + gcc out.c -g -Wno-builtin-declaration-mismatch && ./a.out elif [ "$1" = "pc" ]; then cat out.c fi diff --git a/test.toc b/test.toc index 05f94ec..4b21d20 100644 --- a/test.toc +++ b/test.toc @@ -7,7 +7,7 @@ import ::= fn(x :: []char) &Package { cputs :: fn(&char) i32 = #foreign "puts", "libc.so.6"; -puts ::= fn(s: []char) i32 { +tocputs ::= fn(s: []char) i32 { cstr := new(char, s.len + 1); each i := 0..s.len-1 { cstr[i] = s[i]; @@ -19,9 +19,9 @@ puts ::= fn(s: []char) i32 { }; foo ::= fn() i32 { - puts("Hi"); - puts("Hello"); - puts("Hey") + tocputs("Hi"); + tocputs("Hello"); + tocputs("Hey") }; malloc :: fn(u64) &u8 = #foreign "malloc", "libc.so.6"; @@ -30,10 +30,17 @@ sqrt :: fn(f64) f64 = #foreign "sqrt", "libm.so.6"; cos :: fn(f64) f64 = #foreign "cos", "libm.so.6"; sin :: fn(f64) f64 = #foreign "sin", "libm.so.6"; +stderr :: &u8 = #foreign "stderr"; +fprintf :: fn(&u8, &char) = #foreign "fprintf"; + + main ::= fn() { x ::= foo(); // y ::= malloc(10); sq2 ::= sqrt(2); cospi ::= cos(3.14159); sinpi ::= sin(3.14159); + foo(); + s := "Hello!\n\0"; + fprintf(stderr, &s[0]); }; \ No newline at end of file diff --git a/toc.c b/toc.c index 447abac..fc5945f 100644 --- a/toc.c +++ b/toc.c @@ -18,6 +18,10 @@ #include #include +#ifndef COMPILE_TIME_FOREIGN_FN_SUPPORT +#define COMPILE_TIME_FOREIGN_FN_SUPPORT 0 +#endif + #ifdef __cplusplus #define new new_ diff --git a/types.c b/types.c index 0c79d33..887c39b 100644 --- a/types.c +++ b/types.c @@ -2242,6 +2242,8 @@ static bool types_decl(Typer *tr, Declaration *d) { f->foreign.fn_ptr = NULL; d->flags |= DECL_FOUND_VAL; + } else { + d->foreign.name_str = name_cstr; } } diff --git a/types.h b/types.h index 7b0e498..e6a3ff2 100644 --- a/types.h +++ b/types.h @@ -759,9 +759,15 @@ typedef struct Declaration { union { Expression expr; struct { - /* only exist before typing */ - Expression *name; - Expression *lib; + union { + struct { + /* only exist before typing */ + Expression *name; + Expression *lib; + }; + /* only set for non-functions */ + const char *name_str; + }; } foreign; }; Value val; /* only for constant decls. */ -- cgit v1.2.3