diff --git a/pythonbpf/expr_pass.py b/pythonbpf/expr_pass.py index 17d9500..7accf6e 100644 --- a/pythonbpf/expr_pass.py +++ b/pythonbpf/expr_pass.py @@ -316,7 +316,56 @@ def _handle_unary_op( def _handle_and_op(func, builder, expr, local_sym_tab, map_sym_tab, structs_sym_tab): - pass + """Handle `and` boolean operations.""" + + logger.debug(f"Handling 'and' operator with {len(expr.values)} operands") + + merge_block = func.append_basic_block(name="and.merge") + false_block = func.append_basic_block(name="and.false") + + incoming_values = [] + + for i, value in enumerate(expr.values): + is_last = i == len(expr.values) - 1 + + # Evaluate current operand + operand_result = eval_expr( + func, None, builder, value, local_sym_tab, map_sym_tab, structs_sym_tab + ) + if operand_result is None: + logger.error(f"Failed to evaluate operand {i} in 'and' expression") + return None + + operand_val, operand_type = operand_result + + # Convert to boolean if needed + operand_bool = convert_to_bool(builder, operand_val) + current_block = builder.block + + if is_last: + # Last operand: result is this value + builder.branch(merge_block) + incoming_values.append((operand_bool, current_block)) + else: + # Not last: check if true, continue or short-circuit + next_check = func.append_basic_block(name=f"and.check_{i + 1}") + builder.cbranch(operand_bool, next_check, false_block) + builder.position_at_end(next_check) + + # False block: short-circuit with false + builder.position_at_end(false_block) + builder.branch(merge_block) + false_value = ir.Constant(ir.IntType(1), 0) + incoming_values.append((false_value, false_block)) + + # Merge block: phi node + builder.position_at_end(merge_block) + phi = builder.phi(ir.IntType(1), name="and.result") + for val, block in incoming_values: + phi.add_incoming(val, block) + + logger.debug(f"Generated 'and' with {len(incoming_values)} incoming values") + return phi, ir.IntType(1) def _handle_or_op(func, builder, expr, local_sym_tab, map_sym_tab, structs_sym_tab):