Skip to content

Commit 9d2f131

Browse files
committed
Add field_name type to parser to accept 'type' as a struct field and update struct field access tests
1 parent 3fa859a commit 9d2f131

File tree

2 files changed

+87
-4
lines changed

2 files changed

+87
-4
lines changed

src/parser.mly

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@
151151
%type <Ast.impl_block_item list> impl_block_items
152152
%type <Ast.impl_block_item> impl_block_item
153153
%type <Ast.import_declaration> import_declaration
154+
%type <string> field_name
154155

155156
/* Start symbol */
156157
%start program
@@ -443,8 +444,8 @@ primary_expression:
443444
| literal { make_expr (Literal $1) (make_pos ()) }
444445
| IDENTIFIER { make_expr (Identifier $1) (make_pos ()) }
445446
| LPAREN expression RPAREN { $2 }
446-
| primary_expression DOT IDENTIFIER { make_expr (FieldAccess ($1, $3)) (make_pos ()) }
447-
| primary_expression ARROW IDENTIFIER { make_expr (ArrowAccess ($1, $3)) (make_pos ()) }
447+
| primary_expression DOT field_name { make_expr (FieldAccess ($1, $3)) (make_pos ()) }
448+
| primary_expression ARROW field_name { make_expr (ArrowAccess ($1, $3)) (make_pos ()) }
448449
| NEW bpf_type LPAREN RPAREN { make_expr (New $2) (make_pos ()) }
449450
| NEW bpf_type LPAREN expression RPAREN { make_expr (NewWithFlag ($2, $4)) (make_pos ()) }
450451

@@ -495,7 +496,7 @@ struct_literal_fields:
495496
| struct_literal_field COMMA { [$1] } /* Allow trailing comma */
496497

497498
struct_literal_field:
498-
| IDENTIFIER COLON expression { ($1, $3) }
499+
| field_name COLON expression { ($1, $3) }
499500

500501
/* Map Declarations */
501502
map_declaration:
@@ -565,7 +566,7 @@ struct_fields:
565566
| struct_field { [$1] }
566567

567568
struct_field:
568-
| IDENTIFIER COLON bpf_type { ($1, $3) }
569+
| field_name COLON bpf_type { ($1, $3) }
569570

570571

571572
/* Enum declaration: enum name { variants } - Fixed to eliminate unused production */
@@ -665,4 +666,9 @@ import_declaration:
665666
| IMPORT IDENTIFIER FROM STRING
666667
{ make_import_declaration $2 $4 (make_pos ()) }
667668

669+
/* Field name: allows both identifiers and specific keywords as field names */
670+
field_name:
671+
| IDENTIFIER { $1 }
672+
| TYPE { "type" }
673+
668674
%%

tests/test_struct_field_access.ml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,81 @@ struct PacketStats {
608608
with
609609
| exn -> fail ("Type alias field access test failed: " ^ Printexc.to_string exn)
610610

611+
(** Test 'type' keyword as field name - basic usage *)
612+
let test_type_keyword_as_field_name () =
613+
let input = {|
614+
struct trace_entry {
615+
type: u16,
616+
flags: u8,
617+
pid: u32
618+
}
619+
620+
fn test_function() -> i32 {
621+
var entry: trace_entry = trace_entry {
622+
type: 42,
623+
flags: 1,
624+
pid: 1234
625+
}
626+
627+
var entry_type = entry.type
628+
return entry_type
629+
}
630+
|} in
631+
632+
try
633+
let ast = parse_string input in
634+
635+
(* Verify struct definition with 'type' field *)
636+
match ast with
637+
| [StructDecl struct_def; GlobalFunction func_def] ->
638+
(* Check struct has 'type' field *)
639+
let type_field_exists = List.exists (fun (field_name, _) ->
640+
field_name = "type"
641+
) struct_def.struct_fields in
642+
check bool "'type' field exists in struct" true type_field_exists;
643+
644+
(* Verify we can access the symbol table without errors *)
645+
let symbol_table = create_symbol_table () in
646+
process_declaration symbol_table (StructDecl struct_def);
647+
process_declaration symbol_table (GlobalFunction func_def);
648+
649+
check bool "'type' keyword successfully used as field name" true true
650+
651+
| _ ->
652+
fail "Expected struct declaration and function declaration"
653+
with
654+
| exn -> fail ("'type' keyword field name test failed: " ^ Printexc.to_string exn)
655+
656+
(** Test BTF trace_entry struct with 'type' field *)
657+
let test_btf_trace_entry_struct () =
658+
let input = {|
659+
struct trace_entry {
660+
type: u16,
661+
flags: u8,
662+
preempt_count: u8,
663+
pid: u32
664+
}
665+
|} in
666+
667+
try
668+
let ast = parse_string input in
669+
match ast with
670+
| [StructDecl struct_def] ->
671+
check string "struct name" "trace_entry" struct_def.struct_name;
672+
673+
(* Verify all fields are present *)
674+
let field_names = List.map fst struct_def.struct_fields in
675+
check bool "'type' field present" true (List.mem "type" field_names);
676+
check bool "'flags' field present" true (List.mem "flags" field_names);
677+
check bool "'preempt_count' field present" true (List.mem "preempt_count" field_names);
678+
check bool "'pid' field present" true (List.mem "pid" field_names);
679+
680+
check bool "BTF trace_entry struct with 'type' field parsed successfully" true true
681+
| _ ->
682+
fail "Expected single struct declaration"
683+
with
684+
| exn -> fail ("BTF trace_entry struct test failed: " ^ Printexc.to_string exn)
685+
611686
(** Test runner *)
612687
let tests = [
613688
"top-level struct eBPF parameter", `Quick, test_toplevel_struct_ebpf_parameter;
@@ -626,6 +701,8 @@ let tests = [
626701
"struct field assignment C generation", `Quick, test_struct_field_assignment_c_generation;
627702
"struct field assignment errors", `Quick, test_struct_field_assignment_errors;
628703
"type alias field access", `Quick, test_type_alias_field_access;
704+
"type keyword as field name", `Quick, test_type_keyword_as_field_name;
705+
"BTF trace_entry struct", `Quick, test_btf_trace_entry_struct;
629706
]
630707

631708
let () = Alcotest.run "Struct Field Access and Assignment Tests" [

0 commit comments

Comments
 (0)