summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2019-09-22 12:39:32 -0400
committerLeo Tenenbaum <pommicket@gmail.com>2019-09-22 12:39:32 -0400
commit7e6069c7a137334fed51d1ef8ae2942d941818ad (patch)
treeed36674c954a19a1c4dc657fdd423963dfa40ecf
parentf95d0d7003f22917b0a8e22a5083edee357872d6 (diff)
prevented variables from being captured
-rw-r--r--main.c1
-rw-r--r--parse.c12
-rw-r--r--test.toc13
-rw-r--r--types.c22
4 files changed, 38 insertions, 10 deletions
diff --git a/main.c b/main.c
index d94fcaf..a963d0c 100644
--- a/main.c
+++ b/main.c
@@ -1,6 +1,5 @@
/*
TODO:
-allow void block expression statements not to have semicolons
don't allow nested functions to capture outer variables (constants are allowed though)
if, else
re-do cgen
diff --git a/parse.c b/parse.c
index 8f55c17..e0f6cdc 100644
--- a/parse.c
+++ b/parse.c
@@ -49,10 +49,17 @@ typedef struct Type {
};
} Type;
+typedef enum {
+ BLOCK_FN,
+ BLOCK_EXPR
+} BlockKind;
+
typedef struct Block {
+ BlockKind kind;
Location start;
Location end;
Array stmts;
+ struct Block *parent;
struct Expression *ret_expr; /* the return expression of this block, e.g. {foo(); 3} => 3 NULL for no expression. */
} Block;
@@ -555,6 +562,7 @@ static bool parse_stmt(Parser *p, Statement *s);
static bool parse_block(Parser *p, Block *b) {
Tokenizer *t = p->tokr;
Block *prev_block = p->block;
+ b->parent = prev_block;
p->block = b;
if (!token_is_kw(t->token, KW_LBRACE)) {
tokr_err(t, "Expected '{' to open block.");
@@ -566,7 +574,7 @@ static bool parse_block(Parser *p, Block *b) {
bool ret = true;
b->ret_expr = NULL; /* default to no return unless overwritten later */
if (!token_is_kw(t->token, KW_RBRACE)) {
- /* non-empty function body */
+ /* non-empty block */
while (1) {
Statement *stmt = arr_add(&b->stmts);
bool success = parse_stmt(p, stmt);
@@ -629,6 +637,7 @@ static bool parse_fn_expr(Parser *p, FnExpr *f) {
return false;
}
}
+ f->body.kind = BLOCK_FN;
return parse_block(p, &f->body);
}
@@ -918,6 +927,7 @@ static bool parse_expr(Parser *p, Expression *e, Token *end) {
if (token_is_kw(t->token, KW_LBRACE)) {
/* it's a block */
e->kind = EXPR_BLOCK;
+ e->block.kind = BLOCK_EXPR;
if (!parse_block(p, &e->block)) return false;
if (t->token != end) {
tokr_err(t, "Expression continues after end of block."); /* TODO: improve this err message */
diff --git a/test.toc b/test.toc
index 82666ee..720c87e 100644
--- a/test.toc
+++ b/test.toc
@@ -1,7 +1,12 @@
+x := 3;
+
main @= fn() {
- f := main;
- f();
- { main(); }
- f();
+ y := 5;
+ z @= 10;
+ foo @= fn() {
+ bar := y;
+ asdf := z;
+ gfdij := x;
+ };
};
diff --git a/types.c b/types.c
index f5804bc..472401d 100644
--- a/types.c
+++ b/types.c
@@ -1,5 +1,6 @@
typedef struct {
Array in_decls; /* array of declarations we are currently inside */
+ Block *block;
} Typer;
static bool type_of_expr(Typer *tr, Expression *e);
@@ -128,10 +129,7 @@ static bool expr_must_lval(Expression *e) {
switch (e->kind) {
case EXPR_IDENT: {
IdentDecl *id_decl = ident_decl(e->ident);
- if (!id_decl) {
- err_print(e->where, "Undeclared identifier.");
- return false;
- }
+ assert(id_decl);
Declaration *d = id_decl->decl;
if (d->flags & DECL_FLAG_CONST) {
char *istr = ident_to_str(e->ident);
@@ -163,6 +161,18 @@ static bool type_of_ident(Typer *tr, Location where, Identifier i, Type *t, bool
return false;
}
Declaration *d = decl->decl;
+ bool captured = false;
+ if (decl->scope != NULL)
+ for (Block *block = tr->block; block != decl->scope; block = block->parent) {
+ if (block->kind == BLOCK_FN) {
+ captured = true;
+ break;
+ }
+ }
+ if (captured && !(d->flags & DECL_FLAG_CONST)) {
+ err_print(where, "Variables cannot be captured into inner functions (but constants can).");
+ return false;
+ }
/* are we inside this declaration? */
typedef Declaration *DeclarationPtr;
arr_foreach(&tr->in_decls, DeclarationPtr, in_decl) {
@@ -504,6 +514,8 @@ static bool type_of_expr(Typer *tr, Expression *e) {
static bool types_block(Typer *tr, Block *b) {
bool ret = true;
+ Block *prev_block = tr->block;
+ tr->block = b;
if (!block_enter(b, &b->stmts)) return false;
arr_foreach(&b->stmts, Statement, s) {
if (!types_stmt(tr, s)) ret = false;
@@ -512,6 +524,7 @@ static bool types_block(Typer *tr, Block *b) {
if (!types_expr(tr, b->ret_expr))
ret = false;
block_exit(b, &b->stmts);
+ tr->block = prev_block;
return ret;
}
@@ -617,6 +630,7 @@ static bool types_stmt(Typer *tr, Statement *s) {
}
static void typer_create(Typer *tr) {
+ tr->block = NULL;
arr_create(&tr->in_decls, sizeof(Declaration *));
}