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:
-- Speed. C is one of the most performant programming languages out there. It also has compilers which are very good at optimizing (better than anything I could write).
+- Speed. C is one of the most performant programming languages out there. It also has compilers which are very good at optimizing (better than anything I could write).
- Portability. C is probably the most portable language. It has existed for >30 years and can run on practically anything. Furthermore, all major languages nowadays can call functions written in C.
-- Laziness. I don't really want to deal with writing something which outputs machine code, and it would certainly be more buggy than something which outputs C.
+- Laziness. I don’t really want to deal with writing something which outputs machine code, and it would certainly be more buggy than something which outputs C.
+
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
#include
s toc.c
, which #include
s all of toc
's files.
+toc
is set up as a unity build, meaning that there is only one translation unit. So, main.c
#include
s toc.c
, which #include
s 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…):
- Declare anywhere
@@ -67,15 +68,17 @@ it is nearly as fast in theory.
- Flexible array members
+
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:
- Anonymous structures/unions
-max_align_t
and alignof
- It can still compile without these but it won't technically be standard-compliant
+max_align_t
and alignof
- It can still compile without these but it won’t technically be standard-compliant
+
More
See main.c
for a bit more information.
@@ -93,13 +96,14 @@ it is nearly as fast in theory.
0.1.1 | Better 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:
int
- A 64-bit signed integer (always), -9223372036854775808 to 9223372036854775807
@@ -49,13 +49,14 @@ defaults to a float
.
char
- A character. The specific values are technically platform-dependent, but usually there are 256 of them.
+
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