@@ -94,6 +94,8 @@ and typed_stmt_desc =
9494 | TAssignment of string * typed_expr
9595 | TCompoundAssignment of string * binary_op * typed_expr (* var op= expr *)
9696 | TCompoundIndexAssignment of typed_expr * typed_expr * binary_op * typed_expr (* map[key] op= expr *)
97+ | TCompoundFieldIndexAssignment of typed_expr * typed_expr * string * binary_op * typed_expr
98+ (* map[key].field op= expr *)
9799 | TFieldAssignment of typed_expr * string * typed_expr (* object, field, value *)
98100 | TArrowAssignment of typed_expr * string * typed_expr (* pointer, field, value *)
99101 | TIndexAssignment of typed_expr * typed_expr * typed_expr
@@ -1820,7 +1822,57 @@ and type_check_statement ctx stmt =
18201822 type_error (" Operator " ^ string_of_binary_op op ^
18211823 " not supported for type " ^ string_of_bpf_type element_type) stmt.stmt_pos)
18221824 | _ -> type_error (" Compound index assignment can only be used on maps or arrays" ) stmt.stmt_pos))
1823-
1825+
1826+ | CompoundFieldIndexAssignment (map_expr , key_expr , field , op , value_expr ) ->
1827+ let typed_key = type_check_expression ctx key_expr in
1828+ let typed_value = type_check_expression ctx value_expr in
1829+ let map_name = match map_expr.expr_desc with
1830+ | Identifier name when Hashtbl. mem ctx.maps name -> name
1831+ | _ -> type_error " Compound field-index assignment requires a map identifier" stmt.stmt_pos
1832+ in
1833+ let map_decl = Hashtbl. find ctx.maps map_name in
1834+ (* Key type *)
1835+ let resolved_key_type = resolve_user_type ctx map_decl.ast_key_type in
1836+ let resolved_typed_key_type = resolve_user_type ctx typed_key.texpr_type in
1837+ (match unify_types resolved_key_type resolved_typed_key_type with
1838+ | Some _ -> ()
1839+ | None -> type_error " Map key type mismatch" stmt.stmt_pos);
1840+ (* Resolve the map's value type to a struct *)
1841+ let resolved_value_type = resolve_user_type ctx map_decl.ast_value_type in
1842+ let struct_name = match resolved_value_type with
1843+ | Struct n | UserType n -> n
1844+ | _ -> type_error " map[k].field op= rhs requires the map's value type to be a struct" stmt.stmt_pos
1845+ in
1846+ let fields =
1847+ try
1848+ (match Hashtbl. find ctx.types struct_name with
1849+ | StructDef (_ , fs , _ ) -> fs
1850+ | _ -> type_error (struct_name ^ " is not a struct" ) stmt.stmt_pos)
1851+ with Not_found -> type_error (" Undefined struct: " ^ struct_name) stmt.stmt_pos
1852+ in
1853+ let field_type =
1854+ try List. assoc field fields
1855+ with Not_found ->
1856+ type_error (" Field not found: " ^ field ^ " in struct " ^ struct_name) stmt.stmt_pos
1857+ in
1858+ (* rhs must match field type *)
1859+ let resolved_field_type = resolve_user_type ctx field_type in
1860+ let resolved_typed_value_type = resolve_user_type ctx typed_value.texpr_type in
1861+ (match unify_types resolved_field_type resolved_typed_value_type with
1862+ | Some _ -> ()
1863+ | None -> type_error (" Field value type mismatch for " ^ field) stmt.stmt_pos);
1864+ (* op must be valid for the field type *)
1865+ (match op, resolved_field_type with
1866+ | (Add | Sub | Mul | Div | Mod ), (U8 | U16 | U32 | U64 | I8 | I16 | I32 | I64 ) ->
1867+ let typed_map = { texpr_desc = TIdentifier map_name;
1868+ texpr_type = Map (map_decl.ast_key_type, map_decl.ast_value_type, map_decl.ast_map_type, map_decl.max_entries);
1869+ texpr_pos = map_expr.expr_pos } in
1870+ { tstmt_desc = TCompoundFieldIndexAssignment (typed_map, typed_key, field, op, typed_value);
1871+ tstmt_pos = stmt.stmt_pos }
1872+ | _ , _ ->
1873+ type_error (" Operator " ^ string_of_binary_op op ^
1874+ " not supported for field type " ^ string_of_bpf_type resolved_field_type) stmt.stmt_pos)
1875+
18241876 | Declaration (name , type_opt , expr_opt ) ->
18251877 let typed_expr_opt = Option. map (type_check_expression ctx) expr_opt in
18261878
@@ -2600,6 +2652,8 @@ and typed_stmt_to_stmt tstmt =
26002652 | TCompoundAssignment (name , op , expr ) -> CompoundAssignment (name, op, typed_expr_to_expr expr)
26012653 | TCompoundIndexAssignment (map_expr , key_expr , op , value_expr ) ->
26022654 CompoundIndexAssignment (typed_expr_to_expr map_expr, typed_expr_to_expr key_expr, op, typed_expr_to_expr value_expr)
2655+ | TCompoundFieldIndexAssignment (map_expr , key_expr , field , op , value_expr ) ->
2656+ CompoundFieldIndexAssignment (typed_expr_to_expr map_expr, typed_expr_to_expr key_expr, field, op, typed_expr_to_expr value_expr)
26032657 | TFieldAssignment (obj_expr , field , value_expr ) ->
26042658 FieldAssignment (typed_expr_to_expr obj_expr, field, typed_expr_to_expr value_expr)
26052659 | TArrowAssignment (obj_expr , field , value_expr ) ->
@@ -3272,6 +3326,13 @@ and populate_multi_program_context ast multi_prog_analysis =
32723326 (match map_expr.program_context with
32733327 | Some ctx -> map_expr.program_context < - Some { ctx with data_flow_direction = Some Write }
32743328 | None -> () )
3329+ | CompoundFieldIndexAssignment (map_expr , key_expr , _ , _ , value_expr ) ->
3330+ enhance_expr prog_type map_expr;
3331+ enhance_expr prog_type key_expr;
3332+ enhance_expr prog_type value_expr;
3333+ (match map_expr.program_context with
3334+ | Some ctx -> map_expr.program_context < - Some { ctx with data_flow_direction = Some Write }
3335+ | None -> () )
32753336 | FieldAssignment (obj_expr , _ , value_expr ) ->
32763337 enhance_expr prog_type obj_expr;
32773338 enhance_expr prog_type value_expr
@@ -3377,6 +3438,10 @@ and populate_multi_program_context ast multi_prog_analysis =
33773438 enhance_userspace_expr map_expr;
33783439 enhance_userspace_expr key_expr;
33793440 enhance_userspace_expr value_expr
3441+ | CompoundFieldIndexAssignment (map_expr , key_expr , _ , _ , value_expr ) ->
3442+ enhance_userspace_expr map_expr;
3443+ enhance_userspace_expr key_expr;
3444+ enhance_userspace_expr value_expr
33803445 | FieldAssignment (obj_expr , _ , value_expr ) ->
33813446 enhance_userspace_expr obj_expr;
33823447 enhance_userspace_expr value_expr
0 commit comments