summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cgen.c5
-rw-r--r--decls_cgen.c3
-rw-r--r--development.md3
-rw-r--r--eval.c7
-rw-r--r--main.c34
-rw-r--r--parse.c14
-rw-r--r--test.toc30
-rw-r--r--tests/include.toc16
-rw-r--r--tests/include_expected7
-rw-r--r--tests/included.toc5
-rwxr-xr-xtests/test.sh1
-rw-r--r--types.c62
-rw-r--r--types.h7
13 files changed, 120 insertions, 74 deletions
diff --git a/cgen.c b/cgen.c
index 2f98565..b2312f4 100644
--- a/cgen.c
+++ b/cgen.c
@@ -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.
diff --git a/eval.c b/eval.c
index 1a2451d..830e574 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
}
diff --git a/main.c b/main.c
index 561dac6..fcd7d17 100644
--- a/main.c
+++ b/main.c
@@ -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")) {
diff --git a/parse.c b/parse.c
index 5cecdfb..a39fbf2 100644
--- a/parse.c
+++ b/parse.c
@@ -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;
}
diff --git a/test.toc b/test.toc
index 05975e8..97c30b9 100644
--- a/test.toc
+++ b/test.toc
@@ -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
diff --git a/types.c b/types.c
index 7dcebff..f7538bd 100644
--- a/types.c
+++ b/types.c
@@ -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) {
diff --git a/types.h b/types.h
index 3e40d9c..693c127 100644
--- a/types.h
+++ b/types.h
@@ -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 {