diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2019-08-28 13:59:24 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2019-08-28 13:59:24 -0400 |
commit | 1661532486d742462f834d2e57f1ad827d6e8916 (patch) | |
tree | 67ffb590c5a10bc85a85d16a4792e48342545524 | |
parent | 62dfeef42d6c2e279165b6dbe73ee3abf98db146 (diff) |
cleaned up code; fixed some function stuff
-rw-r--r-- | base_cgen.c | 58 | ||||
-rw-r--r-- | cgen.c | 2 | ||||
-rw-r--r-- | decls_cgen.c | 106 | ||||
-rw-r--r-- | infer.c | 35 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | out.c | 18 | ||||
-rw-r--r-- | parse.c | 33 | ||||
-rw-r--r-- | test.toc | 5 | ||||
-rw-r--r-- | toc.c | 5 | ||||
-rw-r--r-- | types.c | 174 | ||||
-rw-r--r-- | types_cgen.c | 83 | ||||
-rw-r--r-- | util/str.c | 18 |
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, ¶m_types[i])) return true; if (!cgen_type_post(g, ¶m_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); } @@ -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; -} @@ -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"; @@ -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) { @@ -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; @@ -5,7 +5,8 @@ main @= fn() { foo(); bar(); +}; - r := 12; - p @= 13.8; + +asdkfh := fn(x: int) { };
\ No newline at end of file @@ -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" @@ -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(¶m_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; +} |