From 450f16008fd62e9f5daa888f71ae9a6f6111112b Mon Sep 17 00:00:00 2001 From: saqut Date: Fri, 19 Jun 2026 16:09:57 +0300 Subject: [PATCH] =?UTF-8?q?fix(ir):=20break/continue=20IR=20=C3=BCretimi?= =?UTF-8?q?=20=E2=80=94=20d=C3=B6ng=C3=BC=20ba=C4=9Flam=C4=B1=20y=C4=B1?= =?UTF-8?q?=C4=9F=C4=B1n=C4=B1=20(B3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sorun: break ve continue için hiçbir opcode üretilmiyordu (TODO). Düzeltme: her döngüye girerken LoopContext yığına push'lanır, çıkınca pop'lanır. break/continue JMP -1 yazar, instruction indeksi bağlamda toplanır. Döngü üretimi bitince tüm pending jump'lar doğru hedefe patch'lenir: - break → her döngü türünde OUT (döngü sonu) - continue while/do-while → LOOP_START / COND_LABEL - continue for → C_LABEL (güncelleme başı, koşula DEĞİL) (aksi halde i++ atlanır → sonsuz döngü) İç içe döngülerde yığının en üstü en içteki bağlamdır; inner break/continue dıştaki döngüyü etkilemez. Testler (16/16 yeşil): - for_break_continue: continue'nun i++'ı atlamadığını kanıtlar - while_break_continue: while break/continue - nested_break: inner break dış döngüyü etkilemiyor Co-Authored-By: Claude Sonnet 4.6 --- build/.ninja_deps | Bin 77384 -> 80644 bytes build/.ninja_log | 12 +- build/CMakeFiles/VerifyGlobs.cmake | 3 + build/CTestTestfile.cmake | 6 + build/Testing/Temporary/CTestCostData.txt | 29 ++-- build/Testing/Temporary/LastTest.log | 159 +++++++++++------- src/ir/ir_generator.cpp | 86 +++++++--- src/ir/ir_generator.hpp | 9 + .../golden/loops/for_break_continue.expected | 5 + tests/golden/loops/for_break_continue.sqt | 24 +++ tests/golden/loops/nested_break.expected | 6 + tests/golden/loops/nested_break.sqt | 21 +++ .../loops/while_break_continue.expected | 7 + tests/golden/loops/while_break_continue.sqt | 22 +++ 14 files changed, 286 insertions(+), 103 deletions(-) create mode 100644 tests/golden/loops/for_break_continue.expected create mode 100644 tests/golden/loops/for_break_continue.sqt create mode 100644 tests/golden/loops/nested_break.expected create mode 100644 tests/golden/loops/nested_break.sqt create mode 100644 tests/golden/loops/while_break_continue.expected create mode 100644 tests/golden/loops/while_break_continue.sqt diff --git a/build/.ninja_deps b/build/.ninja_deps index b3a166c4f3ad9a9e7a050aeed1bc7125b8b08dac..42530f5d4c5536dd05c10fa328cd0a8b3528e870 100644 GIT binary patch delta 72 zcmX?cho$8kOT!jM4?Vs!tPBlH85tO6do1_Otld0o{vlRA7dD25CZJf%$4%=qYq#Ix bXS8DDTfo53umC97`ObD -Test time = 4.56 sec +Test time = 4.60 sec ---------------------------------------------------------- Test Passed. -"unit_tests" end time: Jun 19 15:59 +03 +"unit_tests" end time: Jun 19 16:09 +03 "unit_tests" time elapsed: 00:00:04 ---------------------------------------------------------- -2/13 Testing: golden_arithmetic_basic -2/13 Test: golden_arithmetic_basic +2/16 Testing: golden_arithmetic_basic +2/16 Test: golden_arithmetic_basic Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/basic.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/basic.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_arithmetic_basic" start time: Jun 19 15:59 +03 +"golden_arithmetic_basic" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_arithmetic_basic" end time: Jun 19 15:59 +03 +"golden_arithmetic_basic" end time: Jun 19 16:09 +03 "golden_arithmetic_basic" time elapsed: 00:00:00 ---------------------------------------------------------- -3/13 Testing: golden_arithmetic_precedence -3/13 Test: golden_arithmetic_precedence +3/16 Testing: golden_arithmetic_precedence +3/16 Test: golden_arithmetic_precedence Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/precedence.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/arithmetic/precedence.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_arithmetic_precedence" start time: Jun 19 15:59 +03 +"golden_arithmetic_precedence" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_arithmetic_precedence" end time: Jun 19 15:59 +03 +"golden_arithmetic_precedence" end time: Jun 19 16:09 +03 "golden_arithmetic_precedence" time elapsed: 00:00:00 ---------------------------------------------------------- -4/13 Testing: golden_fibonacci_fib -4/13 Test: golden_fibonacci_fib +4/16 Testing: golden_fibonacci_fib +4/16 Test: golden_fibonacci_fib Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/fibonacci/fib.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/fibonacci/fib.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_fibonacci_fib" start time: Jun 19 15:59 +03 +"golden_fibonacci_fib" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_fibonacci_fib" end time: Jun 19 15:59 +03 +"golden_fibonacci_fib" end time: Jun 19 16:09 +03 "golden_fibonacci_fib" time elapsed: 00:00:00 ---------------------------------------------------------- -5/13 Testing: golden_logic_short_circuit -5/13 Test: golden_logic_short_circuit +5/16 Testing: golden_logic_short_circuit +5/16 Test: golden_logic_short_circuit Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/short_circuit.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/logic/short_circuit.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_logic_short_circuit" start time: Jun 19 15:59 +03 +"golden_logic_short_circuit" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_logic_short_circuit" end time: Jun 19 15:59 +03 +"golden_logic_short_circuit" end time: Jun 19 16:09 +03 "golden_logic_short_circuit" time elapsed: 00:00:00 ---------------------------------------------------------- -6/13 Testing: golden_loops_basic -6/13 Test: golden_loops_basic +6/16 Testing: golden_loops_basic +6/16 Test: golden_loops_basic Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/basic.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/basic.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_loops_basic" start time: Jun 19 15:59 +03 +"golden_loops_basic" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_loops_basic" end time: Jun 19 15:59 +03 +"golden_loops_basic" end time: Jun 19 16:09 +03 "golden_loops_basic" time elapsed: 00:00:00 ---------------------------------------------------------- -7/13 Testing: golden_loops_do_while_once -7/13 Test: golden_loops_do_while_once +7/16 Testing: golden_loops_do_while_once +7/16 Test: golden_loops_do_while_once Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_once.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_once.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_loops_do_while_once" start time: Jun 19 15:59 +03 +"golden_loops_do_while_once" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_loops_do_while_once" end time: Jun 19 15:59 +03 +"golden_loops_do_while_once" end time: Jun 19 16:09 +03 "golden_loops_do_while_once" time elapsed: 00:00:00 ---------------------------------------------------------- -8/13 Testing: golden_loops_do_while_truthy -8/13 Test: golden_loops_do_while_truthy +8/16 Testing: golden_loops_do_while_truthy +8/16 Test: golden_loops_do_while_truthy Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_truthy.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/do_while_truthy.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_loops_do_while_truthy" start time: Jun 19 15:59 +03 +"golden_loops_do_while_truthy" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_loops_do_while_truthy" end time: Jun 19 15:59 +03 +"golden_loops_do_while_truthy" end time: Jun 19 16:09 +03 "golden_loops_do_while_truthy" time elapsed: 00:00:00 ---------------------------------------------------------- -9/13 Testing: golden_opt_dce_ir_opt -9/13 Test: golden_opt_dce_ir_opt -Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/dce.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/dce.ir_opt.expected" "-DCOMMAND=ir" "-DOPTIMIZED=1" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" +9/16 Testing: golden_loops_for_break_continue +9/16 Test: golden_loops_for_break_continue +Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/for_break_continue.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/for_break_continue.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_opt_dce_ir_opt" start time: Jun 19 15:59 +03 +"golden_loops_for_break_continue" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_opt_dce_ir_opt" end time: Jun 19 15:59 +03 +"golden_loops_for_break_continue" end time: Jun 19 16:09 +03 +"golden_loops_for_break_continue" time elapsed: 00:00:00 +---------------------------------------------------------- + +10/16 Testing: golden_loops_nested_break +10/16 Test: golden_loops_nested_break +Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/nested_break.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/nested_break.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" +Directory: /home/saqut/Masaüstü/saqutcompiler/build +"golden_loops_nested_break" start time: Jun 19 16:09 +03 +Output: +---------------------------------------------------------- + +Test time = 0.01 sec +---------------------------------------------------------- +Test Passed. +"golden_loops_nested_break" end time: Jun 19 16:09 +03 +"golden_loops_nested_break" time elapsed: 00:00:00 +---------------------------------------------------------- + +11/16 Testing: golden_loops_while_break_continue +11/16 Test: golden_loops_while_break_continue +Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/while_break_continue.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/loops/while_break_continue.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" +Directory: /home/saqut/Masaüstü/saqutcompiler/build +"golden_loops_while_break_continue" start time: Jun 19 16:09 +03 +Output: +---------------------------------------------------------- + +Test time = 0.01 sec +---------------------------------------------------------- +Test Passed. +"golden_loops_while_break_continue" end time: Jun 19 16:09 +03 +"golden_loops_while_break_continue" time elapsed: 00:00:00 +---------------------------------------------------------- + +12/16 Testing: golden_opt_dce_ir_opt +12/16 Test: golden_opt_dce_ir_opt +Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/dce.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/dce.ir_opt.expected" "-DCOMMAND=ir" "-DOPTIMIZED=1" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" +Directory: /home/saqut/Masaüstü/saqutcompiler/build +"golden_opt_dce_ir_opt" start time: Jun 19 16:09 +03 +Output: +---------------------------------------------------------- + +Test time = 0.01 sec +---------------------------------------------------------- +Test Passed. +"golden_opt_dce_ir_opt" end time: Jun 19 16:09 +03 "golden_opt_dce_ir_opt" time elapsed: 00:00:00 ---------------------------------------------------------- -10/13 Testing: golden_opt_folding_ir_opt -10/13 Test: golden_opt_folding_ir_opt +13/16 Testing: golden_opt_folding_ir_opt +13/16 Test: golden_opt_folding_ir_opt Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/folding.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/folding.ir_opt.expected" "-DCOMMAND=ir" "-DOPTIMIZED=1" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_opt_folding_ir_opt" start time: Jun 19 15:59 +03 +"golden_opt_folding_ir_opt" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_opt_folding_ir_opt" end time: Jun 19 15:59 +03 +"golden_opt_folding_ir_opt" end time: Jun 19 16:09 +03 "golden_opt_folding_ir_opt" time elapsed: 00:00:00 ---------------------------------------------------------- -11/13 Testing: golden_opt_run_opt -11/13 Test: golden_opt_run_opt +14/16 Testing: golden_opt_run_opt +14/16 Test: golden_opt_run_opt Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_opt_run_opt" start time: Jun 19 15:59 +03 +"golden_opt_run_opt" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- -Test time = 0.01 sec +Test time = 0.02 sec ---------------------------------------------------------- Test Passed. -"golden_opt_run_opt" end time: Jun 19 15:59 +03 +"golden_opt_run_opt" end time: Jun 19 16:09 +03 "golden_opt_run_opt" time elapsed: 00:00:00 ---------------------------------------------------------- -12/13 Testing: golden_opt_run_opt_run_opt -12/13 Test: golden_opt_run_opt_run_opt +15/16 Testing: golden_opt_run_opt_run_opt +15/16 Test: golden_opt_run_opt_run_opt Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/opt/run_opt.run_opt.expected" "-DOPTIMIZED=1" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_opt_run_opt_run_opt" start time: Jun 19 15:59 +03 +"golden_opt_run_opt_run_opt" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_opt_run_opt_run_opt" end time: Jun 19 15:59 +03 +"golden_opt_run_opt_run_opt" end time: Jun 19 16:09 +03 "golden_opt_run_opt_run_opt" time elapsed: 00:00:00 ---------------------------------------------------------- -13/13 Testing: golden_string_hello -13/13 Test: golden_string_hello +16/16 Testing: golden_string_hello +16/16 Test: golden_string_hello Command: "/usr/bin/cmake" "-DBINARY=/home/saqut/Masaüstü/saqutcompiler/build/saqut" "-DSOURCE=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/hello.sqt" "-DEXPECTED=/home/saqut/Masaüstü/saqutcompiler/tests/golden/string/hello.expected" "-P" "/home/saqut/Masaüstü/saqutcompiler/cmake/run_golden.cmake" Directory: /home/saqut/Masaüstü/saqutcompiler/build -"golden_string_hello" start time: Jun 19 15:59 +03 +"golden_string_hello" start time: Jun 19 16:09 +03 Output: ---------------------------------------------------------- Test time = 0.01 sec ---------------------------------------------------------- Test Passed. -"golden_string_hello" end time: Jun 19 15:59 +03 +"golden_string_hello" end time: Jun 19 16:09 +03 "golden_string_hello" time elapsed: 00:00:00 ---------------------------------------------------------- -End testing: Jun 19 15:59 +03 +End testing: Jun 19 16:09 +03 diff --git a/src/ir/ir_generator.cpp b/src/ir/ir_generator.cpp index b1ca33f..e4e4570 100644 --- a/src/ir/ir_generator.cpp +++ b/src/ir/ir_generator.cpp @@ -153,77 +153,101 @@ void IRGenerator::generateStatement(ASTNode* node) { case ASTKind::WhileStatement: { auto* ws = (WhileStatementNode*)node; - // Döngü başının konumu — geri-jump buraya gelecek int loopStart = currentInstrIndex(); + loopContextStack_.push_back({}); - int condSlot = generateExpression(ws->condition); - int exitJump = emitJumpIfFalse(condSlot); // ileri, backpatch bekliyor + int condSlot = generateExpression(ws->condition); + int exitJump = emitJumpIfFalse(condSlot); if (ws->body) generateStatement(ws->body); - // Geri-jump: hedef zaten biliniyor (loopStart) - emitJumpUnconditional(loopStart); + // continue → LOOP_START (hedef baştan beri biliniyor) + for (int idx : loopContextStack_.back().continueJumps) + currentFunction_->instructions[idx].jumpTarget = loopStart; - // Döngü çıkış noktası → exitJump'ı doldur - patchJump(exitJump); + emitJumpUnconditional(loopStart); + patchJump(exitJump); // OUT burası + + // break → OUT + int outTarget = currentInstrIndex(); + for (int idx : loopContextStack_.back().breakJumps) + currentFunction_->instructions[idx].jumpTarget = outTarget; + + loopContextStack_.pop_back(); break; } // ── for (init; koşul; güncelleme) { gövde } ───────────────────────── // - // Üretilen IR yapısı: + // IR yapısı (continue C_LABEL'a, break OUT'a atlar): // [init] // LOOP_START: - // [koşul] → condSlot - // JIF_FALSE condSlot → LOOP_END (ileri-jump, backpatch) + // [koşul] → JIF_FALSE OUT // [gövde] + // C_LABEL: // [güncelleme] - // JMP → LOOP_START (geri-jump, hedef biliniyor) - // LOOP_END: + // JMP LOOP_START + // OUT: // ───────────────────────────────────────────────────────────────────── case ASTKind::ForStatement: { auto* fs = (ForStatementNode*)node; - // Init: genellikle "int i = 0" gibi bir VariableDecl if (fs->init) generateStatement(fs->init); - // Döngü başı konumu — geri-jump'ın hedefi int loopStart = currentInstrIndex(); + loopContextStack_.push_back({}); - // Koşul int condSlot = fs->condition ? generateExpression(fs->condition) : -1; int exitJump = (condSlot != -1) ? emitJumpIfFalse(condSlot) : -1; - // Gövde if (fs->body) generateStatement(fs->body); - // Güncelleme (ör: i = i + 1) — ifade deyimi, sonuç önemsiz + // C_LABEL: güncelleme başlangıcı — continue buraya atlar + int cLabel = currentInstrIndex(); + for (int idx : loopContextStack_.back().continueJumps) + currentFunction_->instructions[idx].jumpTarget = cLabel; + if (fs->update) generateExpression(fs->update); - // Geri-jump: hedef loopStart, zaten biliniyor emitJumpUnconditional(loopStart); - // Döngü çıkışı → exitJump'ı doldur - if (exitJump != -1) patchJump(exitJump); + if (exitJump != -1) patchJump(exitJump); // OUT burası + + // break → OUT + int outTarget = currentInstrIndex(); + for (int idx : loopContextStack_.back().breakJumps) + currentFunction_->instructions[idx].jumpTarget = outTarget; + + loopContextStack_.pop_back(); break; } // ── do { gövde } while (koşul) ─────────────────────────────────────── case ASTKind::DoWhileStatement: { auto* dw = (DoWhileStatementNode*)node; + int loopStart = currentInstrIndex(); + loopContextStack_.push_back({}); if (dw->body) generateStatement(dw->body); + // COND_LABEL: koşul değerlendirmesi — continue buraya atlar + int condLabel = currentInstrIndex(); + for (int idx : loopContextStack_.back().continueJumps) + currentFunction_->instructions[idx].jumpTarget = condLabel; + int condSlot = generateExpression(dw->condition); - // truthy (sıfır-dışı herhangi bir değer) ise başa dön — JIF_TRUE. - // Eski "== 1" geçici çözümü kaldırıldı: koşul 2 gibi 1-olmayan - // truthy bir değer üretince yanlışlıkla çıkıyordu (B4). - // Geri-jump: hedef loopStart zaten biliniyor, backpatch gerekmez. Instruction jit(Opcode::JIF_TRUE); jit.cond = condSlot; jit.jumpTarget = loopStart; currentFunction_->instructions.push_back(std::move(jit)); + + // break → OUT (JIF_TRUE'dan sonraki konum) + int outTarget = currentInstrIndex(); + for (int idx : loopContextStack_.back().breakJumps) + currentFunction_->instructions[idx].jumpTarget = outTarget; + + loopContextStack_.pop_back(); break; } @@ -237,10 +261,18 @@ void IRGenerator::generateStatement(ASTNode* node) { break; } - case ASTKind::BreakStatement: - case ASTKind::ContinueStatement: - // TODO(vm-genişletme): break/continue için JMP + label mekanizması gerekir + case ASTKind::BreakStatement: { + int jumpIdx = emitJumpUnconditional(-1); + if (!loopContextStack_.empty()) + loopContextStack_.back().breakJumps.push_back(jumpIdx); break; + } + case ASTKind::ContinueStatement: { + int jumpIdx = emitJumpUnconditional(-1); + if (!loopContextStack_.empty()) + loopContextStack_.back().continueJumps.push_back(jumpIdx); + break; + } default: break; diff --git a/src/ir/ir_generator.hpp b/src/ir/ir_generator.hpp index eef4d7c..62ef77f 100644 --- a/src/ir/ir_generator.hpp +++ b/src/ir/ir_generator.hpp @@ -75,6 +75,15 @@ private: // Şu an kaç talimat üretildi? (jump hedefi belirlemek için) int currentInstrIndex() const; + // ── Döngü bağlamı yığını — break/continue hedefleri ───────────────── + // Her döngüye girerken bir giriş push'lanır, çıkınca pop'lanır. + // İç içe döngülerde en üstteki giriş en içteki döngüye aittir. + struct LoopContext { + std::vector breakJumps; // patch bekleyen break JMP indeksleri + std::vector continueJumps; // patch bekleyen continue JMP indeksleri + }; + std::vector loopContextStack_; + // ── Per-function üretim durumu ──────────────────────────────────────── IRFunction* currentFunction_ = nullptr; // şu an üretilen fonksiyon int nextSlot_ = 0; // sıradaki boş slot numarası diff --git a/tests/golden/loops/for_break_continue.expected b/tests/golden/loops/for_break_continue.expected new file mode 100644 index 0000000..3134c5a --- /dev/null +++ b/tests/golden/loops/for_break_continue.expected @@ -0,0 +1,5 @@ +1 +3 +5 +1 +2 diff --git a/tests/golden/loops/for_break_continue.sqt b/tests/golden/loops/for_break_continue.sqt new file mode 100644 index 0000000..961302f --- /dev/null +++ b/tests/golden/loops/for_break_continue.sqt @@ -0,0 +1,24 @@ +// for döngüsünde break ve continue golden testi. +// +// continue kanıtı: 2 ve 4 atlanır ama güncelleme (i++) hala çalışır. +// Eğer continue güncellemeyi atlasaydı i==2'de sonsuz döngüye girerdi. +// 5'in çıktıda görünmesi güncellemenin çalıştığını kanıtlar. +// +// break kanıtı: i==3'te erken çık — 3, 4, 5 görünmemeli. + +int main() { + int i = 0; + + for (i = 1; i <= 5; i = i + 1) { + if (i == 2) { continue; } + if (i == 4) { continue; } + print(i); + } + + for (i = 1; i <= 5; i = i + 1) { + if (i == 3) { break; } + print(i); + } + + return 0; +} diff --git a/tests/golden/loops/nested_break.expected b/tests/golden/loops/nested_break.expected new file mode 100644 index 0000000..570bd9e --- /dev/null +++ b/tests/golden/loops/nested_break.expected @@ -0,0 +1,6 @@ +1 +1 +2 +1 +3 +1 diff --git a/tests/golden/loops/nested_break.sqt b/tests/golden/loops/nested_break.sqt new file mode 100644 index 0000000..cf2b75c --- /dev/null +++ b/tests/golden/loops/nested_break.sqt @@ -0,0 +1,21 @@ +// İç içe döngü: içteki break sadece içteki döngüyü etkiler. +// Döngü bağlamı yığınının doğru çalıştığını kanıtlar. +// +// Beklenen: her dış iterasyonda j=1 yazdırılır, j=2'de inner break. +// Dış döngü i=1,2,3 boyunca devam eder — inner break dışarıya sızmaz. + +int main() { + int i = 1; + while (i <= 3) { + int j = 1; + while (j <= 3) { + if (j == 2) { break; } + print(i); + print(j); + j = j + 1; + } + i = i + 1; + } + + return 0; +} diff --git a/tests/golden/loops/while_break_continue.expected b/tests/golden/loops/while_break_continue.expected new file mode 100644 index 0000000..f71f392 --- /dev/null +++ b/tests/golden/loops/while_break_continue.expected @@ -0,0 +1,7 @@ +1 +2 +4 +5 +1 +2 +3 diff --git a/tests/golden/loops/while_break_continue.sqt b/tests/golden/loops/while_break_continue.sqt new file mode 100644 index 0000000..34d976d --- /dev/null +++ b/tests/golden/loops/while_break_continue.sqt @@ -0,0 +1,22 @@ +// while döngüsünde break ve continue golden testi. + +int main() { + int i = 0; + + // continue: 3'ü atla + while (i < 5) { + i = i + 1; + if (i == 3) { continue; } + print(i); + } + + // break: 4'te çık + i = 0; + while (i < 10) { + i = i + 1; + if (i == 4) { break; } + print(i); + } + + return 0; +}