summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--allocator.c6
-rw-r--r--arr.c2
-rwxr-xr-xbuild.sh2
-rw-r--r--cgen.c148
-rw-r--r--decls_cgen.c35
-rw-r--r--eval.c4
-rw-r--r--identifiers.c21
-rw-r--r--main.c8
-rw-r--r--parse.c18
-rw-r--r--test.toc57
-rw-r--r--typedefs_cgen.c15
-rw-r--r--types.c58
-rw-r--r--types.h29
13 files changed, 190 insertions, 213 deletions
diff --git a/allocator.c b/allocator.c
index 1995733..f47cc97 100644
--- a/allocator.c
+++ b/allocator.c
@@ -1,7 +1,7 @@
-#define NO_ALLOCATOR 0 /* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator */
+/* #define NO_ALLOCATOR 0 /\* useful for debugging; valgrind checks writing past the end of a malloc, but that won't work with an allocator *\/ */
/* number of bytes a page hold, not including the header */
#define PAGE_BYTES (16384 - sizeof(Page))
-#define PAGE_MAX_ALIGNS (PAGE_BYTES / sizeof(max_align_t))
+#define PAGE_MAX_ALIGNS (PAGE_BYTES / sizeof(MaxAlign))
static void allocr_create(Allocator *a) {
a->first = a->last = NULL;
@@ -17,7 +17,7 @@ static void *allocr_malloc(Allocator *a, size_t bytes) {
size_t pos = PAGE_MAX_ALIGNS;
if (a->last)
pos = a->last->used;
- size_t max_aligns = (bytes + sizeof(max_align_t) - 1) / sizeof(max_align_t);
+ size_t max_aligns = (bytes + sizeof(MaxAlign) - 1) / sizeof(MaxAlign);
if (pos + max_aligns > PAGE_MAX_ALIGNS) {
/* make a new page for this data */
diff --git a/arr.c b/arr.c
index ab92319..f214fe4 100644
--- a/arr.c
+++ b/arr.c
@@ -2,7 +2,7 @@
typedef struct {
size_t len;
size_t cap;
- max_align_t data[];
+ MaxAlign data[];
} ArrHeader;
static inline ArrHeader *arr_hdr(void *arr) {
diff --git a/build.sh b/build.sh
index 865313a..3e3760c 100755
--- a/build.sh
+++ b/build.sh
@@ -14,7 +14,7 @@ fi
# - must be set if the zero value of a pointer (as might be set by calloc/memset)
# is not the NULL pointer.
-ADDITIONAL_FLAGS='-Wno-unused-function'
+# ADDITIONAL_FLAGS='-Wno-unused-function'
if [ "$CC" = "clang" ]; then
WARNINGS='-Wall -Wextra -Wpedantic -Wshadow -Wconversion -Wimplicit-fallthrough -Wno-unused-parameter'
diff --git a/cgen.c b/cgen.c
index 0e27220..971d2c3 100644
--- a/cgen.c
+++ b/cgen.c
@@ -226,7 +226,7 @@ static void cgen_ident(CGenerator *g, Identifier i) {
cgen_write(g, "main__");
} else {
cgen_indent(g);
- fprint_ident(cgen_writing_to(g), i);
+ fprint_ident_reduced_charset(cgen_writing_to(g), i);
}
}
@@ -449,7 +449,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc
}
}
}
- if (out_param) {
+ if (out_param) {
if (f->ret_type.kind == TYPE_TUPLE) {
/* multiple return variables */
for (size_t i = 0; i < arr_len(f->ret_type.tuple); i++) {
@@ -480,7 +480,7 @@ static bool cgen_fn_header(CGenerator *g, FnExpr *f, Location where, I64 instanc
/*
Either set_expr or set_str should be NULL and either to_expr or to_str should be NULL
Also, set_str and/or to_str should be NULL
- this will call cgen_expr_pre for set_expr and to_expr
+ this DOES NOT call cgen_expr_pre for set_expr or to_expr
*/
static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, Expression *to_expr,
const char *to_str) {
@@ -489,12 +489,10 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E
if (set_expr) {
type = &set_expr->type;
where = set_expr->where;
- if (!cgen_expr_pre(g, set_expr)) return false;
} else {
assert(to_expr);
type = &to_expr->type;
where = to_expr->where;
- if (!cgen_expr_pre(g, to_expr)) return false;
}
type = type_inner(type);
switch (type->kind) {
@@ -562,7 +560,7 @@ static bool cgen_set(CGenerator *g, Expression *set_expr, const char *set_str, E
return true;
}
-/* one of exprs, idents, and prefix should be NULL. */
+/* one of exprs, idents, and prefix should be NULL. does NOT call cgen_expr_pre for to/exprs */
static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents, const char *prefix, Expression *to) {
IdentID prefix_id; /* ID of prefix for block */
switch (to->kind) {
@@ -614,7 +612,7 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents,
cgen_write(g, "&(%s%lu_)", prefix, i);
}
}
- cgen_writeln(g, ");");
+ cgen_writeln(g, "); ");
} break;
case EXPR_IF:
prefix_id = to->if_.c.id;
@@ -667,57 +665,6 @@ static bool cgen_set_tuple(CGenerator *g, Expression *exprs, Identifier *idents,
return true;
}
-/* generates the C code for new'ing a slice of array type t (e.g. [5]int) and putting it in the given ident id. */
-static bool cgen_new_slice(CGenerator *g, Type *t, IdentID id, Location where) {
- Expression *n_expr = t->arr.n_expr;
- assert(!(t->flags & TYPE_IS_RESOLVED)); /* we don't want this to be resolved, because the size might only be known at runtime. */
- if (!cgen_expr_pre(g, n_expr)) return false;
- cgen_write(g, "size_t s");
- cgen_ident_id(g, id);
- cgen_write(g, " = ");
- if (!cgen_expr(g, n_expr)) return false;
- cgen_write(g, "; slice_ ");
- cgen_ident_id(g, id);
- cgen_write(g, ";");
- cgen_ident_id(g, id);
- cgen_write(g, ".data = e__calloc(s");
- cgen_ident_id(g, id);
- cgen_write(g, ", sizeof(");
- if (t->arr.of->kind == TYPE_ARR) {
- cgen_write(g, "slice_");
- } else {
- if (!cgen_type_pre(g, t->arr.of, where))
- return false;
- if (!cgen_type_post(g, t->arr.of, where))
- return false;
- }
- cgen_write(g, ")); ");
- cgen_ident_id(g, id);
- cgen_write(g, ".n = s");
- cgen_ident_id(g, id);
- cgen_write(g, ";");
- if (t->arr.of->kind == TYPE_ARR) {
- /* slice of slices. initialize the inner slices. */
- IdentID child_id = g->ident_counter++;
- cgen_write(g, "for (i64 i_ = 0; i_ < s");
- cgen_ident_id(g, id);
- cgen_write(g, "; i_++) {");
- cgen_nl(g);
- g->indent_lvl++;
- if (!cgen_new_slice(g, t->arr.of, child_id, where))
- return false;
- cgen_write(g, " ((slice_*)");
- cgen_ident_id(g, id);
- cgen_write(g, ".data)[i_] = ");
- cgen_ident_id(g, child_id);
- cgen_write(g, ";");
- cgen_nl(g);
- g->indent_lvl--;
- cgen_write(g, "}");
- }
- return true;
-}
-
static bool cgen_expr_pre(CGenerator *g, Expression *e) {
IdentID id = 0;
char ret_name[64];
@@ -990,7 +937,8 @@ static bool cgen_expr_pre(CGenerator *g, Expression *e) {
}
i++;
}
- if (cgen_uses_ptr(&e->type)) {
+ if (cgen_uses_ptr(&e->type)
+ && e->type.kind != TYPE_TUPLE) {
e->call.c.id = g->ident_counter++;
if (!cgen_type_pre(g, &e->type, e->where)) return false;
cgen_write(g, " ");
@@ -1441,6 +1389,8 @@ static bool cgen_block(CGenerator *g, Block *b, const char *ret_name, U16 flags)
if (!cgen_stmt(g, s))
return false;
if (b->ret_expr && ret_name) {
+ if (!cgen_expr_pre(g, b->ret_expr))
+ return false;
if (b->ret_expr->type.kind == TYPE_TUPLE) {
if (!cgen_set_tuple(g, NULL, NULL, ret_name, b->ret_expr))
return false;
@@ -1529,12 +1479,34 @@ static bool cgen_fn(CGenerator *g, FnExpr *f, Location where, I64 instance, Valu
if (!cgen_block(g, &f->body, NULL, CGEN_BLOCK_NOENTER | CGEN_BLOCK_NOBRACES))
return false;
if (f->ret_decls) {
- if (cgen_uses_ptr(&f->ret_type)) {
+ /* OPTIM */
+
+ /* long-winded code to generate a return expression using the ret_decls. */
+ Expression ret_expr;
+ ret_expr.flags = EXPR_FOUND_TYPE;
+ ret_expr.type = f->ret_type;
+ if (arr_len(f->ret_decls) == 1
+ && arr_len(f->ret_decls[0].idents) == 1) {
+ ret_expr.kind = EXPR_IDENT;
+ ret_expr.ident = f->ret_decls[0].idents[0];
} else {
- cgen_write(g, "return ");
- cgen_ident(g, f->ret_decls[0].idents[0]);
- cgen_writeln(g, ";");
+ ret_expr.kind = EXPR_TUPLE;
+ ret_expr.tuple = NULL;
+ size_t i = 0;
+ arr_foreach(f->ret_decls, Declaration, d) {
+ arr_foreach(d->idents, Identifier, ident) {
+ Expression *element = arr_add(&ret_expr.tuple);
+ element->flags = EXPR_FOUND_TYPE;
+ element->kind = EXPR_IDENT;
+ element->type = f->ret_type.tuple[i];
+ element->ident = *ident;
+ i++;
+ }
+ }
}
+
+ if (!cgen_ret(g, &ret_expr))
+ return false;
} else if (f->body.ret_expr) {
if (!cgen_ret(g, f->body.ret_expr)) return false;
}
@@ -1668,28 +1640,12 @@ static bool cgen_decl(CGenerator *g, Declaration *d) {
Type *type = is_tuple ? &d->type.tuple[idx] : &d->type;
Value *val = is_tuple ? &d->val.tuple[idx] : &d->val;
if (type->kind == TYPE_TYPE) {
- /* mostly handled in typedefs_cgen, except for struct declarations */
- if (val->type->kind == TYPE_STRUCT) {
- cgen_write(g, "struct ");
- if (g->block == NULL)
- cgen_ident(g, i);
- else
- cgen_ident_id(g, d->c.ids[idx]);
- cgen_write(g, "{");
- cgen_nl(g);
- g->indent_lvl++;
- arr_foreach(val->type->struc.fields, Field, f) {
- if (!cgen_type_pre(g, f->type, d->where)) return false;
- cgen_write(g, " ");
- cgen_ident(g, f->name);
- if (!cgen_type_post(g, f->type, d->where)) return false;
- cgen_write(g, ";");
- cgen_nl(g);
- }
- g->indent_lvl--;
- cgen_write(g, "};");
- cgen_nl(g);
- }
+ /*
+ confusingly,
+ struct declarations are handled by typedefs_cgen,
+ and struct definitions are handled by decls_cgen.
+ we don't need to do anything here.
+ */
continue;
} else if (type->kind == TYPE_FN && (d->flags & DECL_IS_CONST)) {
/* don't generate function pointer declaration for constant fns */
@@ -1731,11 +1687,11 @@ static bool cgen_decl(CGenerator *g, Declaration *d) {
cgen_write(g, "; ");
}
if (has_expr) {
+ if (!cgen_expr_pre(g, &d->expr)) return false;
if (d->expr.type.kind == TYPE_TUPLE) {
if (!cgen_set_tuple(g, NULL, d->idents, NULL, &d->expr)) return false;
} else {
cgen_write(g, "{");
-
cgen_nl(g);
if (!cgen_type_pre(g, &d->type, d->expr.where)) return false;
cgen_write(g, " expr__");
@@ -1760,6 +1716,7 @@ static bool cgen_decl(CGenerator *g, Declaration *d) {
return true;
}
+/* does NOT call cgen_expr_pre for ret. */
static bool cgen_ret(CGenerator *g, Expression *ret) {
assert((g->fn->ret_type.kind == TYPE_VOID) == (ret == NULL));
if (!ret) {
@@ -1771,9 +1728,8 @@ static bool cgen_ret(CGenerator *g, Expression *ret) {
} else {
if (!cgen_set(g, NULL, "*ret_", ret, NULL)) return false;
}
- cgen_write(g, "return");
+ cgen_write(g, " return");
} else {
- if (!cgen_expr_pre(g, ret)) return false;
cgen_write(g, "return ");
if (!cgen_expr(g, ret)) return false;
@@ -1787,10 +1743,9 @@ static bool cgen_ret(CGenerator *g, Expression *ret) {
static bool cgen_stmt(CGenerator *g, Statement *s) {
/*
TODO(eventually): optionally this:
+ cgen_write(g, "/\* %s:%d *\/", s->where.ctx->filename, s->where.line);
+ (or even #line directives!)
*/
- // cgen_write(g, "/* %s:%d */", s->where.ctx->filename, s->where.line);
- /* (or even #line directives!) */
-
switch (s->kind) {
case STMT_DECL:
if (!cgen_decl(g, &s->decl)) return false;
@@ -1801,10 +1756,15 @@ static bool cgen_stmt(CGenerator *g, Statement *s) {
cgen_write(g, ";");
cgen_nl(g);
break;
- case STMT_RET:
- if (!cgen_ret(g, s->ret.flags & RET_HAS_EXPR ? &s->ret.expr : NULL))
+ case STMT_RET: {
+ unsigned has_expr = s->ret.flags & RET_HAS_EXPR;
+ if (has_expr) {
+ if (!cgen_expr_pre(g, &s->ret.expr))
+ return false;
+ }
+ if (!cgen_ret(g, has_expr ? &s->ret.expr : NULL))
return false;
- break;
+ } break;
}
return true;
}
diff --git a/decls_cgen.c b/decls_cgen.c
index 1a23a90..0e9fff3 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -4,7 +4,7 @@ static bool cgen_decls_block(CGenerator *g, Block *b);
static bool cgen_decls_expr(CGenerator *g, Expression *e) {
cgen_recurse_subexprs(g, e, cgen_decls_expr, cgen_decls_block);
switch (e->kind) {
- case EXPR_CALL:
+ case EXPR_CALL: {
e->call.c.instance = 0;
assert(e->call.fn->type.kind == TYPE_FN);
FnType *fn_type = &e->call.fn->type.fn;
@@ -53,7 +53,7 @@ static bool cgen_decls_expr(CGenerator *g, Expression *e) {
e->call.c.instance = (U32)instance_number;
}
}
- break;
+ } break;
case EXPR_FN:
e->fn.c.name = NULL;
if (!e->fn.c.id)
@@ -98,6 +98,37 @@ static bool cgen_decls_decl(CGenerator *g, Declaration *d) {
return false;
fn_exit(&d->expr.fn);
} else if (d->flags & DECL_HAS_EXPR) {
+ if (d->flags & DECL_IS_CONST) {
+ for (size_t idx = 0; idx < arr_len(d->idents); idx++) {
+ Identifier i = d->idents[idx];
+ Type *type = d->type.kind == TYPE_TUPLE ? &d->type.tuple[idx] : &d->type;
+ if (type->kind == TYPE_TYPE) {
+ Value *val = d->type.kind == TYPE_TUPLE ? &d->val.tuple[idx] : &d->val;
+ if (val->type->kind == TYPE_STRUCT) {
+ /* generate struct definition */
+ cgen_write(g, "struct ");
+ if (g->block == NULL)
+ cgen_ident(g, i);
+ else
+ cgen_ident_id(g, d->c.ids[idx]);
+ cgen_write(g, "{");
+ cgen_nl(g);
+ g->indent_lvl++;
+ arr_foreach(val->type->struc.fields, Field, f) {
+ if (!cgen_type_pre(g, f->type, d->where)) return false;
+ cgen_write(g, " ");
+ cgen_ident(g, f->name);
+ if (!cgen_type_post(g, f->type, d->where)) return false;
+ cgen_write(g, ";");
+ cgen_nl(g);
+ }
+ g->indent_lvl--;
+ cgen_write(g, "};");
+ cgen_nl(g);
+ }
+ }
+ }
+ }
if (!(d->flags & DECL_IS_CONST) || (d->expr.kind == EXPR_FN)) {
if (!cgen_decls_expr(g, &d->expr))
return false;
diff --git a/eval.c b/eval.c
index b09e41d..6aa5250 100644
--- a/eval.c
+++ b/eval.c
@@ -1526,8 +1526,8 @@ static bool eval_expr(Evaluator *ev, Expression *e, Value *v) {
}
static bool eval_decl(Evaluator *ev, Declaration *d) {
- int has_expr = d->flags & DECL_HAS_EXPR;
- int is_const = d->flags & DECL_IS_CONST;
+ unsigned has_expr = d->flags & DECL_HAS_EXPR;
+ unsigned is_const = d->flags & DECL_IS_CONST;
Value val = {0};
if (has_expr) {
diff --git a/identifiers.c b/identifiers.c
index cc9315f..b7f5e06 100644
--- a/identifiers.c
+++ b/identifiers.c
@@ -188,27 +188,6 @@ static int ident_index_in_decl(Identifier i, Declaration *d) {
return -1;
}
-static Type *ident_typeval(Identifier i) {
- Value *val;
- IdentDecl *idecl = ident_decl(i);
- if (!idecl) return NULL;
- Declaration *d = idecl->decl;
- if (!(d->flags & DECL_IS_CONST))
- return NULL;
- assert(d->flags & DECL_FOUND_TYPE);
- if (d->type.kind == TYPE_TUPLE) {
- size_t idx;
- for (idx = 0; idx < arr_len(d->idents); idx++) {
- if (d->idents[idx] == i)
- break;
- }
- assert(idx < arr_len(d->idents));
- val = &d->val.tuple[idx];
- } else val = &d->val;
-
- return val->type;
-}
-
static bool ident_eq_str(Identifier i, const char *s) {
const char *t = s + (strlen(s) - 1);
while (1) {
diff --git a/main.c b/main.c
index a7a0888..d39ee62 100644
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
/*
TODO:
-evaluate default arguments
-make sure they're only evaluated once
+memory leaks!
+deal with unused functions
compile time arguments + out parameters (in C)
double check that val_get_ptr is being used everywhere it should be
compile-time arguments for out parameter functions
@@ -12,7 +12,6 @@ struct parameters
don't allow while {3; 5} (once break is added)
any odd number of "s for a string
modifiable string literals
-unicode variable names (cgen support)
make sure futurely/currently-declared types are only used by pointer/slice
allow omission of trailing ; in foo @= fn() {}?
*/
@@ -127,7 +126,8 @@ int main(int argc, char **argv) {
free(contents);
allocr_free_all(&main_allocr);
-
+ evalr_free(&ev);
+
fclose(out);
/* fclose(h_out); */
idents_free(&file_idents);
diff --git a/parse.c b/parse.c
index cf67805..ddad492 100644
--- a/parse.c
+++ b/parse.c
@@ -622,7 +622,7 @@ static bool parser_is_definitely_type(Parser *p, Token **end) {
} else break;
}
} break;
- case KW_FN:
+ case KW_FN: {
ret = false;
t->token++;
if (!token_is_kw(t->token, KW_LPAREN)) {
@@ -643,14 +643,16 @@ static bool parser_is_definitely_type(Parser *p, Token **end) {
if (is_decl(t)) /* has return declaration */
goto end;
Type return_type;
- bool prev = t->token->where.ctx->enabled;
- t->token->where.ctx->enabled = false;
+ bool *enabled = &t->token->where.ctx->enabled;
+ bool prev_enabled = *enabled;
+ *enabled = false;
if (!parse_type(p, &return_type)) {
/* couldn't parse a return type. void fn type */
+ *enabled = prev_enabled;
ret = true;
goto end;
}
- t->token->where.ctx->enabled = prev;
+ *enabled = prev_enabled;
if (token_is_kw(t->token, KW_LBRACE)) {
/* non-void fn expr */
goto end;
@@ -664,7 +666,7 @@ static bool parser_is_definitely_type(Parser *p, Token **end) {
}
t->token++;
}
- break;
+ } break;
case KW_AMPERSAND:
t->token++; /* continue; see if next thing is definitely a type */
goto continu;
@@ -804,6 +806,12 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
f->ret_decls = NULL;
if (!parse_decl_list(p, &f->ret_decls, DECL_END_LBRACE_COMMA))
return false;
+ arr_foreach(f->ret_decls, Declaration, d) {
+ if (d->flags & DECL_IS_CONST) {
+ err_print(d->where, "Named return values cannot be constant.");
+ return false;
+ }
+ }
t->token--; /* move back to { */
if (arr_len(f->ret_decls) > 1 || arr_len(f->ret_decls[0].idents) > 1) {
f->ret_type.kind = TYPE_TUPLE;
diff --git a/test.toc b/test.toc
index dda957a..8181d0d 100644
--- a/test.toc
+++ b/test.toc
@@ -1,51 +1,28 @@
-
puti @= fn(x: int) {
#C("printf(\"%ld\\n\", (long)x);
");
};
-// putf @= fn(x: float) {
-// #C("printf(\"%f\\n\", (double)x);
-// ");
-// };
-
-
-// Foo @= struct {
-// x, y: int;
-// z: float;
-// };
-
-
-// bar @= fn() (f: Foo) {
-// f.x = 3;
-// f.y = 123;
-// f.z += 43.2;
-// };
-
-f @= fn(x @ int = 3+5) i: int {
- i = x;
+☃ @= struct {
+ x, y: int;
+ z: float;
};
-g @= fn(x, y : (int, int) = (3+5, 4+9)) i: int {
- i = x + y;
+something @= fn() int {
+ 5
};
+bar @= fn(a := something()) f: ☃, g: int {
+ f.x = a;
+ f.y = 123;
+ f.z += 43.2;
+ g = 17;
+};
main @= fn() {
- puti(f(313));
- puti(f(128));
- puti(f(231));
- puti(f(100+213));
- puti(f());
- puti(g());
-
+f,g := bar();
+puti(g);
+puti(f.x);
+puti(f.y);
+h,i := bar();
+puti(h.x);
};
-// b := bar();
-
-// f @= fn(x: int, y @ int) int { x + y };
-// puti(f(3,5));
-
-// puti(f(4, 5));
-// puti(f(3, 6));
-// puti((fn(x: int, y @ int) int { x + y })(1,2));
-// };
-
diff --git a/typedefs_cgen.c b/typedefs_cgen.c
index 08b582d..879eb2f 100644
--- a/typedefs_cgen.c
+++ b/typedefs_cgen.c
@@ -35,7 +35,20 @@ static bool typedefs_decl(CGenerator *g, Declaration *d) {
/* generate typedef */
IdentID id = 0;
if (g->block != NULL) id = d->c.ids[idx] = g->ident_counter++;
- if (val->type->kind == TYPE_STRUCT) continue; /* we don't need to typedef this; we can just use its tag */
+ if (val->type->kind == TYPE_STRUCT) {
+ /* we'll actually define the struct later; here we can just declare it */
+ cgen_write(g, "struct ");
+ if (g->block == NULL) {
+ /* we can refer to this by its name */
+ cgen_ident(g, i);
+ } else {
+ /* we need to use an ID ): */
+ cgen_ident_id(g, id);
+ }
+ cgen_write(g, ";");
+ cgen_nl(g);
+ continue;
+ }
cgen_write(g, "typedef ");
if (!cgen_type_pre(g, val->type, d->where)) return false;
cgen_write(g, " ");
diff --git a/types.c b/types.c
index dcfbfd8..ec90736 100644
--- a/types.c
+++ b/types.c
@@ -62,7 +62,7 @@ static bool type_eq(Type *a, Type *b) {
}
return true;
}
- case TYPE_TUPLE:
+ case TYPE_TUPLE: {
if (arr_len(a->tuple) != arr_len(b->tuple)) return false;
Type *a_types = a->tuple, *b_types = b->tuple;
for (size_t i = 0; i < arr_len(a->tuple); i++) {
@@ -70,6 +70,7 @@ static bool type_eq(Type *a, Type *b) {
return false;
}
return true;
+ }
case TYPE_ARR:
if (a->arr.n != b->arr.n) return false;
return type_eq(a->arr.of, b->arr.of);
@@ -255,13 +256,15 @@ static bool type_of_fn(Typer *tr, Expression *e, Type *t) {
}
}
if (decl->flags & DECL_HAS_EXPR) {
- Value val;
- if (!eval_expr(tr->evalr, &decl->expr, &val)) {
- info_print(decl->where, "Was trying to evaluate default arguments (which must be constants!)");
- return false;
+ if (decl->expr.kind != EXPR_VAL) {
+ Value val;
+ if (!eval_expr(tr->evalr, &decl->expr, &val)) {
+ info_print(decl->where, "Was trying to evaluate default arguments (which must be constants!)");
+ return false;
+ }
+ decl->expr.kind = EXPR_VAL;
+ decl->expr.val = val;
}
- decl->expr.kind = EXPR_VAL;
- decl->expr.val = val;
}
for (size_t i = 0; i < arr_len(decl->idents); i++) {
Type *param_type = typer_arr_add(tr, &t->fn.types);
@@ -614,22 +617,13 @@ static bool types_expr(Typer *tr, Expression *e) {
switch (e->kind) {
case EXPR_FN: {
e->fn.c.instances = NULL; /* maybe this should be handled by cgen... oh well */
- Type prev_ret_type = tr->ret_type;
- bool prev_can_ret = tr->can_ret;
+ FnExpr *prev_fn = tr->fn;
FnExpr *f = &e->fn;
if (!type_of_fn(tr, e, t)) {
success = false;
goto fn_ret;
}
- bool has_named_ret_vals = f->ret_decls != NULL;
- if (has_named_ret_vals) {
- /* set return type to void to not allow return values */
- tr->ret_type.kind = TYPE_VOID;
- tr->ret_type.flags = 0;
- } else {
- tr->ret_type = t->fn.types[0];
- }
- tr->can_ret = true;
+ tr->fn = f;
if (!fn_enter(f, SCOPE_CHECK_REDECL))
return false;
bool block_success = true;
@@ -642,6 +636,7 @@ static bool types_expr(Typer *tr, Expression *e) {
Expression *ret_expr = f->body.ret_expr;
assert(t->kind == TYPE_FN);
Type *ret_type = t->fn.types;
+ bool has_named_ret_vals = f->ret_decls != NULL;
if (ret_expr) {
if (!types_expr(tr, ret_expr)) {
success = false;
@@ -663,7 +658,8 @@ static bool types_expr(Typer *tr, Expression *e) {
if (last_stmt->kind == STMT_RET) {
/*
last statement is a return, so it doesn't matter that the function has no return value
- ideally this would handle if foo { return 5; } else { return 6; } */
+ ideally this would handle if foo { return 5; } else { return 6; }
+ */
success = true;
goto fn_ret;
}
@@ -677,8 +673,7 @@ static bool types_expr(Typer *tr, Expression *e) {
goto fn_ret;
}
fn_ret:
- tr->ret_type = prev_ret_type;
- tr->can_ret = prev_can_ret;
+ tr->fn = prev_fn;
if (!success) return false;
} break;
case EXPR_LITERAL_INT:
@@ -1567,7 +1562,7 @@ static bool types_decl(Typer *tr, Declaration *d) {
d->type = d->expr.type;
d->type.flags &= (uint16_t)~(uint16_t)TYPE_IS_FLEXIBLE; /* x := 5; => x is not flexible */
}
- if ((d->flags & DECL_IS_CONST) || tr->block == NULL) {
+ if ((d->flags & DECL_IS_CONST) || (tr->block == NULL && tr->fn == NULL)) {
if (!(d->flags & DECL_FOUND_VAL)) {
if (!eval_expr(tr->evalr, &d->expr, &d->val)) {
success = false;
@@ -1633,25 +1628,30 @@ static bool types_stmt(Typer *tr, Statement *s) {
return false;
break;
case STMT_RET:
- if (!tr->can_ret) {
+ if (!tr->fn) {
err_print(s->where, "return outside of a function.");
return false;
}
if (s->ret.flags & RET_HAS_EXPR) {
- if (tr->ret_type.kind == TYPE_VOID) {
- err_print(s->where, "Return value in function which should not return a value.");
+ if (tr->fn->ret_type.kind == TYPE_VOID) {
+ err_print(s->where, "Return value in a void function.");
+ return false;
+ }
+ if (tr->fn->ret_decls) {
+ err_print(s->where, "Return expression in a function with named return values.");
return false;
}
if (!types_expr(tr, &s->ret.expr))
return false;
- if (!type_eq(&tr->ret_type, &s->ret.expr.type)) {
+ if (!type_eq(&tr->fn->ret_type, &s->ret.expr.type)) {
char *got = type_to_str(&s->ret.expr.type);
- char *expected = type_to_str(&tr->ret_type);
+ char *expected = type_to_str(&tr->fn->ret_type);
err_print(s->where, "Returning type %s in function which returns %s.", got, expected);
return false;
}
} else {
- if (tr->ret_type.kind != TYPE_VOID) {
+ if (tr->fn->ret_type.kind != TYPE_VOID
+ && !tr->fn->ret_decls) {
err_print(s->where, "No return value in non-void function.");
return false;
}
@@ -1663,7 +1663,7 @@ static bool types_stmt(Typer *tr, Statement *s) {
static void typer_create(Typer *tr, Evaluator *ev, Allocator *allocr) {
tr->block = NULL;
- tr->can_ret = false;
+ tr->fn = NULL;
tr->evalr = ev;
tr->in_decls = NULL;
tr->in_expr_decls = NULL;
diff --git a/types.h b/types.h
index 152021a..3b0b3ba 100644
--- a/types.h
+++ b/types.h
@@ -3,8 +3,18 @@ typedef uint64_t UInteger;
typedef long double Floating; /* OPTIM: Switch to double, but make sure floating-point literals are right */
#if __STDC_VERSION__ < 201112
-/* assume long double has the strictest alignment */
-typedef long double max_align_t;
+/* try to find the type with the strictest alignment */
+typedef union {
+ long double floating;
+ void *ptr;
+ #if __STDC_VERSION__ >= 199901
+ long
+ #endif
+ long integer;
+ void (*fn_ptr)(void);
+} MaxAlign;
+#else
+typedef max_align_t MaxAlign;
#endif
#define INTEGER_MAX INT64_MAX
@@ -50,8 +60,8 @@ typedef struct {
typedef struct Page {
struct Page *next;
- size_t used; /* number of max_align_t's used, not bytes */
- max_align_t data[];
+ size_t used; /* number MaxAligns used, not bytes */
+ MaxAlign data[];
} Page;
typedef struct {
@@ -376,10 +386,10 @@ typedef enum {
EXPR_DALIGNOF,
EXPR_SLICE,
EXPR_TYPE,
- /* a value (it's useful to have this).
- USE WITH CAUTION
- expression values are never to be cgenerated! if cgen encounters one,
- it will assert(0)!
+ /*
+ a value (it's useful to have this).
+ right now they don't work with cgen_set_tuple
+ (as of yet, that is unneeded)
*/
EXPR_VAL
} ExprKind;
@@ -654,8 +664,7 @@ typedef struct Typer {
Expression **in_expr_decls; /* an array of expressions whose declarations (e.g. each **x := foo**) we are currently inside */
Declaration **in_decls; /* array of declarations we are currently inside */
Block *block;
- bool can_ret;
- Type ret_type; /* the return type of the function we're currently parsing. */
+ FnExpr *fn; /* the function we're currently parsing. */
} Typer;
typedef struct {