summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rwxr-xr-xbuild.sh2
-rw-r--r--decls_cgen.c1
-rw-r--r--foreign64.c10
-rw-r--r--foreign_avcall.c1
-rw-r--r--foreign_msvc.c6
-rw-r--r--foreign_msvc32.c2
-rw-r--r--foreign_unix.c6
-rw-r--r--main.c7
-rw-r--r--make: *** [Makefile0
-rw-r--r--parse.c49
-rw-r--r--std/io.toc6
-rw-r--r--std/mem.toc6
-rw-r--r--systemv64call.asm6
-rw-r--r--systemv64call_test.c9
-rw-r--r--test.toc48
l---------tests/std1
-rw-r--r--tests/std/arr.toc29
-rw-r--r--tests/std/base.toc23
-rw-r--r--tests/std/io.toc65
-rw-r--r--tests/std/mem.toc25
-rw-r--r--types.c153
-rw-r--r--types.h10
23 files changed, 159 insertions, 308 deletions
diff --git a/Makefile b/Makefile
index efc2fca..856e88c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,4 @@
-toc: *.[ch] build.sh
+debug: *.[ch] build.sh
./build.sh
release: *.[ch] build.sh
./build.sh release
diff --git a/build.sh b/build.sh
index 06dc638..3d5e605 100755
--- a/build.sh
+++ b/build.sh
@@ -59,6 +59,6 @@ c() {
echo "$1" && $1 || exit 1
}
-c "$NASM -f elf64 systemv64call.asm"
+[ ! -f systemv64call.o ] && c "$NASM -f elf64 systemv64call.asm"
c "$CC $FLAGS -o toc main.c systemv64call.o"
diff --git a/decls_cgen.c b/decls_cgen.c
index 331d179..5a85b09 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -253,6 +253,7 @@ static void cgen_fn_decl(CGenerator *g, FnExpr *f, Type *t) {
if (ctypes[0].kind == CTYPE_NONE)
cgen_type_post(g, &fn_types[0]);
cgen_write(g, ";");
+
if (!f->c.name || !ident_eq_str(f->c.name, foreign_name) || g->nms != NULL) {
cgen_write(g, "static ");
if (ctypes[0].kind == CTYPE_NONE) {
diff --git a/foreign64.c b/foreign64.c
index 7b577d3..d00d5d2 100644
--- a/foreign64.c
+++ b/foreign64.c
@@ -41,6 +41,11 @@ static inline double foreign_calld(FnPtr fn, U64 *args, I64 nargs, bool *is_floa
}
#endif
+/* disable strict aliasing warnings */
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
static Status val_to_word(Value v, Type *t, Location where, U64 *w) {
switch (t->kind) {
case TYPE_BUILTIN:
@@ -77,12 +82,15 @@ static Status val_to_word(Value v, Type *t, Location where, U64 *w) {
}
return true;
}
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type, Type *arg_types, size_t arg_types_stride, Value *args, size_t nargs, Location call_where, Value *ret) {
possibly_static_assert(sizeof(double) == 8); /* if either of these assertions fails, you'll need to use libffcall */
possibly_static_assert(sizeof(float) == 4);
FnPtr fn_ptr = foreign_get_fn_ptr(ffmgr, fn, call_where);
-
+ if (!fn_ptr) return false;
/* @OPTIM: use alloca/_malloca if available */
U64 *words = err_malloc(nargs * sizeof *words);
bool *is_float = err_malloc(nargs);
diff --git a/foreign_avcall.c b/foreign_avcall.c
index 8c0fe40..3d2ba45 100644
--- a/foreign_avcall.c
+++ b/foreign_avcall.c
@@ -291,6 +291,7 @@ static Status arg_list_add(av_alist *arg_list, Value val, Type *type, Location w
static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type, Type *arg_types, size_t arg_types_stride, Value *args, size_t nargs, Location call_where, Value *ret) {
FnPtr fn_ptr = foreign_get_fn_ptr(ffmgr, fn, call_where);
+ if (!fn_ptr) return false;
av_alist arg_list;
if (!arg_list_start(&arg_list, fn_ptr, ret, ret_type, call_where))
return false;
diff --git a/foreign_msvc.c b/foreign_msvc.c
index 6a8bb7f..6441132 100644
--- a/foreign_msvc.c
+++ b/foreign_msvc.c
@@ -17,7 +17,7 @@ static FnPtr foreign_get_fn_ptr(ForeignFnManager *ffmgr, FnExpr *fn, Location ca
if (!libname) {
err_print(call_where, "Attempt to call function at compile time which does not have an associated library.");
info_print(fn->where, "Function was declared here.");
- return false;
+ return NULL;
}
Library *lib = str_hash_table_get(&ffmgr->libs_loaded, libname, strlen(libname));
if (!lib) {
@@ -25,7 +25,7 @@ static FnPtr foreign_get_fn_ptr(ForeignFnManager *ffmgr, FnExpr *fn, Location ca
if (!handle) {
DWORD err = GetLastError();
err_print(call_where, "Could not open dynamic library %s (error code %ld).", libname, err);
- return false;
+ return NULL;
}
lib = str_hash_table_insert(&ffmgr->libs_loaded, libname, strlen(libname));
lib->handle = handle;
@@ -34,7 +34,7 @@ static FnPtr foreign_get_fn_ptr(ForeignFnManager *ffmgr, FnExpr *fn, Location ca
fn_ptr = (FnPtr)GetProcAddress(lib->handle, name);
if (!fn_ptr) {
err_print(call_where, "Could not get function %s from dynamic library.", name);
- return false;
+ return NULL;
}
fn->foreign.fn_ptr = fn_ptr;
}
diff --git a/foreign_msvc32.c b/foreign_msvc32.c
index 35b09db..3afbe20 100644
--- a/foreign_msvc32.c
+++ b/foreign_msvc32.c
@@ -170,7 +170,7 @@ static Status foreign_call(ForeignFnManager *ffmgr, FnExpr *fn, Type *ret_type,
possibly_static_assert(sizeof(double) == 8);
possibly_static_assert(sizeof(float) == 4);
FnPtr fn_ptr = foreign_get_fn_ptr(ffmgr, fn, call_where);
-
+ if (!fn_ptr) return false;
Word words[10];
Word *word = words;
char *type = (char *)arg_types;
diff --git a/foreign_unix.c b/foreign_unix.c
index 3b4222a..0e39b95 100644
--- a/foreign_unix.c
+++ b/foreign_unix.c
@@ -11,14 +11,14 @@ static FnPtr foreign_get_fn_ptr(ForeignFnManager *ffmgr, FnExpr *fn, Location ca
if (!libname) {
err_print(call_where, "Attempt to call function at compile time which does not have an associated library.");
info_print(fn->where, "Function was declared here.");
- return false;
+ return NULL;
}
Library *lib = str_hash_table_get(&ffmgr->libs_loaded, libname, strlen(libname));
if (!lib) {
void *handle = dlopen(libname, RTLD_LAZY);
if (!handle) {
err_print(call_where, "Could not open dynamic library: %s.", libname);
- return false;
+ return NULL;
}
lib = str_hash_table_insert(&ffmgr->libs_loaded, libname, strlen(libname));
lib->handle = handle;
@@ -35,7 +35,7 @@ static FnPtr foreign_get_fn_ptr(ForeignFnManager *ffmgr, FnExpr *fn, Location ca
if (!fn_ptr) {
err_print(call_where, "Could not get function from dynamic library: %s.", name);
- return false;
+ return NULL;
}
fn->foreign.fn_ptr = fn_ptr;
}
diff --git a/main.c b/main.c
index 1b2dbc0..74aada4 100644
--- a/main.c
+++ b/main.c
@@ -8,10 +8,7 @@
/*
@TODO:
-allow
-#include "foo.toc", foo;
-#include "foo.toc", foo;
-then do #include "std/base.toc", base; in std/io.toc and std/mem.toc
+do #include "std/base.toc", base; in std/io.toc and std/mem.toc
does our use before declare thing work with #include?
#no_warn
start making a standard library... (printf; stringbuilder would be nice to have)
@@ -62,7 +59,7 @@ passing untyped expressions to macros
#include "toc.c"
-#if defined TOC_DEBUG && defined __GNU_LIBRARY__ && defined UNISTD_AVAILABLE
+#if defined TOC_DEBUG && defined __GNU_LIBRARY__ && defined UNISTD_AVAILABLE && !defined BACKTRACE
#define BACKTRACE 1
#endif
#if BACKTRACE
diff --git a/make: *** [Makefile b/make: *** [Makefile
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/make: *** [Makefile
diff --git a/parse.c b/parse.c
index 8c6beb1..0aacaff 100644
--- a/parse.c
+++ b/parse.c
@@ -1331,7 +1331,7 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
goto success;
}
case KW_NMS: {
- Namespace *n = e->nms = parser_malloc(p, sizeof *n);
+ Namespace *n = e->nms = parser_calloc(p, 1, sizeof *n);
e->kind = EXPR_NMS;
++t->token;
if (!parse_block(p, &n->body, 0))
@@ -1559,14 +1559,12 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
}
if (token_is_kw(t->token, KW_COMMA)) {
++t->token;
- } else if (token_is_kw(t->token, KW_RPAREN)) {
- ++t->token;
- break;
- } else {
+ } else if (!token_is_kw(t->token, KW_RPAREN)) {
tokr_err(t, "Expected , or ) following #foreign fn type.");
return false;
}
}
+ ++t->token;
Type *ret_type = &fn_type->types[0];
CType *ret_ctype = &fn->foreign.ctypes[0];
@@ -2464,48 +2462,15 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
return false;
}
if (token_is_kw(t->token, KW_COMMA)) {
- Expression filename = i->filename;
++t->token;
if (t->token->kind != TOKEN_IDENT) {
- tokr_err(t, "Expected identifier for #include name (after comma).");
- tokr_skip_semicolon(t);
+ tokr_err(t, "Expected identifier after , in #include (to specify include namespace).");
return false;
}
- Identifier ident = parser_ident_insert(p, t->token->ident);
+ i->nms = t->token->ident;
++t->token;
- /* this isn't actually a STMT_INCLUDE, but a STMT_DECL! */
- /* replace #include "io.toc", io => io ::= nms { #include "io.toc"; } */
- s->kind = STMT_DECL;
- Declaration *d = s->decl = parser_calloc(p, 1, sizeof *d);
- d->where = s->where;
- parser_put_end(p, &d->where); /* we haven't set s->where.end, so... */
- d->flags |= DECL_HAS_EXPR|DECL_IS_CONST;
- parser_arr_add(p, d->idents, ident);
-
- if (!check_ident_redecl(p, ident)) {
- tokr_skip_semicolon(t);
- return false;
- }
- ident->decl = d;
-
- Expression *e = &d->expr;
- e->kind = EXPR_NMS;
- e->nms = parser_calloc(p, 1, sizeof *e->nms);
- e->where = s->where;
- e->nms->associated_ident = ident;
- Block *body = &e->nms->body;
- body->kind = BLOCK_NMS;
- body->where = s->where;
- parser_put_end(p, &body->where);
- ++body->where.end; /* past semicolon */
- body->parent = p->block;
- 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 = 0;
- inc_stmt->where = body->where;
- inc_stmt->inc = parser_calloc(p, 1, sizeof *inc_stmt->inc);
- inc_stmt->inc->filename = filename;
+ } else {
+ i->nms = NULL;
}
if (!token_is_kw(t->token, KW_SEMICOLON)) {
tokr_err(t, "Expected ; after #include directive");
diff --git a/std/io.toc b/std/io.toc
index a56ef55..9fa7e08 100644
--- a/std/io.toc
+++ b/std/io.toc
@@ -1,8 +1,8 @@
-/* TODO: use write / WriteFile */
+/* @TODO: use write / WriteFile */
-#include "std/base.toc";
+#include "std/base.toc", base;
-putchar ::= #foreign("putchar", libc) fn(#C int) #C int;
+putchar ::= #foreign("putchar", base.libc) fn(#C int) #C int;
toc_putchar ::= fn(x: char) {
putchar(x as #C int);
}
diff --git a/std/mem.toc b/std/mem.toc
index e283364..ef4e638 100644
--- a/std/mem.toc
+++ b/std/mem.toc
@@ -1,8 +1,8 @@
-#include "std/base.toc";
+#include "std/base.toc", base;
// TODO: check for failed calloc
-calloc ::= #foreign("calloc", libc) fn(#C size_t, #C size_t) #C &"void";
-free ::= #foreign("free", libc) fn(#C &"void");
+calloc ::= #foreign("calloc", base.libc) fn(#C size_t, #C size_t) #C &"void";
+free ::= #foreign("free", base.libc) fn(#C &"void");
new ::= fn(t :: Type) &t {
calloc(1, (sizeof t) as #C size_t)
diff --git a/systemv64call.asm b/systemv64call.asm
index e12f304..e2caa70 100644
--- a/systemv64call.asm
+++ b/systemv64call.asm
@@ -113,6 +113,8 @@ systemv64_call_other:
mov r11, 0 ; floating point index
mov rbx, 0 ; arg index
.fp_loop:
+ cmp rbx, rdx ; if arg_index >= nargs
+ jge .fp_loop_end
cmp byte [rcx], 0
jne .fp_loop_float
; integer argument
@@ -123,8 +125,8 @@ systemv64_call_other:
.fp_continue:
inc rbx ; ++arg_index
inc rcx ; ++is_float
- cmp rbx, rdx ; if arg_index < nargs
- jl .fp_loop
+ jmp .fp_loop
+.fp_loop_end:
; r10 now holds the number of integer arguments, and r11 holds the number of floating point arguments
diff --git a/systemv64call_test.c b/systemv64call_test.c
index 3febbba..0d7165a 100644
--- a/systemv64call_test.c
+++ b/systemv64call_test.c
@@ -31,11 +31,13 @@ should output:
Hello 3.000000 -2848239.700000 -123 456 789 43873243.234982 111.100000 222.200000 333.300000 444.400000 555.500000 666.600000
126
foo returned: -298.100006
+that's all!
*/
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
+#include <stdlib.h>
#include <math.h>
@@ -77,6 +79,11 @@ Point mkpoint(int a, int b, int c) {
return ret;
}
+void end(void) {
+ puts("that's all!");
+ exit(0);
+}
+
int main(void) {
uint64_t params[13] = {
123,
@@ -145,5 +152,7 @@ int main(void) {
int ret3 = systemv64_call((FnPtr)printf, params3, arr_sz(params3), is_fp3);
printf("%d\n",ret3);
main2();
+ systemv64_call(end, NULL, 0, NULL);
+ puts("this shouldn't be printed");
return 0;
}
diff --git a/test.toc b/test.toc
index b63bb2f..57063b1 100644
--- a/test.toc
+++ b/test.toc
@@ -1,48 +1,10 @@
#include "std/io.toc", io;
-#include "std/mem.toc";
+#include "std/io.toc", io;
+
+foo ::= #foreign("abort", "libc.so.6") fn();
main ::= fn() {
- 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);
+ io.puts("hi");
+ foo();
}
main();
-
-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/std b/tests/std
new file mode 120000
index 0000000..6ef7545
--- /dev/null
+++ b/tests/std
@@ -0,0 +1 @@
+../std \ No newline at end of file
diff --git a/tests/std/arr.toc b/tests/std/arr.toc
deleted file mode 100644
index a2d202b..0000000
--- a/tests/std/arr.toc
+++ /dev/null
@@ -1,29 +0,0 @@
-// this could be made quite a bit faster with realloc
-
-Arr ::= struct (t :: Type) {
- data : []t;
- cap : int;
-};
-
-resv ::= fn(t ::=, a : &Arr(t), n: int) {
- if a.cap >= n {
- return;
- }
- a.cap = n;
- new_data := new(t, a.cap);
- new_data.len = a.data.len;
- for x, i := &new_data {
- *x = a.data[i];
- }
- a.data = new_data;
-};
-
-add ::= fn(t ::=, a : &Arr(t), x : t) {
- if a.data.len >= a.cap {
- resv(a, a.cap * 2 + 2);
- }
- a.data.len += 1;
- a.data[a.data.len-1] = x;
-};
-
-len ::= fn(t ::=, a : Arr(t)) int { a.data.len };
diff --git a/tests/std/base.toc b/tests/std/base.toc
deleted file mode 100644
index bdb91e0..0000000
--- a/tests/std/base.toc
+++ /dev/null
@@ -1,23 +0,0 @@
-PLATFORM_OTHER ::= 0;
-PLATFORM_LINUX ::= 1;
-PLATFORM_WINDOWS ::= 2;
-PLATFORM_OSX ::= 3;
-PLATFORM_FREEBSD ::= 4;
-PLATFORM_OPENBSD ::= 5;
-PLATFORM_MISC_UNIX ::= 6;
-
-PLATFORM ::= #builtin("platform");
-#if PLATFORM == PLATFORM_LINUX {
- libc ::= "libc.so.6";
-} elif PLATFORM == PLATFORM_WINDOWS {
- libc ::= "msvcrt.dll";
-} elif PLATFORM == PLATFORM_OSX {
- libc ::= "libc.dylib";
-} elif PLATFORM == PLATFORM_FREEBSD || PLATFORM == PLATFORM_OPENBSD {
- libc ::= "libc.so";
-} else {
- /* maybe it's non-linux gnu? */
- libc ::= "libc.so.6";
-}
-
-
diff --git a/tests/std/io.toc b/tests/std/io.toc
deleted file mode 100644
index 994cd2a..0000000
--- a/tests/std/io.toc
+++ /dev/null
@@ -1,65 +0,0 @@
-/* @TODO: use write / WriteFile */
-
-#include "std/base.toc";
-
-putchar ::= #foreign("putchar", libc) fn(#C int) #C int;
-toc_putchar ::= fn(x: char) {
- putchar(x as #C int);
-}
-
-/*
-unfortunately, we can't use fwrite because MSVC doesn't like it when you
-use a file handle that's not from the DLL. (i.e. you can't pass your stdout
-to the imported version of fwrite)
-*/
-
-writes ::= fn(x: []char) {
- for c := x {
- toc_putchar(c);
- }
-}
-
-puts ::= fn(x: []char) {
- writes(x);
- toc_putchar('\n');
-}
-
-writei ::= fn(x: int) {
- if x < 0 {
- toc_putchar('-');
- // NOTE: don't do x = -x; here to make sure I64_MIN works
- }
- if x == 0 {
- toc_putchar('0');
- } else {
- abs ::= fn(x: int) int { if x < 0 { -x } else { x } };
- scan_digit := 1000000000000000000;
- started := false;
- while scan_digit > 0 {
- digit := abs((x / scan_digit) % 10);
- if digit > 0 { started = true; }
- if started {
- toc_putchar((('0' as int) + digit) as char);
- }
- scan_digit /= 10;
- }
- }
-}
-
-puti ::= fn(x: int) {
- writei(x);
- toc_putchar('\n');
-}
-
-/* @TODO: write your own version of this */
-printf ::= #foreign("printf", libc) fn(#C &"const char", #C ..) #C int;
-writef ::= fn(x: float) {
- fmt := "%f\0";
- printf(&fmt[0], x as f64);
-};
-putf ::= fn(x: float) {
- writef(x);
- toc_putchar('\n');
-}
-
-
diff --git a/tests/std/mem.toc b/tests/std/mem.toc
deleted file mode 100644
index e283364..0000000
--- a/tests/std/mem.toc
+++ /dev/null
@@ -1,25 +0,0 @@
-#include "std/base.toc";
-
-// TODO: check for failed calloc
-calloc ::= #foreign("calloc", libc) fn(#C size_t, #C size_t) #C &"void";
-free ::= #foreign("free", libc) fn(#C &"void");
-
-new ::= fn(t :: Type) &t {
- calloc(1, (sizeof t) as #C size_t)
-}
-
-news ::= fn(t :: Type, n : int) []t {
- s: []t;
- s.data = calloc(n as #C size_t, (sizeof t) as #C size_t);
- s.len = n;
- s
-}
-
-// TODO(eventually): use type information to make this just one function
-del ::= fn(t::=, x: &t) {
- free(x);
-}
-
-dels ::= fn(t::=, x: []t) {
- free(x.data);
-}
diff --git a/types.c b/types.c
index 9b5b6e1..7e4b56c 100644
--- a/types.c
+++ b/types.c
@@ -3598,7 +3598,7 @@ static Status include_stmts_link_to_nms(Typer *tr, Namespace *nms, Statement *st
arr_foreach(d->idents, Identifier, ident) {
/* @OPTIM: only hash once */
Identifier preexisting = ident_translate(*ident, idents);
- if (preexisting) {
+ if (preexisting && preexisting->decl != d) {
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);
@@ -3728,70 +3728,115 @@ static Status types_stmt(Typer *tr, Statement *s) {
char *filename = eval_expr_as_cstr(tr, &inc->filename, "import filename");
if (!filename)
return false;
- size_t filename_len = strlen(filename);
IncludedFile *inc_f = NULL;
+
+ Namespace *inc_nms = NULL; /* non-NULL if this is an include to nms */
+ if (inc->nms) {
+ inc_nms = typer_calloc(tr, 1, sizeof *inc_nms);
+ Block *body = &inc_nms->body;
+ body->kind = BLOCK_NMS;
+ body->where = s->where;
+ idents_create(&body->idents, tr->allocr, body);
+ body->parent = tr->block;
+ }
s->kind = STMT_INLINE_BLOCK;
- {
- if (!(inc->flags & INC_FORCED)) {
- inc_f = str_hash_table_get(&tr->included_files, filename, filename_len);
- if (inc_f) {
- /* 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;
- }
+ if (!(inc->flags & INC_FORCED)) {
+ size_t filename_len = strlen(filename);
+ inc_f = str_hash_table_get(&tr->included_files, filename, filename_len);
+ if (inc_f) {
+ /* has already been included */
+ s->inline_block = NULL; /* nothing needed here */
+ /* just set ident declarations */
+ if (!include_stmts_link_to_nms(tr, inc_f->main_nms, inc_f->stmts))
+ return false;
+ goto nms_transform;
}
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) {
- tr->had_include_err = true;
- return false;
}
+ {
+ char *contents = read_file_contents(tr->allocr, filename, s->where);
+ if (!contents) {
+ tr->had_include_err = true;
+ return false;
+ }
- Tokenizer tokr;
- tokr_create(&tokr, tr->err_ctx, tr->allocr);
- File *file = typer_calloc(tr, 1, sizeof *file);
- file->filename = filename;
- file->contents = contents;
- file->ctx = tr->err_ctx;
-
- if (!tokenize_file(&tokr, file))
- return false;
- Parser parser;
- parser_create(&parser, tr->globals, &tokr, tr->allocr);
- parser.block = tr->block;
- ParsedFile parsed_file;
- if (!parse_file(&parser, &parsed_file)) {
- return false;
- }
- Statement *stmts_inc = parsed_file.stmts;
- if (inc_f) {
- inc_f->stmts = stmts_inc;
- }
- s->inline_block = stmts_inc;
- arr_foreach(stmts_inc, Statement, s_incd) {
- if (!types_stmt(tr, s_incd)) {
+ Tokenizer tokr;
+ tokr_create(&tokr, tr->err_ctx, tr->allocr);
+ File *file = typer_calloc(tr, 1, sizeof *file);
+ file->filename = filename;
+ file->contents = contents;
+ file->ctx = tr->err_ctx;
+
+ if (!tokenize_file(&tokr, file))
+ return false;
+ Parser parser;
+ parser_create(&parser, tr->globals, &tokr, tr->allocr);
+ parser.block = inc_nms ? &inc_nms->body : tr->block;
+ ParsedFile parsed_file;
+ if (!parse_file(&parser, &parsed_file)) {
return false;
}
+ Statement *stmts_inc = parsed_file.stmts;
+ if (inc_f) {
+ inc_f->stmts = stmts_inc;
+ }
+ s->inline_block = stmts_inc;
+ Namespace *prev_nms = tr->nms;
+ Block *prev_block = tr->block;
+ if (inc_nms) {
+ tr->nms = inc_nms;
+ tr->block = &inc_nms->body;
+ }
+ arr_foreach(stmts_inc, Statement, s_incd) {
+ if (!types_stmt(tr, s_incd)) {
+ return false;
+ }
+ }
+ if (inc_nms) {
+ tr->nms = prev_nms;
+ tr->block = prev_block;
+ inc_nms->body.stmts = stmts_inc;
+ }
+ }
+ nms_transform:
+ if (inc_nms) {
+ inc_nms->inc_file = inc_f;
+ /* turn #include "foo", bar into bar ::= nms { ... } */
+ s->kind = STMT_DECL;
+ Declaration *d = s->decl = typer_calloc(tr, 1, sizeof *d);
+ d->flags = DECL_FOUND_TYPE | DECL_HAS_EXPR | DECL_IS_CONST | DECL_FOUND_VAL;
+ construct_resolved_builtin_type(&d->type, BUILTIN_NMS);
+ char *ident_str = inc->nms;
+ Identifier i = ident_insert(typer_get_idents(tr), &ident_str);
+ typer_arr_add(tr, d->idents, i);
+ if (i->decl) {
+ Declaration *d2 = i->decl;
+ /* maybe they included it twice into one namespace */
+ if ((d2->flags & DECL_HAS_EXPR) && (d2->expr.kind == EXPR_NMS) &&
+ (d2->expr.nms->inc_file == inc_f)) {
+ /* that's okay; get rid of this declaration */
+ s->kind = STMT_INLINE_BLOCK;
+ s->inline_block = NULL;
+ break;
+ } else {
+ char *istr = ident_to_str(i);
+ err_print(s->where, "Redeclaration of identifier %s.", istr);
+ info_print(ident_decl_location(i), "Previous declaration was here.");
+ free(istr);
+ return false;
+ }
+ }
+ i->decl = d;
+ inc_nms->associated_ident = i;
+ d->expr.kind = EXPR_NMS;
+ d->expr.nms = inc_nms;
+ d->expr.flags = EXPR_FOUND_TYPE;
+ d->expr.type = d->type;
+ d->val.nms = inc_nms;
+ d->where = d->expr.where = s->where;
}
} break;
case STMT_MESSAGE: {
diff --git a/types.h b/types.h
index 45b5752..ed5f75f 100644
--- a/types.h
+++ b/types.h
@@ -765,6 +765,7 @@ 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 IncludedFile *inc_file; /* NULL if this is not generated from an include to nms */
struct {
char *prefix; /* generated during sdecls_cgen */
} c;
@@ -941,20 +942,21 @@ enum {
INC_FILE_CGEND = 0x08
};
-typedef struct {
+typedef struct IncludedFile {
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 {
- INC_FORCED = 0x01
+ INC_FORCED = 0x01,
+ INC_TO_NMS = 0x02
};
-typedef union {
+typedef struct {
U8 flags;
Expression filename;
+ char *nms; /* NULL if this is just a plain old #include, otherwise string which can be used with ident_get */
} Include;
typedef enum {