summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-08-28 13:59:24 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-08-28 13:59:24 -0400
commit1661532486d742462f834d2e57f1ad827d6e8916 (patch)
tree67ffb590c5a10bc85a85d16a4792e48342545524
parent62dfeef42d6c2e279165b6dbe73ee3abf98db146 (diff)
cleaned up code; fixed some function stuff
-rw-r--r--base_cgen.c58
-rw-r--r--cgen.c2
-rw-r--r--decls_cgen.c106
-rw-r--r--infer.c35
-rw-r--r--main.c2
-rw-r--r--out.c18
-rw-r--r--parse.c33
-rw-r--r--test.toc5
-rw-r--r--toc.c5
-rw-r--r--types.c174
-rw-r--r--types_cgen.c83
-rw-r--r--util/str.c18
12 files changed, 342 insertions, 197 deletions
diff --git a/base_cgen.c b/base_cgen.c
index dc793f8..3b92c8e 100644
--- a/base_cgen.c
+++ b/base_cgen.c
@@ -179,15 +179,18 @@ static bool cgen_type_post(CGenerator *g, Type *t) {
cgen_write(g, ")(");
if (nparams) {
for (size_t i = 0; i < nparams; i++) {
+ if (i) {
+ cgen_write(g, ",");
+ cgen_write_space(g);
+ }
if (!cgen_type_pre(g, &param_types[i])) return true;
if (!cgen_type_post(g, &param_types[i])) return true;
- cgen_write(g, ",");
- cgen_write_space(g);
}
} else {
cgen_write(g, "void");
}
cgen_write(g, ")");
+ cgen_write_space(g);
if (!cgen_type_post(g, ret_type)) return false;
} break;
}
@@ -195,7 +198,7 @@ static bool cgen_type_post(CGenerator *g, Type *t) {
}
static bool cgen_fn_name(CGenerator *g, FnExpr *f, Location *where) {
- if (f->name) {
+ if (f->name && g->block == NULL) {
if (ident_eq_str(f->name, "main"))
cgen_write(g, "main__");
else
@@ -237,58 +240,13 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f) {
}
static bool cgen_block_enter(CGenerator *g, Block *b) {
- bool ret = true;
g->block = b;
- arr_foreach(&b->stmts, Statement, stmt) {
- if (stmt->kind == STMT_DECL) {
- Declaration *decl = &stmt->decl;
- arr_foreach(&decl->idents, Identifier, ident) {
- Array *decls = &(*ident)->decls;
- if (decls->len) {
- /* check that it hasn't been declared in this block */
- IdentDecl *prev = decls->last;
- if (prev->scope == b) {
- err_print(decl->where, "Re-declaration of identifier in the same block.");
- info_print(prev->decl->where, "Previous declaration was here.");
- ret = false;
- continue;
- }
- } else {
- /* array not initialized yet */
- arr_create(&(*ident)->decls, sizeof(IdentDecl));
- }
- if (infer_decl(decl)) {
- IdentDecl *ident_decl = arr_add(decls);
- ident_decl->decl = decl;
- ident_decl->scope = b;
- } else {
- ret = false;
- }
- }
- }
- }
- return ret;
+ return block_enter(b);
}
static bool cgen_block_exit(CGenerator *g, Block *into) {
- /* OPTIM: figure out some way of not re-iterating over everything */
- bool ret = true;
Block *b = g->block;
g->block = into;
- arr_foreach(&b->stmts, Statement, stmt) {
- if (stmt->kind == STMT_DECL) {
- Declaration *decl = &stmt->decl;
- arr_foreach(&decl->idents, Identifier, ident) {
- Array *decls = &(*ident)->decls;
- assert(decls->item_sz);
- IdentDecl *last_decl = decls->last;
- if (last_decl->scope == b) {
- arr_remove_last(decls); /* remove that declaration */
- }
-
- }
- }
- }
- return ret;
+ return block_exit(b);
}
diff --git a/cgen.c b/cgen.c
index 2cb7dcb..9337ad7 100644
--- a/cgen.c
+++ b/cgen.c
@@ -159,7 +159,7 @@ static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) {
static bool cgen_file(CGenerator *g, ParsedFile *f) {
cgen_write_line_comment(g, "toc");
bool ret = true;
- if (!cgen_types(g, f)) return false;
+ if (!cgen_decls_file(g, f)) return false;
arr_foreach(&f->stmts, Statement, s) {
if (!cgen_fns_in_stmt(g, s)) return false;
}
diff --git a/decls_cgen.c b/decls_cgen.c
new file mode 100644
index 0000000..0d9e5d1
--- /dev/null
+++ b/decls_cgen.c
@@ -0,0 +1,106 @@
+/* C declarations of functions and global variables */
+static bool cgen_decl_fn(CGenerator *g, FnExpr *f, Location where) {
+ /* assign an ID to the function */
+ if (f->name && g->block == NULL) {
+ f->id = f->name->c_fn_reps++;
+ } else {
+ f->id = g->anon_fn_count++;
+ }
+
+ if (!cgen_fn_header(g, f)) return false;
+ cgen_writeln(g, ";");
+ return true;
+}
+
+static bool cgen_decls_stmt(CGenerator *g, Statement *s);
+
+static bool cgen_decls_expr(CGenerator *g, Expression *e) {
+ switch (e->kind) {
+ case EXPR_FN: {
+ FnExpr *f = &e->fn;
+ if (f->name && g->block == NULL) { /* write named function prototypes in global scope to header file */
+ g->writing_to = CGEN_WRITING_TO_H;
+ } else {
+ g->writing_to = CGEN_WRITING_TO_C;
+ }
+ if (!cgen_decl_fn(g, f, e->where))
+ return false;
+ g->writing_to = CGEN_WRITING_TO_C;
+
+
+ bool ret = true;
+ Block *prev_block = g->block;
+ cgen_block_enter(g, &f->body);
+ arr_foreach(&f->body.stmts, Statement, s) {
+ if (!cgen_decls_stmt(g, s))
+ ret = false;
+ }
+ cgen_block_exit(g, prev_block);
+ return ret;
+ }
+ case EXPR_CALL:
+ if (!cgen_decls_expr(g, e->call.fn))
+ return false;
+ arr_foreach(&e->call.args, Expression, arg) {
+ if (!cgen_decls_expr(g, arg))
+ return false;
+ }
+ break;
+ default: break;
+ }
+ return true;
+}
+
+
+static bool cgen_expr(CGenerator *g, Expression *e);
+static bool cgen_decls_stmt(CGenerator *g, Statement *s) {
+ switch (s->kind) {
+ case STMT_EXPR:
+ return cgen_decls_expr(g, &s->expr);
+ case STMT_DECL: {
+ Declaration *d = &s->decl;
+ bool is_const_fn = (d->flags & DECL_FLAG_HAS_EXPR) && (d->flags & DECL_FLAG_CONST)
+ && d->expr.kind == EXPR_FN;
+
+ if (is_const_fn) {
+ /* e.g. foo @= fn() {}; (we want to set the function's name to "foo") */
+ d->expr.fn.name = *(Identifier*)d->idents.data;
+ }
+
+ if (d->flags & DECL_FLAG_HAS_EXPR) {
+ cgen_decls_expr(g, &d->expr);
+ }
+
+ if (!is_const_fn) {
+ if (g->block == NULL) {
+ /* declare this/these global variable(s) */
+ arr_foreach(&d->idents, Identifier, i) {
+ if (!cgen_type_pre(g, &d->type)) return false;
+ cgen_ident(g, *i, NULL);
+ if (!cgen_type_post(g, &d->type)) return false;
+ if (d->flags & DECL_FLAG_HAS_EXPR) { /* TODO: check if expr is const */
+ cgen_write_space(g);
+ cgen_write(g, "=");
+ cgen_write_space(g);
+ if (!cgen_expr(g, &d->expr))
+ return false;
+ }
+ cgen_write(g, ";");
+ cgen_write_space(g);
+ }
+ cgen_writeln(g, "");
+ }
+ }
+
+ } break;
+ }
+ return true;
+}
+
+static bool cgen_decls_file(CGenerator *g, ParsedFile *f) {
+ arr_foreach(&f->stmts, Statement, s) {
+ if (!cgen_decls_stmt(g, s))
+ return false;
+ }
+ return true;
+}
diff --git a/infer.c b/infer.c
deleted file mode 100644
index dad5241..0000000
--- a/infer.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/* if check_curr, this will check against the current value of t */
-static bool infer_expr(Expression *e) {
- Type *t = &e->type;
- switch (e->kind) {
- case EXPR_INT_LITERAL:
- t->kind = TYPE_BUILTIN;
- t->builtin = BUILTIN_I64;
- break;
- case EXPR_FLOAT_LITERAL:
- t->kind = TYPE_BUILTIN;
- t->builtin = BUILTIN_FLOAT;
- break;
- }
- return true;
-}
-
-static bool type_eq(Type *a, Type *b) {
- return true; /* TODO */
-}
-
-static bool infer_decl(Declaration *d) {
- if (d->flags & DECL_FLAG_FOUND_TYPE) return true;
- if (!infer_expr(&d->expr)) return false;
- if (d->flags & DECL_FLAG_INFER_TYPE) {
- d->type = d->expr.type;
- } else {
- if (!type_eq(&d->type, &d->expr.type)) {
- /* TODO more helpful error */
- err_print(d->where, "Type mismatch");
- return false;
- }
- }
- d->flags |= DECL_FLAG_FOUND_TYPE;
- return true;
-}
diff --git a/main.c b/main.c
index 2776f59..0a3d00b 100644
--- a/main.c
+++ b/main.c
@@ -55,6 +55,8 @@ int main(int argc, char **argv) {
fprint_parsed_file(stdout, &f);
tokr_free(&t);
+ types_file(&f);
+
/* TODO (eventually): use a tmp file (don't overwrite old output if there's an error) */
const char *c_out_filename = "out.c";
const char *h_out_filename = "out.h";
diff --git a/out.c b/out.c
index 33076c5..35ba8a9 100644
--- a/out.c
+++ b/out.c
@@ -1,19 +1,21 @@
#include "out.h"
/* toc */
-static void foo(void);
static void a___(void);
+static void a___1(void);
+static void a___2(int64_t x);
+void (*asdkfh)(int64_t ) = a___2;
void main__(void) {
- void (*bar)(void) = a___;
- foo();
+ void (*bar)(void) = a___1;
a___();
- int64_t r = 12;
- float p = 13.800000;
-}
-static void foo(void) {
- void (*x)(void) = a___;
+ a___1();
}
static void a___(void) {
+ void (*x)(void) = a___1;
+}
+static void a___1(void) {
+}
+static void a___2(int64_t x) {
}
int main(void) {
diff --git a/parse.c b/parse.c
index 5b1326b..5e63e17 100644
--- a/parse.c
+++ b/parse.c
@@ -75,7 +75,7 @@ typedef struct Expression {
Location where;
ExprKind kind;
Type type;
- uint16_t flags;
+ unsigned short flags;
union {
FloatLiteral floatl;
IntLiteral intl;
@@ -109,7 +109,7 @@ typedef struct Declaration {
Array idents;
Type type;
Expression expr;
- uint16_t flags;
+ unsigned short flags;
} Declaration;
typedef enum {
@@ -474,6 +474,20 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
return true;
}
+ if (token_is_kw(t->token, KW_FN)) {
+ /* this is a function */
+ e->kind = EXPR_FN;
+ if (!parse_fn_expr(p, &e->fn))
+ return false;
+
+ if (t->token != end) {
+ tokr_err(t, "Direct function calling in an expression is not supported yet.\nYou can wrap the function in parentheses.");
+ /* TODO */
+ return false;
+ }
+ return true;
+ }
+
/* Find the lowest-precedence operator not in parentheses/braces */
int paren_level = 0;
int brace_level = 0;
@@ -545,20 +559,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
}
if (lowest_precedence == NOT_AN_OP) {
- /* functions, function calls, array accesses, etc. */
- if (token_is_kw(t->token, KW_FN)) {
- /* this is a function */
- e->kind = EXPR_FN;
- if (!parse_fn_expr(p, &e->fn))
- return false;
-
- if (t->token != end) {
- tokr_err(t, "Direct function calling in an expression is not supported yet.\nYou can wrap the function in parentheses.");
- /* TODO */
- return false;
- }
- return true;
- }
+ /* function calls, array accesses, etc. */
/* try a function call */
Token *token = t->token;
diff --git a/test.toc b/test.toc
index 94c5a84..547d731 100644
--- a/test.toc
+++ b/test.toc
@@ -5,7 +5,8 @@ main @= fn() {
foo();
bar();
+};
- r := 12;
- p @= 13.8;
+
+asdkfh := fn(x: int) {
}; \ No newline at end of file
diff --git a/toc.c b/toc.c
index c452ddb..8ef8287 100644
--- a/toc.c
+++ b/toc.c
@@ -11,10 +11,11 @@
#include "util/err.c"
#include "util/arr.c"
#include "util/blockarr.c"
+#include "util/str.c"
#include "identifiers.c"
#include "tokenizer.c"
#include "parse.c"
-#include "infer.c"
+#include "types.c"
#include "base_cgen.c"
-#include "types_cgen.c"
+#include "decls_cgen.c"
#include "cgen.c"
diff --git a/types.c b/types.c
new file mode 100644
index 0000000..ffc0a8a
--- /dev/null
+++ b/types.c
@@ -0,0 +1,174 @@
+static bool block_enter(Block *b) {
+ bool ret = true;
+ arr_foreach(&b->stmts, Statement, stmt) {
+ if (stmt->kind == STMT_DECL) {
+ Declaration *decl = &stmt->decl;
+ arr_foreach(&decl->idents, Identifier, ident) {
+ Array *decls = &(*ident)->decls;
+ if (decls->len) {
+ /* check that it hasn't been declared in this block */
+ IdentDecl *prev = decls->last;
+ if (prev->scope == b) {
+ err_print(decl->where, "Re-declaration of identifier in the same block.");
+ info_print(prev->decl->where, "Previous declaration was here.");
+ ret = false;
+ continue;
+ }
+ } else {
+ /* array not initialized yet */
+ arr_create(&(*ident)->decls, sizeof(IdentDecl));
+ }
+
+ IdentDecl *ident_decl = arr_add(decls);
+ ident_decl->decl = decl;
+ ident_decl->scope = b;
+ }
+ }
+ }
+ return ret;
+}
+
+static bool block_exit(Block *b) {
+ /* OPTIM: figure out some way of not re-iterating over everything */
+ bool ret = true;
+ arr_foreach(&b->stmts, Statement, stmt) {
+ if (stmt->kind == STMT_DECL) {
+ Declaration *decl = &stmt->decl;
+ arr_foreach(&decl->idents, Identifier, ident) {
+ Array *decls = &(*ident)->decls;
+ assert(decls->item_sz);
+ IdentDecl *last_decl = decls->last;
+ if (last_decl->scope == b) {
+ arr_remove_last(decls); /* remove that declaration */
+ }
+
+ }
+ }
+ }
+ return ret;
+}
+
+
+/* returns the number of characters written, not including the null character */
+static size_t type_to_string(Type *a, char *buffer, size_t bufsize) {
+ switch (a->kind) {
+ case TYPE_VOID:
+ return str_copy(buffer, bufsize, "void");
+ case TYPE_BUILTIN: {
+ const char *s = keywords[builtin_type_to_kw(a->builtin)];
+ return str_copy(buffer, bufsize, s);
+ }
+ case TYPE_FN: {
+ /* number of chars written */
+ size_t written = str_copy(buffer, bufsize, "fn (");
+ Type *ret_type = a->fn.types.data;
+ Type *param_types = ret_type + 1;
+ size_t nparams = a->fn.types.len - 1;
+ for (size_t i = 0; i < nparams; i++) {
+ if (i > 0)
+ written += str_copy(buffer + written, bufsize - written, ", ");
+ written += type_to_string(&param_types[i], buffer + written, bufsize - written);
+ }
+ written += str_copy(buffer + written, bufsize - written, ")");
+ if (ret_type->kind != TYPE_VOID) {
+ written += str_copy(buffer + written, bufsize - written, " ");
+ written += type_to_string(ret_type, buffer + written, bufsize - written);
+ }
+ return written;
+ } break;
+ }
+
+ assert(0);
+ return 0;
+}
+
+
+static bool type_eq(Type *a, Type *b) {
+ if (a->kind != b->kind) return false;
+ switch (a->kind) {
+ case TYPE_BUILTIN:
+ return a->builtin == b->builtin;
+ /* TODO */
+ }
+ return true;
+}
+
+/* expected must equal got, or an error will be produced */
+static bool type_must_eq(Location where, Type *expected, Type *got) {
+ if (!type_eq(expected, got)) {
+ char str_ex[128];
+ char str_got[128];
+ type_to_string(expected, str_ex, sizeof str_ex);
+ type_to_string(got, str_got, sizeof str_got);
+ err_print(where, "Type mismatch: expected %s, but got %s.", str_ex, str_got);
+ return false;
+ }
+ return true;
+}
+
+static bool types_stmt(Statement *s);
+
+static bool types_expr(Expression *e) {
+ Type *t = &e->type;
+ switch (e->kind) {
+ case EXPR_FN: {
+ FnExpr *f = &e->fn;
+ t->kind = TYPE_FN;
+ arr_create(&t->fn.types, sizeof(Type));
+ Type *ret_type = arr_add(&t->fn.types);
+ *ret_type = f->ret_type;
+ arr_foreach(&f->params, Param, param) {
+ Type *param_type = arr_add(&t->fn.types);
+ *param_type = param->type;
+ }
+
+ } break;
+ case EXPR_INT_LITERAL:
+ t->kind = TYPE_BUILTIN;
+ t->builtin = BUILTIN_I64;
+ break;
+ case EXPR_FLOAT_LITERAL:
+ t->kind = TYPE_BUILTIN;
+ t->builtin = BUILTIN_FLOAT;
+ break;
+ /* TODO */
+ }
+ return true;
+}
+
+
+static bool types_stmt(Statement *s) {
+ switch (s->kind) {
+ case STMT_EXPR:
+ if (!types_expr(&s->expr))
+ return false;
+ break;
+ case STMT_DECL: {
+ Declaration *d = &s->decl;
+
+ if (d->flags & DECL_FLAG_FOUND_TYPE) return true;
+ if (!types_expr(&d->expr)) return false;
+ if (d->flags & DECL_FLAG_INFER_TYPE) {
+ d->type = d->expr.type;
+ } else {
+ if (!type_must_eq(d->expr.where, &d->type, &d->expr.type)) {
+ return false;
+ }
+ }
+ d->flags |= DECL_FLAG_FOUND_TYPE;
+
+ return types_expr(&d->expr);
+ } break;
+
+ }
+ return true;
+}
+
+static bool types_file(ParsedFile *f) {
+ arr_foreach(&f->stmts, Statement, s) {
+ if (!types_stmt(s)) {
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/types_cgen.c b/types_cgen.c
deleted file mode 100644
index 28db722..0000000
--- a/types_cgen.c
+++ /dev/null
@@ -1,83 +0,0 @@
-static bool cgen_types_stmt(CGenerator *g, Statement *s);
-static bool cgen_types_fn(CGenerator *g, FnExpr *f, Location where) {
- bool ret = true;
- /* assign an ID to the function */
- if (f->name) {
- f->id = f->name->c_fn_reps++;
- } else {
- f->id = g->anon_fn_count++;
- }
-
- if (!cgen_fn_header(g, f)) return false;
- cgen_writeln(g, ";");
- Block *prev_block = g->block;
- cgen_block_enter(g, &f->body);
- arr_foreach(&f->body.stmts, Statement, s) {
- if (!cgen_types_stmt(g, s))
- ret = false;
- }
- cgen_block_exit(g, prev_block);
- return ret;
-}
-
-
-static bool cgen_types_expr(CGenerator *g, Expression *e) {
- switch (e->kind) {
- case EXPR_FN: {
- if (e->fn.name && g->block == NULL) { /* write named function prototypes in global scope to header file */
- g->writing_to = CGEN_WRITING_TO_H;
- } else {
- g->writing_to = CGEN_WRITING_TO_C;
- }
- if (!cgen_types_fn(g, &e->fn, e->where))
- return false;
- g->writing_to = CGEN_WRITING_TO_C;
- } break;
- case EXPR_CALL:
- if (!cgen_types_expr(g, e->call.fn))
- return false;
- arr_foreach(&e->call.args, Expression, arg) {
- if (!cgen_types_expr(g, arg))
- return false;
- }
- break;
- default: /* TODO */ break;
- }
- return true;
-}
-
-
-static bool cgen_types_stmt(CGenerator *g, Statement *s) {
- switch (s->kind) {
- case STMT_EXPR:
- if (!cgen_types_expr(g, &s->expr))
- return false;
- break;
- case STMT_DECL: {
- Declaration *d = &s->decl;
- if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->flags & DECL_FLAG_CONST)) {
- /* e.g. foo @= fn() {}; (we want to set the function's name to "foo") */
- if (d->expr.kind == EXPR_FN) {
- d->expr.fn.name = *(Identifier*)d->idents.data;
- if (ident_eq_str(d->expr.fn.name, "main") && g->block != NULL) {
- /* TODO (eventually): Consider just renaming the function */
- err_print(d->where, "main function defined in local scope.");
- return false;
- }
- }
- }
- return cgen_types_expr(g, &d->expr);
- } break;
-
- }
- return true;
-}
-
-static bool cgen_types(CGenerator *g, ParsedFile *f) {
- arr_foreach(&f->stmts, Statement, s) {
- if (!cgen_types_stmt(g, s)) {
- return false;
- }
- }
- return true;
-}
diff --git a/util/str.c b/util/str.c
new file mode 100644
index 0000000..b05cc63
--- /dev/null
+++ b/util/str.c
@@ -0,0 +1,18 @@
+/*
+A better alternative to strncpy. dest is guaranteed to be a null-terminated string
+after this function is run.
+Returns the number of characters copied to dest, not including the null character.
+destsz must be greater than 0.
+*/
+size_t str_copy(char *dest, size_t destsz, const char *src) {
+ assert(destsz);
+ for (size_t i = 0; i < destsz-1; i++) {
+ if (!*src) {
+ *dest = 0;
+ return i;
+ }
+ *dest++ = *src++;
+ }
+ dest[destsz] = 0;
+ return destsz-1;
+}