Skip to content

Commit b0ea93a

Browse files
authored
Merge pull request #50 from pythonbpf/dep_inv
Use dependency inversion to remove handler delayed import in eval_expr
2 parents 158cc42 + fc058c4 commit b0ea93a

File tree

3 files changed

+83
-45
lines changed

3 files changed

+83
-45
lines changed

pythonbpf/expr/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .expr_pass import eval_expr, handle_expr, get_operand_value
1+
from .expr_pass import eval_expr, handle_expr, get_operand_value, CallHandlerRegistry
22
from .type_normalization import convert_to_bool, get_base_type_and_depth, deref_to_depth
33

44
__all__ = [
@@ -8,4 +8,5 @@
88
"get_base_type_and_depth",
99
"deref_to_depth",
1010
"get_operand_value",
11+
"CallHandlerRegistry",
1112
]

pythonbpf/expr/expr_pass.py

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,28 @@
1515
logger: Logger = logging.getLogger(__name__)
1616

1717

18+
class CallHandlerRegistry:
19+
"""Registry for handling different types of calls (helpers, etc.)"""
20+
21+
_handler = None
22+
23+
@classmethod
24+
def set_handler(cls, handler):
25+
"""Set the handler for unknown calls"""
26+
cls._handler = handler
27+
28+
@classmethod
29+
def handle_call(
30+
cls, call, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab
31+
):
32+
"""Handle a call using the registered handler"""
33+
if cls._handler is None:
34+
return None
35+
return cls._handler(
36+
call, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab
37+
)
38+
39+
1840
def get_operand_value(
1941
func, module, operand, builder, local_sym_tab, map_sym_tab, structs_sym_tab=None
2042
):
@@ -478,51 +500,14 @@ def eval_expr(
478500
structs_sym_tab,
479501
)
480502

481-
# delayed import to avoid circular dependency
482-
from pythonbpf.helper import HelperHandlerRegistry, handle_helper_call
503+
result = CallHandlerRegistry.handle_call(
504+
expr, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab
505+
)
506+
if result is not None:
507+
return result
483508

484-
if isinstance(expr.func, ast.Name) and HelperHandlerRegistry.has_handler(
485-
expr.func.id
486-
):
487-
return handle_helper_call(
488-
expr,
489-
module,
490-
builder,
491-
func,
492-
local_sym_tab,
493-
map_sym_tab,
494-
structs_sym_tab,
495-
)
496-
elif isinstance(expr.func, ast.Attribute):
497-
logger.info(f"Handling method call: {ast.dump(expr.func)}")
498-
if isinstance(expr.func.value, ast.Call) and isinstance(
499-
expr.func.value.func, ast.Name
500-
):
501-
method_name = expr.func.attr
502-
if HelperHandlerRegistry.has_handler(method_name):
503-
return handle_helper_call(
504-
expr,
505-
module,
506-
builder,
507-
func,
508-
local_sym_tab,
509-
map_sym_tab,
510-
structs_sym_tab,
511-
)
512-
elif isinstance(expr.func.value, ast.Name):
513-
obj_name = expr.func.value.id
514-
method_name = expr.func.attr
515-
if obj_name in map_sym_tab:
516-
if HelperHandlerRegistry.has_handler(method_name):
517-
return handle_helper_call(
518-
expr,
519-
module,
520-
builder,
521-
func,
522-
local_sym_tab,
523-
map_sym_tab,
524-
structs_sym_tab,
525-
)
509+
logger.warning(f"Unknown call: {ast.dump(expr)}")
510+
return None
526511
elif isinstance(expr, ast.Attribute):
527512
return _handle_attribute_expr(expr, local_sym_tab, structs_sym_tab, builder)
528513
elif isinstance(expr, ast.BinOp):

pythonbpf/helper/__init__.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,58 @@
22
from .bpf_helper_handler import handle_helper_call
33
from .helpers import ktime, pid, deref, XDP_DROP, XDP_PASS
44

5+
6+
# Register the helper handler with expr module
7+
def _register_helper_handler():
8+
"""Register helper call handler with the expression evaluator"""
9+
from pythonbpf.expr.expr_pass import CallHandlerRegistry
10+
11+
def helper_call_handler(
12+
call, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab
13+
):
14+
"""Check if call is a helper and handle it"""
15+
import ast
16+
17+
# Check for direct helper calls (e.g., ktime(), print())
18+
if isinstance(call.func, ast.Name):
19+
if HelperHandlerRegistry.has_handler(call.func.id):
20+
return handle_helper_call(
21+
call,
22+
module,
23+
builder,
24+
func,
25+
local_sym_tab,
26+
map_sym_tab,
27+
structs_sym_tab,
28+
)
29+
30+
# Check for method calls (e.g., map.lookup())
31+
elif isinstance(call.func, ast.Attribute):
32+
method_name = call.func.attr
33+
34+
# Handle: my_map.lookup(key)
35+
if isinstance(call.func.value, ast.Name):
36+
obj_name = call.func.value.id
37+
if map_sym_tab and obj_name in map_sym_tab:
38+
if HelperHandlerRegistry.has_handler(method_name):
39+
return handle_helper_call(
40+
call,
41+
module,
42+
builder,
43+
func,
44+
local_sym_tab,
45+
map_sym_tab,
46+
structs_sym_tab,
47+
)
48+
49+
return None
50+
51+
CallHandlerRegistry.set_handler(helper_call_handler)
52+
53+
54+
# Register on module import
55+
_register_helper_handler()
56+
557
__all__ = [
658
"HelperHandlerRegistry",
759
"reset_scratch_pool",

0 commit comments

Comments
 (0)