diff --git a/tests/test_binary_op.py b/tests/test_binary_op.py index af962103..29111f3a 100644 --- a/tests/test_binary_op.py +++ b/tests/test_binary_op.py @@ -5,9 +5,9 @@ import pytest from irx import astx +from irx.astx import PrintExpr from irx.builders.base import Builder from irx.builders.llvmliteir import Builder as LLVMBuilder -from irx.system import PrintExpr from .conftest import check_result @@ -255,3 +255,63 @@ def test_binary_op_logical_and_or( module.block.append(main_fn) check_result("build", builder, module, expected_output=expect) + + +@pytest.mark.parametrize( + "a_val, b_val, op, true_label, false_label", + [ + (2.0, 3.0, "<=", "le_true", "le_false"), + (3.0, 2.0, ">=", "ge_true", "ge_false"), + (2.0, 2.0, "==", "eq_true", "eq_false"), + (1.0, 2.0, "!=", "ne_true", "ne_false"), + ], +) +@pytest.mark.parametrize("builder_class", [LLVMBuilder]) +def test_binary_op_float_comparison( + builder_class: type[Builder], + a_val: float, + b_val: float, + op: str, + true_label: str, + false_label: str, +) -> None: + """ + title: Test Float32 comparison operators cover fcmp_ordered paths. + parameters: + builder_class: + type: type[Builder] + a_val: + type: float + b_val: + type: float + op: + type: str + true_label: + type: str + false_label: + type: str + """ + builder = builder_class() + module = builder.module() + + cond = astx.BinaryOp( + op_code=op, + lhs=astx.LiteralFloat32(a_val), + rhs=astx.LiteralFloat32(b_val), + ) + then_blk = astx.Block() + then_blk.append(PrintExpr(astx.LiteralUTF8String(true_label))) + else_blk = astx.Block() + else_blk.append(PrintExpr(astx.LiteralUTF8String(false_label))) + if_stmt = astx.IfStmt(condition=cond, then=then_blk, else_=else_blk) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(if_stmt) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output=true_label) diff --git a/tests/test_while.py b/tests/test_while.py index 2e015551..10ef2387 100644 --- a/tests/test_while.py +++ b/tests/test_while.py @@ -5,6 +5,7 @@ import pytest from irx import astx +from irx.astx import PrintExpr from irx.builders.base import Builder from irx.builders.llvmliteir import Builder as LLVMBuilder from llvmlite import binding as llvm @@ -19,6 +20,8 @@ (astx.Int16, astx.LiteralInt16), (astx.Int8, astx.LiteralInt8), (astx.Int64, astx.LiteralInt64), + (astx.Float32, astx.LiteralFloat32), + (astx.Float64, astx.LiteralFloat64), ], ) @pytest.mark.parametrize( @@ -69,8 +72,15 @@ def test_while_expr( var_a = astx.Identifier("a") cond = astx.BinaryOp(op_code="<", lhs=var_a, rhs=literal_type(5)) - # Update: ++a - update = astx.UnaryOp(op_code="++", operand=var_a) + # Update: a = a + 1 (works for int and float; ++ only works for int) + update = astx.VariableAssignment( + name="a", + value=astx.BinaryOp( + op_code="+", + lhs=astx.Identifier("a"), + rhs=literal_type(1), + ), + ) # Body body = astx.Block() @@ -276,3 +286,56 @@ def test_while_false_condition( module.block.append(fn_main) check_result(action, builder, module, expected_file) + + +@pytest.mark.parametrize("builder_class", [LLVMBuilder]) +def test_while_float_condition( + builder_class: type[Builder], +) -> None: + """ + title: Test WhileStmt with a Float32 condition covers fcmp_ordered path. + parameters: + builder_class: + type: type[Builder] + """ + builder = builder_class() + + # float a = 3.0 + init_var = astx.InlineVariableDeclaration( + "a", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + + # condition: a (evaluates to float, hits fcmp_ordered 0.0) + var_a = astx.Identifier("a") + cond = var_a + + # body: a = a - 1.0 + dec = astx.VariableAssignment( + name="a", + value=astx.BinaryOp( + op_code="-", lhs=var_a, rhs=astx.LiteralFloat32(1.0) + ), + ) + body = astx.Block() + body.append(dec) + + while_expr = astx.WhileStmt(condition=cond, body=body) + + # Print "done" after loop to prove execution completed. + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + fn_block = astx.Block() + fn_block.append(init_var) + fn_block.append(while_expr) + fn_block.append(PrintExpr(astx.LiteralUTF8String("done"))) + fn_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + + fn_main = astx.FunctionDef(prototype=proto, body=fn_block) + module = builder.module() + module.block.append(fn_main) + + check_result("build", builder, module, expected_output="done")