summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-01-22 13:45:47 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-01-22 13:45:47 -0500
commitc169e55a4bf4e278b712176ae7a9787f3db8d610 (patch)
treec16499c1c223b86bfdf7759ce949fb1bd0bf24ab
parent18740f2f8502adf410ac3d4fa853730bedade787 (diff)
runtime foreign
-rw-r--r--cgen.c30
-rw-r--r--decls_cgen.c49
-rw-r--r--foreign.c1
-rw-r--r--parse.c13
-rwxr-xr-xrunv2
-rw-r--r--test.toc15
-rw-r--r--toc.c4
-rw-r--r--types.c2
-rw-r--r--types.h12
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 <stdint.h>\n"
- "#include <stdio.h>\n"
+ "#include <stddef.h>\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 <float.h>
#include <inttypes.h>
+#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. */