diff options
author | Leo Tenenbaum <pommicket@gmail.com> | 2020-05-02 14:39:51 -0400 |
---|---|---|
committer | Leo Tenenbaum <pommicket@gmail.com> | 2020-05-02 14:39:51 -0400 |
commit | 41c0e26f48c80835afe962c8c6a64d4cc7c18b13 (patch) | |
tree | 76873cca22420c556daa52dc1df48c369d242e77 | |
parent | f9d970a0535ec3ae4aaff6842788a89b139cfdaa (diff) |
fixed including something multiple times
-rw-r--r-- | cgen.c | 5 | ||||
-rw-r--r-- | decls_cgen.c | 3 | ||||
-rw-r--r-- | development.md | 3 | ||||
-rw-r--r-- | eval.c | 7 | ||||
-rw-r--r-- | main.c | 34 | ||||
-rw-r--r-- | parse.c | 14 | ||||
-rw-r--r-- | test.toc | 30 | ||||
-rw-r--r-- | tests/include.toc | 16 | ||||
-rw-r--r-- | tests/include_expected | 7 | ||||
-rw-r--r-- | tests/included.toc | 5 | ||||
-rwxr-xr-x | tests/test.sh | 1 | ||||
-rw-r--r-- | types.c | 62 | ||||
-rw-r--r-- | types.h | 7 |
13 files changed, 120 insertions, 74 deletions
@@ -1386,11 +1386,6 @@ static void cgen_expr(CGenerator *g, Expression *e) { bool is_ptr = lhs->type.kind == TYPE_PTR; cgen_write(g, is_ptr ? "->" :"."); cgen_write(g, "data"); - } else { - assert(type_is_builtin(struct_type, BUILTIN_NMS)); - char *prefix = lhs->val.nms->c.prefix; - cgen_write(g, "%s", prefix); - cgen_ident_simple(g, rhs->ident); } handled = true; } break; diff --git a/decls_cgen.c b/decls_cgen.c index 5b2603b..331d179 100644 --- a/decls_cgen.c +++ b/decls_cgen.c @@ -45,9 +45,6 @@ static void cgen_sdecls_block(CGenerator *g, Block *b) { static char *cgen_nms_prefix_part(CGenerator *g, Namespace *n) { char *s; - while (n->points_to) { - n = n->points_to; - } if (n->associated_ident) { size_t ident_len = n->associated_ident->len; s = malloc(ident_len + 3); diff --git a/development.md b/development.md index 255c09a..6795987 100644 --- a/development.md +++ b/development.md @@ -22,6 +22,9 @@ Functions which can fail (i.e. print an error message and stop) return a Status, which is a bool, but GCC/clang warns about not using the return value. Almost all of toc's types are defined in types.h. +Sometimes a type ending in Ptr is defined, e.g. typedef Declaration \*DeclarationPtr. This is +for the arr\_foreach macro, and not meant for normal use. + The fixed-width types U8/16/32/64 and I8/16/32/64 have been defined. data\_structures.c contains a dynamic array implementation which is very useful. @@ -747,13 +747,6 @@ static Status eval_ptr_to_struct_field(Evaluator *ev, Expression *dot_expr, void return false; /* access struct data */ *p = &((Slice *)ptr)->data; - } else { - void *ptr; - Identifier ident = dot_expr->binary.rhs->ident; - assert(type_is_builtin(struct_type, BUILTIN_NMS)); - if (!eval_address_of_ident(ev, ident, dot_expr->where, &dot_expr->type, &ptr)) - return false; - *p = ptr; } return true; } @@ -8,8 +8,10 @@ /* @TODO: -fix including something twice - just use the non-namespacey version if it exists or pick one namespace to use everywhere otherwise - - maybe store info about namespaces which are secretly the same as inline blocks/other namespaces in the Typer +#foreign non-functions (e.g. stderr) +remove some now-unnecessary #builtins (all are unnecessary except for "compiling", + which probably isn't even that useful but maybe more builtins will exist in + the future) &&, || #no_warn start making a standard library... (printf; stringbuilder would be nice to have) @@ -21,6 +23,7 @@ switch enums unions --- +either detect circular #includes or set a #include limit (maybe sometimes you want finite circular includes with #if) switch to / add as an alternative: libffi - better yet, inline assembly don't bother generating ret_ if nothing's deferred @@ -29,6 +32,7 @@ any odd number of "s for a string use point #except x; optional -Wshadow format errors so that vim/emacs can jump to them +show include stack--especially for redeclarations with #include #force --- make sure that floating point literals are as exact as possible have some way of doing Infinity and s/qNaN (you can @@ -72,8 +76,20 @@ static void signal_handler(int num) { case SIGSEGV: fprintf(stderr, "Segmentation fault.\n"); break; + case SIGFPE: + fprintf(stderr, "Floating point exception.\n"); + break; + case SIGINT: + fprintf(stderr, "Interrupted.\n"); + break; + case SIGTERM: + fprintf(stderr, "Terminated.\n"); + break; + case SIGILL: + fprintf(stderr, "Illegal instruction.\n"); + break; default: - fprintf(stderr, "Terminated for unknown reason.\n"); + fprintf(stderr, "Terminated for unknown reason (signal %d).\n", num); break; } fprintf(stderr, "Stack trace:\n"); @@ -91,7 +107,8 @@ static void signal_handler(int num) { } system(command); /* free(syms); */ - + signal(SIGABRT, SIG_DFL); + abort(); } #endif int main(int argc, char **argv) { @@ -99,12 +116,15 @@ int main(int argc, char **argv) { program_name = argv[0]; signal(SIGABRT, signal_handler); signal(SIGSEGV, signal_handler); + signal(SIGINT, signal_handler); + signal(SIGTERM, signal_handler); + signal(SIGILL, signal_handler); + signal(SIGFPE, signal_handler); #endif #if RUN_TESTS printf("running tests...\n"); test_all(); #endif - const char *in_filename = NULL; const char *out_filename = "out.c"; @@ -116,7 +136,7 @@ int main(int argc, char **argv) { #if UNISTD_AVAILABLE #if defined _POSIX_VERSION && _POSIX_VERSION >= 200112L /* isatty available */ - default_color_enabled = isatty(2); /* is /dev/stderr a tty? */ + default_color_enabled = (bool)isatty(2); /* is /dev/stderr a tty? */ #else default_color_enabled = false; /* old posix version */ #endif @@ -124,7 +144,7 @@ int main(int argc, char **argv) { default_color_enabled = false; /* probably windows */ #endif err_ctx.color_enabled = default_color_enabled; - + for (int i = 1; i < argc; ++i) { char *arg = argv[i]; if (strs_equal(arg, "-no-color")) { @@ -2471,16 +2471,10 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) { idents_create(&body->idents, p->allocr, body); Statement *inc_stmt = parser_arr_add_ptr(p, body->stmts); inc_stmt->kind = STMT_INCLUDE; - inc_stmt->flags = STMT_INC_TO_NMS; + inc_stmt->flags = 0; inc_stmt->where = body->where; inc_stmt->inc = parser_calloc(p, 1, sizeof *inc_stmt->inc); inc_stmt->inc->filename = filename; - } else if (i->flags & INC_FORCED) { - /* go back to #forced */ - while (!token_is_direct(t->token, DIRECT_FORCE)) --t->token; - err_print(token_location(p->file, t->token), "You don't need to specify #force if you're not including into a namespace (this is the default behaviour)."); - tokr_skip_semicolon(t); - return false; } if (!token_is_kw(t->token, KW_SEMICOLON)) { tokr_err(t, "Expected ; after #include directive"); @@ -2940,7 +2934,11 @@ static void fprint_parsed_file(FILE *out, ParsedFile *f) { static int decl_ident_index(Declaration *d, Identifier i) { int idx = 0; arr_foreach(d->idents, Identifier, j) { - if (i == *j) + /* this can't just be i == *j because sometimes identifiers point to declarations which don't declare + **that specific identifier** - e.g. including something twice makes one identifier point to the + declaration in the other include + */ + if (ident_eq(i, *j)) return idx; ++idx; } @@ -1,33 +1,5 @@ #include "std/io.toc"; -#include "std/mem.toc"; - -ptr_arithmetic_test ::= fn() total := 0 { - foo := news(int, 10); - for p, i := &foo { - *p = i; - } - p := &foo[0]; - - p += 2; - total += *p; - total += *(p + 3); - total += *(p - 1); - - voidp : &void = &foo[7]; - total += *(voidp as &int); - voidp = voidp + 8; - total += *(voidp as &int); - voidp += 8; - total += *(voidp as &int); - voidp = voidp - 8; - total += *(voidp as &int); - voidp -= 8; - total += *(voidp as &int); -} main ::= fn() { - x ::= ptr_arithmetic_test(); - y := ptr_arithmetic_test(); - puti(x); - puti(y); + puts("hello"); } diff --git a/tests/include.toc b/tests/include.toc new file mode 100644 index 0000000..dee6c16 --- /dev/null +++ b/tests/include.toc @@ -0,0 +1,16 @@ +#include "std/io.toc", io; +#include "std/io.toc", foo; +#include "std/io.toc", bar; +#include "std/io.toc", baz; +#include "std/io.toc"; +#include "included.toc", inc; + +main ::= fn() { + puts("hello"); + io.puts("hello"); + foo.puts("hello"); + bar.puts("hello"); + baz.puts("hello"); + inc.puts("hello"); + inc.foo.puts("hello"); +} diff --git a/tests/include_expected b/tests/include_expected new file mode 100644 index 0000000..5b04198 --- /dev/null +++ b/tests/include_expected @@ -0,0 +1,7 @@ +hello +hello +hello +hello +hello +hello +hello diff --git a/tests/included.toc b/tests/included.toc new file mode 100644 index 0000000..548a3e5 --- /dev/null +++ b/tests/included.toc @@ -0,0 +1,5 @@ +// included by include.toc + +#include "std/io.toc"; +#include "std/io.toc", foo; + diff --git a/tests/test.sh b/tests/test.sh index bf58042..1d01f06 100755 --- a/tests/test.sh +++ b/tests/test.sh @@ -3,6 +3,7 @@ tests='bf control_flow types +include arrs_slices ptr_arithmetic defer @@ -3281,19 +3281,19 @@ static Status types_expr(Typer *tr, Expression *e) { if (!eval_expr(tr->evalr, lhs, &nms_val)) return false; Namespace *nms = nms_val.nms; - lhs->kind = EXPR_VAL; - lhs->val.nms = nms; String str = rhs->ident_str; - rhs->ident = ident_get_with_len(&nms->body.idents, str.str, str.len); - if (!rhs->ident) { + Identifier i = rhs->ident = ident_get_with_len(&nms->body.idents, str.str, str.len); + if (!i) { char *s = cstr(str.str, str.len); err_print(e->where, "\"%s\" is not a member of this namespace.", s); free(s); return false; } - if (!type_of_ident(tr, rhs->where, rhs->ident, t)) { + if (!type_of_ident(tr, rhs->where, i, t)) { return false; } + e->kind = EXPR_IDENT; + e->ident = i; } else { char *s = type_to_str(lhs_type); err_print(e->where, "Operator . applied to type %s, which is not a structure or pointer to structure.", s); @@ -3355,7 +3355,6 @@ static Status types_expr(Typer *tr, Expression *e) { case EXPR_NMS: { Namespace *prev_nms = tr->nms; Namespace *n = tr->nms = e->nms; - n->points_to = NULL; if (!types_block(tr, &n->body)) { tr->nms = prev_nms; return false; @@ -3630,6 +3629,33 @@ static Status fix_ident_decls_inline_block(Typer *tr, Statement *stmts) { return true; } +/* introduce identifiers from stmts into current scope, setting their "nms" field to nms */ +static Status include_stmts_link_to_nms(Typer *tr, Namespace *nms, Statement *stmts) { + Identifiers *idents = typer_get_idents(tr); + arr_foreach(stmts, Statement, s) { + if (s->kind == STMT_INLINE_BLOCK) { + if (!include_stmts_link_to_nms(tr, nms, s->inline_block)) + return false; + } else if (s->kind == STMT_DECL) { + Declaration *d = s->decl; + arr_foreach(d->idents, Identifier, ident) { + /* @OPTIM: only hash once */ + Identifier preexisting = ident_translate(*ident, idents); + if (preexisting) { + char *istr = ident_to_str(preexisting); + err_print(d->where, "Redeclaration of identifier %s.", istr); + info_print(preexisting->decl->where, "%s was first declared here.", istr); + free(istr); + } + Identifier i = ident_translate_forced(*ident, idents); + i->nms = nms; + i->decl = d; + } + } + } + return true; +} + static Status types_stmt(Typer *tr, Statement *s) { if (s->flags & STMT_TYPED) return true; switch (s->kind) { @@ -3750,19 +3776,33 @@ static Status types_stmt(Typer *tr, Statement *s) { s->kind = STMT_INLINE_BLOCK; - if (s->flags & STMT_INC_TO_NMS) { + { if (!(inc->flags & INC_FORCED)) { inc_f = str_hash_table_get(&tr->included_files, filename, filename_len); if (inc_f) { - tr->nms->body.idents = inc_f->main_nms->body.idents; - tr->nms->body.idents.scope = &tr->nms->body; - tr->nms->points_to = inc_f->main_nms; - s->inline_block = inc_f->stmts; + /* has already been included */ + + s->inline_block = NULL; /* nothing needed here */ + bool already_included_to_this_namespace = false; + arr_foreach(inc_f->all_namespaces, NamespacePtr, npp) { + if (*npp == tr->nms) { + already_included_to_this_namespace = true; + break; + } + } + + if (!already_included_to_this_namespace) { + typer_arr_add(tr, inc_f->all_namespaces, tr->nms); + if (!include_stmts_link_to_nms(tr, inc_f->main_nms, inc_f->stmts)) + return false; + } break; } } inc_f = str_hash_table_insert(&tr->included_files, filename, filename_len); inc_f->main_nms = tr->nms; + inc_f->all_namespaces = NULL; + typer_arr_add(tr, inc_f->all_namespaces, tr->nms); } char *contents = read_file_contents(tr->allocr, filename, s->where); if (!contents) { @@ -192,7 +192,7 @@ typedef struct IdentSlot { struct Declaration *decl; /* if NULL, a declaration hasn't been found for it yet */ struct Identifiers *idents; union { - struct Namespace *nms; /* only exists after typing, and only for namespace-level declarations (i.e. not local variables) */ + struct Namespace *nms; /* only exists after typing, and only for namespace-level declarations (i.e. not local variables inside namespaces) */ UsedFrom *used_from; /* for stuff used inside structs -- NULL if this is actually in the struct body */ }; } IdentSlot; @@ -768,12 +768,11 @@ const char *const builtin_val_names[BUILTIN_VAL_COUNT] = typedef struct Namespace { Block body; Identifier associated_ident; /* if this is foo ::= nms { ... }, then associated_ident is foo; can be NULL. used by cgen. only non-null if the namespace isn't in a non-namespace block */ - struct Namespace *points_to; /* if not NULL, this namespace just points to another namespace, because something has been included twice */ struct { char *prefix; /* generated during sdecls_cgen */ } c; } Namespace; - +typedef Namespace *NamespacePtr; enum { EXPR_FOUND_TYPE = 0x01 @@ -950,6 +949,7 @@ typedef struct { U8 flags; Namespace *main_nms; /* namespace of first inclusion */ struct Statement *stmts; + Namespace **all_namespaces; /* namespaces which this file has been included to */ } IncludedFile; enum { @@ -979,7 +979,6 @@ typedef Use *UsePtr; enum { STMT_EXPR_NO_SEMICOLON = 0x01, - STMT_INC_TO_NMS = 0x01, STMT_TYPED = 0x02 }; typedef struct Statement { |