summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-05-13 11:59:35 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2020-05-13 11:59:35 -0400
commit2804529f75b149b579eb0f724358d519935ff08a (patch)
tree53d5826a4bdc7ee412ee4d1b045b92d07cb474e4
parentc466d81a2423d7122d7a0cbdc8059e69e88899f2 (diff)
fixed some problems with cgen_recurse_stuff
-rw-r--r--cgen.c285
-rw-r--r--decls_cgen.c61
-rw-r--r--main.c2
-rw-r--r--parse.c13
-rw-r--r--test.toc74
-rw-r--r--tests/types.toc23
-rw-r--r--tests/types_expected2
-rw-r--r--types.c11
8 files changed, 289 insertions, 182 deletions
diff --git a/cgen.c b/cgen.c
index 4702226..6a63eba 100644
--- a/cgen.c
+++ b/cgen.c
@@ -36,145 +36,159 @@ static void cgen_val_ptr(CGenerator *g, void *v, Type *t);
static void cgen_defs_block(CGenerator *g, Block *b);
static void cgen_defs_decl(CGenerator *g, Declaration *d);
-#define cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f) \
- if (!(fn->flags & FN_EXPR_FOREIGN)) { \
- FnExpr *prev_fn = g->f##n; \
- Block *prev_block = g->block; \
- g->f##n = fn; \
- g->block = &fn->body; \
- arr_foreach(fn->params, Declaration, param) \
- decl_f(g, param); \
- arr_foreach(fn->ret_decls, Declaration, r) \
- decl_f(g, r); \
- block_f(g, &fn->body); \
- g->f##n = prev_fn; \
- g->block = prev_block; \
+#define cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f, type_f) \
+ if (!(fn->flags & FN_EXPR_FOREIGN)) { \
+ FnExpr *prev_fn = g->f##n; \
+ Block *prev_block = g->block; \
+ g->f##n = fn; \
+ g->block = &fn->body; \
+ arr_foreach(fn->params, Declaration, param) \
+ decl_f(g, param); \
+ if (fn->ret_decls) { \
+ arr_foreach(fn->ret_decls, Declaration, r) \
+ decl_f(g, r); \
+ } else { \
+ type_f(g, &fn->ret_type); \
+ } \
+ block_f(g, &fn->body); \
+ g->f##n = prev_fn; \
+ g->block = prev_block; \
}
/* calls f on every sub-expression of e, block_f on every sub-block, type_f on every type, and decl_f on every sub-declaration. */
-#define cgen_recurse_subexprs(g, e, f, block_f, decl_f, type_f) \
- switch (e->kind) { \
- case EXPR_VAL: \
- case EXPR_C: \
- case EXPR_BUILTIN: \
- case EXPR_IDENT: \
- case EXPR_LITERAL_BOOL: \
- case EXPR_LITERAL_INT: \
- case EXPR_LITERAL_STR: \
- case EXPR_LITERAL_CHAR: \
- case EXPR_LITERAL_FLOAT: \
+#define cgen_recurse_subexprs(g, e, f, block_f, decl_f, type_f) \
+ switch (e->kind) { \
+ case EXPR_VAL: \
+ case EXPR_C: \
+ case EXPR_BUILTIN: \
+ case EXPR_IDENT: \
+ case EXPR_LITERAL_BOOL: \
+ case EXPR_LITERAL_INT: \
+ case EXPR_LITERAL_STR: \
+ case EXPR_LITERAL_CHAR: \
+ case EXPR_LITERAL_FLOAT: \
break; \
- case EXPR_TYPE: \
+ case EXPR_TYPE: \
type_f(g, e->typeval); \
- break; \
- case EXPR_UNARY_OP: \
- f(g, e->unary.of); \
- break; \
- case EXPR_BINARY_OP: \
- f(g, e->binary.lhs); \
- if (e->binary.op != BINARY_DOT) \
- f(g, e->binary.rhs); \
- break; \
- case EXPR_CAST: \
- f(g, e->cast.expr); \
+ break; \
+ case EXPR_UNARY_OP: \
+ f(g, e->unary.of); \
+ break; \
+ case EXPR_BINARY_OP: \
+ f(g, e->binary.lhs); \
+ if (e->binary.op != BINARY_DOT) \
+ f(g, e->binary.rhs); \
+ break; \
+ case EXPR_CAST: \
+ f(g, e->cast.expr); \
type_f(g, &e->cast.type); \
- break; \
- case EXPR_CALL: \
- f(g, e->call.fn); \
- arr_foreach(e->call.arg_exprs, Expression, arg) \
- f(g, arg); \
- break; \
- case EXPR_BLOCK: \
- block_f(g, e->block); \
- break; \
- case EXPR_NMS: { \
- Namespace *prev = g->nms; \
- g->nms = e->nms; \
- block_f(g, &e->nms->body); \
- g->nms = prev; \
- } break; \
- case EXPR_IF: { \
- IfExpr *i = e->if_; \
- if (i->cond) \
- f(g, i->cond); \
- block_f(g, &i->body); \
- if (i->next_elif) \
- f(g, i->next_elif); \
- } break; \
- case EXPR_WHILE: { \
- WhileExpr *w = e->while_; \
- f(g, w->cond); \
- block_f(g, &w->body); \
- } break; \
- case EXPR_FOR: { \
- ForExpr *fo = e->for_; \
- if (fo->flags & FOR_IS_RANGE) { \
- f(g, fo->range.from); \
- if (fo->range.to) f(g, fo->range.to); \
- /* step is a value, not an expression */ \
- } else { \
- f(g, fo->of); \
- } \
- block_f(g, &fo->body); \
- } break; \
- case EXPR_TUPLE: \
- arr_foreach(e->tuple, Expression, x) \
- f(g, x); \
- break; \
- case EXPR_SLICE: \
- f(g, e->slice.of); \
- if (e->slice.from) f(g, e->slice.from); \
- if (e->slice.to) f(g, e->slice.to); \
- break; \
- case EXPR_FN: { \
- FnExpr *fn = e->fn; \
- if (fn_has_instances(fn)) { \
- Instance **data = fn->instances->data; \
- for (U64 i = 0; i < fn->instances->cap; ++i) { \
- if (fn->instances->occupied[i]) { \
- cgen_recurse_subexprs_fn_simple(((*data)->fn), decl_f, block_f); \
- } \
- ++data; \
- } \
- } else { \
- cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f); \
- } \
- } break; \
+ break; \
+ case EXPR_CALL: \
+ f(g, e->call.fn); \
+ arr_foreach(e->call.arg_exprs, Expression, arg) \
+ f(g, arg); \
+ break; \
+ case EXPR_BLOCK: \
+ block_f(g, e->block); \
+ break; \
+ case EXPR_NMS: { \
+ Namespace *prev = g->nms; \
+ g->nms = e->nms; \
+ block_f(g, &e->nms->body); \
+ g->nms = prev; \
+ } break; \
+ case EXPR_IF: { \
+ IfExpr *i = e->if_; \
+ if (i->cond) \
+ f(g, i->cond); \
+ block_f(g, &i->body); \
+ if (i->next_elif) \
+ f(g, i->next_elif); \
+ } break; \
+ case EXPR_WHILE: { \
+ WhileExpr *w = e->while_; \
+ f(g, w->cond); \
+ block_f(g, &w->body); \
+ } break; \
+ case EXPR_FOR: { \
+ ForExpr *fo = e->for_; \
+ if (fo->flags & FOR_IS_RANGE) { \
+ f(g, fo->range.from); \
+ if (fo->range.to) f(g, fo->range.to); \
+ /* step is a value, not an expression */ \
+ } else { \
+ f(g, fo->of); \
+ } \
+ block_f(g, &fo->body); \
+ } break; \
+ case EXPR_TUPLE: \
+ arr_foreach(e->tuple, Expression, x) \
+ f(g, x); \
+ break; \
+ case EXPR_SLICE: \
+ f(g, e->slice.of); \
+ if (e->slice.from) f(g, e->slice.from); \
+ if (e->slice.to) f(g, e->slice.to); \
+ break; \
+ case EXPR_FN: { \
+ FnExpr *fn = e->fn; \
+ if (fn_has_instances(fn)) { \
+ Instance **data = fn->instances->data; \
+ for (U64 i = 0; i < fn->instances->cap; ++i) { \
+ if (fn->instances->occupied[i]) { \
+ cgen_recurse_subexprs_fn_simple(((*data)->fn), decl_f, block_f, type_f); \
+ } \
+ ++data; \
+ } \
+ } else { \
+ cgen_recurse_subexprs_fn_simple(fn, decl_f, block_f, type_f); \
+ } \
+ } break; \
}
-
-#define cgen_recurse_subtypes(g, type, f) \
- switch (type->kind) { \
- case TYPE_STRUCT: \
- /* don't descend into fields */ \
- break; \
- case TYPE_FN: \
+#include <signal.h>
+
+#define cgen_recurse_subtypes(g, type, f, decl_f, block_f, struct_flag) \
+ switch (type->kind) { \
+ case TYPE_STRUCT: { \
+ StructDef *struc = type->struc; \
+ if (!(struc->flags & struct_flag)) { \
+ struc->flags |= struct_flag; \
+ if (struc->params) { \
+ if (struct_is_template(struc)) break; \
+ arr_foreach(struc->params, Declaration, param) \
+ decl_f(g, param); \
+ } \
+ block_f(g, &struc->body); \
+ } \
+ } break; \
+ case TYPE_FN: \
if (type->kind == TYPE_FN && (type->fn.constness || fn_type_has_varargs(&type->fn))) { \
- /* we don't want to do this, because it's a template-y thing */ \
- } \
- else { \
- arr_foreach(type->fn.types, Type, sub) { \
- f(g, sub); \
- } \
- } \
- break; \
- case TYPE_TUPLE: \
- arr_foreach(type->tuple, Type, sub) \
- f(g, sub); \
- break; \
- case TYPE_ARR: \
- f(g, type->arr.of); \
- break; \
- case TYPE_SLICE: \
- f(g, type->slice); \
- break; \
- case TYPE_PTR: \
- f(g, type->ptr); \
- break; \
- case TYPE_BUILTIN: \
- case TYPE_UNKNOWN: \
- break; \
- case TYPE_EXPR: assert(0); \
+ /* we don't want to do this, because it's a template-y thing */ \
+ } \
+ else { \
+ arr_foreach(type->fn.types, Type, sub) { \
+ f(g, sub); \
+ } \
+ } \
+ break; \
+ case TYPE_TUPLE: \
+ arr_foreach(type->tuple, Type, sub) \
+ f(g, sub); \
+ break; \
+ case TYPE_ARR: \
+ f(g, type->arr.of); \
+ break; \
+ case TYPE_SLICE: \
+ f(g, type->slice); \
+ break; \
+ case TYPE_PTR: \
+ f(g, type->ptr); \
+ break; \
+ case TYPE_BUILTIN: \
+ case TYPE_UNKNOWN: \
+ break; \
+ case TYPE_EXPR: assert(0); \
}
@@ -2168,14 +2182,7 @@ static void cgen_stmt(CGenerator *g, Statement *s) {
}
static void cgen_defs_type(CGenerator *g, Type *t) {
- if (t->kind == TYPE_STRUCT) {
- StructDef *sdef = t->struc;
- if (!(sdef->flags & STRUCT_DEF_CGEN_FN_DEFS)) {
- sdef->flags |= STRUCT_DEF_CGEN_FN_DEFS;
- cgen_defs_block(g, &sdef->body);
- }
- }
- cgen_recurse_subtypes(g, t, cgen_defs_type);
+ cgen_recurse_subtypes(g, t, cgen_defs_type, cgen_defs_decl, cgen_defs_block, STRUCT_DEF_CGEN_FN_DEFS);
}
static void cgen_defs_fn(CGenerator *g, FnExpr *f) {
@@ -2205,6 +2212,8 @@ static void cgen_defs_decl(CGenerator *g, Declaration *d) {
if (d->flags & DECL_HAS_EXPR) {
cgen_defs_expr(g, &d->expr);
}
+ if (d->flags & DECL_ANNOTATES_TYPE)
+ cgen_defs_type(g, &d->type); /* we only need to do this if d has an annotated type, because otherwise we've already generated the defs for that type (because it can't be a new type) */
}
diff --git a/decls_cgen.c b/decls_cgen.c
index 896c287..67e6a80 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -30,7 +30,6 @@ static void cgen_sdecls_type(CGenerator *g, Type *type) {
/* we'll actually define the struct later; here we can just declare it */
if ((sdef->flags & STRUCT_DEF_RESOLVED) && !(sdef->flags & STRUCT_DEF_CGEN_DECLARED)) {
- sdef->flags |= STRUCT_DEF_CGEN_DECLARED;
cgen_write(g, "struct ");
if (!sdef->name) {
sdef->c.id = ++g->ident_counter;
@@ -38,10 +37,10 @@ static void cgen_sdecls_type(CGenerator *g, Type *type) {
cgen_struct_name(g, sdef);
cgen_write(g, ";");
cgen_nl(g);
- cgen_sdecls_block(g, &sdef->body);
+ /* we don't need to set the STRUCT_DEF_CGEN_DECLARED flag; that's done in cgen_recurse_subtypes */
}
}
- cgen_recurse_subtypes(g, type, cgen_sdecls_type);
+ cgen_recurse_subtypes(g, type, cgen_sdecls_type, cgen_sdecls_decl, cgen_sdecls_block, STRUCT_DEF_CGEN_DECLARED);
}
static char *cgen_nms_prefix_part(CGenerator *g, Namespace *n) {
@@ -168,32 +167,44 @@ static void cgen_sdecls_file(CGenerator *g, ParsedFile *f) {
}
static void cgen_decls_type(CGenerator *g, Type *type) {
- if (type->kind == TYPE_STRUCT) {
+ /* this check needs to go before cgen_recurse_subtypes, because that sets the STRUCT_DEF_CGEN_DEFINED flag */
+ bool need_to_generate_struct_definition = type->kind == TYPE_STRUCT && !(type->struc->flags & STRUCT_DEF_CGEN_DEFINED)
+ && !struct_is_template(type->struc);
+ /*
+ this has to go BEFORE defining the struct, so that if it has struct fields, they're defined before it is,
+ because
+ struct Foo;
+ struct Bar {
+ struct Foo f;
+ }
+ struct Foo {
+ int x;
+ }
+ does not work in C
+ */
+ cgen_recurse_subtypes(g, type, cgen_decls_type, cgen_decls_decl, cgen_decls_block, STRUCT_DEF_CGEN_DEFINED);
+
+ if (need_to_generate_struct_definition) {
StructDef *sdef = type->struc;
- if ((sdef->flags & STRUCT_DEF_RESOLVED) && !(sdef->flags & STRUCT_DEF_CGEN_DEFINED)) {
- sdef->flags |= STRUCT_DEF_CGEN_DEFINED;
- /* generate struct definition */
- cgen_write(g, "struct ");
- cgen_struct_name(g, sdef);
- cgen_write(g, "{");
- cgen_nl(g);
- ++g->indent_lvl;
- arr_foreach(sdef->fields, Field, f) {
- cgen_type_pre(g, f->type);
- cgen_write(g, " ");
- cgen_ident_simple(g, f->name);
- cgen_type_post(g, f->type);
- cgen_write(g, ";");
- cgen_nl(g);
- }
- --g->indent_lvl;
- cgen_write(g, "};");
+ /* generate struct definition */
+ cgen_write(g, "struct ");
+ cgen_struct_name(g, sdef);
+ cgen_write(g, "{");
+ cgen_nl(g);
+ ++g->indent_lvl;
+ arr_foreach(sdef->fields, Field, f) {
+ cgen_type_pre(g, f->type);
+ cgen_write(g, " ");
+ cgen_ident_simple(g, f->name);
+ cgen_type_post(g, f->type);
+ cgen_write(g, ";");
cgen_nl(g);
- cgen_decls_block(g, &sdef->body);
}
-
+ --g->indent_lvl;
+ cgen_write(g, "};");
+ cgen_nl(g);
+ /* we don't need to set the STRUCT_DEF_CGEN_DEFINED flag; that's done in cgen_recurse_subtypes */
}
- cgen_recurse_subtypes(g, type, cgen_decls_type);
}
static void cgen_single_fn_decl(CGenerator *g, FnExpr *f, U64 which_are_const) {
diff --git a/main.c b/main.c
index 15d8862..0c8bd0b 100644
--- a/main.c
+++ b/main.c
@@ -8,8 +8,6 @@
/*
@TODO:
-test #include inside a struct
-cgen_recurse_subtypes should go inside struct params. maybe it could also go into the body?
get rid of UNARY_LEN?
detect circular declarations (A ::= B; B ::= A)
either detect circular #includes or set a #include depth limit (maybe sometimes you want finite circular includes with #if)
diff --git a/parse.c b/parse.c
index 4ba2af2..2add2cb 100644
--- a/parse.c
+++ b/parse.c
@@ -1324,13 +1324,16 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
case KW_FN: {
/* this is a function */
e->kind = EXPR_FN;
+ Token *fn_start = t->token;
if (!parse_fn_expr(p, e->fn = parser_calloc(p, 1, sizeof *e->fn)))
return false;
if (t->token != end) {
- if (token_is_kw(t->token, KW_LPAREN))
+ if (token_is_kw(t->token, KW_LPAREN)) {
tokr_err(t, "Direct function calling in an expression is not supported.\nYou can wrap the function in parentheses.");
- else
- tokr_err(t, "Expected end of function (did you forget a semicolon?).");
+ } else {
+ tokr_err(t, "Expected end of function.");
+ info_print(token_location(p->file, fn_start), "Note that if there is an opening brace { in the return type, you need to put the type in parentheses ().");
+ }
return false;
}
goto success;
@@ -3067,3 +3070,7 @@ char *location_to_str(Location *where) {
*end = tmp;
return str_dup(buf);
}
+
+static inline bool struct_is_template(StructDef *s) {
+ return s->params && !(s->params[0].flags & DECL_FOUND_VAL);
+}
diff --git a/test.toc b/test.toc
index 53a092c..af1c2fd 100644
--- a/test.toc
+++ b/test.toc
@@ -1,14 +1,70 @@
-Point ::= struct {
- #if 1 {
- #include "point.toc";
- } else {
- z: int;
+#include "tests/std/io.toc", io;
+#include "std/mem.toc";
+
+
+z ::= nms {
+ Foo ::= struct(f ::= fn() int { 7 }) {
+ x: int;
+ }
+
+ Bar ::= fn() &(struct { x, y: int; f ::= fn() int { 13 } } ) {
+ x : u64;
+ &x as &void
+ }
+
+
+ foo ::= fn() total : int = 0 {
+ f: Foo();
+ total += f.f();
+ total += Bar().f();
}
}
main ::= fn() {
- p : Point;
- p.x;
- p.y;
- p.z;
+ nums := news(int, 10);
+ for x, i := &nums {
+ *x = i*i;
+ }
+ l := slice_to_ll(nums);
+ p := &l;
+ while p {
+ io.puti(p.head);
+ p = p.tail;
+ }
+ f: Foo;
+ f.k = -173;
+ f.b = new(Bar);
+ f.b.f.b = new(Bar);
+ f.b.f.b.f.k = 9;
+ io.puti(f.k);
+ io.puti(f.b.f.k);
+ io.puti(f.b.f.b.f.k);
+ x := z.foo();
+ y ::= z.foo();
+ io.puti(x);
+ io.puti(y);
+}
+
+slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) {
+ head = slice[0];
+ if slice.len == 1 {
+ tail = null;
+ } else {
+ tail = new(LinkedList(t));
+ *tail = slice_to_ll(slice[1:]);
+ }
+}
+
+LinkedList ::= struct (of :: Type) {
+ head: of;
+ tail: &LinkedList(of);
+}
+
+Foo ::= struct {
+ k: int;
+ b: &Bar;
+}
+
+Bar ::= struct {
+ f: Foo;
}
diff --git a/tests/types.toc b/tests/types.toc
index 5117906..31d6962 100644
--- a/tests/types.toc
+++ b/tests/types.toc
@@ -20,6 +20,10 @@ main ::= fn() {
io.puti(f.k);
io.puti(f.b.f.k);
io.puti(f.b.f.b.f.k);
+ x := z.foo();
+ y ::= z.foo();
+ io.puti(x);
+ io.puti(y);
}
slice_to_ll ::= fn(t::=, slice: []t) use ll: LinkedList(t) {
@@ -45,3 +49,22 @@ Foo ::= struct {
Bar ::= struct {
f: Foo;
}
+
+z ::= nms {
+ Foo ::= struct(f ::= fn() int { 7 }) {
+ x: int;
+ }
+
+ Bar ::= fn() &(struct { x, y: int; f ::= fn() int { 13 } } ) {
+ x : u64;
+ &x as &void
+ }
+
+
+ foo ::= fn() total : int = 0 {
+ f: Foo();
+ total += f.f();
+ total += Bar().f();
+ }
+}
+
diff --git a/tests/types_expected b/tests/types_expected
index eef051c..f2d60e0 100644
--- a/tests/types_expected
+++ b/tests/types_expected
@@ -11,3 +11,5 @@
-173
0
9
+20
+20
diff --git a/types.c b/types.c
index e65207e..afc69e4 100644
--- a/types.c
+++ b/types.c
@@ -965,10 +965,9 @@ static Status type_resolve(Typer *tr, Type *t, Location where) {
return false;
*t = *typeval.type;
if (t->kind == TYPE_STRUCT) {
- Declaration *params = t->struc->params;
- if (params && !(params[0].flags & DECL_FOUND_VAL)) {
- err_print(where, "Expected arguments to structure, but you didn't provide any.");
- info_print(t->struc->where, "Structure was declared here.");
+ if (struct_is_template(t->struc)) {
+ err_print(where, "Expected arguments to struct, but you didn't provide any.");
+ info_print(t->struc->where, "struct was declared here.");
return false;
}
}
@@ -3428,7 +3427,7 @@ static Status types_decl(Typer *tr, Declaration *d) {
size_t n_idents; n_idents = arr_len(d->idents);
if (e) {
- if (e->kind == EXPR_FN && tr->block && tr->block->kind == BLOCK_STRUCT) {
+ if (e->kind == EXPR_FN && tr->block && tr->block->kind == BLOCK_STRUCT && !tr->in_decls /* don't include params */) {
warn_print(d->where, "This function is in the body of a struct. Are you trying to declare a method, because they don't exist in this language.\n"
"Try moving the function outside of the struct, otherwise you might run into problems.");
}
@@ -4003,3 +4002,5 @@ static Status types_file(Typer *tr, ParsedFile *f) {
assert(arr_len(tr->blocks) && tr->blocks[0] == NULL);
return ret;
}
+
+