diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index ac24cfb6..4069e299 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,2 +1 @@ github: [LunaStev] -custom: [https://www.lunastev.org/ko/sponsor] diff --git a/llvm_temporary/src/llvm_temporary/statement.rs b/llvm_temporary/src/llvm_temporary/statement.rs index 0f713aed..1e981aea 100644 --- a/llvm_temporary/src/llvm_temporary/statement.rs +++ b/llvm_temporary/src/llvm_temporary/statement.rs @@ -575,7 +575,7 @@ pub fn generate_statement_ir<'ctx>( }) => { let current_fn = builder.get_insert_block().unwrap().get_parent().unwrap(); - let cond_value = generate_expression_ir( + let cond_any = generate_expression_ir( context, builder, condition, @@ -587,15 +587,32 @@ pub fn generate_statement_ir<'ctx>( struct_field_indices, ); + let cond_i1 = match cond_any { + BasicValueEnum::IntValue(iv) => { + if iv.get_type().get_bit_width() == 1 { + iv + } else { + let zero = iv.get_type().const_zero(); + builder.build_int_compare(inkwell::IntPredicate::NE, iv, zero, "if_cond").unwrap() + } + } + BasicValueEnum::FloatValue(fv) => { + let zero = fv.get_type().const_float(0.0); + builder.build_float_compare(inkwell::FloatPredicate::ONE, fv, zero, "if_cond").unwrap() + } + BasicValueEnum::PointerValue(pv) => builder.build_is_not_null(pv, "if_cond").unwrap(), + _ => panic!("Unsupported if condition type"), + }; + let then_block = context.append_basic_block(current_fn, "then"); let else_block_bb = context.append_basic_block(current_fn, "else"); let merge_block = context.append_basic_block(current_fn, "merge"); let _ = builder.build_conditional_branch( - cond_value.try_into().unwrap(), + cond_i1, then_block, else_block_bb, - ); + ).unwrap(); // ---- then block ---- builder.position_at_end(then_block); @@ -615,19 +632,20 @@ pub fn generate_statement_ir<'ctx>( struct_field_indices, ); } - let then_has_terminator = then_block.get_terminator().is_some(); - if !then_has_terminator { - let _ = builder.build_unconditional_branch(merge_block); + + let then_end = builder.get_insert_block().unwrap(); + if then_end.get_terminator().is_none() { + builder.build_unconditional_branch(merge_block).unwrap(); } - // ---- else block ---- - builder.position_at_end(else_block_bb); + let _ = builder.position_at_end(else_block_bb); + let mut current_check_bb = else_block_bb; - let else_has_terminator = if let Some(else_ifs) = else_if_blocks { - let mut current_bb = else_block_bb; + if let Some(else_ifs) = else_if_blocks { for (else_if_cond, else_if_body) in else_ifs.iter() { - let current_fn = builder.get_insert_block().unwrap().get_parent().unwrap(); - let cond_value = generate_expression_ir( + builder.position_at_end(current_check_bb); + + let c_any = generate_expression_ir( context, builder, else_if_cond, @@ -638,13 +656,30 @@ pub fn generate_statement_ir<'ctx>( &struct_types, struct_field_indices, ); + let c_i1 = match c_any { + BasicValueEnum::IntValue(iv) => { + if iv.get_type().get_bit_width() == 1 { iv } else { + let zero = iv.get_type().const_zero(); + builder.build_int_compare(inkwell::IntPredicate::NE, iv, zero, "elif_cond").unwrap() + } + } + BasicValueEnum::FloatValue(fv) => { + let zero = fv.get_type().const_float(0.0); + builder.build_float_compare(inkwell::FloatPredicate::ONE, fv, zero, "elif_cond").unwrap() + } + BasicValueEnum::PointerValue(pv) => builder.build_is_not_null(pv, "elif_cond").unwrap(), + _ => panic!("Unsupported else-if condition type"), + }; + let then_bb = context.append_basic_block(current_fn, "else_if_then"); let next_check_bb = context.append_basic_block(current_fn, "next_else_if"); + let _ = builder.build_conditional_branch( - cond_value.try_into().unwrap(), + c_i1, then_bb, next_check_bb, - ); + ).unwrap(); + builder.position_at_end(then_bb); for stmt in else_if_body { generate_statement_ir( @@ -662,13 +697,17 @@ pub fn generate_statement_ir<'ctx>( struct_field_indices, ); } - if then_bb.get_terminator().is_none() { + + let end_bb = builder.get_insert_block().unwrap(); + if end_bb.get_terminator().is_none() { let _ = builder.build_unconditional_branch(merge_block); } - builder.position_at_end(next_check_bb); - current_bb = next_check_bb; + + current_check_bb = next_check_bb; } + builder.position_at_end(current_check_bb); + // === FIX: Generate else_block after else_if blocks === if let Some(else_body) = else_block { for stmt in else_body.iter() { @@ -687,11 +726,18 @@ pub fn generate_statement_ir<'ctx>( struct_field_indices, ); } - current_bb.get_terminator().is_some() - } else { - current_bb.get_terminator().is_some() } - } else if let Some(else_body) = else_block { + let else_end = builder.get_insert_block().unwrap(); + if else_end.get_terminator().is_none() { + builder.build_unconditional_branch(merge_block).unwrap(); + } + + builder.position_at_end(merge_block); + } + + builder.position_at_end(current_check_bb); + + if let Some(else_body) = else_block.as_deref() { for stmt in else_body.iter() { generate_statement_ir( context, @@ -708,18 +754,14 @@ pub fn generate_statement_ir<'ctx>( struct_field_indices, ); } - else_block_bb.get_terminator().is_some() - } else { - false - }; - - if !else_has_terminator { - let _ = builder.build_unconditional_branch(merge_block); } - if !then_has_terminator || !else_has_terminator { - builder.position_at_end(merge_block); + let else_end = builder.get_insert_block().unwrap(); + if else_end.get_terminator().is_none() { + builder.build_unconditional_branch(merge_block).unwrap(); } + + builder.position_at_end(merge_block); } ASTNode::Statement(StatementNode::While { condition, body }) => { let current_fn = builder.get_insert_block().unwrap().get_parent().unwrap(); diff --git a/tools/run_tests.py b/tools/run_tests.py index 64721ad6..0d05aae2 100644 --- a/tools/run_tests.py +++ b/tools/run_tests.py @@ -2,6 +2,8 @@ import subprocess import time from pathlib import Path +import threading +import socket ROOT = Path(__file__).resolve().parent.parent TEST_DIR = ROOT / "test" @@ -13,18 +15,33 @@ RED = "\033[91m" YELLOW = "\033[93m" BLUE = "\033[94m" +CYAN = "\033[96m" RESET = "\033[0m" +KNOWN_TIMEOUT = { + "test22.wave", # input() not implemented +} + if not WAVEC.exists(): print("wavec not found. Run `cargo build --release` first.") exit(1) results = [] +def send_udp_for_test61(): + time.sleep(0.5) + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock.sendto(b"hello from python\n", ("127.0.0.1", 8080)) + sock.close() + def run_and_classify(name, cmd): print(f"{BLUE}RUN {name}{RESET}") try: + if name == "test61.wave": + t = threading.Thread(target=send_udp_for_test61, daemon=True) + t.start() + result = subprocess.run( cmd, stdout=subprocess.PIPE, @@ -41,11 +58,13 @@ def run_and_classify(name, cmd): return 0 except subprocess.TimeoutExpired: - print(f"{YELLOW}→ TIMEOUT ({TIMEOUT_SEC}s){RESET}\n") - return -1 - + if name in KNOWN_TIMEOUT: + print(f"{CYAN}→ SKIP (expected blocking / unimplemented){RESET}\n") + return 2 + else: + print(f"{YELLOW}→ TIMEOUT ({TIMEOUT_SEC}s){RESET}\n") + return -1 -# test*.wave for path in sorted(TEST_DIR.glob("test*.wave")): name = path.name cmd = [str(WAVEC), "run", f"test/{name}"] @@ -63,12 +82,11 @@ def run_and_classify(name, cmd): ) results.append(("test28 (dir)", result)) -# 집계 pass_tests = [name for name, r in results if r == 1] fail_tests = [name for name, r in results if r == 0] timeout_tests = [name for name, r in results if r == -1] +skip_tests = [name for name, r in results if r == 2] -# 최종 출력 print("\n=========================") print("🎉 FINAL TEST RESULT") print("=========================\n") @@ -77,6 +95,10 @@ def run_and_classify(name, cmd): for name in pass_tests: print(f" - {name}") +print(f"\n{CYAN}SKIP ({len(skip_tests)}){RESET}") +for name in skip_tests: + print(f" - {name}") + print(f"\n{RED}FAIL ({len(fail_tests)}){RESET}") for name in fail_tests: print(f" - {name}") @@ -87,6 +109,7 @@ def run_and_classify(name, cmd): print("\n=========================") print(f"{GREEN}PASS: {len(pass_tests)}{RESET}") +print(f"{CYAN}SKIP: {len(skip_tests)}{RESET}") print(f"{RED}FAIL: {len(fail_tests)}{RESET}") print(f"{YELLOW}TIMEOUT: {len(timeout_tests)}{RESET}") print("=========================\n")