summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--base_cgen.c2
-rwxr-xr-xbuild.sh2
-rw-r--r--eval.c2
-rw-r--r--identifiers.c9
-rw-r--r--main.c24
-rw-r--r--parse.c153
-rw-r--r--test.toc18
-rw-r--r--toc.c5
-rw-r--r--types.c28
-rw-r--r--util/location.c3
-rw-r--r--util/where.c3
11 files changed, 112 insertions, 137 deletions
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 <stdio.h>\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 = &params->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(&param->type);
- *param_type = param->type;
+ type_resolve(&param_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;
-}