From 32e8dc1da3cfed115fd449667c5b6134705b0089 Mon Sep 17 00:00:00 2001 From: Leo Tenenbaum Date: Wed, 18 Dec 2019 17:35:54 -0500 Subject: fixed leaks --- README.html | 36 +++++++++++++++++++++--------------- allocator.c | 2 +- arr.c | 21 +++++++++++++++------ docs/00.html | 7 ++++--- docs/01.html | 4 ++-- toc.c | 3 +++ types.c | 27 ++++++++++++++++++--------- 7 files changed, 64 insertions(+), 36 deletions(-) diff --git a/README.html b/README.html index ca851af..2f08d15 100644 --- a/README.html +++ b/README.html @@ -11,17 +11,17 @@ and there are almost definitely bugs right now. I would recommend against using it for anything big or important. Many parts of it may change in the future.

-

toc improves on C's syntax (and semantics) in many ways, +

toc improves on C’s syntax (and semantics) in many ways, To declare x as an integer and set it to 5, you can do:

-x := 5; // Declare x and set x to 5 (infer type)
-x : int = 5; // Explicitly make the type int.
-x : int; x = 5; // Declare x as an integer, then set it to 5. +x := 5; // Declare x and set x to 5 (infer type) +x : int = 5; // Explicitly make the type int. +x : int; x = 5; // Declare x as an integer, then set it to 5.

-

toc is statically typed and has many of C's features, but +

toc is statically typed and has many of C’s features, but it is nearly as fast in theory.

See docs for more information (in progress).

@@ -37,11 +37,12 @@ it is nearly as fast in theory.

toc compiles to C for three reasons:

+

toc Source Code

@@ -50,15 +51,15 @@ it is nearly as fast in theory.

Build system

-

toc is set up as a unity build, meaning that there is only one translation unit. So, main.c #includes toc.c, which #includes all of toc's files.

+

toc is set up as a unity build, meaning that there is only one translation unit. So, main.c #includes toc.c, which #includes all of toc’s files.

Why?
-

This improves compilation speeds (especially from scratch), since you don't have to include headers a bunch of times for each translation unit. This is more of a problem in C++, where, for example, doing #include <map> ends up turning into 25,000 lines after preprocessing. All of toc's source code, which includes most of the C standard library, at the time of this writing (Dec 2019) is only 22,000 lines after preprocessing; imagine including all of that once for each translation unit which includes map. It also obviates the need for fancy build systems like CMake.

+

This improves compilation speeds (especially from scratch), since you don’t have to include headers a bunch of times for each translation unit. This is more of a problem in C++, where, for example, doing #include <map> ends up turning into 25,000 lines after preprocessing. All of toc’s source code, which includes most of the C standard library, at the time of this writing (Dec 2019) is only 22,000 lines after preprocessing; imagine including all of that once for each translation unit which includes map. It also obviates the need for fancy build systems like CMake.

New features

-

Here are all the C99 features which toc depends on (I might have forgotten some...):

+

Here are all the C99 features which toc depends on (I might have forgotten some…):

+

The last three of those could all be removed fairly easily (assuming the system actually has 8-, 16-, 32-, and 64-bit signed and unsigned types).

And here are all of its C11 features:

+

More

See main.c for a bit more information.

@@ -93,13 +96,14 @@ it is nearly as fast in theory.

0.1.1Better constant parameter inference.2019 Dec 16 +

Report a bug

-

If you find a bug, you can report it through GitHub's issue tracker, or by emailing pommicket@gmail.com.

+

If you find a bug, you can report it through GitHub’s issue tracker, or by emailing pommicket@gmail.com.

-

Just send me the toc source code which results in the bug, and I'll try to fix it.

+

Just send me the toc source code which results in the bug, and I’ll try to fix it.


@@ -114,7 +118,8 @@ int main() { } -

Is completely fine. x will hold an unspecified value after the jump (but it isn't used so it doesn't really matter). Apparently, in C++, this is an ill-formed program. This is a bit ridiculous since

+ +

Is completely fine. x will hold an unspecified value after the jump (but it isn’t used so it doesn’t really matter). Apparently, in C++, this is an ill-formed program. This is a bit ridiculous since


 int main() {  
@@ -125,4 +130,5 @@ int main() {
 }
 
-

is fine. So that's an interesting little "fun fact": int x = 5; isn't always the same as int x; x = 5; in C++.

+ +

is fine. So that’s an interesting little “fun fact”: int x = 5; isn’t always the same as int x; x = 5; in C++.

diff --git a/allocator.c b/allocator.c index 6721e94..da255e4 100644 --- a/allocator.c +++ b/allocator.c @@ -8,7 +8,7 @@ static void *err_malloc(size_t bytes); static void *err_calloc(size_t n, size_t sz); static void *err_realloc(void *prev, size_t new_size); #ifdef TOC_DEBUG -#define NO_ALLOCATOR 1 /* useful for debugging; valgrind (maybe) checks writing past the end of a malloc, but that won't work with an allocator */ +/* #define NO_ALLOCATOR 1 /\* useful for debugging; valgrind (maybe) checks writing past the end of a malloc, but that won't work with an allocator *\/ */ #endif /* number of bytes a page hold, not including the header */ #define PAGE_BYTES (16384 - sizeof(Page)) diff --git a/arr.c b/arr.c index 16737d4..4b67f4f 100644 --- a/arr.c +++ b/arr.c @@ -130,14 +130,22 @@ static void *arr_end_(void *arr, size_t item_sz) { } /* OPTIM: shrink array */ -static void arr_remove_last_(void **arr, size_t item_sz) { +static void arr_remove_last_(void **arr) { assert(arr_hdr(*arr)->len); - if (--arr_hdr(*arr)->len == 0) - *arr = NULL; - (void)item_sz; - + if (--arr_hdr(*arr)->len == 0) { + arr_clear_(arr); + } } +static void arr_remove_lasta_(void **arr, size_t item_sz, Allocator *a) { + assert(arr_hdr(*arr)->len); + if (--arr_hdr(*arr)->len == 0) { + arr_cleara_(arr, item_sz, a); + } +} + + + static void arr_copya_(void **out, void *in, size_t item_sz, Allocator *a) { size_t len = arr_len(in); arr_resva_(out, len, item_sz, a); @@ -179,7 +187,8 @@ You shouldn't rely on this, though, e.g. by doing /* one past last, or NULL if empty */ #define arr_end(arr) arr_end_((void *)(arr), sizeof *(arr)) #define arr_foreach(arr, type, var) for (type *var = arr, *join(var,_foreach_end) = arr_end(arr); var < join(var,_foreach_end); ++var) /* NOTE: < is useful here because currently it's possible for var_foreach_end to be NULL but var could start out not null */ -#define arr_remove_last(arr) arr_remove_last_((void **)(arr), sizeof **(arr)) +#define arr_remove_last(arr) arr_remove_last_((void **)(arr)), (void)sizeof **(arr) +#define arr_remove_lasta(arr, a) arr_remove_lasta_((void **)(arr), sizeof **(arr), (a)) #define arr_copya(out, in, a) do { assert(sizeof *(in) == sizeof **(out)); arr_copya_((void **)(out), (in), sizeof **(out), (a)); } while(0) #ifdef TOC_DEBUG diff --git a/docs/00.html b/docs/00.html index cd0c352..b8c961c 100644 --- a/docs/00.html +++ b/docs/00.html @@ -30,7 +30,7 @@ x := 0.0; when no type is specified, it defaults to an int, whereas 0.0 defaults to a float.

-

Here are all of toc's builtin types and their ranges of values:

+

Here are all of toc’s builtin types and their ranges of values:

+

At the moment, it is not technically guaranteed that f32/float is actually 32-bit and that f64 is actually 64-bit; they are platform dependent. Perhaps someday there will be a version of toc which does not compile to C, where that could be guaranteed.

To make declarations constant, use :: instead of :. e.g.

-x ::= 5+3;
+x ::= 5+3; y :: float = 5.123;

-

Here, "constant" means constant at compile time, not read-only as it does in C. One interesting thing about toc is that normal functions can run at compile time, so pretty much any expression is a valid initializer for a constant, e.g. doing x ::= some_function(); runs some_function at compile time, not at run time.

+

Here, “constant” means constant at compile time, not read-only as it does in C. One interesting thing about toc is that normal functions can run at compile time, so pretty much any expression is a valid initializer for a constant, e.g. doing x ::= some_function(); runs some_function at compile time, not at run time.

diff --git a/docs/01.html b/docs/01.html index 633295b..6dce358 100644 --- a/docs/01.html +++ b/docs/01.html @@ -7,7 +7,7 @@ main ::= fn() { };

-

It declares a constant, main, which is a function with an empty body. Note that the syntax for declaring functions is the same as the syntax for declaring constants (it isn't something like fn main() { ... }).

+

It declares a constant, main, which is a function with an empty body. Note that the syntax for declaring functions is the same as the syntax for declaring constants (it isn’t something like fn main() { ... }).

Assuming you have compiled the compiler (see README.md for instructions about that), you can compile it with

@@ -15,4 +15,4 @@ main ::= fn() { toc <your filename>

-

You will get a file called out.c, which you can then put through your C compiler to get an executable file which does nothing. Congratulations! You've written your first toc program.

+

You will get a file called out.c, which you can then put through your C compiler to get an executable file which does nothing. Congratulations! You’ve written your first toc program.

diff --git a/toc.c b/toc.c index 1a6684c..e58f4ec 100644 --- a/toc.c +++ b/toc.c @@ -3,6 +3,9 @@ This file is part of toc. toc is distributed under version 3 of the GNU General Public License, without any warranty whatsoever. You should have received a copy of the GNU General Public License along with toc. If not, see . */ + +/* NOTE: all stages should use the same allocator! */ + /* Includes all of toc's files */ #include #include diff --git a/types.c b/types.c index 46b51c4..be95204 100644 --- a/types.c +++ b/types.c @@ -337,7 +337,7 @@ static bool type_of_fn(Typer *tr, FnExpr *f, Type *t, U16 flags) { } ret: - arr_remove_last(&tr->blocks); + arr_remove_lasta(&tr->blocks, tr->allocr); tr->block = prev_block; /* cleanup */ if (entered_fn) { @@ -854,7 +854,7 @@ static bool types_expr(Typer *tr, Expression *e) { break; case EXPR_EACH: { EachExpr *ea = e->each; - *(Expression **)arr_add(&tr->in_expr_decls) = e; + *(Expression **)typer_arr_add(tr, &tr->in_expr_decls) = e; if (!each_enter(e)) return false; if (ea->flags & EACH_IS_RANGE) { /* TODO: allow user-defined numerical types */ @@ -971,7 +971,7 @@ static bool types_expr(Typer *tr, Expression *e) { ea->range.stepval = stepval; } - arr_remove_last(&tr->in_expr_decls); + arr_remove_lasta(&tr->in_expr_decls, tr->allocr); if (!types_block(tr, &ea->body)) return false; each_exit(e); @@ -1252,7 +1252,7 @@ static bool types_expr(Typer *tr, Expression *e) { arr_foreach(fn->params, Declaration, param) { arr_foreach(param->idents, Identifier, ident) { if (param->flags & DECL_INFER) { - *(Identifier *)arr_add(&inferred_idents) = *ident; + *(Identifier *)typer_arr_add(tr, &inferred_idents) = *ident; } else if ((param->flags & DECL_ANNOTATES_TYPE) && !(param->flags & DECL_HAS_EXPR)) { @@ -1270,11 +1270,18 @@ static bool types_expr(Typer *tr, Expression *e) { size_t ninferred_idents = arr_len(inferred_idents); if (ninferred_idents) { - Value *inferred_vals = typer_malloc(tr, ninferred_idents * sizeof *inferred_vals); - Type *inferred_types = typer_malloc(tr, ninferred_idents * sizeof *inferred_types); + Value *inferred_vals; + Type *inferred_types; + size_t inferred_vals_size = ninferred_idents * sizeof *inferred_vals; + inferred_vals = typer_malloc(tr, inferred_vals_size); + size_t inferred_types_size = ninferred_idents * sizeof *inferred_types; + inferred_types = typer_malloc(tr, inferred_types_size); if (!infer_ident_vals(tr, decl_types, arg_types, inferred_idents, inferred_vals, inferred_types)) return false; + + allocr_free(tr->allocr, inferred_idents, ninferred_idents * sizeof *inferred_idents); + { Type *type = inferred_types; for (i = 0; i < ninferred_idents; ++i) { @@ -1307,6 +1314,8 @@ static bool types_expr(Typer *tr, Expression *e) { ++i; } } + allocr_free(tr->allocr, inferred_vals, inferred_vals_size); + allocr_free(tr->allocr, inferred_types, inferred_types_size); } @@ -1444,7 +1453,7 @@ static bool types_expr(Typer *tr, Expression *e) { ErrCtx *err_ctx = e->where.ctx; *(Location *)typer_arr_add(tr, &err_ctx->instance_stack) = e->where; bool success = types_fn(tr, &c->instance->fn, &f->type, e->where, c->instance); - arr_remove_last(&err_ctx->instance_stack); + arr_remove_lasta(&err_ctx->instance_stack, tr->allocr); if (!success) return false; arr_cleara(&table_index_type.tuple, tr->allocr); } @@ -1910,7 +1919,7 @@ static bool types_block(Typer *tr, Block *b) { goto ret; } b->ret_expr = e; - arr_remove_last(&b->stmts); + arr_remove_lasta(&b->stmts, tr->allocr); } } } @@ -2019,7 +2028,7 @@ static bool types_decl(Typer *tr, Declaration *d) { d->type.kind = TYPE_UNKNOWN; tr->evalr->enabled = false; /* disable evaluator completely so that it doesn't accidentally try to access this declaration */ } - arr_remove_last(&tr->in_decls); + arr_remove_lasta(&tr->in_decls, tr->allocr); return success; } -- cgit v1.2.3