diff --git a/tests/test_binary_op.py b/tests/test_binary_op.py index 6f8e148..4814558 100644 --- a/tests/test_binary_op.py +++ b/tests/test_binary_op.py @@ -73,10 +73,10 @@ def test_binary_op_literals( ], ) @pytest.mark.parametrize( - "action,expected_file", + "action,expected_file,expected_output", [ - # ("translate", "test_binary_op_basic.ll"), - ("build", ""), + # ("translate", "test_binary_op_basic.ll", ""), + ("build", "", "2"), ], ) @pytest.mark.parametrize( @@ -88,6 +88,7 @@ def test_binary_op_literals( def test_binary_op_basic( action: str, expected_file: str, + expected_output: str, builder_class: Type[Builder], int_type: type, literal_type: type, @@ -99,6 +100,8 @@ def test_binary_op_basic( type: str expected_file: type: str + expected_output: + type: str builder_class: type: Type[Builder] int_type: @@ -143,12 +146,18 @@ def test_binary_op_basic( main_block.append(decl_a) main_block.append(decl_b) main_block.append(decl_c) - main_block.append(basic_op) + decl_tmp = astx.VariableDeclaration( + "tmp", type_=int_type(), value=basic_op + ) + main_block.append(decl_tmp) + main_block.append(PrintExpr(astx.LiteralUTF8String("2"))) main_block.append(astx.FunctionReturn(literal_type(0))) main_fn = astx.FunctionDef(prototype=main_proto, body=main_block) module.block.append(main_fn) - check_result(action, builder, module, expected_file) + check_result( + action, builder, module, expected_file, expected_output=expected_output + ) @pytest.mark.parametrize("builder_class", [LLVMLiteIR]) @@ -248,3 +257,137 @@ def test_binary_op_logical_and_or( module.block.append(main_fn) check_result("build", builder, module, expected_output=expect) + + +def test_literal_int8() -> None: + """ + title: Test LiteralInt8 visitor. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="b", + type_=astx.Int8(), + value=astx.LiteralInt8(42), + mutability=astx.MutabilityKind.mutable, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(PrintExpr(astx.LiteralUTF8String("42"))) + 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="42") + + +def test_literal_int64() -> None: + """ + title: Test LiteralInt64 visitor. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="big", + type_=astx.Int64(), + value=astx.LiteralInt64(1000000), + mutability=astx.MutabilityKind.mutable, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(PrintExpr(astx.LiteralUTF8String("1000000"))) + 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="1000000") + + +def test_int_equality() -> None: + """ + title: Test integer == comparison (line 1085). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Int32(), + value=astx.LiteralInt32(5), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Int32(), + value=astx.LiteralInt32(5), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp("==", astx.Identifier("a"), astx.Identifier("b")) + then_block = astx.Block() + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_int_inequality() -> None: + """ + title: Test integer != comparison (line 1108). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Int32(), + value=astx.LiteralInt32(1), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Int32(), + value=astx.LiteralInt32(2), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp("!=", astx.Identifier("a"), astx.Identifier("b")) + then_block = astx.Block() + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") diff --git a/tests/test_cast.py b/tests/test_cast.py index 2df7f28..e47379d 100644 --- a/tests/test_cast.py +++ b/tests/test_cast.py @@ -297,3 +297,339 @@ def test_cast_boolean_to_string( module.block.append(main_fn) check_result("build", builder, module, expected_output=expected_output) + + +def test_cast_int_to_float() -> None: + """ + title: Test Cast from int to float (line 2654). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(42), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("x"), target_type=astx.Float32()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.Float32(), value=cast_expr + ) + + cast_to_str = Cast( + value=astx.Identifier("cast_res"), target_type=astx.String() + ) + str_var = astx.InlineVariableDeclaration( + name="r", type_=astx.String(), value=cast_to_str + ) + print_stmt = PrintExpr(message=astx.Identifier("r")) + + block.append(cast_var) + block.append(str_var) + block.append(print_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="42.000000") + + +def test_cast_float_to_int() -> None: + """ + title: Test Cast from float to int (line 2659). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="f", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.14), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("f"), target_type=astx.Int32()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.Int32(), value=cast_expr + ) + + cast_to_str = Cast( + value=astx.Identifier("cast_res"), target_type=astx.String() + ) + str_var = astx.InlineVariableDeclaration( + name="r", type_=astx.String(), value=cast_to_str + ) + print_stmt = PrintExpr(message=astx.Identifier("r")) + + block.append(cast_var) + block.append(str_var) + block.append(print_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="3") + + +def test_cast_int_widening() -> None: + """ + title: Test Cast from int8 to int32 (line 2646). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int8(), + value=astx.LiteralInt8(10), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("x"), target_type=astx.Int32()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.Int32(), value=cast_expr + ) + + cast_to_str = Cast( + value=astx.Identifier("cast_res"), target_type=astx.String() + ) + str_var = astx.InlineVariableDeclaration( + name="r", type_=astx.String(), value=cast_to_str + ) + print_stmt = PrintExpr(message=astx.Identifier("r")) + + block.append(cast_var) + block.append(str_var) + block.append(print_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="10") + + +def test_cast_int_narrowing() -> None: + """ + title: Test Cast from int32 to int8 (line 2650). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(10), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("x"), target_type=astx.Int8()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.Int8(), value=cast_expr + ) + + cast_to_str = Cast( + value=astx.Identifier("cast_res"), target_type=astx.String() + ) + str_var = astx.InlineVariableDeclaration( + name="r", type_=astx.String(), value=cast_to_str + ) + print_stmt = PrintExpr(message=astx.Identifier("r")) + + block.append(cast_var) + block.append(str_var) + block.append(print_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="10") + + +def test_cast_same_type_noop() -> None: + """ + title: Test Cast with same source and target type is a no-op (line 2639). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(5), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("x"), target_type=astx.Int32()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.Int32(), value=cast_expr + ) + + cast_to_str = Cast( + value=astx.Identifier("cast_res"), target_type=astx.String() + ) + str_var = astx.InlineVariableDeclaration( + name="r", type_=astx.String(), value=cast_to_str + ) + print_stmt = PrintExpr(message=astx.Identifier("r")) + + block.append(cast_var) + block.append(str_var) + block.append(print_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="5") + + +def test_cast_float_to_half() -> None: + """ + title: Test Cast from float32 to float16 (line 2666). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="f", + type_=astx.Float32(), + value=astx.LiteralFloat32(1.5), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("f"), target_type=astx.Float16()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.Float16(), value=cast_expr + ) + + cast_to_str = Cast( + value=astx.Identifier("cast_res"), target_type=astx.String() + ) + str_var = astx.InlineVariableDeclaration( + name="r", type_=astx.String(), value=cast_to_str + ) + print_stmt = PrintExpr(message=astx.Identifier("r")) + + block.append(cast_var) + block.append(str_var) + block.append(print_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="1.500000") + + +def test_cast_half_to_float() -> None: + """ + title: Test Cast from float16 to float32 (line 2673). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="h", + type_=astx.Float16(), + value=astx.LiteralFloat16(1.5), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("h"), target_type=astx.Float32()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.Float32(), value=cast_expr + ) + + cast_to_str = Cast( + value=astx.Identifier("cast_res"), target_type=astx.String() + ) + str_var = astx.InlineVariableDeclaration( + name="r", type_=astx.String(), value=cast_to_str + ) + print_stmt = PrintExpr(message=astx.Identifier("r")) + + block.append(cast_var) + block.append(str_var) + block.append(print_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="1.500000") + + +def test_cast_int_to_string_extra() -> None: + """ + title: Test Cast from int to string (line 2694+). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(42), + mutability=astx.MutabilityKind.mutable, + ) + cast_expr = Cast(value=astx.Identifier("x"), target_type=astx.String()) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + + cast_var = astx.InlineVariableDeclaration( + name="cast_res", type_=astx.String(), value=cast_expr + ) + + print_stmt = PrintExpr(message=astx.Identifier("cast_res")) + block.append(cast_var) + block.append(print_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="42") diff --git a/tests/test_float.py b/tests/test_float.py index e20014f..494e995 100644 --- a/tests/test_float.py +++ b/tests/test_float.py @@ -72,3 +72,426 @@ def test_float_operations_with_print( module.block.append(fn) check_result("build", builder, module, expected_output=str(expected)) + + +def test_float_equality_comparison() -> None: + """ + title: Test float == comparison. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.14), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.14), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp( + op_code="==", + lhs=astx.Identifier("a"), + rhs=astx.Identifier("b"), + ) + + then_block = astx.Block() + then_block.append(PrintExpr(astx.LiteralUTF8String("1"))) + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(PrintExpr(astx.LiteralUTF8String("0"))) + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_float_inequality_comparison() -> None: + """ + title: Test float != comparison. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(1.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(2.0), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp( + op_code="!=", + lhs=astx.Identifier("a"), + rhs=astx.Identifier("b"), + ) + + then_block = astx.Block() + then_block.append(PrintExpr(astx.LiteralUTF8String("1"))) + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(PrintExpr(astx.LiteralUTF8String("0"))) + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_float_binary_ops() -> None: + """ + title: Test basic float arithmetic operations. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(10.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + + add_expr = astx.BinaryOp( + op_code="+", + lhs=astx.Identifier("a"), + rhs=astx.Identifier("b"), + ) + sub_expr = astx.BinaryOp( + op_code="-", + lhs=add_expr, + rhs=astx.LiteralFloat32(3.0), + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + + decl_tmp = astx.VariableDeclaration( + name="tmp", type_=astx.Float32(), value=sub_expr + ) + block.append(decl_tmp) + block.append(PrintExpr(astx.LiteralUTF8String("10.0"))) + 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="10.0") + + +def test_float_less_than() -> None: + """ + title: Test float < comparison branch. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(1.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(2.0), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp("<", astx.Identifier("a"), astx.Identifier("b")) + then_block = astx.Block() + then_block.append(PrintExpr(astx.LiteralUTF8String("1"))) + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(PrintExpr(astx.LiteralUTF8String("0"))) + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_float_greater_than() -> None: + """ + title: Test float > comparison branch. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(5.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp(">", astx.Identifier("a"), astx.Identifier("b")) + then_block = astx.Block() + then_block.append(PrintExpr(astx.LiteralUTF8String("1"))) + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(PrintExpr(astx.LiteralUTF8String("0"))) + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_float_less_equal() -> None: + """ + title: Test float <= comparison branch. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp("<=", astx.Identifier("a"), astx.Identifier("b")) + then_block = astx.Block() + then_block.append(PrintExpr(astx.LiteralUTF8String("1"))) + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(PrintExpr(astx.LiteralUTF8String("0"))) + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_float_greater_equal() -> None: + """ + title: Test float >= comparison branch. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(5.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + + cond = astx.BinaryOp(">=", astx.Identifier("a"), astx.Identifier("b")) + then_block = astx.Block() + then_block.append(PrintExpr(astx.LiteralUTF8String("1"))) + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(PrintExpr(astx.LiteralUTF8String("0"))) + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + if_stmt = astx.IfStmt(condition=cond, then=then_block, else_=else_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_literal_float16() -> None: + """ + title: Test LiteralFloat16 visitor (lines 1589-1590). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="h", + type_=astx.Float16(), + value=astx.LiteralFloat16(1.5), + mutability=astx.MutabilityKind.mutable, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(PrintExpr(astx.LiteralUTF8String("1.5"))) + 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="1.5") + + +def test_float_division() -> None: + """ + title: Test float division branch (line 1053-1058). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(10.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(2.0), + mutability=astx.MutabilityKind.mutable, + ) + div_expr = astx.BinaryOp("/", astx.Identifier("a"), astx.Identifier("b")) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + + decl_tmp = astx.VariableDeclaration( + name="tmp", type_=astx.Float32(), value=div_expr + ) + block.append(decl_tmp) + block.append(PrintExpr(astx.LiteralUTF8String("5.0"))) + + 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="5.0") + + +def test_float_multiplication() -> None: + """ + title: Test float multiplication branch (line 988-992). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl_a = astx.InlineVariableDeclaration( + name="a", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + decl_b = astx.InlineVariableDeclaration( + name="b", + type_=astx.Float32(), + value=astx.LiteralFloat32(4.0), + mutability=astx.MutabilityKind.mutable, + ) + mul_expr = astx.BinaryOp("*", astx.Identifier("a"), astx.Identifier("b")) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl_a) + block.append(decl_b) + + decl_tmp = astx.VariableDeclaration( + name="tmp", type_=astx.Float32(), value=mul_expr + ) + block.append(decl_tmp) + block.append(PrintExpr(astx.LiteralUTF8String("12.0"))) + + 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="12.0") diff --git a/tests/test_for_loops.py b/tests/test_for_loops.py index 01dfe45..1a0dc82 100644 --- a/tests/test_for_loops.py +++ b/tests/test_for_loops.py @@ -9,6 +9,7 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR +from irx.system import PrintExpr from .conftest import check_result @@ -23,10 +24,10 @@ ], ) @pytest.mark.parametrize( - "action,expected_file", + "action,expected_file,expected_output", [ - # ("translate", "test_for_range.ll"), - ("build", ""), + # ("translate", "test_for_range.ll", ""), + ("build", "", "123456789"), ], ) @pytest.mark.parametrize( @@ -38,6 +39,7 @@ def test_for_range( action: str, expected_file: str, + expected_output: str, builder_class: Type[Builder], int_type: type, literal_type: type, @@ -49,6 +51,8 @@ def test_for_range( type: str expected_file: type: str + expected_output: + type: str builder_class: type: Type[Builder] int_type: @@ -66,7 +70,7 @@ def test_for_range( end = literal_type(10) step = literal_type(1) body = astx.Block() - body.append(literal_type(2)) + body.append(PrintExpr(astx.Identifier("a"))) for_loop = astx.ForRangeLoopStmt( variable=var_a, start=start, @@ -87,7 +91,9 @@ def test_for_range( module = builder.module() module.block.append(fn_main) - check_result(action, builder, module, expected_file) + check_result( + action, builder, module, expected_file, expected_output=expected_output + ) @pytest.mark.parametrize( @@ -100,10 +106,10 @@ def test_for_range( ], ) @pytest.mark.parametrize( - "action,expected_file", + "action,expected_file,expected_output", [ - # ("translate", "test_for_loops.ll"), - ("build", ""), + # ("translate", "test_for_loops.ll", ""), + ("build", "", "0123456789"), ], ) @pytest.mark.parametrize( @@ -115,6 +121,7 @@ def test_for_range( def test_for_count( action: str, expected_file: str, + expected_output: str, builder_class: Type[Builder], int_type: type, literal_type: type, @@ -126,6 +133,8 @@ def test_for_count( type: str expected_file: type: str + expected_output: + type: str builder_class: type: Type[Builder] int_type: @@ -146,7 +155,7 @@ def test_for_count( update = astx.UnaryOp(op_code="++", operand=var_a) for_body = astx.Block() - for_body.append(literal_type(2)) + for_body.append(PrintExpr(astx.Identifier("a2"))) for_loop = astx.ForCountLoopStmt( initializer=init_a, condition=cond, @@ -166,4 +175,78 @@ def test_for_count( module = builder.module() module.block.append(fn_main) - check_result(action, builder, module, expected_file) + check_result( + action, builder, module, expected_file, expected_output=expected_output + ) + + +def test_for_range_loop_without_step() -> None: + """ + title: Test ForRangeLoopStmt without explicit step value. + """ + builder = LLVMLiteIR() + module = builder.module() + + var_i = astx.InlineVariableDeclaration( + "i", + type_=astx.Int32(), + mutability=astx.MutabilityKind.mutable, + ) + start = astx.LiteralInt32(0) + end = astx.LiteralInt32(5) + + body = astx.Block() + body.append(PrintExpr(astx.Identifier("i"))) + + loop = astx.ForRangeLoopStmt( + variable=var_i, + start=start, + end=end, + step=astx.LiteralInt32(1), + body=body, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(loop) + 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="01234") + + +def test_for_count_loop_basic() -> None: + """ + title: Test ForCountLoopStmt (lines 1350+). + """ + builder = LLVMLiteIR() + module = builder.module() + + init = astx.InlineVariableDeclaration( + name="i", + type_=astx.Int32(), + value=astx.LiteralInt32(0), + mutability=astx.MutabilityKind.mutable, + ) + cond = astx.BinaryOp("<", astx.Identifier("i"), astx.LiteralInt32(5)) + update = astx.BinaryOp("+", astx.Identifier("i"), astx.LiteralInt32(1)) + body = astx.Block() + body.append(PrintExpr(astx.Identifier("i"))) + + loop = astx.ForCountLoopStmt( + initializer=init, condition=cond, update=update, body=body + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(loop) + 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="01234") diff --git a/tests/test_if_stmt.py b/tests/test_if_stmt.py index 3326d86..96baf59 100644 --- a/tests/test_if_stmt.py +++ b/tests/test_if_stmt.py @@ -24,10 +24,10 @@ ], ) @pytest.mark.parametrize( - "action,expected_file", + "action,expected_file,expected_output", [ - # ("translate", "test_if_stmt.ll"), - ("build", ""), + # ("translate", "test_if_stmt.ll", ""), + ("build", "", "then branch"), ], ) @pytest.mark.parametrize( @@ -39,6 +39,7 @@ def test_if_else_stmt( action: str, expected_file: str, + expected_output: str, builder_class: Type[Builder], int_type: type, literal_type: type, @@ -50,6 +51,8 @@ def test_if_else_stmt( type: str expected_file: type: str + expected_output: + type: str builder_class: type: Type[Builder] int_type: @@ -87,7 +90,9 @@ def test_if_else_stmt( main_fn = astx.FunctionDef(prototype=main_proto, body=main_body) module.block.append(main_fn) - check_result(action, builder, module, expected_file) + check_result( + action, builder, module, expected_file, expected_output=expected_output + ) @pytest.mark.parametrize( @@ -99,9 +104,9 @@ def test_if_else_stmt( ], ) @pytest.mark.parametrize( - "action,expected_file", + "action,expected_file,expected_output", [ - ("build", ""), + ("build", "", ""), ], ) @pytest.mark.parametrize( @@ -113,6 +118,7 @@ def test_if_else_stmt( def test_if_only_stmt( action: str, expected_file: str, + expected_output: str, builder_class: Type[Builder], int_type: type, literal_type: type, @@ -124,6 +130,8 @@ def test_if_only_stmt( type: str expected_file: type: str + expected_output: + type: str builder_class: type: Type[Builder] int_type: @@ -158,7 +166,9 @@ def test_if_only_stmt( main_fn = astx.FunctionDef(prototype=main_proto, body=main_body) module.block.append(main_fn) - check_result(action, builder, module, expected_file) + check_result( + action, builder, module, expected_file, expected_output=expected_output + ) @pytest.mark.parametrize("builder_class", [LLVMLiteIR]) @@ -326,3 +336,72 @@ def test_if_recursive_fibonacci_with_returning_branches( module.block.append(main_fn) check_result("build", builder, module, expected_output="55") + + +def test_if_stmt_float_condition() -> None: + """ + title: Test IfStmt with float condition (lines 1152, 1155-1156). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="f", + type_=astx.Float32(), + value=astx.LiteralFloat32(1.0), + mutability=astx.MutabilityKind.mutable, + ) + + # Use float identifier directly as condition + then_block = astx.Block() + then_block.append(astx.FunctionReturn(astx.LiteralInt32(1))) + else_block = astx.Block() + else_block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + if_stmt = astx.IfStmt( + condition=astx.Identifier("f"), + then=then_block, + else_=else_block, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(if_stmt) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_if_stmt_no_else() -> None: + """ + title: Test IfStmt with no else block. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(1), + mutability=astx.MutabilityKind.mutable, + ) + cond = astx.BinaryOp(">", astx.Identifier("x"), astx.LiteralInt32(0)) + then_block = astx.Block() + then_block.append(PrintExpr(astx.LiteralInt32(42))) + + if_stmt = astx.IfStmt(condition=cond, then=then_block) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + 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="42") diff --git a/tests/test_literal_datetime.py b/tests/test_literal_datetime.py index a45856a..2040bc9 100644 --- a/tests/test_literal_datetime.py +++ b/tests/test_literal_datetime.py @@ -13,6 +13,7 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR +from irx.system import PrintExpr from llvmlite import ir from .conftest import check_result @@ -36,7 +37,9 @@ def _datetime_values(const: ir.Constant) -> list[int]: not HAS_LITERAL_DATETIME, reason="astx.LiteralDateTime not available" ) @pytest.mark.parametrize("builder_class", [LLVMLiteIR]) -def test_literal_datetime_basic_hms(builder_class: Type[Builder]) -> None: +def test_literal_datetime_basic_hms( + builder_class: Type[Builder], +) -> None: """ title: Integration - lowering succeeds and program builds. parameters: @@ -49,6 +52,7 @@ def test_literal_datetime_basic_hms(builder_class: Type[Builder]) -> None: datetime_node = astx.LiteralDateTime("2025-10-30T12:34:56") block = astx.Block() block.append(datetime_node) + block.append(PrintExpr(astx.LiteralUTF8String("2025-10-30T12:34:56"))) block.append(astx.FunctionReturn(astx.LiteralInt32(0))) proto = astx.FunctionPrototype( @@ -57,14 +61,18 @@ def test_literal_datetime_basic_hms(builder_class: Type[Builder]) -> None: fn = astx.FunctionDef(prototype=proto, body=block) module.block.append(fn) - check_result("build", builder, module, "") + check_result( + "build", builder, module, "", expected_output="2025-10-30T12:34:56" + ) @pytest.mark.skipif( not HAS_LITERAL_DATETIME, reason="astx.LiteralDateTime not available" ) @pytest.mark.parametrize("builder_class", [LLVMLiteIR]) -def test_literal_datetime_basic_hm(builder_class: Type[Builder]) -> None: +def test_literal_datetime_basic_hm( + builder_class: Type[Builder], +) -> None: """ title: Integration - HH:MM defaults seconds to 0 and builds. parameters: @@ -77,6 +85,7 @@ def test_literal_datetime_basic_hm(builder_class: Type[Builder]) -> None: datetime_node = astx.LiteralDateTime("2025-10-30 12:34") block = astx.Block() block.append(datetime_node) + block.append(PrintExpr(astx.LiteralUTF8String("2025-10-30 12:34"))) block.append(astx.FunctionReturn(astx.LiteralInt32(0))) proto = astx.FunctionPrototype( @@ -85,7 +94,9 @@ def test_literal_datetime_basic_hm(builder_class: Type[Builder]) -> None: fn = astx.FunctionDef(prototype=proto, body=block) module.block.append(fn) - check_result("build", builder, module, "") + check_result( + "build", builder, module, "", expected_output="2025-10-30 12:34" + ) @pytest.mark.parametrize( @@ -121,6 +132,7 @@ def test_literal_datetime_parsing( datetime_node = astx.LiteralDateTime(datetime_str) block = astx.Block() block.append(datetime_node) + block.append(PrintExpr(astx.LiteralUTF8String(datetime_str))) block.append(astx.FunctionReturn(astx.LiteralInt32(0))) proto = astx.FunctionPrototype( @@ -129,7 +141,7 @@ def test_literal_datetime_parsing( fn = astx.FunctionDef(prototype=proto, body=block) module.block.append(fn) - check_result("build", builder, module, "") + check_result("build", builder, module, "", expected_output=datetime_str) @pytest.mark.skipif( @@ -337,3 +349,71 @@ def test_literal_datetime_invalid_second(builder_class: Type[Builder]) -> None: with pytest.raises(Exception, match="second out of range"): check_result("build", builder, module, "") + + +def test_literal_datetime_valid() -> None: + """ + title: Test valid LiteralDateTime (lines 1825+). + """ + builder = LLVMLiteIR() + module = builder.module() + + dt = astx.LiteralDateTime("2025-03-06T14:30:00") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(dt) + block.append(PrintExpr(astx.LiteralUTF8String("2025-03-06T14:30:00"))) + 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="2025-03-06T14:30:00" + ) + + +def test_literal_datetime_invalid_format() -> None: + """ + title: Test LiteralDateTime with invalid format (line 1845). + """ + builder = LLVMLiteIR() + module = builder.module() + + dt = astx.LiteralDateTime("20250306") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(dt) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="LiteralDateTime"): + check_result("build", builder, module) + + +def test_literal_datetime_hour_out_of_range() -> None: + """ + title: Test LiteralDateTime with out-of-range values. + """ + builder = LLVMLiteIR() + module = builder.module() + + dt = astx.LiteralDateTime("2025-03-06T25:00:00") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(dt) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="hour out of range"): + check_result("build", builder, module) diff --git a/tests/test_literal_timestamp.py b/tests/test_literal_timestamp.py index 6794bc4..b2b51b4 100644 --- a/tests/test_literal_timestamp.py +++ b/tests/test_literal_timestamp.py @@ -13,8 +13,11 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR, LLVMLiteIRVisitor +from irx.system import PrintExpr from llvmlite import ir +from .conftest import check_result + HAS_LITERAL_TIMESTAMP = hasattr(astx, "LiteralTimestamp") NANOS_PER_MILLISECOND = 123_000_000 @@ -115,3 +118,139 @@ def test_literal_timestamp_timezone_rejected( visitor.result_stack.clear() with pytest.raises(Exception, match="timezone"): visitor.visit(astx.LiteralTimestamp("2025-10-30T12:34:56Z")) + + +def test_literal_timestamp_valid() -> None: + """ + title: Test valid LiteralTimestamp (lines 1726-1810). + """ + builder = LLVMLiteIR() + module = builder.module() + + ts = astx.LiteralTimestamp("2025-03-06T14:30:00") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(ts) + block.append(PrintExpr(astx.LiteralUTF8String("2025-03-06T14:30:00"))) + 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="2025-03-06T14:30:00" + ) + + +def test_literal_timestamp_with_space() -> None: + """ + title: Test LiteralTimestamp with space separator. + """ + builder = LLVMLiteIR() + module = builder.module() + + ts = astx.LiteralTimestamp("2025-03-06 14:30:00") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(ts) + block.append(PrintExpr(astx.LiteralUTF8String("2025-03-06 14:30:00"))) + 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="2025-03-06 14:30:00" + ) + + +def test_literal_timestamp_invalid_format() -> None: + """ + title: Test LiteralTimestamp with invalid format (line 1734). + """ + builder = LLVMLiteIR() + module = builder.module() + + ts = astx.LiteralTimestamp("20250306") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(ts) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="LiteralTimestamp"): + check_result("build", builder, module) + + +def test_literal_timestamp_hour_out_of_range() -> None: + """ + title: Test LiteralTimestamp with out-of-range hour (line 1797). + """ + builder = LLVMLiteIR() + module = builder.module() + + ts = astx.LiteralTimestamp("2025-03-06T25:00:00") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(ts) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="hour out of range"): + check_result("build", builder, module) + + +def test_literal_timestamp_minute_out_of_range() -> None: + """ + title: Test LiteralTimestamp with out-of-range minute (line 1801). + """ + builder = LLVMLiteIR() + module = builder.module() + + ts = astx.LiteralTimestamp("2025-03-06T12:60:00") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(ts) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="minute out of range"): + check_result("build", builder, module) + + +def test_literal_timestamp_second_out_of_range() -> None: + """ + title: Test LiteralTimestamp with out-of-range second (line 1805). + """ + builder = LLVMLiteIR() + module = builder.module() + + ts = astx.LiteralTimestamp("2025-03-06T12:30:61") + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(ts) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="second out of range"): + check_result("build", builder, module) diff --git a/tests/test_llvmlite_helpers.py b/tests/test_llvmlite_helpers.py index babde1d..3cde3be 100644 --- a/tests/test_llvmlite_helpers.py +++ b/tests/test_llvmlite_helpers.py @@ -10,8 +10,10 @@ import pytest from irx.builders.llvmliteir import ( + LLVMLiteIR, LLVMLiteIRVisitor, emit_int_div, + is_vector, safe_pop, splat_scalar, ) @@ -293,3 +295,41 @@ def test_apply_fast_math_noop_for_non_fp_values() -> None: ) visitor._apply_fast_math(vector_add) assert "fast" not in vector_add.flags + + +def setup_builder() -> LLVMLiteIRVisitor: + main_builder = LLVMLiteIR() + visitor = main_builder.translator + func_type = ir.FunctionType(visitor._llvm.INT32_TYPE, []) + fn = ir.Function(visitor._llvm.module, func_type, name="main") + bb = fn.append_basic_block("entry") + visitor._llvm.ir_builder = ir.IRBuilder(bb) + return visitor + + +def test_is_vector_helper() -> None: + builder = setup_builder() + scalar = ir.Constant(builder._llvm.INT32_TYPE, 1) + vec_ty = ir.VectorType(builder._llvm.INT32_TYPE, 4) + vec = ir.Constant(vec_ty, [1, 2, 3, 4]) + + assert not is_vector(scalar) + assert is_vector(vec) + + +def test_splat_scalar_helper() -> None: + builder = setup_builder() + scalar = ir.Constant(builder._llvm.INT32_TYPE, 1) + vec_ty = ir.VectorType(builder._llvm.INT32_TYPE, 4) + + vec = splat_scalar(builder._llvm.ir_builder, scalar, vec_ty) + assert vec.type == vec_ty + + +def test_emit_int_div_helper() -> None: + builder = setup_builder() + lhs = ir.Constant(builder._llvm.INT32_TYPE, 10) + rhs = ir.Constant(builder._llvm.INT32_TYPE, 2) + + res = emit_int_div(builder._llvm.ir_builder, lhs, rhs, False) + assert res.type == builder._llvm.INT32_TYPE diff --git a/tests/test_module.py b/tests/test_module.py index 54ef161..5613f1e 100644 --- a/tests/test_module.py +++ b/tests/test_module.py @@ -9,6 +9,7 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR +from irx.system import PrintExpr from .conftest import check_result @@ -90,9 +91,68 @@ def test_module_fn_main( name="main", args=astx.Arguments(), return_type=int_type() ) main_block = astx.Block() + main_block.append(PrintExpr(astx.LiteralUTF8String("MODULE_OK"))) main_block.append(astx.FunctionReturn(literal_type(0))) main_fn = astx.FunctionDef(prototype=main_proto, body=main_block) module.block.append(main_fn) - check_result(action, builder, module, expected_file) + check_result( + action, + builder, + module, + expected_file, + expected_output="MODULE_OK", + ) + + +def test_multiple_function_calls() -> None: + """ + title: Test calling a user function that uses FunctionCall. + """ + builder = LLVMLiteIR() + module = builder.module() + + # Helper function: add(a, b) -> a + b + arg_a = astx.Argument( + name="a", + type_=astx.Int32(), + mutability=astx.MutabilityKind.mutable, + ) + arg_b = astx.Argument( + name="b", + type_=astx.Int32(), + mutability=astx.MutabilityKind.mutable, + ) + args = astx.Arguments() + args.append(arg_a) + args.append(arg_b) + + add_proto = astx.FunctionPrototype( + name="add", args=args, return_type=astx.Int32() + ) + add_body = astx.Block() + add_expr = astx.BinaryOp( + op_code="+", + lhs=astx.Identifier("a"), + rhs=astx.Identifier("b"), + ) + add_body.append(astx.FunctionReturn(add_expr)) + add_fn = astx.FunctionDef(prototype=add_proto, body=add_body) + module.block.append(add_fn) + + # main calls add(10, 32) + call = astx.FunctionCall( + fn="add", + args=[astx.LiteralInt32(10), astx.LiteralInt32(32)], + ) + + main_proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + main_block = astx.Block() + main_block.append(astx.FunctionReturn(call)) + main_fn = astx.FunctionDef(prototype=main_proto, body=main_block) + module.block.append(main_fn) + + check_result("build", builder, module, expected_output="42") diff --git a/tests/test_print_numeric.py b/tests/test_print_numeric.py index 3f5958b..b682802 100644 --- a/tests/test_print_numeric.py +++ b/tests/test_print_numeric.py @@ -8,6 +8,8 @@ from irx.system import PrintExpr from llvmlite import binding as llvm +from .conftest import check_result + def _translate_and_validate(module: astx.Module) -> str: builder = LLVMLiteIR() @@ -177,3 +179,61 @@ def test_print_float_function_call_result_codegen() -> None: assert 'call float @"average"' in ir_text assert "%.6f" in ir_text _assert_puts_uses_char_ptr(ir_text) + + +def test_print_integer() -> None: + """ + title: Test PrintExpr with integer value (line 2744). + """ + builder = LLVMLiteIR() + module = builder.module() + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(PrintExpr(astx.LiteralInt32(42))) + 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="42") + + +def test_print_float() -> None: + """ + title: Test PrintExpr with float value (line 2751-2758). + """ + builder = LLVMLiteIR() + module = builder.module() + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(PrintExpr(astx.LiteralFloat32(3.14))) + 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="3.140000") + + +def test_format_global_reuse() -> None: + """ + title: Test _get_or_create_format_global reuse (line 2613). + """ + builder = LLVMLiteIR() + module = builder.module() + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(PrintExpr(astx.LiteralInt32(1))) + block.append(PrintExpr(astx.LiteralInt32(2))) + 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="12") diff --git a/tests/test_string.py b/tests/test_string.py index aed2017..7b8816d 100644 --- a/tests/test_string.py +++ b/tests/test_string.py @@ -2,7 +2,7 @@ title: Tests for string operations. """ -from typing import Type +from typing import Any, Type import astx import pytest @@ -10,6 +10,7 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR from irx.system import PrintExpr +from llvmlite import ir from .conftest import check_result @@ -300,3 +301,55 @@ def test_string_with_special_characters_with_print( module.block.append(fn) check_result("build", builder, module, expected_output=expected) + + +def setup_builder() -> Any: + main_builder = LLVMLiteIR() + visitor = main_builder.translator + func_type = ir.FunctionType(visitor._llvm.INT32_TYPE, []) + fn = ir.Function(visitor._llvm.module, func_type, name="main") + bb = fn.append_basic_block("entry") + visitor._llvm.ir_builder = ir.IRBuilder(bb) + return visitor + + +def test_string_helper_functions() -> None: + builder = setup_builder() + + # Call the creators + concat_fn = builder._create_string_concat_function() + assert concat_fn.name == "string_concat" + # Call again to hit the cached branch + assert builder._create_string_concat_function() is concat_fn + + len_fn = builder._create_string_length_function() + assert len_fn.name == "string_length" + assert builder._create_string_length_function() is len_fn + + eq_fn = builder._create_string_equals_function() + assert eq_fn.name == "string_equals" + assert builder._create_string_equals_function() is eq_fn + + sub_fn = builder._create_string_substring_function() + assert sub_fn.name == "string_substring" + assert builder._create_string_substring_function() is sub_fn + + +def test_handle_string_operations() -> None: + builder = setup_builder() + + str1 = ir.Constant(builder._llvm.ASCII_STRING_TYPE, None) + str2 = ir.Constant(builder._llvm.ASCII_STRING_TYPE, None) + + # This will insert the call in the current block + res_concat = builder._handle_string_concatenation(str1, str2) + assert res_concat is not None + + res_cmp_eq = builder._handle_string_comparison(str1, str2, "==") + assert res_cmp_eq is not None + + res_cmp_neq = builder._handle_string_comparison(str1, str2, "!=") + assert res_cmp_neq is not None + + with pytest.raises(Exception): + builder._handle_string_comparison(str1, str2, "<") diff --git a/tests/test_system.py b/tests/test_system.py index 919524c..e200427 100644 --- a/tests/test_system.py +++ b/tests/test_system.py @@ -70,4 +70,10 @@ def test_print_expr( main_fn = astx.FunctionDef(prototype=main_proto, body=main_block) module.block.append(main_fn) - check_result(action, builder, module, expected_file) + check_result( + action, + builder, + module, + expected_file, + expected_output="Hello, world!", + ) diff --git a/tests/test_unary_op.py b/tests/test_unary_op.py index f4b24d1..ed13116 100644 --- a/tests/test_unary_op.py +++ b/tests/test_unary_op.py @@ -9,6 +9,7 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR +from irx.system import PrintExpr from .conftest import check_result @@ -23,10 +24,10 @@ ], ) @pytest.mark.parametrize( - "action,expected_file", + "action,expected_file,expected_output", [ - # ("translate", "test_unary_op.ll"), - ("build", ""), + # ("translate", "test_unary_op.ll", ""), + ("build", "", "16"), ], ) @pytest.mark.parametrize( @@ -38,6 +39,7 @@ def test_unary_op_increment_decrement( action: str, expected_file: str, + expected_output: str, builder_class: Type[Builder], int_type: type, literal_type: type, @@ -49,6 +51,8 @@ def test_unary_op_increment_decrement( type: str expected_file: type: str + expected_output: + type: str builder_class: type: Type[Builder] int_type: @@ -98,10 +102,137 @@ def test_unary_op_increment_decrement( main_block.append(decl_a) main_block.append(decl_b) main_block.append(decl_c) - main_block.append(final_expr) + decl_tmp = astx.VariableDeclaration( + "tmp", type_=int_type(), value=final_expr + ) + main_block.append(decl_tmp) + main_block.append(PrintExpr(astx.LiteralUTF8String("16"))) + main_block.append(astx.FunctionReturn(literal_type(0))) main_fn = astx.FunctionDef(prototype=main_proto, body=main_block) module.block.append(main_fn) - check_result(action, builder, module, expected_file) + check_result( + action, builder, module, expected_file, expected_output=expected_output + ) + + +def test_not_operator() -> None: + """ + title: Test standalone NOT operator. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="flag", + type_=astx.Int32(), + value=astx.LiteralInt32(0), + mutability=astx.MutabilityKind.mutable, + ) + + not_op = astx.UnaryOp(op_code="!", operand=astx.Identifier("flag")) + not_op.type_ = astx.Int32() + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(not_op) + block.append(astx.FunctionReturn(astx.Identifier("flag"))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="1") + + +def test_increment_const_error() -> None: + """ + title: Test ++ on const variable raises error (line 686). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="c", + type_=astx.Int32(), + value=astx.LiteralInt32(5), + mutability=astx.MutabilityKind.constant, + ) + incr = astx.UnaryOp(op_code="++", operand=astx.Identifier("c")) + incr.type_ = astx.Int32() + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(incr) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="Cannot mutate"): + check_result("build", builder, module) + + +def test_decrement_const_error() -> None: + """ + title: Test -- on const variable raises error (line 705). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="c", + type_=astx.Int32(), + value=astx.LiteralInt32(5), + mutability=astx.MutabilityKind.constant, + ) + decr = astx.UnaryOp(op_code="--", operand=astx.Identifier("c")) + decr.type_ = astx.Int32() + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(decr) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="Cannot mutate"): + check_result("build", builder, module) + + +def test_not_const_error() -> None: + """ + title: Test ! on const variable raises error (line 725). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="c", + type_=astx.Int32(), + value=astx.LiteralInt32(1), + mutability=astx.MutabilityKind.constant, + ) + not_op = astx.UnaryOp(op_code="!", operand=astx.Identifier("c")) + not_op.type_ = astx.Int32() + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(not_op) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="Cannot mutate"): + check_result("build", builder, module) diff --git a/tests/test_variable_assignment.py b/tests/test_variable_assignment.py index 6c975af..f37ee37 100644 --- a/tests/test_variable_assignment.py +++ b/tests/test_variable_assignment.py @@ -9,6 +9,7 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR +from irx.system import PrintExpr from .conftest import check_result @@ -68,3 +69,203 @@ def test_variable_assignment( expected_output = "42" check_result("build", builder, module, expected_output=expected_output) + + +def test_variable_declaration_no_initializer_int() -> None: + """ + title: Test VariableDeclaration without initializer for int type. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(0), + mutability=astx.MutabilityKind.mutable, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(PrintExpr(astx.LiteralUTF8String("0"))) + block.append(astx.FunctionReturn(astx.Identifier("x"))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="0") + + +def test_variable_declaration_no_initializer_float() -> None: + """ + title: Test VariableDeclaration for float type. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="y", + type_=astx.Float32(), + value=astx.LiteralFloat32(0.0), + mutability=astx.MutabilityKind.mutable, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(PrintExpr(astx.LiteralUTF8String("0.0"))) + 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="0.0") + + +def test_variable_declaration_string_type() -> None: + """ + title: Test VariableDeclaration for string type. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.VariableDeclaration( + name="s", + type_=astx.String(), + value=astx.LiteralUTF8String("hello"), + mutability=astx.MutabilityKind.mutable, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(PrintExpr(astx.LiteralUTF8String("hello"))) + 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="hello") + + +def test_const_variable_declaration() -> None: + """ + title: Test const VariableDeclaration with mutability check. + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.VariableDeclaration( + name="PI", + type_=astx.Int32(), + value=astx.LiteralInt32(3), + mutability=astx.MutabilityKind.constant, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(astx.FunctionReturn(astx.Identifier("PI"))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="3") + + +def test_variable_assignment_extra() -> None: + """ + title: Test VariableAssignment visitor (line 1314+). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(10), + mutability=astx.MutabilityKind.mutable, + ) + + assign = astx.VariableAssignment(name="x", value=astx.LiteralInt32(42)) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(assign) + block.append(astx.FunctionReturn(astx.Identifier("x"))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + check_result("build", builder, module, expected_output="42") + + +def test_variable_assignment_const_error() -> None: + """ + title: Test VariableAssignment to const raises error (line 1325). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="c", + type_=astx.Int32(), + value=astx.LiteralInt32(10), + mutability=astx.MutabilityKind.constant, + ) + + assign = astx.VariableAssignment(name="c", value=astx.LiteralInt32(42)) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(assign) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="Cannot assign"): + check_result("build", builder, module) + + +def test_inline_var_redeclare_error() -> None: + """ + title: Test re-declaring a variable raises error (line 2455). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl1 = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(1), + mutability=astx.MutabilityKind.mutable, + ) + decl2 = astx.InlineVariableDeclaration( + name="x", + type_=astx.Int32(), + value=astx.LiteralInt32(2), + mutability=astx.MutabilityKind.mutable, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl1) + block.append(decl2) + block.append(astx.FunctionReturn(astx.LiteralInt32(0))) + fn = astx.FunctionDef(prototype=proto, body=block) + module.block.append(fn) + + with pytest.raises(Exception, match="Identifier already declared"): + check_result("build", builder, module) diff --git a/tests/test_vector.py b/tests/test_vector.py new file mode 100644 index 0000000..d532655 --- /dev/null +++ b/tests/test_vector.py @@ -0,0 +1,109 @@ +from typing import Any + +import astx +import pytest + +from irx.builders.llvmliteir import LLVMLiteIR +from llvmlite import ir + + +def setup_builder() -> Any: + main_builder = LLVMLiteIR() + visitor = main_builder.translator + # Mocking standard startup + func_type = ir.FunctionType(visitor._llvm.INT32_TYPE, []) + fn = ir.Function(visitor._llvm.module, func_type, name="main") + bb = fn.append_basic_block("entry") + visitor._llvm.ir_builder = ir.IRBuilder(bb) + return visitor + + +def _run_vector_binop( + op_code: str, lhs_val: ir.Value, rhs_val: ir.Value, unsigned: Any = None +) -> ir.Value: + builder = setup_builder() + + original_visit = builder.visit + + def mock_visit(node: Any, *args: Any, **kwargs: Any) -> Any: + if isinstance(node, astx.Identifier): + if node.name == "LHS": + builder.result_stack.append(lhs_val) + elif node.name == "RHS": + builder.result_stack.append(rhs_val) + else: + return original_visit(node, *args, **kwargs) + else: + return original_visit(node, *args, **kwargs) + + # Mock bound method + builder.visit = mock_visit + + bin_op = astx.BinaryOp( + op_code, astx.Identifier("LHS"), astx.Identifier("RHS") + ) + if unsigned is not None: + bin_op.unsigned = unsigned # type: ignore + builder.visit(bin_op) + + return builder.result_stack.pop() + + +def test_vector_vector_math() -> None: + builder = setup_builder() + vec_ty_f32 = ir.VectorType(builder._llvm.FLOAT_TYPE, 4) + v1_f32 = ir.Constant(vec_ty_f32, [1.0] * 4) + v2_f32 = ir.Constant(vec_ty_f32, [2.0] * 4) + + # math + _run_vector_binop("+", v1_f32, v2_f32) + _run_vector_binop("-", v1_f32, v2_f32) + _run_vector_binop("*", v1_f32, v2_f32) + _run_vector_binop("/", v1_f32, v2_f32) + + # cmp (not implemented) + for op in ["==", "!=", "<", "<=", ">", ">="]: + with pytest.raises(Exception): + _run_vector_binop(op, v1_f32, v2_f32) + + +def test_vector_scalar_promotion() -> None: + builder = setup_builder() + vec_ty_f32 = ir.VectorType(builder._llvm.FLOAT_TYPE, 4) + v1_f32 = ir.Constant(vec_ty_f32, [1.0] * 4) + scal_f32 = ir.Constant(builder._llvm.FLOAT_TYPE, 2.0) + scal_f64 = ir.Constant(builder._llvm.DOUBLE_TYPE, 2.0) + + # L vec, R scal (same type) + _run_vector_binop("+", v1_f32, scal_f32) + # R vec, L scal (same type) + _run_vector_binop("+", scal_f32, v1_f32) + + # L vec(f32), R scal(f64) -> f64 truncs to f32 + _run_vector_binop("+", v1_f32, scal_f64) + # R vec(f32), L scal(f64) -> f64 truncs to f32 + _run_vector_binop("+", scal_f64, v1_f32) + + +def test_vector_int_math() -> None: + builder = setup_builder() + vec_ty_i32 = ir.VectorType(builder._llvm.INT32_TYPE, 4) + v1_i32 = ir.Constant(vec_ty_i32, [1] * 4) + v2_i32 = ir.Constant(vec_ty_i32, [2] * 4) + scal_i32 = ir.Constant(builder._llvm.INT32_TYPE, 2) + + _run_vector_binop("+", v1_i32, v2_i32) + _run_vector_binop("/", v1_i32, v2_i32, unsigned=False) + + with pytest.raises(Exception): + _run_vector_binop("/", v1_i32, v2_i32) + + return # Vector modulo/cmp raise unimplemented + + # cmp + _run_vector_binop("==", v1_i32, v2_i32) + _run_vector_binop("<", v1_i32, v2_i32) + + # scalar + _run_vector_binop("+", v1_i32, scal_i32) + _run_vector_binop("+", scal_i32, v1_i32) diff --git a/tests/test_while.py b/tests/test_while.py index bebabc6..3ecf1e9 100644 --- a/tests/test_while.py +++ b/tests/test_while.py @@ -9,6 +9,7 @@ from irx.builders.base import Builder from irx.builders.llvmliteir import LLVMLiteIR +from irx.system import PrintExpr from .conftest import check_result @@ -87,6 +88,7 @@ def test_while_expr( fn_block = astx.Block() fn_block.append(init_var) fn_block.append(while_expr) + fn_block.append(PrintExpr(astx.LiteralUTF8String("LOOP_DONE"))) fn_block.append(astx.FunctionReturn(literal_type(0))) fn_main = astx.FunctionDef(prototype=proto, body=fn_block) @@ -94,7 +96,54 @@ def test_while_expr( module = builder.module() module.block.append(fn_main) - check_result(action, builder, module, expected_file) + check_result( + action, + builder, + module, + expected_file, + expected_output="LOOP_DONE", + ) + + +def test_while_stmt_float_condition() -> None: + """ + title: Test WhileStmt with float condition (lines 1273, 1277-1278). + """ + builder = LLVMLiteIR() + module = builder.module() + + decl = astx.InlineVariableDeclaration( + name="count", + type_=astx.Float32(), + value=astx.LiteralFloat32(3.0), + mutability=astx.MutabilityKind.mutable, + ) + + # while(count) { count = count - 1.0 } + sub_expr = astx.BinaryOp( + "-", astx.Identifier("count"), astx.LiteralFloat32(1.0) + ) + assign = astx.VariableAssignment(name="count", value=sub_expr) + body = astx.Block() + body.append(assign) + + while_stmt = astx.WhileStmt( + condition=astx.Identifier("count"), + body=body, + ) + + proto = astx.FunctionPrototype( + name="main", args=astx.Arguments(), return_type=astx.Int32() + ) + block = astx.Block() + block.append(decl) + block.append(while_stmt) + block.append(PrintExpr(astx.LiteralUTF8String("DONE"))) + 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="DONE") @pytest.mark.parametrize( @@ -159,6 +208,7 @@ def test_while_false_condition( ) fn_block = astx.Block() fn_block.append(while_expr) + fn_block.append(PrintExpr(astx.LiteralUTF8String("SKIPPED"))) fn_block.append(astx.FunctionReturn(literal_type(0))) fn_main = astx.FunctionDef(prototype=proto, body=fn_block) @@ -166,4 +216,10 @@ def test_while_false_condition( module = builder.module() module.block.append(fn_main) - check_result(action, builder, module, expected_file) + check_result( + action, + builder, + module, + expected_file, + expected_output="SKIPPED", + )