feat: implement break
This commit is contained in:
@@ -19,6 +19,7 @@ typedef enum
|
||||
FZL_NODETYPE_FIELD,
|
||||
FZL_NODETYPE_CONSTRUCT,
|
||||
FZL_NODETYPE_LOOP,
|
||||
FZL_NODETYPE_BREAK,
|
||||
|
||||
FZL_NODETYPE_ADD,
|
||||
FZL_NODETYPE_SUB,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user