diff options
-rw-r--r-- | Makefile | 2 | ||||
-rwxr-xr-x | build.sh | 2 | ||||
-rw-r--r-- | decls_cgen.c | 1 | ||||
-rw-r--r-- | foreign64.c | 10 | ||||
-rw-r--r-- | foreign_avcall.c | 1 | ||||
-rw-r--r-- | foreign_msvc.c | 6 | ||||
-rw-r--r-- | foreign_msvc32.c | 2 | ||||
-rw-r--r-- | foreign_unix.c | 6 | ||||
-rw-r--r-- | main.c | 7 | ||||
-rw-r--r-- | make: *** [Makefile | 0 | ||||
-rw-r--r-- | parse.c | 49 | ||||
-rw-r--r-- | std/io.toc | 6 | ||||
-rw-r--r-- | std/mem.toc | 6 | ||||
-rw-r--r-- | systemv64call.asm | 6 | ||||
-rw-r--r-- | systemv64call_test.c | 9 | ||||
-rw-r--r-- | test.toc | 48 | ||||
l--------- | tests/std | 1 | ||||
-rw-r--r-- | tests/std/arr.toc | 29 | ||||
-rw-r--r-- | tests/std/base.toc | 23 | ||||
-rw-r--r-- | tests/std/io.toc | 65 | ||||
-rw-r--r-- | tests/std/mem.toc | 25 | ||||
-rw-r--r-- | types.c | 153 | ||||
-rw-r--r-- | types.h | 10 |
23 files changed, 159 insertions, 308 deletions
@@ -1,4 +1,4 @@ -toc: *.[ch] build.sh +debug: *.[ch] build.sh ./build.sh release: *.[ch] build.sh ./build.sh release @@ -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; } @@ -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 @@ -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"); @@ -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; } @@ -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); -} @@ -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: { @@ -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 { |