feat: implement break

This commit is contained in:
samsonium
2026-10-22 21:30:32 +03:00
parent b5ae959d14
commit 7cfb8efef4
6 changed files with 60 additions and 13 deletions
+1
View File
@@ -19,6 +19,7 @@ typedef enum
FZL_NODETYPE_FIELD,
FZL_NODETYPE_CONSTRUCT,
FZL_NODETYPE_LOOP,
FZL_NODETYPE_BREAK,
FZL_NODETYPE_ADD,
FZL_NODETYPE_SUB,
+1
View File
@@ -16,6 +16,7 @@ typedef enum
FZL_TOKTYPE_FOR, // for
FZL_TOKTYPE_WHILE, // while
FZL_TOKTYPE_BREAK, // break
FZL_TOKTYPE_IF, // if
FZL_TOKTYPE_ELSE, // else
+2 -7
View File
@@ -20,6 +20,7 @@ void ghost_walk_changed(fzl_node_t *node, bool *changed, fzl_sym_t *sym)
switch (node->type)
{
case FZL_NODETYPE_BREAK:
case FZL_NODETYPE_DECLARATION:
case FZL_NODETYPE_CONSTRUCT:
case FZL_NODETYPE_CLASS:
@@ -134,6 +135,7 @@ bool retrieve_cond_sym(fzl_walker_t *walker, fzl_node_t *node, fzl_sym_t *sym)
switch (node->type)
{
case FZL_NODETYPE_BREAK:
case FZL_NODETYPE_BLOCK:
case FZL_NODETYPE_CALL:
case FZL_NODETYPE_LITERAL:
@@ -202,13 +204,6 @@ bool is_infinite_loop(fzl_walker_t *walker, fzl_node_t *node, size_t start_ip,
bool sym_exists = retrieve_cond_sym(walker, node->loop.cond, &sym);
if (sym_exists)
{
// fzl_sym_t sym;
// bool found = false;
// for (ssize_t i = walker->sym_top - 1; i >= 0; i--)
// if ((found = fzl_symt_get(walker->syms[i],
// (char *)declared->as.string.chars, &sym)))
// break;
if (sym.type >= FZL_TYPE_INT8)
{
bool value_changed = value_is_changed(node, &sym);
+10
View File
@@ -1198,6 +1198,13 @@ fzl_node_t *parse_loop(fzl_parser_t *parser)
return NULL;
}
// `break` keyword parsing
fzl_node_t *parse_break(fzl_parser_t *parser)
{
fzl_token_t *tok = consume(parser);
return fzl_mknode(FZL_NODETYPE_BREAK, tok);
}
// Statement parsing
fzl_node_t *parse_statement(fzl_parser_t *parser)
{
@@ -1218,6 +1225,8 @@ fzl_node_t *parse_statement(fzl_parser_t *parser)
return parse_block(parser);
else if (is(parser, FZL_TOKTYPE_FOR) || is(parser, FZL_TOKTYPE_WHILE))
return parse_loop(parser);
else if (is(parser, FZL_TOKTYPE_BREAK))
res = parse_break(parser);
if (!res)
res = parse_expression(parser);
@@ -1303,6 +1312,7 @@ void fzl_freeast(fzl_node_t *root)
{
switch (root->type)
{
case FZL_NODETYPE_BREAK:
case FZL_NODETYPE_IDENTIFIER:
case FZL_NODETYPE_LITERAL:
break;
+3
View File
@@ -78,6 +78,9 @@ fzl_token_t *parse_name(fzl_reader_t *reader)
else if (strcmp(value, "while") == 0)
tok =
fzl_mktoken(FZL_TOKTYPE_WHILE, l.line, l.col, value, size, l.filename);
else if (strcmp(value, "break") == 0)
tok =
fzl_mktoken(FZL_TOKTYPE_BREAK, l.line, l.col, value, size, l.filename);
else if (strcmp(value, "new") == 0)
tok = fzl_mktoken(FZL_TOKTYPE_NEW, l.line, l.col, value, size, l.filename);
else if (strcmp(value, "fn") == 0)
+43 -6
View File
@@ -203,9 +203,45 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
{
switch (node->type)
{
case FZL_NODETYPE_BREAK:
{
fzl_walk_ctx_t *ctx = walker->ctx;
while (ctx)
{
if (ctx->type == FZL_WALK_CTX_TYPE_LOOP)
break;
ctx = ctx->parent;
}
if (!ctx || ctx->type != FZL_WALK_CTX_TYPE_LOOP)
{
snprintf(wlast_err, sizeof(wlast_err),
"'%s': usage of 'break' outsude the loop at %ld:%ld",
node->token->filename, node->token->ln, node->token->cn);
return (fzl_walk_res_t){.error = true, .error_msg = wlast_err};
}
for (size_t i = walker->sym_top - 1; i > ctx->initial_env_lvl + 1; i--)
push_op(walker, FZL_OPCODE_RM_ENVTABLE);
if (ctx->breaks_remainder <= ctx->breaks_count)
{
ctx->breaks_remainder *= 2;
ctx->breaks =
realloc(ctx->breaks, ctx->breaks_remainder * sizeof(size_t));
}
push_op(walker, FZL_OPCODE_JMP);
ctx->breaks[ctx->breaks_count++] = walker->op_count;
push_word(walker, 0);
current_res = (fzl_walk_res_t){.type = FZL_TYPE_NULL, .error = false};
break;
}
// NOTE: add new levels for infinite loop check:
// 1. Dead condition (f.e. `while (i < 5)` w/o `i` increment)
// 2. Step direction (f.e. `for (; i > 5; i = i - 1)`)
// 1. Step direction (f.e. `for (; i > 5; i = i - 1)`)
case FZL_NODETYPE_LOOP:
{
fzl_walk_ctx_t *newctx = nest_ctx(walker, FZL_WALK_CTX_TYPE_LOOP);
@@ -273,6 +309,11 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
push_op(walker, FZL_OPCODE_JMP);
push_word(walker, start_ip);
// backpatch `break`s
for (size_t i = 0; i < newctx->breaks_count; i++)
walker->ops[newctx->breaks[i]] = walker->op_count;
push_op(walker, FZL_OPCODE_RM_ENVTABLE);
bool is_infinite =
@@ -289,10 +330,6 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node)
for (size_t i = walker->sym_top - 1; i > newctx->initial_env_lvl; i--)
fzl_freesymt(walker->syms[--walker->sym_top]);
// backpatch `break`s
for (size_t i = 0; i < newctx->breaks_count; i++)
walker->ops[newctx->breaks[i]] = walker->op_count - 1;
free(newctx->breaks);
if (!fin_ctx(walker))
{