summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c8
-rw-r--r--decls_cgen.c68
-rw-r--r--main.c1
-rw-r--r--parse.c36
-rw-r--r--test.toc4
-rw-r--r--types.c113
-rw-r--r--types.h21
7 files changed, 142 insertions, 109 deletions
diff --git a/cgen.c b/cgen.c
index 6e91d21..fb10a0e 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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);
diff --git a/main.c b/main.c
index 0ff8002..e1af365 100644
--- a/main.c
+++ b/main.c
@@ -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
diff --git a/parse.c b/parse.c
index 4ccf19b..f2d5540 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
diff --git a/test.toc b/test.toc
index 086de07..825da51 100644
--- a/test.toc
+++ b/test.toc
@@ -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
diff --git a/types.c b/types.c
index 1da876d..fa5d60b 100644
--- a/types.c
+++ b/types.c
@@ -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;
diff --git a/types.h b/types.h
index 027a89e..ff9d2c1 100644
--- a/types.h
+++ b/types.h
@@ -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;
};