From 24305209ebea722da0c9d7a3ff35dca41a2a4ef8 Mon Sep 17 00:00:00 2001 From: hanez Date: Sun, 14 Sep 2025 15:40:09 +0200 Subject: [PATCH] While loops. --- .gitignore | 1 + examples/while_test.fun | 35 ++++++++++++++++++++++++ src/parser.c | 60 +++++++++++++++++++++++++++++++++++++++-- 3 files changed, 94 insertions(+), 2 deletions(-) create mode 100755 examples/while_test.fun diff --git a/.gitignore b/.gitignore index febde90..f6b8d6a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ out/ src/*.o tmp/ .aiignore +dev.txt fun fun_test test_opcodes diff --git a/examples/while_test.fun b/examples/while_test.fun new file mode 100755 index 0000000..1a97e12 --- /dev/null +++ b/examples/while_test.fun @@ -0,0 +1,35 @@ +#!/usr/bin/env fun + +// While loops feature test: simple loops, nested with if/else, and functions + +print("=== while test start ===") + +// Simple counter 0..4 +number i = 0 +while (i < 5) + print(i) // expect 0,1,2,3,4 + i = i + 1 + +// Nested while with if/else +number a = 3 +while (a > 0) + if (a == 2) + print(99) // special case when a == 2 + else + print(a) + a = a - 1 // expect: 3, 99, 1 + +// While with false condition: body should not run +while (0) + print(123) + +// Function using while +fun countdown(n) + while (n > 0) + print(n) + n = n - 1 + return 0 + +print(countdown(3)) // expect: 3,2,1 then 0 + +print("=== while test end ===") diff --git a/src/parser.c b/src/parser.c index 5d4987c..813aa54 100644 --- a/src/parser.c +++ b/src/parser.c @@ -380,6 +380,22 @@ static int emit_multiplicative(Bytecode *bc, const char *src, size_t len, size_t if (!emit_unary(bc, src, len, pos)) return 0; for (;;) { skip_spaces(src, len, pos); + + /* Stop expression at start of inline comment */ + if (*pos + 1 < len && src[*pos] == '/' && src[*pos + 1] == '/') { + break; + } + /* Skip block comments inside expressions */ + if (*pos + 1 < len && src[*pos] == '/' && src[*pos + 1] == '*') { + size_t p = *pos + 2; + while (p + 1 < len && !(src[p] == '*' && src[p + 1] == '/')) { + p++; + } + if (p + 1 < len) p += 2; /* consume closing marker */ + *pos = p; + continue; + } + if (*pos < len && src[*pos] == '*') { (*pos)++; if (!emit_unary(bc, src, len, pos)) { parser_fail(*pos, "Expected expression after '*'"); return 0; } @@ -684,13 +700,18 @@ static void parse_simple_statement(Bytecode *bc, const char *src, size_t len, si } /* assignment or simple call */ - int gi = sym_index(name); + int lidx = local_find(name); + int gi = (lidx < 0) ? sym_index(name) : -1; free(name); skip_spaces(src, len, &local_pos); if (local_pos < len && src[local_pos] == '=') { local_pos++; /* '=' */ if (emit_expression(bc, src, len, &local_pos)) { - bytecode_add_instruction(bc, OP_STORE_GLOBAL, gi); + if (lidx >= 0) { + bytecode_add_instruction(bc, OP_STORE_LOCAL, lidx); + } else { + bytecode_add_instruction(bc, OP_STORE_GLOBAL, gi); + } } *pos = local_pos; skip_to_eol(src, len, pos); @@ -937,6 +958,41 @@ static void parse_block(Bytecode *bc, const char *src, size_t len, size_t *pos, continue; } + /* while loop */ + if (starts_with(src, len, *pos, "while")) { + *pos += 5; + skip_spaces(src, len, pos); + + int loop_start = bc->instr_count; + + /* condition */ + if (!emit_expression(bc, src, len, pos)) { + int ci = bytecode_add_constant(bc, make_int(0)); + bytecode_add_instruction(bc, OP_LOAD_CONST, ci); + } + /* end of condition */ + skip_to_eol(src, len, pos); + + /* jump over body if false */ + int jmp_false = bytecode_add_instruction(bc, OP_JUMP_IF_FALSE, 0); + + /* parse body at increased indent (peek indent without advancing pos) */ + int body_indent = 0; + size_t look_body = *pos; + if (read_line_start(src, len, &look_body, &body_indent) && body_indent > current_indent) { + parse_block(bc, src, len, pos, body_indent); + } else { + /* empty body allowed */ + } + + /* back edge to loop start */ + bytecode_add_instruction(bc, OP_JUMP, loop_start); + + /* patch false jump to here (after body) */ + bytecode_set_operand(bc, jmp_false, bc->instr_count); + continue; + } + /* otherwise: simple statement on this line */ parse_simple_statement(bc, src, len, pos); }