diff options
-rw-r--r-- | base_cgen.c | 10 | ||||
-rw-r--r-- | cgen.c | 55 | ||||
-rw-r--r-- | eval.c | 11 | ||||
-rw-r--r-- | main.c | 4 | ||||
-rw-r--r-- | out.c | 6 | ||||
-rw-r--r-- | out.h | 2 | ||||
-rw-r--r-- | parse.c | 129 | ||||
-rw-r--r-- | test.toc | 7 | ||||
-rw-r--r-- | types.c | 20 | ||||
-rw-r--r-- | util/err.c | 1 |
10 files changed, 182 insertions, 63 deletions
diff --git a/base_cgen.c b/base_cgen.c index 817354f..64d96d0 100644 --- a/base_cgen.c +++ b/base_cgen.c @@ -154,6 +154,9 @@ static void cgen_type_pre(CGenerator *g, Type *t) { case TYPE_TUPLE: assert(0); return; + case TYPE_UNKNOWN: + err_print(t->where, "Type of unknown-typed expression required (x := #C(\"...\") will not work; you need to annotate the type of x)."); + abort(); case TYPE_ARR: cgen_type_pre(g, t->arr.of); break; @@ -226,6 +229,9 @@ static void cgen_type_post(CGenerator *g, Type *t) { cgen_write(g, "[%lu]", t->arr.n); cgen_type_post(g, t->arr.of); break; + case TYPE_UNKNOWN: /* we should always do pre first */ + assert(0); + break; } } @@ -269,12 +275,12 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f) { static bool cgen_block_enter(CGenerator *g, Block *b) { g->block = b; - return block_enter(b); + return block_enter(b, &b->stmts); } static bool cgen_block_exit(CGenerator *g, Block *into) { Block *b = g->block; g->block = into; - return block_exit(b); + return block_exit(b, &b->stmts); } @@ -16,6 +16,27 @@ static void cgen_create(CGenerator *g, Identifiers *ids, FILE *c_out, FILE *h_ou cgen_writeln(g, ""); /* extra newline between includes and code */ } +static bool cgen_direct(CGenerator *g, DirectExpr *direct, Location where) { + switch (direct->which) { + case DIRECT_C: { + Expression *args = direct->args.data; + size_t nargs = direct->args.len; + if (nargs != 1) { + err_print(where, "Expected 1 argument to #C directive, but got %lu.", nargs); + } + /* TODO: compile-time constants */ + if (args[0].kind != EXPR_STR_LITERAL) { + err_print(args[0].where, "Argument to #C directive must be a string literal."); + } + cgen_write(g, "%s", args[0].strl.str); + } break; + case DIRECT_COUNT: + assert(0); + return false; + } + return true; +} + static bool cgen_expr(CGenerator *g, Expression *e) { switch (e->kind) { case EXPR_INT_LITERAL: @@ -88,6 +109,9 @@ static bool cgen_expr(CGenerator *g, Expression *e) { } cgen_write(g, ")"); break; + case EXPR_DIRECT: + if (!cgen_direct(g, &e->direct, e->where)) return false; + break; } return true; } @@ -117,6 +141,9 @@ static void cgen_zero_value(CGenerator *g, Type *t) { assert(0); } break; + case TYPE_UNKNOWN: + assert(0); + break; } } @@ -245,12 +272,38 @@ static bool cgen_fns_in_stmt(CGenerator *g, Statement *s) { return true; } +/* generate a statement at top level, including any functions in it. */ +static bool cgen_stmt_top(CGenerator *g, Statement *s) { + if (!cgen_fns_in_stmt(g, s)) return false; + switch (s->kind) { + case STMT_EXPR: { + Expression *e = &s->expr; + bool ignored = true; + switch (e->kind) { + case EXPR_DIRECT: + switch (e->direct.which) { + case DIRECT_C: + ignored = false; + cgen_direct(g, &e->direct, e->where); + break; + case DIRECT_COUNT: assert(0); break; + } + default: break; + } + if (ignored) + warn_print(e->where, "Expression at top level currently ignored."); /* TODO */ + } break; + case STMT_DECL: break; + } + return true; +} + static bool cgen_file(CGenerator *g, ParsedFile *f) { cgen_write_line_comment(g, "toc"); bool ret = true; if (!cgen_decls_file(g, f)) return false; arr_foreach(&f->stmts, Statement, s) { - if (!cgen_fns_in_stmt(g, s)) return false; + if (!cgen_stmt_top(g, s)) return false; } g->writing_to = CGEN_WRITING_TO_C; /* write actual main function */ @@ -94,6 +94,17 @@ static bool eval_expr_as_int(Expression *e, Integer *i) { case EXPR_FN: err_print(e->where, "Expected integer, but found function."); return false; + case EXPR_CALL: + err_print(e->where, "Compile time function calling not supported yet."); /* TODO */ + break; + case EXPR_DIRECT: + switch (e->direct.which) { + case DIRECT_C: + err_print(e->where, "Can't run C code at compile time."); + return false; + case DIRECT_COUNT: assert(0); break; + } + break; } err_print(e->where, "Not implemented yet"); return false; @@ -62,6 +62,9 @@ int main(int argc, char **argv) { fprint_parsed_file(stdout, &f); tokr_free(&t); + + + block_enter(NULL, &f.stmts); /* enter global scope */ if (!types_file(&f)) { err_fprint(TEXT_IMPORTANT("Errors occured while determining types.\n")); return EXIT_FAILURE; @@ -79,6 +82,7 @@ int main(int argc, char **argv) { return EXIT_FAILURE; } + block_exit(NULL, &f.stmts); /* exit global scope */ free(contents); fclose(c_out); @@ -1,10 +1,12 @@ #include "out.h" /* toc */ -void x__c5x__b3x__c5x__84x__c4x__a8x__f0x__9fx__90x__9f(void) { +#include <stdio.h> +void x__c5x__b3x__c5x__84x__c4x__a8(void) { + printf("Hello, World!\n"); } void main__(void) { - x__c5x__b3x__c5x__84x__c4x__a8x__f0x__9fx__90x__9f(); + x__c5x__b3x__c5x__84x__c4x__a8(); } int main(void) { @@ -1,4 +1,4 @@ #include <stddef.h> #include <stdint.h> -void x__c5x__b3x__c5x__84x__c4x__a8x__f0x__9fx__90x__9f(void); +void x__c5x__b3x__c5x__84x__c4x__a8(void); void main__(void); @@ -1,6 +1,7 @@ /* TODO: stmt_parse -> parse_stmt, etc. */ typedef enum { TYPE_VOID, + TYPE_UNKNOWN, TYPE_BUILTIN, TYPE_FN, TYPE_TUPLE, @@ -69,7 +70,8 @@ typedef enum { EXPR_BINARY_OP, EXPR_UNARY_OP, EXPR_FN, - EXPR_CALL + EXPR_CALL, + EXPR_DIRECT } ExprKind; typedef enum { @@ -84,6 +86,12 @@ typedef enum { BINARY_AT_INDEX /* e.g. x[i] */ } BinaryOp; +typedef struct { + Directive which; + Array args; /* of Expression */ +} DirectExpr; + + #define EXPR_FLAG_FLEXIBLE 0x01 /* e.g. 4 => float/i32/etc. */ typedef struct Expression { @@ -105,8 +113,9 @@ typedef struct Expression { } binary; struct { struct Expression *fn; - Array args; /* of expression */ + Array args; /* of Expression */ } call; + DirectExpr direct; Identifier ident; FnExpr fn; }; @@ -232,6 +241,8 @@ static size_t type_to_str(Type *t, char *buffer, size_t bufsize) { switch (t->kind) { case TYPE_VOID: return str_copy(buffer, bufsize, "void"); + case TYPE_UNKNOWN: + return str_copy(buffer, bufsize, "???"); case TYPE_BUILTIN: { const char *s = keywords[builtin_type_to_kw(t->builtin)]; return str_copy(buffer, bufsize, s); @@ -600,6 +611,35 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { return parse_block(p, &f->body); } +/* parses, e.g. "(3, 5, foo)" */ +static bool parse_args(Parser *p, Array *args) { + Tokenizer *t = p->tokr; + Token *start = t->token; + assert(token_is_kw(start, KW_LPAREN)); + arr_create(args, sizeof(Expression)); + t->token++; /* move past ( */ + if (!token_is_kw(t->token, KW_RPAREN)) { + /* non-empty arg list */ + while (1) { + if (t->token->kind == TOKEN_EOF) { + tokr_err(t, "Expected argument list to continue."); + info_print(start->where, "This is where the argument list starts."); + return false; + } + Expression *arg = arr_add(args); + if (!parse_expr(p, arg, expr_find_end(p, EXPR_END_RPAREN_OR_COMMA))) { + return false; + } + if (token_is_kw(t->token, KW_RPAREN)) + break; + assert(token_is_kw(t->token, KW_COMMA)); + t->token++; /* move past , */ + } + } + t->token++; /* move past ) */ + return true; +} + static bool parse_expr(Parser *p, Expression *e, Token *end) { Tokenizer *t = p->tokr; if (end == NULL) return false; @@ -750,6 +790,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { /* try a function call or array access */ Token *token = t->token; + /* currently unnecessary: paren_level = square_level = 0; */ /* can't call at start, e.g. in (fn() {})(), it is not the empty function "" @@ -765,7 +806,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { if (token->kind == TOKEN_KW) { switch (token->kw) { case KW_LPAREN: - if (square_level == 0 && paren_level == 0) + if (square_level == 0 && paren_level == 0 && token != t->tokens.data + && token[-1].kind != TOKEN_DIRECT /* don't include directives */) opening_bracket = token; /* maybe this left parenthesis opens the function call */ paren_level++; break; @@ -804,26 +846,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { if (!parse_expr(p, e->call.fn, opening_bracket)) { /* parse up to ( as function */ return false; } - arr_create(&e->call.args, sizeof(Expression)); - t->token = opening_bracket + 1; /* move past ( */ - if (!token_is_kw(t->token, KW_RPAREN)) { - /* non-empty arg list */ - while (1) { - if (t->token->kind == TOKEN_EOF) { - tokr_err(t, "Expected argument list to continue."); - return false; - } - Expression *arg = arr_add(&e->call.args); - if (!parse_expr(p, arg, expr_find_end(p, EXPR_END_RPAREN_OR_COMMA))) { - return false; - } - if (token_is_kw(t->token, KW_RPAREN)) - break; - t->token++; /* move past , */ - } - } - t->token++; /* move past ) */ - return true; + t->token = opening_bracket; + return parse_args(p, &e->call.args); } case KW_LSQUARE: { /* it's an array access */ @@ -846,6 +870,22 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { return false; } } + + if (t->token->kind == TOKEN_DIRECT) { + /* it's a directive */ + e->kind = EXPR_DIRECT; + e->direct.which = t->token->direct; + if (token_is_kw(&t->token[1], KW_LPAREN)) { + /* has args (but maybe it's just "#foo()") */ + t->token++; /* move to ( */ + return parse_args(p, &e->direct.args); + } else { + /* no args */ + arr_create(&e->direct.args, sizeof(Expression)); + t->token++; + return true; + } + } tokr_err(t, "Not implemented yet."); return false; } @@ -943,25 +983,6 @@ static bool parse_single_type_in_decl(Parser *p, Declaration *d) { return false; } *ident = t->token->ident; - /* - only keep track of file scoped declarations--- - block enter/exit code will handle the rest - */ - IdentTree *ident_info = *ident; - if (p->block == NULL) { - if (ident_info->decls.len) { - /* this was already declared! */ - IdentDecl *prev = ident_info->decls.data; - tokr_err(t, "Re-declaration of identifier in global scope."); - info_print(prev->decl->where, "Previous declaration was here."); - return false; - } - assert(!ident_info->decls.item_sz); /* we shouldn't have created this array already */ - arr_create(&ident_info->decls, sizeof(IdentDecl)); - IdentDecl *ident_decl = arr_add(&ident_info->decls); - ident_decl->decl = d; - ident_decl->scope = NULL; - } t->token++; if (token_is_kw(t->token, KW_COMMA)) { t->token++; @@ -1139,6 +1160,9 @@ static void fprint_type(FILE *out, Type *t) { case TYPE_VOID: fprintf(out, "void"); break; + case TYPE_UNKNOWN: + fprintf(out, "???"); + break; case TYPE_FN: { Type *types = t->fn.types.data; fprintf(out, "fn ("); @@ -1202,6 +1226,15 @@ static void fprint_fn_expr(FILE *out, FnExpr *f) { fprint_block(out, &f->body); } +static void fprint_args(FILE *out, Array *args) { + fprintf(out, "("); + arr_foreach(args, Expression, arg) { + if (arg != args->data) fprintf(out, ", "); + fprint_expr(out, arg); + } + fprintf(out, ")"); +} + static void fprint_expr(FILE *out, Expression *e) { PARSE_PRINT_LOCATION(e->where); switch (e->kind) { @@ -1256,12 +1289,12 @@ static void fprint_expr(FILE *out, Expression *e) { break; case EXPR_CALL: fprint_expr(out, e->call.fn); - fprintf(out, "("); - arr_foreach(&e->call.args, Expression, arg) { - if (arg != e->call.args.data) fprintf(out, ", "); - fprint_expr(out, arg); - } - fprintf(out, ")"); + fprint_args(out, &e->call.args); + break; + case EXPR_DIRECT: + fprintf(out, "#"); + fprintf(out, directives[e->direct.which]); + fprint_args(out, &e->direct.args); break; } } @@ -1,6 +1,9 @@ -ųńĨ🐟 @= fn() { +#C("#include <stdio.h>\n"); + +ųńĨ @= fn() { + #C("printf(\"Hello, World!\\n\")"); }; main @= fn() { - ųńĨ🐟(); + ųńĨ(); }; @@ -1,6 +1,7 @@ -static bool block_enter(Block *b) { +/* pass NULL for block for global scope */ +static bool block_enter(Block *b, Array *stmts) { bool ret = true; - arr_foreach(&b->stmts, Statement, stmt) { + arr_foreach(stmts, Statement, stmt) { if (stmt->kind == STMT_DECL) { Declaration *decl = &stmt->decl; arr_foreach(&decl->idents, Identifier, ident) { @@ -29,10 +30,10 @@ static bool block_enter(Block *b) { return ret; } -static bool block_exit(Block *b) { +static bool block_exit(Block *b, Array *stmts) { /* OPTIM: figure out some way of not re-iterating over everything */ bool ret = true; - arr_foreach(&b->stmts, Statement, stmt) { + arr_foreach(stmts, Statement, stmt) { if (stmt->kind == STMT_DECL) { Declaration *decl = &stmt->decl; arr_foreach(&decl->idents, Identifier, ident) { @@ -50,6 +51,8 @@ static bool block_exit(Block *b) { } static bool type_eq(Type *a, Type *b) { + if (a->kind == TYPE_UNKNOWN || b->kind == TYPE_UNKNOWN) + return true; /* allow things such as 3 + #C("5") */ if (a->kind != b->kind) return false; if (a->flags & TYPE_FLAG_FLEXIBLE) { if (b->flags & TYPE_FLAG_FLEXIBLE) return true; @@ -66,6 +69,7 @@ static bool type_eq(Type *a, Type *b) { } switch (a->kind) { case TYPE_VOID: return true; + case TYPE_UNKNOWN: assert(0); return false; case TYPE_BUILTIN: return a->builtin == b->builtin; case TYPE_FN: { @@ -244,7 +248,6 @@ static bool type_of_expr(Expression *e, Type *t) { break; case EXPR_IDENT: { if (!type_of_ident(e->where, e->ident, t, false)) return false; - } break; case EXPR_CALL: { Expression *f = e->call.fn; @@ -265,6 +268,9 @@ static bool type_of_expr(Expression *e, Type *t) { *t = *(Type*)fn_type.fn.types.data; break; } + case EXPR_DIRECT: + t->kind = TYPE_UNKNOWN; + break; case EXPR_UNARY_OP: { Type *of_type = &e->unary.of->type; if (!type_of_expr(e->unary.of, of_type)) return false; @@ -380,11 +386,11 @@ static bool types_stmt(Statement *s); static bool types_block(Block *b) { bool ret = true; - if (!block_enter(b)) return false; + if (!block_enter(b, &b->stmts)) return false; arr_foreach(&b->stmts, Statement, s) { if (!types_stmt(s)) ret = false; } - if (!block_exit(b)) return false; + if (!block_exit(b, &b->stmts)) return false; return ret; } @@ -57,6 +57,7 @@ static void err_print_footer_(const char *context) { if (!has_newline) end = strchr(context, '\0'); assert(end); + err_fprint("\n\there: --> "); err_fwrite(context, 1, (size_t)(end - context)); if (!has_newline) err_fprint("<end of file>"); |