2929
3030from pycparser import c_ast , parse_file
3131import argparse
32+ from pathlib import Path
33+
34+ # Constants for repeated strings
35+ CPP_ARGS = [
36+ "-E" ,
37+ "-D__attribute__(x)=" ,
38+ "-D__asm__(x)=" ,
39+ "-D__asm(x)=" ,
40+ "-D__builtin_va_list=int" ,
41+ "-D__extension__=" ,
42+ "-D__inline__=" ,
43+ "-D__restrict=" ,
44+ "-D__restrict__=" ,
45+ "-D_Static_assert(x, y)=" ,
46+ "-D__signed=" ,
47+ "-D__volatile__(x)=" ,
48+ "-Dstatic_assert(x, y)=" ,
49+ ]
50+
51+ RESULT_STRUCT_TEMPLATE = """
52+ typedef struct {
53+ int error_code; // Error code (0 for success, non-zero for errors)
54+ union {
55+ // Add other types as needed
56+ } value;
57+ } Result;
58+ """
3259
60+ INCLUDE_HEADERS = ["<stdbool.h>" , "<stdint.h>" , "<stdlib.h>" ]
3361
34- def collect_typedefs (ast ):
35- """Collect all typedefs in the AST."""
36- typedefs = {}
37- for node in ast .ext :
38- if not isinstance (node , c_ast .Typedef ):
39- continue
4062
41- if node .name in typedefs :
42- raise Exception (f"Duplicate typedef found: { node .name } " )
63+ def extract_typedefs (ast ):
64+ """Extract all typedefs from the AST."""
65+ return {node .name : node .type for node in ast .ext if isinstance (node , c_ast .Typedef )}
66+
67+
68+ def generate_result_struct (return_types ):
69+ """Generate the Result struct based on return types."""
70+ result_struct = RESULT_STRUCT_TEMPLATE
71+ for return_type in return_types :
72+ if return_type != "void" :
73+ result_struct = result_struct .replace (
74+ "// Add other types as needed" ,
75+ f" { return_type } { return_type } _value;\n // Add other types as needed" ,
76+ )
77+ return result_struct
78+
79+
80+ def write_checked_header (output_path , result_struct , functions , typedefs ):
81+ """Write the checked header file."""
82+ with open (output_path , "w" ) as f :
83+ f .write ("#ifndef WASM_EXPORT_CHECKED_H\n #define WASM_EXPORT_CHECKED_H\n \n " )
84+
85+ for header in INCLUDE_HEADERS :
86+ f .write (f"#include { header } \n " )
87+ f .write ("\n " )
88+ f .write ('#include "wasm_export.h"\n ' )
89+ f .write ('#include "lib_export.h"\n ' )
90+ f .write ("\n " )
4391
44- typedef_name = node .name
45- typedef_type = node .type
46- typedefs [typedef_name ] = typedef_type
92+ f .write (result_struct + "\n " )
4793
48- return typedefs
94+ for func in functions :
95+ new_func = generate_checked_function (func , typedefs )
96+ f .write (new_func + "\n \n " )
97+
98+ f .write ("#endif // WASM_EXPORT_CHECKED_H\n " )
4999
50100
51101def resolve_typedef (typedefs , type_name ):
@@ -97,6 +147,7 @@ def resolve_base_type(ptr_decl):
97147
98148
99149def generate_checked_function (func , typedefs ):
150+ """Generate a checked version of the given function."""
100151 func_name = func .name # Access the name directly from Decl
101152 new_func_name = f"{ func_name } _checked"
102153
@@ -194,6 +245,7 @@ def generate_checked_function(func, typedefs):
194245
195246
196247def parse_arguments ():
248+ """Parse command-line arguments."""
197249 parser = argparse .ArgumentParser (
198250 description = "Generate checked functions from header files."
199251 )
@@ -206,67 +258,40 @@ def parse_arguments():
206258 return parser .parse_args ()
207259
208260
209- # Updated process_header to scan all return types and create a proper Result type
210-
211-
212- def process_headers (header_paths ):
213- # Define the Result struct as a string
214- RESULT_STRUCT = """
215- typedef struct {
216- int error_code; // Error code (0 for success, non-zero for errors)
217- union {
218- // Add other types as needed
219- } value;
220- } Result;
221- """
222-
261+ def generate_checked_headers (header_paths ):
262+ """Process each header file and generate checked versions."""
223263 for input_header in header_paths :
224- output_header = input_header .replace (".h" , "_checked.h" )
264+ input_path = Path (input_header )
265+ output_path = input_path .with_name (input_path .stem + "_checked.h" )
225266
226- # Parse the header file with preprocessing
227267 ast = parse_file (
228- input_header ,
268+ str ( input_path ) ,
229269 use_cpp = True ,
230270 cpp_path = "gcc" ,
231- cpp_args = [
232- "-E" ,
233- "-D__attribute__(x)=" ,
234- "-D__asm__(x)=" ,
235- "-D__asm(x)=" ,
236- "-D__builtin_va_list=int" ,
237- "-D__extension__=" ,
238- for return_type in return_types :
239- if return_type == "void" :
240- continue # No need to add void type
241-
242- RESULT_STRUCT = RESULT_STRUCT .replace (
243- "// Add other types as needed" ,
244- f" { return_type } { return_type } _value;\n // Add other types as needed" ,
245- )
271+ cpp_args = CPP_ARGS ,
272+ )
246273
247- # Generate the new header file
248- with open (output_header , "w" ) as f :
249- f .write ("#ifndef WASM_EXPORT_CHECKED_H\n #define WASM_EXPORT_CHECKED_H\n \n " )
274+ typedefs = extract_typedefs (ast )
275+ functions = [
276+ node
277+ for node in ast .ext
278+ if isinstance (node , c_ast .Decl ) and isinstance (node .type , c_ast .FuncDecl )
279+ ]
250280
251- # necessary headers
252- f .write ("#include <stdbool.h>\n " )
253- f .write ("#include <stdint.h>\n " )
254- f .write ("#include <stdlib.h>\n " )
255- f .write ("\n " )
256- f .write ('#include "wasm_export.h"\n ' )
257- f .write ('#include "lib_export.h"\n ' )
258- f .write ("\n " )
281+ return_types = {
282+ " " .join (func .type .type .type .names )
283+ for func in functions
284+ if isinstance (func .type .type , c_ast .TypeDecl )
285+ }
259286
260- # Write the updated Result struct
261- f . write ( RESULT_STRUCT + " \n " )
287+ result_struct = generate_result_struct ( return_types )
288+ write_checked_header ( output_path , result_struct , functions , typedefs )
262289
263- for func in functions :
264- new_func = generate_checked_function (func , typedefs )
265- f .write (new_func + "\n \n " )
266290
267- f .write ("#endif // WASM_EXPORT_CHECKED_H\n " )
291+ def main ():
292+ args = parse_arguments ()
293+ generate_checked_headers (args .headers )
268294
269295
270296if __name__ == "__main__" :
271- args = parse_arguments ()
272- process_headers (args .headers )
297+ main ()
0 commit comments