summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--abbrevs.txt1
-rw-r--r--cgen.c8
-rw-r--r--copy.c3
-rw-r--r--decls_cgen.c158
-rw-r--r--parse.c32
-rw-r--r--sdecls_cgen.c153
-rw-r--r--test.toc41
-rw-r--r--types.c15
-rw-r--r--types.h11
9 files changed, 228 insertions, 194 deletions
diff --git a/abbrevs.txt b/abbrevs.txt
index eb9f3f2..3b37880 100644
--- a/abbrevs.txt
+++ b/abbrevs.txt
@@ -1,6 +1,7 @@
allocr - allocator
arg - argument
cap - capacity
+cont - continue
ctx - context
decl - declaration
del - delete
diff --git a/cgen.c b/cgen.c
index 7eebc08..fe905fc 100644
--- a/cgen.c
+++ b/cgen.c
@@ -1997,6 +1997,12 @@ static void cgen_stmt(CGenerator *g, Statement *s) {
cgen_stmt(g, sub);
}
break;
+ case STMT_BREAK:
+ cgen_writeln(g, "break;");
+ break;
+ case STMT_CONT:
+ cgen_writeln(g, "continue;");
+ break;
case STMT_MESSAGE:
break;
}
@@ -2053,6 +2059,8 @@ static void cgen_defs_stmt(CGenerator *g, Statement *s) {
cgen_defs_stmt(g, sub);
}
break;
+ case STMT_BREAK:
+ case STMT_CONT:
case STMT_MESSAGE:
break;
}
diff --git a/copy.c b/copy.c
index 9ff5128..e3d2076 100644
--- a/copy.c
+++ b/copy.c
@@ -440,6 +440,9 @@ static void copy_stmt(Copier *c, Statement *out, Statement *in) {
case STMT_MESSAGE:
copy_expr(c, &out->message.text, &in->message.text);
break;
+ case STMT_BREAK:
+ case STMT_CONT:
+ break;
}
}
diff --git a/decls_cgen.c b/decls_cgen.c
index b9f7a04..72d9105 100644
--- a/decls_cgen.c
+++ b/decls_cgen.c
@@ -3,11 +3,165 @@
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 void cgen_sdecls_stmt(CGenerator *g, Statement *s);
+static void cgen_sdecls_decl(CGenerator *g, Declaration *d);
+static void cgen_sdecls_expr(CGenerator *g, Expression *e);
static void cgen_decls_stmt(CGenerator *g, Statement *s);
static void cgen_decls_block(CGenerator *g, Block *b);
static void cgen_decls_decl(CGenerator *g, Declaration *d);
+/* i is the name for this type, NULL if not available */
+static void cgen_sdecls_type(CGenerator *g, Type *type) {
+ if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */
+ return;
+ if (type->kind == TYPE_STRUCT) {
+ StructDef *sdef = type->struc;
+ /* we'll actually define the struct later; here we can just declare it */
+
+ if (sdef->flags & STRUCT_DEF_CGEN_DECLARED) {
+ /* we've already done this */
+ } else {
+ cgen_write(g, "struct ");
+ if (!sdef->name) {
+ sdef->c.id = ++g->ident_counter;
+ }
+ cgen_struct_name(g, sdef);
+ cgen_write(g, ";");
+ cgen_nl(g);
+ sdef->flags |= STRUCT_DEF_CGEN_DECLARED;
+ }
+ }
+ cgen_recurse_subtypes(cgen_sdecls_type, g, type);
+}
+
+static void cgen_sdecls_block(CGenerator *g, Block *b) {
+ Block *prev_block = g->block;
+ g->block = b;
+
+ arr_foreach(b->stmts, Statement, s)
+ cgen_sdecls_stmt(g, s);
+ if (b->ret_expr)
+ cgen_sdecls_expr(g, b->ret_expr);
+ g->block = prev_block;
+}
+
+static char *cgen_nms_prefix_part(CGenerator *g, Namespace *n) {
+ char *s;
+ while (n->points_to) {
+ n = n->points_to;
+ }
+ if (n->associated_ident) {
+ size_t ident_len = n->associated_ident->len;
+ s = malloc(ident_len + 3);
+ memcpy(s, n->associated_ident->str, ident_len);
+ s[ident_len] = '_';
+ s[ident_len+1] = '_';
+ s[ident_len+2] = '\0';
+ } else {
+ s = calloc(CGEN_IDENT_ID_STR_SIZE + 3, 1);
+ cgen_ident_id_to_str(s, ++g->ident_counter);
+ size_t len = strlen(s);
+ s[len] = '_';
+ s[len+1] = '_';
+ s[len+2] = '\0';
+ }
+ return s;
+}
+
+static void cgen_sdecls_expr(CGenerator *g, Expression *e) {
+ switch (e->kind) {
+ case EXPR_CAST:
+ cgen_sdecls_type(g, &e->cast.type);
+ break;
+ case EXPR_FN:
+ /* needs to go before decls_cgen.c... */
+ e->fn->c.id = ++g->ident_counter;
+ break;
+ case EXPR_TYPE:
+ cgen_sdecls_type(g, e->typeval);
+ break;
+ case EXPR_NMS: {
+ char *prefix_part = cgen_nms_prefix_part(g, e->nms);
+ size_t prefix_part_len = strlen(prefix_part);
+ char const *prev_prefix = g->nms_prefixes ? *(char const **)arr_last(g->nms_prefixes)
+ : "";
+ size_t prev_prefix_len = strlen(prev_prefix);
+ char *new_prefix = cgen_malloc(g, prev_prefix_len + prefix_part_len + 1);
+ memcpy(new_prefix, prev_prefix, prev_prefix_len);
+ memcpy(new_prefix + prev_prefix_len, prefix_part, prefix_part_len);
+ free(prefix_part);
+ *(char const **)arr_add(&g->nms_prefixes) = new_prefix;
+ new_prefix[prev_prefix_len + prefix_part_len] = 0;
+ e->nms->c.prefix = new_prefix;
+ } break;
+ default: break;
+ }
+ if (e->kind != EXPR_IDENT) {
+ cgen_recurse_subexprs(g, e, cgen_sdecls_expr, cgen_sdecls_block, cgen_sdecls_decl);
+ }
+ if (e->kind == EXPR_NMS) {
+ arr_remove_last(&g->nms_prefixes);
+ }
+}
+
+
+static void cgen_sdecls_decl(CGenerator *g, Declaration *d) {
+ cgen_sdecls_type(g, &d->type);
+ if (cgen_fn_is_direct(g, d)) {
+ d->expr.fn->c.name = d->idents[0];
+ }
+ for (int idx = 0; idx < (int)arr_len(d->idents); ++idx) {
+ Type *type = decl_type_at_index(d, idx);
+
+ if (type_is_builtin(type, BUILTIN_TYPE) && !(d->flags & DECL_IS_PARAM)) {
+ Value *val = decl_val_at_index(d, idx);
+ cgen_sdecls_type(g, val->type);
+ }
+ }
+ if (d->flags & DECL_HAS_EXPR) {
+ cgen_sdecls_expr(g, &d->expr);
+ if (d->flags & DECL_EXPORT) {
+ if (d->expr.kind == EXPR_FN)
+ d->expr.fn->flags |= FN_EXPR_EXPORT;
+ }
+ }
+}
+
+static void cgen_sdecls_stmt(CGenerator *g, Statement *s) {
+ switch (s->kind) {
+ case STMT_DECL:
+ cgen_sdecls_decl(g, s->decl);
+ break;
+ case STMT_EXPR:
+ cgen_sdecls_expr(g, &s->expr);
+ break;
+ case STMT_RET:
+ if (s->ret.flags & RET_HAS_EXPR)
+ cgen_sdecls_expr(g, &s->ret.expr);
+ break;
+ case STMT_INCLUDE:
+
+ if (s->inc.inc_file && (s->inc.inc_file->flags & INC_FILE_CGEND_SDECLS)) {
+ /* already generated */
+ } else {
+ if (s->inc.inc_file) s->inc.inc_file->flags |= INC_FILE_CGEND_SDECLS;
+ arr_foreach(s->inc.stmts, Statement, sub)
+ cgen_sdecls_stmt(g, sub);
+ }
+ break;
+ case STMT_BREAK:
+ case STMT_CONT:
+ case STMT_MESSAGE:
+ break;
+ }
+}
+
+static void cgen_sdecls_file(CGenerator *g, ParsedFile *f) {
+ arr_foreach(f->stmts, Statement, s) {
+ cgen_sdecls_stmt(g, s);
+ }
+}
+
static void cgen_decls_type(CGenerator *g, Type *type) {
if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */
return;
@@ -268,6 +422,8 @@ static void cgen_decls_stmt(CGenerator *g, Statement *s) {
cgen_decls_stmt(g, sub);
}
break;
+ case STMT_BREAK:
+ case STMT_CONT:
case STMT_MESSAGE:
break;
}
diff --git a/parse.c b/parse.c
index 01ed3e4..4b95c70 100644
--- a/parse.c
+++ b/parse.c
@@ -1547,6 +1547,7 @@ static Status parse_expr(Parser *p, Expression *e, Token *end) {
p->block = prev_block;
if (!parse_block(p, &fo->body, PARSE_BLOCK_DONT_CREATE_IDENTS))
goto for_fail;
+ fo->body.flags |= BLOCK_IS_LOOP;
goto success;
for_fail:
p->block = prev_block;
@@ -2444,14 +2445,33 @@ static Status parse_stmt(Parser *p, Statement *s, bool *was_a_statement) {
return false;
}
if (!token_is_kw(end, KW_SEMICOLON)) {
- err_print(token_location(p->file, end), "Expected ';' at end of return statement.");
+ err_print(token_location(p->file, end), "Expected ; at end of return statement.");
t->token = end->kind == TOKEN_EOF ? end : end + 1;
return false;
}
- bool success = parse_expr(p, &s->ret.expr, end);
+ bool parsed = parse_expr(p, &s->ret.expr, end);
t->token = end + 1;
- return success;
+ if (!parsed) return false;
+ goto success;
}
+ case KW_BREAK:
+ s->kind = STMT_BREAK;
+ ++t->token;
+ if (!token_is_kw(t->token, KW_SEMICOLON)) {
+ tokr_err(t, "Expected ; after break.");
+ tokr_skip_semicolon(t);
+ return false;
+ }
+ goto success;
+ case KW_CONTINUE:
+ s->kind = STMT_CONT;
+ ++t->token;
+ if (!token_is_kw(t->token, KW_SEMICOLON)) {
+ tokr_err(t, "Expected ; after continue.");
+ tokr_skip_semicolon(t);
+ return false;
+ }
+ goto success;
default: break;
}
} else if (t->token->kind == TOKEN_DIRECT) {
@@ -2934,6 +2954,12 @@ static void fprint_stmt(FILE *out, Statement *s) {
break;
}
} break;
+ case STMT_BREAK:
+ fprintf(out, "break;");
+ break;
+ case STMT_CONT:
+ fprintf(out, "continue;");
+ break;
}
}
diff --git a/sdecls_cgen.c b/sdecls_cgen.c
index 0445851..4033d4d 100644
--- a/sdecls_cgen.c
+++ b/sdecls_cgen.c
@@ -3,156 +3,3 @@
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 void cgen_sdecls_stmt(CGenerator *g, Statement *s);
-static void cgen_sdecls_decl(CGenerator *g, Declaration *d);
-static void cgen_sdecls_expr(CGenerator *g, Expression *e);
-
-/* i is the name for this type, NULL if not available */
-static void cgen_sdecls_type(CGenerator *g, Type *type) {
- if (!(type->flags & TYPE_IS_RESOLVED)) /* non-instance constant fn parameter type */
- return;
- if (type->kind == TYPE_STRUCT) {
- StructDef *sdef = type->struc;
- /* we'll actually define the struct later; here we can just declare it */
-
- if (sdef->flags & STRUCT_DEF_CGEN_DECLARED) {
- /* we've already done this */
- } else {
- cgen_write(g, "struct ");
- if (!sdef->name) {
- sdef->c.id = ++g->ident_counter;
- }
- cgen_struct_name(g, sdef);
- cgen_write(g, ";");
- cgen_nl(g);
- sdef->flags |= STRUCT_DEF_CGEN_DECLARED;
- }
- }
- cgen_recurse_subtypes(cgen_sdecls_type, g, type);
-}
-
-static void cgen_sdecls_block(CGenerator *g, Block *b) {
- Block *prev_block = g->block;
- g->block = b;
-
- arr_foreach(b->stmts, Statement, s)
- cgen_sdecls_stmt(g, s);
- if (b->ret_expr)
- cgen_sdecls_expr(g, b->ret_expr);
- g->block = prev_block;
-}
-
-static char *cgen_nms_prefix_part(CGenerator *g, Namespace *n) {
- char *s;
- while (n->points_to) {
- n = n->points_to;
- }
- if (n->associated_ident) {
- size_t ident_len = n->associated_ident->len;
- s = malloc(ident_len + 3);
- memcpy(s, n->associated_ident->str, ident_len);
- s[ident_len] = '_';
- s[ident_len+1] = '_';
- s[ident_len+2] = '\0';
- } else {
- s = calloc(CGEN_IDENT_ID_STR_SIZE + 3, 1);
- cgen_ident_id_to_str(s, ++g->ident_counter);
- size_t len = strlen(s);
- s[len] = '_';
- s[len+1] = '_';
- s[len+2] = '\0';
- }
- return s;
-}
-
-static void cgen_sdecls_expr(CGenerator *g, Expression *e) {
- switch (e->kind) {
- case EXPR_CAST:
- cgen_sdecls_type(g, &e->cast.type);
- break;
- case EXPR_FN:
- /* needs to go before decls_cgen.c... */
- e->fn->c.id = ++g->ident_counter;
- break;
- case EXPR_TYPE:
- cgen_sdecls_type(g, e->typeval);
- break;
- case EXPR_NMS: {
- char *prefix_part = cgen_nms_prefix_part(g, e->nms);
- size_t prefix_part_len = strlen(prefix_part);
- char const *prev_prefix = g->nms_prefixes ? *(char const **)arr_last(g->nms_prefixes)
- : "";
- size_t prev_prefix_len = strlen(prev_prefix);
- char *new_prefix = cgen_malloc(g, prev_prefix_len + prefix_part_len + 1);
- memcpy(new_prefix, prev_prefix, prev_prefix_len);
- memcpy(new_prefix + prev_prefix_len, prefix_part, prefix_part_len);
- free(prefix_part);
- *(char const **)arr_add(&g->nms_prefixes) = new_prefix;
- new_prefix[prev_prefix_len + prefix_part_len] = 0;
- e->nms->c.prefix = new_prefix;
- } break;
- default: break;
- }
- if (e->kind != EXPR_IDENT) {
- cgen_recurse_subexprs(g, e, cgen_sdecls_expr, cgen_sdecls_block, cgen_sdecls_decl);
- }
- if (e->kind == EXPR_NMS) {
- arr_remove_last(&g->nms_prefixes);
- }
-}
-
-
-static void cgen_sdecls_decl(CGenerator *g, Declaration *d) {
- cgen_sdecls_type(g, &d->type);
- if (cgen_fn_is_direct(g, d)) {
- d->expr.fn->c.name = d->idents[0];
- }
- for (int idx = 0; idx < (int)arr_len(d->idents); ++idx) {
- Type *type = decl_type_at_index(d, idx);
-
- if (type_is_builtin(type, BUILTIN_TYPE) && !(d->flags & DECL_IS_PARAM)) {
- Value *val = decl_val_at_index(d, idx);
- cgen_sdecls_type(g, val->type);
- }
- }
- if (d->flags & DECL_HAS_EXPR) {
- cgen_sdecls_expr(g, &d->expr);
- if (d->flags & DECL_EXPORT) {
- if (d->expr.kind == EXPR_FN)
- d->expr.fn->flags |= FN_EXPR_EXPORT;
- }
- }
-}
-
-static void cgen_sdecls_stmt(CGenerator *g, Statement *s) {
- switch (s->kind) {
- case STMT_DECL:
- cgen_sdecls_decl(g, s->decl);
- break;
- case STMT_EXPR:
- cgen_sdecls_expr(g, &s->expr);
- break;
- case STMT_RET:
- if (s->ret.flags & RET_HAS_EXPR)
- cgen_sdecls_expr(g, &s->ret.expr);
- break;
- case STMT_INCLUDE:
-
- if (s->inc.inc_file && (s->inc.inc_file->flags & INC_FILE_CGEND_SDECLS)) {
- /* already generated */
- } else {
- if (s->inc.inc_file) s->inc.inc_file->flags |= INC_FILE_CGEND_SDECLS;
- arr_foreach(s->inc.stmts, Statement, sub)
- cgen_sdecls_stmt(g, sub);
- }
- break;
- case STMT_MESSAGE:
- break;
- }
-}
-
-static void cgen_sdecls_file(CGenerator *g, ParsedFile *f) {
- arr_foreach(f->stmts, Statement, s) {
- cgen_sdecls_stmt(g, s);
- }
-}
diff --git a/test.toc b/test.toc
index 03ffe28..398f7b7 100644
--- a/test.toc
+++ b/test.toc
@@ -1,38 +1,9 @@
-
-printf ::= #foreign("printf","libc.so.6") fn(#C &"const char", #C ..) #C int;
-
-
-// NOTE: this doesn't work (e.g. "%%%")
-tprintf_valid ::= fn(fmt :: []char, nargs: int) bool {
- if fmt[fmt.len-1] != '\0' {
- return false;
- }
- count := 0;
- for x, i := fmt {
- if x == '%' {
- if i == fmt.len-1 {
- count += 1;
- } elif fmt[i+1] != '%' {
- count += 1;
- } else {
- count -= 1;
- }
- }
- }
- count == nargs
-}
-
-
-tprintf ::= fn(fmt :: []char, args: ..) {
- #if !tprintf_valid(fmt, args.len) {
- #error "Invalid printf format";
- }
- f := fmt;
- printf(&f[0], args);
-}
+#include "std/io.toc", io;
main ::= fn() {
- tprintf("%d %d%%\n\0", 3, 4);
+ for i := 1..10 {
+ if i % 2 == 0 { continue; }
+ io.puti(i);
+ if i == 7 { break; }
+ }
}
-
-main(); \ No newline at end of file
diff --git a/types.c b/types.c
index 9d36e78..f202bca 100644
--- a/types.c
+++ b/types.c
@@ -3375,6 +3375,21 @@ static Status types_stmt(Typer *tr, Statement *s) {
return false;
}
} break;
+ case STMT_BREAK:
+ case STMT_CONT: {
+ /* make sure we are actually in a loop */
+ Block *block;
+ for (block = tr->block; block; block = block->parent) {
+ if (block->flags & BLOCK_IS_LOOP) {
+ s->referring_to = block;
+ break;
+ }
+ }
+ if (!block) {
+ err_print(s->where, "%s not in loop.", s->kind == STMT_BREAK ? "break" : "continue");
+ return false;
+ }
+ } break;
}
s->flags |= STMT_TYPED;
return true;
diff --git a/types.h b/types.h
index 6b6df59..a9c2268 100644
--- a/types.h
+++ b/types.h
@@ -296,6 +296,8 @@ typedef enum {
KW_WHILE,
KW_FOR,
KW_RETURN,
+ KW_BREAK,
+ KW_CONTINUE,
KW_FN,
KW_AS,
KW_NEW,
@@ -330,7 +332,8 @@ static const char *const keywords[KW_COUNT] =
"!=", "<=", "<", ">=", ">",
"+", "-", "*", "!", "&", "/", "%", "..", ".",
"=",
- "if", "elif", "else", "while", "for", "return", "fn", "as",
+ "if", "elif", "else", "while", "for", "return", "break",
+ "continue", "fn", "as",
"new", "del", "struct",
"int", "i8", "i16", "i32", "i64",
"u8", "u16", "u32", "u64", "float", "f32", "f64", "Type",
@@ -492,7 +495,8 @@ enum {
BLOCK_IS_FN = 0x01,
BLOCK_IS_NMS = 0x02,
BLOCK_FINDING_TYPES = 0x04,
- BLOCK_FOUND_TYPES = 0x08
+ BLOCK_FOUND_TYPES = 0x08,
+ BLOCK_IS_LOOP = 0x10 /* can we break/continue in this block? */
};
typedef U8 BlockFlags;
typedef struct Block {
@@ -904,6 +908,8 @@ typedef enum {
STMT_DECL,
STMT_EXPR,
STMT_RET,
+ STMT_BREAK,
+ STMT_CONT,
STMT_INCLUDE,
STMT_MESSAGE
} StatementKind;
@@ -968,6 +974,7 @@ typedef struct Statement {
Return ret;
Include inc;
Message message; /* #error, #warn, #info */
+ Block *referring_to; /* for break/continue */
};
} Statement;