2222 from libdestruct .common .obj import obj
2323
2424
25+ PARSED_STRUCT = {}
26+ """A cache for parsed struct definitions, indexed by name."""
27+
28+ TYPEDEFS = {}
29+ """A cache for parsed type definitions, indexed by name."""
30+
2531def definition_to_type (definition : str ) -> type [obj ]:
2632 """Converts a C struct definition to a struct object."""
2733 parser = c_parser .CParser ()
2834
2935 # If the definition contains includes, we must expand them.
3036 if "#include" in definition :
3137 definition = cleanup_attributes (expand_includes (definition ))
32- force_more_tops = True
33- elif "typedef" in definition :
34- force_more_tops = True
35- else :
36- force_more_tops = False
3738
3839 try :
3940 ast = parser .parse (definition )
4041 except c_parser .ParseError as e :
4142 raise ValueError ("Invalid definition. Please add the necessary includes if using non-standard type definitions." ) from e
4243
43- if not force_more_tops and len (ast .ext ) != 1 :
44- raise ValueError ("Definition must contain exactly one top object." )
45-
46- # If force_more_tops is True, we take the last top object.
47- # This is useful when a struct definition is preceded by typedefs.
48- root = ast .ext [- 1 ].type if force_more_tops else ast .ext [0 ].type
44+ # We assume that the root declaration is the last one.
45+ root = ast .ext [- 1 ].type
4946
5047 if not isinstance (root , c_ast .Struct ):
5148 raise TypeError ("Definition must be a struct." )
5249
50+ # We parse each declaration in the definition, except the last one, if it is a struct.
51+ for decl in ast .ext [:- 1 ]:
52+ if isinstance (decl .type , c_ast .Struct ):
53+ struct_node = decl .type
54+
55+ if struct_node .name :
56+ PARSED_STRUCT [struct_node .name ] = struct_to_type (struct_node )
57+ elif isinstance (decl , c_ast .Typedef ):
58+ name , definition = typedef_to_pair (decl )
59+ TYPEDEFS [name ] = definition
60+
61+ print (TYPEDEFS )
62+
5363 return struct_to_type (root )
5464
5565
@@ -60,6 +70,12 @@ def struct_to_type(struct_node: c_ast.Struct) -> type[struct]:
6070
6171 fields = {}
6272
73+ if not struct_node .decls and struct_node .name in PARSED_STRUCT :
74+ # We can check if the struct is already parsed.
75+ return PARSED_STRUCT [struct_node .name ]
76+ elif not struct_node .decls :
77+ raise ValueError ("Struct must have fields." )
78+
6379 for decl in struct_node .decls :
6480 name = decl .name
6581 typ = type_decl_to_type (decl .type , struct_node )
@@ -122,6 +138,20 @@ def type_decl_to_type(decl: c_ast.TypeDecl, parent: c_ast.Struct | None = None)
122138 raise TypeError ("Unsupported type." )
123139
124140
141+ def typedef_to_pair (typedef : c_ast .Typedef ) -> tuple [str , type [obj ]]:
142+ """Converts a C typedef to a pair of name and definition."""
143+ if not isinstance (typedef , c_ast .Typedef ):
144+ raise TypeError ("Definition must be a typedef." )
145+
146+ if not isinstance (typedef .type , c_ast .TypeDecl ):
147+ raise TypeError ("Definition must be a type declaration." )
148+
149+ name = "" .join (typedef .name )
150+ definition = type_decl_to_type (typedef .type )
151+
152+ return name , definition
153+
154+
125155def to_uniform_name (name : str ) -> str :
126156 """Converts a name to a uniform name."""
127157 name = name .replace ("unsigned" , "u" )
@@ -182,4 +212,8 @@ def identifier_to_type(identifier: c_ast.IdentifierType) -> type[obj]:
182212 if hasattr (ctypes , ctypes_name ):
183213 return getattr (ctypes , ctypes_name )
184214
215+ # Check if we have a typedef to resolve this
216+ if identifier_name in TYPEDEFS :
217+ return TYPEDEFS [identifier_name ]
218+
185219 raise ValueError (f"Unsupported identifier: { identifier_name } ." )
0 commit comments