diff options
-rw-r--r-- | base_cgen.c | 218 | ||||
-rw-r--r-- | cgen.c | 294 | ||||
-rw-r--r-- | main.c | 13 | ||||
-rw-r--r-- | out.c | 19 | ||||
-rw-r--r-- | out.h | 2 | ||||
-rw-r--r-- | parse.c | 13 | ||||
-rw-r--r-- | test.toc | 19 | ||||
-rw-r--r-- | toc.c | 2 | ||||
-rw-r--r-- | tokenizer.c | 6 | ||||
-rw-r--r-- | types_cgen.c | 74 | ||||
-rw-r--r-- | util/arr.c | 30 |
11 files changed, 415 insertions, 275 deletions
diff --git a/base_cgen.c b/base_cgen.c new file mode 100644 index 0000000..52cd3d6 --- /dev/null +++ b/base_cgen.c @@ -0,0 +1,218 @@ +/* figures out types and writes function prototypes */ +/* TODO: check ferror */ +typedef enum { + CGEN_WRITING_TO_H, + CGEN_WRITING_TO_C +} CGenWritingTo; +typedef struct { + FILE *c_out; + FILE *h_out; + unsigned long anon_fn_count; + Block *block; + int indent_level; + bool indent_next; /* should the next thing written be indented? */ + CGenWritingTo writing_to; +} CGenerator; + +static FILE *cgen_writing_to(CGenerator *g) { + switch (g->writing_to) { + case CGEN_WRITING_TO_H: + return g->h_out; + case CGEN_WRITING_TO_C: + return g->c_out; + } + assert(0); + return NULL; +} + +static void cgen_vwrite(CGenerator *g, const char *fmt, va_list args) { + if (g->indent_next) { + for (int i = 0; i < g->indent_level; i++) + fprintf(cgen_writing_to(g), "\t"); + g->indent_next = false; + } + vfprintf(cgen_writing_to(g), fmt, args); +} + +static void cgen_write(CGenerator *g, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + cgen_vwrite(g, fmt, args); + va_end(args); +} + +/* Used to write an UNNECESSARY space */ +static void cgen_write_space(CGenerator *g) { + cgen_write(g, " "); +} + +/* Used to write something followed by an UNNECESSARY newline */ +static void cgen_writeln(CGenerator *g, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + cgen_vwrite(g, fmt, args); + va_end(args); + cgen_write(g, "\n"); + g->indent_next = true; +} + +static void cgen_write_comment(CGenerator *g, const char *fmt, ...) { + cgen_write(g, "/* "); + va_list args; + va_start(args, fmt); + cgen_vwrite(g, fmt, args); + va_end(args); + cgen_write(g, " */"); +} + +static void cgen_write_line_comment(CGenerator *g, const char *fmt, ...) { + /* could switch to // for c99 */ + cgen_write(g, "/* "); + va_list args; + va_start(args, fmt); + cgen_vwrite(g, fmt, args); + va_end(args); + cgen_write(g, " */\n"); +} + +static void cgen_create(CGenerator *g, FILE *c_out, FILE *h_out, const char *h_filename) { + g->c_out = c_out; + g->h_out = h_out; + g->anon_fn_count = 0; + g->indent_level = 0; + g->block = NULL; + g->writing_to = CGEN_WRITING_TO_C; + g->indent_next = true; + + cgen_write(g, "#include \"%s\"\n", h_filename); + cgen_write(g, "#include <stdint.h>\n"); + cgen_writeln(g, ""); /* extra newline between includes and code */ +} + +static void cgen_ident(CGenerator *g, Identifier i) { + fprint_ident(cgen_writing_to(g), i); +} + +static const char *builtin_type_to_str(BuiltinType b) { + /* TODO: make this return int/long/etc. if stdint.h is not available */ + switch (b) { + case BUILTIN_INT: return "int64_t"; + case BUILTIN_I8: return "int8_t"; + case BUILTIN_I16: return "int16_t"; + case BUILTIN_I32: return "int32_t"; + case BUILTIN_I64: return "int64_t"; + case BUILTIN_U8: return "uint8_t"; + case BUILTIN_U16: return "uint16_t"; + case BUILTIN_U32: return "uint32_t"; + case BUILTIN_U64: return "uint64_t"; + case BUILTIN_FLOAT: return "float"; + case BUILTIN_DOUBLE: return "double"; + case BUILTIN_TYPE_COUNT: break; + } + assert(0); + return NULL; +} + +/* NOTE: this will eventually be split into two functions when functions/arrays are added */ +static bool cgen_type(CGenerator *g, Type *t) { + switch (t->kind) { + case TYPE_VOID: + cgen_write(g, "void"); + break; + case TYPE_BUILTIN: + cgen_write(g, "%s", builtin_type_to_str(t->builtin)); + break; + } + return true; +} + +static void cgen_fn_name(CGenerator *g, FnExpr *f) { + if (f->name) + cgen_ident(g, f->name); + else + cgen_write(g, "a___"); + + if (f->id != 0) + cgen_write(g, "%lu", f->id); +} + +static bool cgen_fn_header(CGenerator *g, FnExpr *f) { + CGenWritingTo writing_to_before = g->writing_to; + if (!f->name || g->block != NULL) { + cgen_write(g, "static "); /* anonymous functions only exist in this translation unit */ + } + if (!cgen_type(g, &f->ret_type)) return false; + cgen_write(g, " "); + cgen_fn_name(g, f); + cgen_write(g, "("); + arr_foreach(&f->params, Param, p) { + if (p != f->params.data) { + cgen_write(g, ","); + cgen_write_space(g); + } + if (!cgen_type(g, &p->type)) + return false; + cgen_write(g, " "); + cgen_ident(g, p->name); + } + cgen_write(g, ")"); + g->writing_to = writing_to_before; + return true; +} + +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; +} + +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; +} + @@ -1,92 +1,3 @@ -/* the generation of C code */ -/* TODO: check ferror */ -typedef struct { - FILE *out; - unsigned long anon_fn_count; -} CGenerator; - - -static void cgen_vwrite(CGenerator *g, const char *fmt, va_list args) { - vfprintf(g->out, fmt, args); -} - -static void cgen_write(CGenerator *g, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - cgen_vwrite(g, fmt, args); - va_end(args); -} - -static void cgen_writeln(CGenerator *g, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - cgen_vwrite(g, fmt, args); - va_end(args); - cgen_write(g, "\n"); -} - -static void cgen_write_comment(CGenerator *g, const char *fmt, ...) { - cgen_write(g, "/* "); - va_list args; - va_start(args, fmt); - cgen_vwrite(g, fmt, args); - va_end(args); - cgen_write(g, " */"); -} - -static void cgen_write_line_comment(CGenerator *g, const char *fmt, ...) { - /* could switch to // for c99 */ - cgen_write(g, "/* "); - va_list args; - va_start(args, fmt); - cgen_vwrite(g, fmt, args); - va_end(args); - cgen_write(g, " */\n"); -} - -static void cgen_create(CGenerator *g, FILE *out) { - g->out = out; - g->anon_fn_count = 0; -} - -static void cgen_ident(CGenerator *g, Identifier i) { - fprint_ident(g->out, i); -} - -static const char *builtin_type_to_str(BuiltinType b) { - /* TODO: make this return int/long/etc. if stdint.h is not available */ - switch (b) { - case BUILTIN_INT: return "int64_t"; - case BUILTIN_I8: return "int8_t"; - case BUILTIN_I16: return "int16_t"; - case BUILTIN_I32: return "int32_t"; - case BUILTIN_I64: return "int64_t"; - case BUILTIN_U8: return "uint8_t"; - case BUILTIN_U16: return "uint16_t"; - case BUILTIN_U32: return "uint32_t"; - case BUILTIN_U64: return "uint64_t"; - case BUILTIN_FLOAT: return "float"; - case BUILTIN_F32: return "float"; - case BUILTIN_F64: return "double"; - case BUILTIN_TYPE_COUNT: break; - } - assert(0); - return NULL; -} - -/* NOTE: this will eventually be split into two functions when functions/arrays are added */ -static bool cgen_type(CGenerator *g, Type *t) { - switch (t->kind) { - case TYPE_VOID: - cgen_write(g, "void"); - break; - case TYPE_BUILTIN: - cgen_write(g, "%s", builtin_type_to_str(t->builtin)); - break; - } - return true; -} - static bool cgen_expr(CGenerator *g, Expression *e) { switch (e->kind) { case EXPR_INT_LITERAL: @@ -134,71 +45,57 @@ static bool cgen_expr(CGenerator *g, Expression *e) { cgen_write(g, ")"); break; case EXPR_FN: - err_print(e->where, "Function expression not part of declaration or call."); - return false; - } - return true; -} - -/* b = NULL => file */ -static bool cgen_block_enter(Array stmts, Block *b) { - bool ret = true; - - arr_foreach(&stmts, Statement, stmt) { - if (stmt->kind == STMT_DECL) { - Declaration *decl = &stmt->decl; - arr_foreach(&decl->idents, Identifier, ident) { - Array *decls = &(*ident)->decls; - if (decls->item_sz) { - /* 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; - } - } - if (decl->expr.kind == EXPR_FN) { - /* TODO */ + cgen_fn_name(g, &e->fn); + break; + case EXPR_CALL: + cgen_expr(g, e->call.fn); + cgen_write(g, "("); + arr_foreach(&e->call.args, Expression, arg) { + if (arg != e->call.args.data) { + cgen_write(g, ","); + cgen_write_space(g); } + cgen_expr(g, arg); } + cgen_write(g, ")"); + break; } - return ret; + return true; } -static bool cgen_block_exit(Array stmts, Block *b) { - /* OPTIM: figure out some way of not re-iterating over everything */ +static bool cgen_stmt(CGenerator *g, Statement *s); + +/* Generates the definition of a function, not just the identifier */ +static bool cgen_fn(CGenerator *g, FnExpr *f) { + if (!cgen_fn_header(g, f)) return false; bool ret = true; - arr_foreach(&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 */ - - } - } + cgen_write_space(g); + cgen_writeln(g, "{"); + g->indent_level++; + Block *prev_block = g->block; + cgen_block_enter(g, &f->body); + arr_foreach(&f->body.stmts, Statement, s) { + if (!cgen_stmt(g, s)) + ret = false; } + cgen_block_exit(g, prev_block); + g->indent_level--; + cgen_writeln(g, "}"); return ret; } static bool cgen_decl(CGenerator *g, Declaration *d) { - /* TODO */ + arr_foreach(&d->idents, Identifier, ident) { + cgen_type(g, &d->type); + cgen_write(g, " "); + cgen_ident(g, *ident); + cgen_write_space(g); + cgen_write(g, "="); + cgen_write_space(g); + cgen_expr(g, &d->expr); + cgen_write(g, "; "); + } + cgen_writeln(g, ""); return true; } @@ -209,95 +106,48 @@ static bool cgen_stmt(CGenerator *g, Statement *s) { return false; cgen_writeln(g, ";"); break; - case STMT_DECL: + case STMT_DECL: { + Declaration *d = &s->decl; + if ((d->flags & DECL_FLAG_HAS_EXPR) && (d->flags & DECL_FLAG_CONST)) + if (d->expr.kind == EXPR_FN) + return true; /* already dealt with below */ + return cgen_decl(g, &s->decl); } + } return true; } -/* - -because functions can have circular dependencies, we need two passes: -one declares the functions, and one defines them. - -*/ - -static bool cgen_fns_stmt(CGenerator *g, Statement *s, bool def); +static bool cgen_fns_in_stmt(CGenerator *g, Statement *s); -static bool cgen_fns_expr(CGenerator *g, Expression *e, Identifier fn_name, bool def) { +static bool cgen_fns_in_expr(CGenerator *g, Expression *e) { switch (e->kind) { - case EXPR_FN: { - bool ret = true; - FnExpr *f = &e->fn; - cgen_type(g, &f->ret_type); - if (!def) { - /* get id for function */ - if (fn_name) { - f->id = fn_name->c_fn_reps++; - } else { - f->id = g->anon_fn_count++; - } - } - cgen_write(g, " "); - if (fn_name) { - cgen_ident(g, fn_name); - } else { - cgen_write(g, "a__"); - } - if (f->id != 0) - cgen_write(g, "%lu", f->id); - cgen_write(g, "("); - arr_foreach(&f->params, Param, p) { - if (p != f->params.data) - cgen_write(g, ", "); - cgen_type(g, &p->type); - cgen_write(g, " "); - cgen_ident(g, p->name); - } - cgen_write(g, ")"); - if (def) { - cgen_writeln(g, " {"); - arr_foreach(&f->body.stmts, Statement, s) { - if (!cgen_stmt(g, s)) ret = false; - } - cgen_writeln(g, "}"); - } else { - cgen_writeln(g, ";"); - } - - arr_foreach(&f->body.stmts, Statement, s) { - if (!cgen_fns_stmt(g, s, def)) - ret = false; + case EXPR_FN: + cgen_fn(g, &e->fn); + arr_foreach(&e->fn.body.stmts, Statement, stmt) { + cgen_fns_in_stmt(g, stmt); } - return ret; - } + return true; case EXPR_CALL: - cgen_fns_expr(g, e->call.fn, NULL, def); - break; - default: break; + return cgen_fns_in_expr(g, e->call.fn); + default: return true; } - return true; } -static bool cgen_fns_stmt(CGenerator *g, Statement *s, bool def) { +static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) { switch (s->kind) { case STMT_EXPR: - if (!cgen_fns_expr(g, &s->expr, NULL, def)) return false; - break; - case STMT_DECL: - if (s->decl.flags & DECL_FLAG_HAS_EXPR) { - if (!cgen_fns_expr(g, &s->decl.expr, *(Identifier*)s->decl.idents.data, def)) - return false; + if (s->expr.kind == EXPR_FN) { + warn_print(s->where, "Statement of function has no effect (try assigning the function to a variable)."); + } else { + return cgen_fns_in_expr(g, &s->expr); } break; - - } - return true; -} - -static bool cgen_fns(ParsedFile *f, CGenerator *g, bool def) { - arr_foreach(&f->stmts, Statement, s) { - cgen_fns_stmt(g, s, def); + case STMT_DECL: { + Declaration *d = &s->decl; + if (d->flags & DECL_FLAG_HAS_EXPR) + cgen_fns_in_expr(g, &d->expr); + } break; } return true; } @@ -305,15 +155,9 @@ static bool cgen_fns(ParsedFile *f, CGenerator *g, bool def) { static bool cgen_file(CGenerator *g, ParsedFile *f) { cgen_write_line_comment(g, "toc"); bool ret = true; - if (!cgen_fns(f, g, false)) return false; - if (!cgen_fns(f, g, true)) return false; - arr_foreach(&f->stmts, Statement, stmt) { - if (stmt->kind == STMT_EXPR) { - /* TODO: eventually make this an error / compile-time statement */ - warn_print(stmt->where, "Expression statement at top level."); - } - if (!cgen_stmt(g, stmt)) - ret = false; + if (!cgen_types(g, f)) return false; + arr_foreach(&f->stmts, Statement, s) { + if (!cgen_fns_in_stmt(g, s)) return false; } return ret; } @@ -29,6 +29,7 @@ int main(int argc, char **argv) { fprintf(stderr, "Error reading input file: %s.\n", argv[1]); return EXIT_FAILURE; } + fclose(in); err_filename = in_filename; Tokenizer t; @@ -55,11 +56,12 @@ int main(int argc, char **argv) { tokr_free(&t); - const char *out_filename = "out.c"; - - FILE *out = fopen(out_filename, "w"); + const char *c_out_filename = "out.c"; + const char *h_out_filename = "out.h"; + FILE *c_out = fopen(c_out_filename, "w"); + FILE *h_out = fopen(h_out_filename, "w"); CGenerator cgen; - cgen_create(&cgen, out); + cgen_create(&cgen, c_out, h_out, h_out_filename); if (!cgen_file(&cgen, &f)) { err_fprint(TEXT_IMPORTANT("Errors occured while generating C code.\n")); return EXIT_FAILURE; @@ -67,6 +69,7 @@ int main(int argc, char **argv) { free(contents); - fclose(in); + fclose(c_out); + fclose(h_out); idents_free(); } @@ -1,15 +1,12 @@ +#include "out.h" +#include <stdint.h> + /* toc */ -void xasfd(); -void a__(); -void a__1(int64_t y); -double foo(int64_t x, int64_t y, uint64_t z); -void xasfd() { +static void bar(); +void main() { + int64_t x = ((12+(-(-3)))+3); } -void a__() { +int8_t foo(int64_t x, float y, double z) { } -void a__1(int64_t y) { -} -double foo(int64_t x, int64_t y, uint64_t z) { -(3+5); -(5+6); +void bar() { } @@ -0,0 +1,2 @@ +void main(); +static int8_t foo(int64_t x, float y, double z); @@ -15,8 +15,7 @@ typedef enum { BUILTIN_U32, BUILTIN_U64, BUILTIN_FLOAT, - BUILTIN_F32, - BUILTIN_F64, + BUILTIN_DOUBLE, BUILTIN_TYPE_COUNT } BuiltinType; @@ -42,6 +41,7 @@ typedef struct { Array params; Type ret_type; Block body; + Identifier name; /* NULL if the function is anonymous (set to NULL by parse.c, set to actual value by types_cgen.c) */ unsigned long id; /* this is used to keep track of local vs global/other local functions (there might be multiple functions called "foo") */ } FnExpr; /* an expression such as fn(x: int) int {return 2 * x;} */ @@ -152,8 +152,7 @@ static BuiltinType kw_to_builtin_type(Keyword kw) { case KW_U32: return BUILTIN_U32; case KW_U64: return BUILTIN_U64; case KW_FLOAT: return BUILTIN_FLOAT; - case KW_F32: return BUILTIN_F32; - case KW_F64: return BUILTIN_F64; + case KW_DOUBLE: return BUILTIN_DOUBLE; default: return BUILTIN_TYPE_COUNT; } } @@ -170,8 +169,7 @@ static Keyword builtin_type_to_kw(BuiltinType t) { case BUILTIN_U32: return KW_U32; case BUILTIN_U64: return KW_U64; case BUILTIN_FLOAT: return KW_FLOAT; - case BUILTIN_F32: return KW_F32; - case BUILTIN_F64: return KW_F64; + case BUILTIN_DOUBLE: return KW_DOUBLE; case BUILTIN_TYPE_COUNT: break; } assert(0); @@ -255,6 +253,7 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { Tokenizer *t = p->tokr; /* only called when token is fn */ assert(token_is_kw(t->token, KW_FN)); + f->name = NULL; t->token++; if (!token_is_kw(t->token, KW_LPAREN)) { tokr_err(t, "Expected '(' after 'fn'."); @@ -658,7 +657,7 @@ static bool decl_parse(Declaration *d, Parser *p) { *ident = t->token->ident; /* only keep track of file scoped declarations--- - blocks.c will handle the rest + block enter/exit code will handle the rest */ if (p->block == NULL) { if ((*ident)->decls.len) { @@ -1,11 +1,8 @@ -xasfd @ int = fn () { - x @= (fn( ) { - x @= (fn(y: int) { - })(3); - })(); -}; - -foo @= fn (x: int, y: int, z: u64) f64 { - 3+5; - 5+6; -}; +main @= fn() { + foo @= fn(x: int, y: float, z: double) i8 { + }; + bar @= fn() { + + }; + x : int = 12 + --3 + 3; +};
\ No newline at end of file @@ -15,4 +15,6 @@ #include "tokenizer.c" #include "parse.c" #include "infer.c" +#include "base_cgen.c" +#include "types_cgen.c" #include "cgen.c" diff --git a/tokenizer.c b/tokenizer.c index 7bede8c..7333db8 100644 --- a/tokenizer.c +++ b/tokenizer.c @@ -34,15 +34,13 @@ typedef enum { KW_U32, KW_U64, KW_FLOAT, - KW_F32, - KW_F64, + KW_DOUBLE, KW_COUNT } Keyword; static const char *keywords[KW_COUNT] = {";", "=", ":", "@", ",", "(", ")", "{", "}", "==", "<", "<=", "-", "+", "fn", - "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "f32", - "f64"}; + "int", "i8", "i16", "i32", "i64", "u8", "u16", "u32", "u64", "float", "double"}; /* Returns KW_COUNT if it's not a keyword */ /* OPTIM: don't use strncmp so much */ diff --git a/types_cgen.c b/types_cgen.c new file mode 100644 index 0000000..fb1e690 --- /dev/null +++ b/types_cgen.c @@ -0,0 +1,74 @@ +static bool cgen_types_stmt(CGenerator *g, Statement *s); +static bool cgen_types_fn(CGenerator *g, FnExpr *f) { + 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; + } + if (!cgen_types_fn(g, &e->fn)) + 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; + } + } + cgen_types_expr(g, &d->expr); + } break; + + } + return true; +} + +static bool cgen_types(CGenerator *g, ParsedFile *f) { + arr_foreach(&f->stmts, Statement, s) { + cgen_types_stmt(g, s); + } + return true; +} @@ -6,20 +6,20 @@ typedef struct { size_t item_sz; } Array; -void arr_create(Array *arr, size_t item_sz) { +static void arr_create(Array *arr, size_t item_sz) { arr->len = arr->cap = 0; arr->item_sz = item_sz; arr->data = NULL; arr->last = NULL; } -void arr_reserve(Array *arr, size_t n) { +static void arr_reserve(Array *arr, size_t n) { arr->cap = n; arr->data = realloc(arr->data, arr->item_sz * arr->cap); arr->last = (void*)((char*)arr->data + arr->item_sz * (arr->len - 1)); } -void *arr_add(Array *arr) { +static void *arr_add(Array *arr) { if (arr->len >= arr->cap) { arr_reserve(arr, (arr->cap + 2) * 2); } @@ -29,20 +29,26 @@ void *arr_add(Array *arr) { return item; } -void arr_remove_last(Array *arr) { - arr->len--; - /* OPTIM (memory): Shorten array. */ +static void arr_clear(Array *arr) { + free(arr->data); + arr->len = arr->cap = 0; + arr->data = NULL; + arr->last = NULL; } -void arr_free(Array *arr) { - free(arr->data); +static void arr_remove_last(Array *arr) { + /* OPTIM (memory): Shorten array. */ + arr->len--; + if (arr->len) { + arr->last = (char*)arr->last - arr->item_sz; + } else { + arr_clear(arr); + } + } -void arr_clear(Array *arr) { +static void arr_free(Array *arr) { free(arr->data); - arr->len = arr->cap = 0; - arr->data = NULL; - arr->last = NULL; } #define arr_foreach(arr, type, var) for (type *var = (arr)->data; var; var == (arr)->last ? var = NULL : var++) |