From ad062bd0ad547447f74840b89fb0dced35be0fdc Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Wed, 18 Sep 2019 11:36:40 -0400 Subject: improved fn params --- base_cgen.c | 2 +- build.sh | 2 +- eval.c | 2 +- identifiers.c | 9 ++++ main.c | 24 ++++----- parse.c | 153 ++++++++++++++++++++++++-------------------------------- test.toc | 18 +++---- toc.c | 5 +- types.c | 28 +++++------ util/location.c | 3 ++ util/where.c | 3 -- 11 files changed, 112 insertions(+), 137 deletions(-) create mode 100644 util/location.c delete mode 100644 util/where.c diff --git a/base_cgen.c b/base_cgen.c index 1f0b09c..d773ba9 100644 --- a/base_cgen.c +++ b/base_cgen.c @@ -94,7 +94,7 @@ static bool cgen_ident(CGenerator *g, Identifier i, Location *where) { Declaration *decl = id_decl->decl; if ((decl->flags & DECL_FLAG_HAS_EXPR) && (decl->flags & DECL_FLAG_CONST)) { if (decl->expr.kind == EXPR_FN) { - cgen_fn_name(g, &decl->expr.fn, NULL); + cgen_fn_name(g, decl->expr.fn, NULL); return true; } } diff --git a/build.sh b/build.sh index cd337dd..e256f9f 100755 --- a/build.sh +++ b/build.sh @@ -7,7 +7,7 @@ CC=clang # - must be set if the zero value of a pointer (as might be set by calloc/memset) # is not the NULL pointer. -ADDITIONAL_FLAGS='' +ADDITIONAL_FLAGS='-Wno-unused-function -Wno-unneeded-internal-declaration' WARNINGS='-Wall -Wextra -Wpedantic -Wconversion -Wshadow' DEBUG_FLAGS="-O0 -g3 $WARNINGS -std=c11" diff --git a/eval.c b/eval.c index bbefde5..9958718 100644 --- a/eval.c +++ b/eval.c @@ -74,7 +74,7 @@ static bool eval_expr_as_int(Expression *e, Integer *i) { return false; } Declaration *d = id_decl->decl; - if (is_after(d->where, e->where)) { + if (location_after(d->where, e->where)) { err_print(e->where, "Use of constant before its declaration."); info_print(d->where, "Declaration will be here."); return false; diff --git a/identifiers.c b/identifiers.c index eb82c7b..0f083c0 100644 --- a/identifiers.c +++ b/identifiers.c @@ -177,6 +177,15 @@ static char *ident_to_str(Identifier i) { return str; } +static void ident_add_decl(Identifier i, struct Declaration *d, struct Block *b) { + if (!i->decls.item_sz) { + arr_create(&i->decls, sizeof(IdentDecl)); + } + IdentDecl *id_decl = arr_add(&i->decls); + id_decl->decl = d; + id_decl->scope = b; +} + static IdentDecl *ident_decl(Identifier i) { assert(i->decls.item_sz); return (IdentDecl*)arr_last(&i->decls); diff --git a/main.c b/main.c index 120ebe8..6ea2855 100644 --- a/main.c +++ b/main.c @@ -72,21 +72,21 @@ int main(int argc, char **argv) { } /* 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"; - FILE *c_out = fopen(c_out_filename, "w"); - FILE *h_out = fopen(h_out_filename, "w"); - CGenerator cgen; - cgen_create(&cgen, &file_idents, 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; - } + /* 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, &file_idents, 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; */ + /* } */ block_exit(NULL, &f.stmts); /* exit global scope */ free(contents); - fclose(c_out); - fclose(h_out); + /* fclose(c_out); */ + /* fclose(h_out); */ idents_free(&file_idents); } diff --git a/parse.c b/parse.c index 49668fd..1127a56 100644 --- a/parse.c +++ b/parse.c @@ -45,24 +45,11 @@ typedef struct Type { }; } Type; -typedef struct { - Identifier name; - Type type; -} Param; - typedef struct Block { Array stmts; struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */ } Block; -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;} */ - typedef enum { EXPR_INT_LITERAL, EXPR_FLOAT_LITERAL, @@ -116,7 +103,7 @@ typedef struct Expression { } call; DirectExpr direct; Identifier ident; - FnExpr fn; + struct FnExpr *fn; }; } Expression; @@ -134,6 +121,14 @@ typedef struct Declaration { Expression expr; } Declaration; +typedef struct FnExpr { + Declaration params; /* declaration of the parameters to this function */ + 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;} */ + typedef enum { STMT_DECL, STMT_EXPR @@ -160,6 +155,14 @@ typedef struct { Block *block; /* which block are we in? NULL = file scope */ } Parser; +typedef enum { + DECL_END_SEMICOLON, + DECL_END_RPAREN +} DeclEndType; + +static bool parse_expr(Parser *p, Expression *e, Token *end); +static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with); + static const char *binary_op_to_str(BinaryOp b) { switch (b) { case BINARY_PLUS: return "+"; @@ -390,7 +393,6 @@ static Token *expr_find_end(Parser *p, unsigned flags) { } } -static bool parse_expr(Parser *p, Expression *e, Token *end); static bool parse_type(Parser *p, Type *type) { Tokenizer *t = p->tokr; type->where = t->token->where; @@ -493,24 +495,6 @@ static bool parse_type(Parser *p, Type *type) { } -static bool parse_param(Parser *parser, Param *p) { - Tokenizer *t = parser->tokr; - if (t->token->kind != TOKEN_IDENT) { - tokr_err(t, "Expected parameter name."); - return false; - } - p->name = t->token->ident; - t->token++; - if (!token_is_kw(t->token, KW_COLON)) { - tokr_err(t, "Expected ':' between parameter name and type."); - return false; - } - t->token++; - if (!parse_type(parser, &p->type)) - return false; - return true; -} - static bool parse_stmt(Parser *p, Statement *s); static bool parse_block(Parser *p, Block *b) { @@ -529,11 +513,13 @@ static bool parse_block(Parser *p, Block *b) { /* non-empty function body */ while (1) { Statement *stmt = arr_add(&b->stmts); - if (!parse_stmt(p, stmt)) { + bool success = parse_stmt(p, stmt); + if (!success) { ret = false; } + if (token_is_kw(t->token, KW_RBRACE)) { - if (stmt->kind == STMT_EXPR) { + if (success && stmt->kind == STMT_EXPR) { if (!(stmt->flags & STMT_FLAG_VOIDED_EXPR)) { b->ret_expr = parser_new_expr(p); *b->ret_expr = stmt->expr; @@ -541,15 +527,21 @@ static bool parse_block(Parser *p, Block *b) { } } break; - } else if (stmt->kind == STMT_EXPR && !(stmt->flags & STMT_FLAG_VOIDED_EXPR)) { - /* in theory, this should never happen right now */ - err_print(stmt->where, "Non-voided expression is not the last statement in a block (you might want to add a ';' to the end of this statement)."); - return false; } + + if (success) { + if (stmt->kind == STMT_EXPR && !(stmt->flags & STMT_FLAG_VOIDED_EXPR)) { + /* in theory, this should never happen right now */ + err_print(stmt->where, "Non-voided expression is not the last statement in a block (you might want to add a ';' to the end of this statement)."); + return false; + } + } + if (t->token->kind == TOKEN_EOF) { tokr_err(t, "Expected '}' to close function body."); return false; } + } } else { b->ret_expr = NULL; @@ -569,27 +561,9 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) { tokr_err(t, "Expected '(' after 'fn'."); return false; } - arr_create(&f->params, sizeof(Param)); - t->token++; + parse_decl(p, &f->params, DECL_END_RPAREN); - if (!token_is_kw(t->token, KW_RPAREN)) { - /* non-empty parameter list */ - while (1) { - Param *param = arr_add(&f->params); - if (!parse_param(p, param)) - return false; - if (token_is_kw(t->token, KW_RPAREN)) break; - if (token_is_kw(t->token, KW_COMMA)) { - t->token++; - continue; - } - tokr_err(t, "Expected ',' or ')' to continue or end parameter list."); - return false; - } - } - - t->token++; /* move past ) */ if (token_is_kw(t->token, KW_LBRACE)) { /* void function */ f->ret_type.kind = TYPE_VOID; @@ -680,7 +654,8 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) { if (token_is_kw(t->token, KW_FN)) { /* this is a function */ e->kind = EXPR_FN; - if (!parse_fn_expr(p, &e->fn)) + e->fn = err_malloc(sizeof *e->fn); + if (!parse_fn_expr(p, e->fn)) return false; if (t->token != end) { @@ -964,7 +939,7 @@ NOTE: this function actually parses all types in the declaration, but it just calls itself to do that. */ -static bool parse_single_type_in_decl(Parser *p, Declaration *d) { +static bool parse_single_type_in_decl(Parser *p, Declaration *d, DeclEndType ends_with) { Tokenizer *t = p->tokr; /* OPTIM: Maybe don't use a dynamic array or use parser allocator. */ size_t n_idents_with_this_type = 1; @@ -995,7 +970,7 @@ static bool parse_single_type_in_decl(Parser *p, Declaration *d) { } - if (token_is_kw(t->token, KW_SEMICOLON)) { + if (token_is_kw(t->token, KW_SEMICOLON) || token_is_kw(t->token, KW_RPAREN)) { /* e.g. foo :; */ tokr_err(t, "Cannot infer type without expression."); return false; @@ -1040,7 +1015,7 @@ static bool parse_single_type_in_decl(Parser *p, Declaration *d) { if (token_is_kw(t->token, KW_COMMA)) { /* next type in declaration */ t->token++; /* move past , */ - return parse_single_type_in_decl(p, d); + return parse_single_type_in_decl(p, d, ends_with); } /* OPTIM: switch t->token->kw ? */ @@ -1049,28 +1024,39 @@ static bool parse_single_type_in_decl(Parser *p, Declaration *d) { if (!parse_expr(p, &d->expr, expr_find_end(p, 0))) return false; d->flags |= DECL_FLAG_HAS_EXPR; - if (token_is_kw(t->token, KW_SEMICOLON)) { + if ((token_is_kw(t->token, KW_SEMICOLON) && ends_with == DECL_END_SEMICOLON) + || (token_is_kw(t->token, KW_RPAREN) && ends_with == DECL_END_RPAREN)) { t->token++; return true; } - tokr_err(t, "Expected ';' at end of expression"); /* should never happen in theory right now */ + tokr_err(t, "Expected '%c' at end of expression.", + ends_with == DECL_END_SEMICOLON ? ';' : ')'); return false; - } else if (token_is_kw(t->token, KW_SEMICOLON)) { + + } else if ((token_is_kw(t->token, KW_SEMICOLON) && ends_with == DECL_END_SEMICOLON) + || (token_is_kw(t->token, KW_RPAREN) && ends_with == DECL_END_RPAREN)) { t->token++; return true; } else { - tokr_err(t, "Expected ';' or '=' at end of delaration."); + tokr_err(t, "Expected '%c' or '=' at end of delaration.", + ends_with == DECL_END_SEMICOLON ? ';' : ')'); return false; } } -static bool parse_decl(Parser *p, Declaration *d) { +static bool parse_decl(Parser *p, Declaration *d, DeclEndType ends_with) { d->type.kind = TYPE_VOID; d->where = p->tokr->token->where; arr_create(&d->idents, sizeof(Identifier)); - + Tokenizer *t = p->tokr; d->flags = 0; - return parse_single_type_in_decl(p, d); /* recursively calls itself to parse all types */ + /* TODO: extract cond */ + if ((token_is_kw(t->token, KW_SEMICOLON) && ends_with == DECL_END_SEMICOLON) + || (token_is_kw(t->token, KW_RPAREN) && ends_with == DECL_END_RPAREN)) { + t->token++; + return true; + } + return parse_single_type_in_decl(p, d, ends_with); /* recursively calls itself to parse all types */ } static bool parse_stmt(Parser *p, Statement *s) { @@ -1085,7 +1071,7 @@ static bool parse_stmt(Parser *p, Statement *s) { if (token_is_kw(t->token + 1, KW_COLON) || token_is_kw(t->token + 1, KW_COMMA) || token_is_kw(t->token + 1, KW_AT)) { s->kind = STMT_DECL; - if (!parse_decl(p, &s->decl)) { + if (!parse_decl(p, &s->decl, DECL_END_SEMICOLON)) { /* move to next statement */ /* TODO: This might cause unhelpful errors if the first semicolon is inside a block, etc. */ while (!token_is_kw(t->token, KW_SEMICOLON)) { @@ -1111,10 +1097,9 @@ static bool parse_stmt(Parser *p, Statement *s) { while (t->token->kind != TOKEN_EOF) t->token++; /* move to end of file */ return false; } - if (!parse_expr(p, &s->expr, end)) { - return false; - } - /* go past end */ + bool success = parse_expr(p, &s->expr, end); + + /* go past end regardless of whether successful or not */ if (end->kind == TOKEN_KW) { switch (end->kw) { case KW_SEMICOLON: @@ -1129,7 +1114,7 @@ static bool parse_stmt(Parser *p, Statement *s) { t->token = end + 1; } - return true; + return success; } } @@ -1154,6 +1139,9 @@ static bool parse_file(Parser *p, ParsedFile *f) { #define PARSE_PRINT_LOCATION(l) //fprintf(out, "[l%lu]", (unsigned long)(l).line); static void fprint_expr(FILE *out, Expression *e); +static void fprint_stmt(FILE *out, Statement *s); +static void fprint_decl(FILE *out, Declaration *d); + static void fprint_type(FILE *out, Type *t) { PARSE_PRINT_LOCATION(t->where); switch (t->kind) { @@ -1199,13 +1187,6 @@ static void fprint_type(FILE *out, Type *t) { } } -static void fprint_param(FILE *out, Param *p) { - fprint_ident(out, p->name); - fprintf(out, ": "); - fprint_type(out, &p->type); -} - -static void fprint_stmt(FILE *out, Statement *s); static void fprint_block(FILE *out, Block *b) { fprintf(out, "{\n"); @@ -1218,11 +1199,7 @@ static void fprint_block(FILE *out, Block *b) { static void fprint_fn_expr(FILE *out, FnExpr *f) { fprintf(out, "fn ("); - arr_foreach(&f->params, Param, param) { - if (param != f->params.data) - fprintf(out, ", "); - fprint_param(out, param); - } + fprint_decl(out, &f->params); fprintf(out, ") "); fprint_type(out, &f->ret_type); fprintf(out, " "); @@ -1288,7 +1265,7 @@ static void fprint_expr(FILE *out, Expression *e) { fprintf(out, ")"); break; case EXPR_FN: - fprint_fn_expr(out, &e->fn); + fprint_fn_expr(out, e->fn); break; case EXPR_CALL: fprint_expr(out, e->call.fn); diff --git a/test.toc b/test.toc index f3ebac3..be7d33f 100644 --- a/test.toc +++ b/test.toc @@ -1,16 +1,12 @@ #C("#include \n"); -N @= 10; -foo @= fn() [N][N]int { - x : [N][N]int; - x +print_int @= fn(x: int) { + #C("printf(\"%ld\\n\", (long)x);\n"); }; + +times2 @= fn(x: int) int { 5 /* x*/ }; + main @= fn() { - x : [N][N]int = foo(); - #C(" -for (int i = 0; i < 10; i++) - for (int j = 0; j < 10; j++) - printf(\"%ld\", x[i][j]); -puts(\"\"); - "); + print_int(times2(5)); + foo := fn (x, y, z : float, y:double) {}; }; diff --git a/toc.c b/toc.c index b36c5fa..3965e18 100644 --- a/toc.c +++ b/toc.c @@ -22,10 +22,7 @@ typedef long double Floating; /* OPTIM: Switch to double */ #include "util/str.c" #include "identifiers.c" #include "tokenizer.c" -#include "util/where.c" +#include "util/location.c" #include "parse.c" #include "eval.c" #include "types.c" -#include "base_cgen.c" -#include "decls_cgen.c" -#include "cgen.c" diff --git a/types.c b/types.c index da55937..2e57245 100644 --- a/types.c +++ b/types.c @@ -8,8 +8,7 @@ static bool block_enter(Block *b, Array *stmts) { if (stmt->kind == STMT_DECL) { Declaration *decl = &stmt->decl; arr_foreach(&decl->idents, Identifier, ident) { - IdentTree *id_info = *ident; - Array *decls = &id_info->decls; + Array *decls = &(*ident)->decls; if (decls->len) { /* check that it hasn't been declared in this block */ IdentDecl *prev = arr_last(decls); @@ -19,14 +18,8 @@ static bool block_enter(Block *b, Array *stmts) { ret = false; continue; } - } else { - /* array not initialized yet */ - arr_create(decls, sizeof(IdentDecl)); } - - IdentDecl *ident_decl = arr_add(decls); - ident_decl->decl = decl; - ident_decl->scope = b; + ident_add_decl(*ident, decl, b); } } } @@ -154,7 +147,7 @@ static bool type_of_ident(Location where, Identifier i, Type *t, bool allow_use_ Declaration *d = decl->decl; if (!allow_use_before_decl) { /* TODO: Check self-referential declarations */ - if (d->where.code > where.code) { + if (location_after(d->where, where)) { char *s = ident_to_str(i); err_print(where, "Use of identifier %s before its declaration.", s); info_print(d->where, "%s will be declared here.", s); @@ -227,16 +220,19 @@ static bool type_of_expr(Expression *e, Type *t) { t->kind = TYPE_UNKNOWN; /* default to unknown type (in the case of an error) */ switch (e->kind) { case EXPR_FN: { - FnExpr *f = &e->fn; + FnExpr *f = e->fn; t->kind = TYPE_FN; arr_create(&t->fn.types, sizeof(Type)); Type *ret_type = arr_add(&t->fn.types); type_resolve(&f->ret_type); *ret_type = f->ret_type; - arr_foreach(&f->params, Param, param) { + Declaration *params = &f->params; + Type *type = ¶ms->type; + Type *param_types = type->kind == TYPE_TUPLE ? type->tuple.data : type; + for (size_t i = 0; i < params->idents.len; i++) { Type *param_type = arr_add(&t->fn.types); - type_resolve(¶m->type); - *param_type = param->type; + type_resolve(¶m_types[i]); + *param_type = param_types[i]; } } break; case EXPR_INT_LITERAL: @@ -398,11 +394,11 @@ static bool types_expr(Expression *e) { if (!type_of_expr(e, t)) return false; switch (e->kind) { case EXPR_FN: - if (!types_block(&e->fn.body)) + if (!types_block(&e->fn->body)) return false; assert(e->type.kind == TYPE_FN); Type *ret_type = e->type.fn.types.data; - Expression *ret_expr = e->fn.body.ret_expr; + Expression *ret_expr = e->fn->body.ret_expr; if (ret_expr) { if (!type_eq(ret_type, &ret_expr->type)) { char *got = type_to_str(&ret_expr->type); diff --git a/util/location.c b/util/location.c new file mode 100644 index 0000000..f588146 --- /dev/null +++ b/util/location.c @@ -0,0 +1,3 @@ +bool location_after(Location a, Location b) { /* a is after b? */ + return a.code > b.code; +} diff --git a/util/where.c b/util/where.c deleted file mode 100644 index 4ac786d..0000000 --- a/util/where.c +++ /dev/null @@ -1,3 +0,0 @@ -bool is_after(Location a, Location b) { /* a is after b? */ - return a.code > b.code; -} -- cgit v1.2.3