summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2020-01-03 23:57:33 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2020-01-03 23:57:33 -0500
commit50c892e0a68c7e6d17ce49edf0c13ada7e1cdbfc (patch)
tree024761d74f69ebd869ece7475c935b0157b42ff3
parent5665bde91427725cf0231cab7e54a6b37b6fba7f (diff)
fixed a bug with returning
-rw-r--r--arr.c2
-rw-r--r--binfile.c1
-rw-r--r--cgen.c12
-rw-r--r--err.c6
-rw-r--r--location.c6
-rw-r--r--main.c16
-rw-r--r--package.c139
-rw-r--r--parse.c2
-rw-r--r--test.toc6
-rw-r--r--toc.c7
-rw-r--r--types.h20
11 files changed, 195 insertions, 22 deletions
diff --git a/arr.c b/arr.c
index 92f0d62..16584f1 100644
--- a/arr.c
+++ b/arr.c
@@ -186,7 +186,7 @@ You shouldn't rely on this, though, e.g. by doing
#define arr_last(arr) arr_last_((void *)(arr), sizeof *(arr))
/* 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_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)), (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)
diff --git a/binfile.c b/binfile.c
index 7f58736..2df96e2 100644
--- a/binfile.c
+++ b/binfile.c
@@ -15,6 +15,7 @@ static inline void write_u8(FILE *fp, U8 u8) {
col = 0;
printf("\n");
}
+ fflush(stdout);
#endif
}
diff --git a/cgen.c b/cgen.c
index fd5b1a5..b5282e1 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1819,10 +1819,13 @@ static bool cgen_decl(CGenerator *g, Declaration *d) {
return true;
}
-/* does NOT call cgen_expr_pre for ret. */
static bool cgen_ret(CGenerator *g, Expression *ret) {
assert((g->fn->ret_type.kind == TYPE_VOID) == (ret == NULL));
- if (ret) assert(type_eq(&g->fn->ret_type, &ret->type));
+ if (ret) {
+ assert(type_eq(&g->fn->ret_type, &ret->type));
+ if (!cgen_expr_pre(g, ret))
+ return false;
+ }
if (!ret) {
cgen_write(g, "return");
} else if (cgen_uses_ptr(&g->fn->ret_type)) {
@@ -1835,7 +1838,6 @@ static bool cgen_ret(CGenerator *g, Expression *ret) {
cgen_write(g, " return");
} else {
cgen_write(g, "return ");
-
if (!cgen_expr(g, ret)) return false;
}
cgen_write(g, ";");
@@ -1862,10 +1864,6 @@ static bool cgen_stmt(CGenerator *g, Statement *s) {
break;
case STMT_RET: {
unsigned has_expr = s->ret.flags & RET_HAS_EXPR;
- if (has_expr) {
- if (!cgen_expr_pre(g, &s->ret.expr))
- return false;
- }
if (!cgen_ret(g, has_expr ? &s->ret.expr : NULL))
return false;
} break;
diff --git a/err.c b/err.c
index 6d57cdc..1ca103e 100644
--- a/err.c
+++ b/err.c
@@ -55,6 +55,8 @@ static void err_vfprint(const char *fmt, va_list args) {
}
static void err_print_header_(Location where) {
+ if (!where.ctx)
+ err_fprint("Error (no location available):\n");
#if ERR_EMACS
err_fprint("%s:%lu: " TEXT_ERROR("error") ":\n", where.ctx->filename, (unsigned long)where.line);
#else
@@ -63,6 +65,8 @@ static void err_print_header_(Location where) {
}
static void info_print_header_(Location where) {
+ if (!where.ctx)
+ err_fprint("Info (no location available):\n");
#if ERR_EMACS
err_fprint("%s:%lu: " TEXT_INFO("info") ":\n", where.ctx->filename, (unsigned long)where.line);
#else
@@ -71,6 +75,8 @@ static void info_print_header_(Location where) {
}
static void warn_print_header_(Location where) {
+ if (!where.ctx)
+ err_fprint("Warning (no location available):\n");
#if ERR_EMACS
err_fprint("%s:%lu: " TEXT_WARN("warning") ":\n", where.ctx->filename, (unsigned long)where.line);
#else
diff --git a/location.c b/location.c
index c5db626..481c033 100644
--- a/location.c
+++ b/location.c
@@ -8,8 +8,14 @@ static bool location_after(Location a, Location b) { /* a is after b? */
return a.pos > b.pos;
}
+static Location const LOCATION_NONE = {0};
+
/* for debugging */
static void fprint_location(FILE *out, Location location) {
+ if (!location.ctx) {
+ fprintf(out, "No location available.");
+ return;
+ }
char *str = location.ctx->str + location.pos;
char *newline = strchr(str, '\n');
if (newline) *newline = 0;
diff --git a/main.c b/main.c
index 215bbeb..7b91cea 100644
--- a/main.c
+++ b/main.c
@@ -122,10 +122,12 @@ int main(int argc, char **argv) {
evalr_create(&ev, &tr, &main_allocr);
typer_create(&tr, &ev, &main_allocr);
tr.exptr = &exptr;
-
+
#ifdef TOC_DEBUG
FILE *out_pkg = fopen("out.top", "wb");
exptr_create(&exptr, out_pkg);
+ exptr.export_locations = false;
+
#endif
if (!block_enter(NULL, f.stmts, SCOPE_CHECK_REDECL)) /* enter global scope */
return false;
@@ -136,6 +138,15 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
#ifdef TOC_DEBUG
+ if (!exptr_finish(&exptr)) {
+ fclose(out_pkg);
+ err_fprint(TEXT_IMPORTANT("Errors occured while exporting things.\n"));
+ return EXIT_FAILURE;
+ }
+ fclose(out_pkg);
+#endif
+#ifdef TOC_DEBUG
+ printf("\n\n");
fprint_parsed_file(stdout, &f);
#endif
FILE *out = fopen(out_filename, "w");
@@ -158,9 +169,6 @@ int main(int argc, char **argv) {
evalr_free(&ev);
fclose(out);
-#ifdef TOC_DEBUG
- fclose(out_pkg);
-#endif
idents_free(&file_idents);
return 0;
}
diff --git a/package.c b/package.c
index 0090ab5..3dfaab6 100644
--- a/package.c
+++ b/package.c
@@ -3,11 +3,17 @@
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 <https://www.gnu.org/licenses/>.
*/
+static bool export_decl(Exporter *ex, Declaration *d);
+static bool export_block(Exporter *ex, Block *b);
+
+
static void exptr_create(Exporter *exptr, FILE *out) {
exptr->out = out;
exptr->export_locations = true;
+ exptr->exported_fns = NULL;
}
+
static void export_u8(Exporter *ex, U8 u8) {
write_u8(ex->out, u8);
}
@@ -63,16 +69,33 @@ static void export_ident(Exporter *ex, Identifier i) {
}
}
+static bool export_len8(Exporter *ex, size_t len, const char *for_, Location where) {
+ if (len > U8_MAX) {
+ err_print(where, "Too many %s (the maximum is " STRINGIFY(U8_MAX) ").", for_);
+ return false;
+ }
+ export_u8(ex, (U8)len);
+ return true;
+}
static bool export_len16(Exporter *ex, size_t len, const char *for_, Location where) {
- if (len > 65535) {
- err_print(where, "Too many %s (the maximum is 65535).", for_);
+ if (len > U16_MAX) {
+ err_print(where, "Too many %s (the maximum is " STRINGIFY(U16_MAX) ").", for_);
return false;
}
export_u16(ex, (U16)len);
return true;
}
+static bool export_len32(Exporter *ex, size_t len, const char *for_, Location where) {
+ if (len > U32_MAX) {
+ err_print(where, "Too many %s (the maximum is " STRINGIFY(U32_MAX) ").", for_);
+ return false;
+ }
+ export_u32(ex, (U32)len);
+ return true;
+}
+
static bool export_type(Exporter *ex, Type *type, Location where) {
assert(type->flags & TYPE_IS_RESOLVED);
export_u8(ex, (U8)type->kind);
@@ -98,6 +121,18 @@ static bool export_type(Exporter *ex, Type *type, Location where) {
if (!export_type(ex, type->arr.of, where))
return false;
break;
+ case TYPE_FN:
+ if (!export_len16(ex, arr_len(type->fn.types), "types in a function type", where))
+ return false;
+ arr_foreach(type->fn.types, Type, sub)
+ if (!export_type(ex, sub, where))
+ return false;
+ export_u8(ex, type->fn.constness != NULL);
+ /* [implied] if (type->fn.constness) */
+ assert(sizeof(Constness) == 1); /* future-proofing */
+ arr_foreach(type->fn.constness, Constness, c)
+ export_u8(ex, *c);
+ break;
case TYPE_EXPR:
assert(0);
return false;
@@ -105,6 +140,20 @@ static bool export_type(Exporter *ex, Type *type, Location where) {
return true;
}
+static bool export_fn_ptr(Exporter *ex, FnExpr *f, Location where) {
+ if (f->export.id == 0) {
+ FnWithLocation *floc = arr_add(&ex->exported_fns);
+ floc->fn = f;
+ floc->where = where;
+ if (arr_len(ex->exported_fns) > U32_MAX) {
+ err_print(where, "Too many exported functions (the maximum is " STRINGIFY(U32_MAX) ").");
+ }
+ f->export.id = (U32)arr_len(ex->exported_fns);
+ }
+ export_u32(ex, f->export.id);
+ return true;
+}
+
static bool export_val(Exporter *ex, Value val, Type *type, Location where);
static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where) {
switch (type->kind) {
@@ -168,6 +217,10 @@ static bool export_val_ptr(Exporter *ex, void *val, Type *type, Location where)
ptr += item_size;
}
} break;
+ case TYPE_FN:
+ if (!export_fn_ptr(ex, *(FnExpr **)val, where))
+ return false;
+ break;
case TYPE_UNKNOWN:
case TYPE_EXPR:
assert(0);
@@ -237,6 +290,22 @@ static bool export_expr(Exporter *ex, Expression *e) {
if (!export_type(ex, &e->typeval, e->where))
return false;
break;
+ case EXPR_FN:
+ if (!export_fn_ptr(ex, e->fn, e->where))
+ return false;
+ break;
+ case EXPR_BLOCK:
+ if (!export_block(ex, &e->block))
+ return false;
+ break;
+ case EXPR_NEW:
+ if (!export_type(ex, &e->new.type, e->where))
+ return false;
+ export_u8(ex, e->new.n != NULL);
+ if (e->new.n)
+ if (!export_expr(ex, e->new.n))
+ return false;
+ break;
case EXPR_DSIZEOF:
case EXPR_DALIGNOF:
assert(0);
@@ -287,3 +356,69 @@ static bool export_decl(Exporter *ex, Declaration *d) {
}
return true;
}
+
+static bool export_stmt(Exporter *ex, Statement *s) {
+ export_u8(ex, (U8)s->kind);
+ switch (s->kind) {
+ case STMT_EXPR:
+ if (!export_expr(ex, &s->expr))
+ return false;
+ break;
+ case STMT_DECL:
+ if (!export_decl(ex, &s->decl))
+ return false;
+ break;
+ case STMT_RET:
+ assert(sizeof s->ret.flags == 1);
+ export_u8(ex, (U8)s->ret.flags);
+ if (s->ret.flags & RET_HAS_EXPR)
+ if (!export_expr(ex, &s->ret.expr))
+ return false;
+ break;
+ }
+ return true;
+}
+
+static bool export_block(Exporter *ex, Block *b) {
+ export_location(ex, b->start);
+ export_location(ex, b->end);
+ if (!export_len32(ex, arr_len(b->stmts), "statements in a block", b->start))
+ return false;
+ arr_foreach(b->stmts, Statement, s) {
+ if (!export_stmt(ex, s))
+ return false;
+ }
+ export_u8(ex, b->ret_expr != NULL);
+ if (b->ret_expr)
+ if (!export_expr(ex, b->ret_expr))
+ return false;
+ return true;
+}
+
+static bool export_fn(Exporter *ex, FnExpr *f, Location where) {
+ if (!export_len16(ex, arr_len(f->params), "parameters in a function", where))
+ return false;
+ arr_foreach(f->params, Declaration, param)
+ if (!export_decl(ex, param))
+ return false;
+ if (!export_len8(ex, arr_len(f->ret_decls), "return declarations", where))
+ return false;
+ arr_foreach(f->ret_decls, Declaration, ret_decl)
+ if (!export_decl(ex, ret_decl))
+ return false;
+ /* no need to export the return type */
+ if (!export_block(ex, &f->body))
+ return false;
+ return true;
+}
+
+/* does NOT close the file */
+static bool exptr_finish(Exporter *ex) {
+ if (!export_len32(ex, arr_len(ex->exported_fns), "exported functions", LOCATION_NONE))
+ return false;
+ arr_foreach(ex->exported_fns, FnWithLocation, f) {
+ if (!export_fn(ex, f->fn, f->where))
+ return false;
+ }
+ return true;
+}
diff --git a/parse.c b/parse.c
index 78341fb..d8765de 100644
--- a/parse.c
+++ b/parse.c
@@ -1021,7 +1021,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
e->kind = EXPR_FN;
if (!parse_fn_expr(p, e->fn = parser_malloc(p, sizeof *e->fn)))
return false;
-
+ e->fn->export.id = 0;
if (t->token != end) {
if (token_is_kw(t->token, KW_LPAREN))
tokr_err(t, "Direct function calling in an expression is not supported.\nYou can wrap the function in parentheses.");
diff --git a/test.toc b/test.toc
index fba8ffb..24b6bcf 100644
--- a/test.toc
+++ b/test.toc
@@ -1,2 +1,4 @@
-#export asdf ::= int;
-#export ghjk := #sizeof(asdf); \ No newline at end of file
+#export main ::= fn() int {
+ {3}
+};
+// #export ghjk := #sizeof(asdf); \ No newline at end of file
diff --git a/toc.c b/toc.c
index cd19afb..18c79bb 100644
--- a/toc.c
+++ b/toc.c
@@ -31,6 +31,12 @@
/* forward declarations for debugging */
static void print_val(Value v, Type *t);
+
+/* misc */
+#define JOIN(a,b) a##b
+#define STRINGIFY2(x) #x
+#define STRINGIFY(x) STRINGIFY2(x)
+
static void fprint_char_literal(FILE *f, char c) {
if (isprint(c))
fprintf(f, "'%c'", c);
@@ -39,6 +45,7 @@ static void fprint_char_literal(FILE *f, char c) {
}
+
/* utilities */
#include "allocator.c"
#include "arr.c"
diff --git a/types.h b/types.h
index d2d6757..e15e550 100644
--- a/types.h
+++ b/types.h
@@ -69,13 +69,11 @@ typedef double F64;
typedef U32 IdentID; /* identifier ID for cgen (anonymous variables). not to be confused with IdentTree.id */
-#define join(a,b) a##b
-
/* for keeping track of whence something came */
#ifdef TOC_DEBUG
#define SOURCE_LOCATION char *src_file; int src_line;
#define SOURCE_LOCATION_PARAMS char *src_file, int src_line,
-#define DEBUG_UNDERSCORE(x) join(x,_)
+#define DEBUG_UNDERSCORE(x) JOIN(x,_)
#else
#define SOURCE_LOCATION
#define SOURCE_LOCATION_PARAMS
@@ -547,6 +545,7 @@ typedef struct EachExpr {
};
} EachExpr;
+
typedef struct FnExpr {
struct Declaration *params; /* declarations of the parameters to this function */
struct Declaration *ret_decls; /* array of decls, if this has named return values. otherwise, NULL */
@@ -557,6 +556,11 @@ typedef struct FnExpr {
if the ith semi-constant parameter is constant.
*/
struct {
+ U32 id; /* (index of function in ex->exported_fns) + 1,
+ or 0 if this function has not been
+ added to the exporting array yet */
+ } export;
+ struct {
/* if name = NULL, this is an anonymous function, and id will be the ID of the fn. */
Identifier name;
IdentID id;
@@ -669,7 +673,7 @@ enum {
DECL_EXPORT = 0x0200
};
-typedef U32 DeclFlags;
+typedef U16 DeclFlags;
/* OPTIM: Instead of using dynamic arrays, do two passes. */
typedef struct Declaration {
@@ -691,7 +695,7 @@ enum {
RET_HAS_EXPR = 0x01,
};
typedef struct Return {
- U16 flags;
+ U8 flags; /* if this changes, go to package.c */
Expression expr;
} Return;
@@ -745,9 +749,15 @@ typedef struct Typer {
FnExpr *fn; /* the function we're currently parsing. */
} Typer;
+typedef struct {
+ FnExpr *fn;
+ Location where;
+} FnWithLocation;
+
typedef struct Exporter {
FILE *out; /* .top (toc package) to output to */
bool export_locations;
+ FnWithLocation *exported_fns;
} Exporter;
typedef struct CGenerator {