diff options
-rw-r--r-- | cgen.c | 285 | ||||
-rw-r--r-- | decls_cgen.c | 61 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | parse.c | 13 | ||||
-rw-r--r-- | test.toc | 74 | ||||
-rw-r--r-- | tests/types.toc | 23 | ||||
-rw-r--r-- | tests/types_expected | 2 | ||||
-rw-r--r-- | types.c | 11 |
8 files changed, 289 insertions, 182 deletions
@@ -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) { @@ -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) @@ -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); +} @@ -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 @@ -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; } + + |