decy_parser/
parser.rs

1//! C parser implementation using clang-sys.
2//!
3//! This module provides the core parsing functionality to convert C source code
4//! into an AST representation using LLVM/Clang bindings.
5
6use anyhow::{Context, Result};
7use clang_sys::*;
8use std::ffi::{CStr, CString};
9use std::path::Path;
10use std::ptr;
11
12/// C parser using clang-sys.
13///
14/// # Examples
15///
16/// ```no_run
17/// use decy_parser::parser::CParser;
18///
19/// let parser = CParser::new()?;
20/// let ast = parser.parse("int main() { return 0; }")?;
21/// assert_eq!(ast.functions().len(), 1);
22/// # Ok::<(), anyhow::Error>(())
23/// ```
24#[derive(Debug)]
25pub struct CParser {
26    index: CXIndex,
27}
28
29impl CParser {
30    /// Create a new C parser.
31    ///
32    /// # Examples
33    ///
34    /// ```no_run
35    /// use decy_parser::parser::CParser;
36    ///
37    /// let parser = CParser::new()?;
38    /// # Ok::<(), anyhow::Error>(())
39    /// ```
40    pub fn new() -> Result<Self> {
41        // SAFETY: clang_createIndex is safe to call with these parameters
42        let index = unsafe { clang_createIndex(0, 0) };
43        if index.is_null() {
44            anyhow::bail!("Failed to create clang index");
45        }
46        Ok(Self { index })
47    }
48
49    /// Parse C source code into an AST.
50    ///
51    /// # Arguments
52    ///
53    /// * `source` - The C source code to parse
54    ///
55    /// # Returns
56    ///
57    /// * `Ok(Ast)` - The parsed AST
58    /// * `Err(anyhow::Error)` - If parsing fails
59    ///
60    /// # Examples
61    ///
62    /// ```no_run
63    /// use decy_parser::parser::CParser;
64    ///
65    /// let parser = CParser::new()?;
66    /// let ast = parser.parse("int add(int a, int b) { return a + b; }")?;
67    /// # Ok::<(), anyhow::Error>(())
68    /// ```
69    pub fn parse(&self, source: &str) -> Result<Ast> {
70        let filename = CString::new("input.c").context("Failed to create filename")?;
71        let source_cstr = CString::new(source).context("Failed to convert source to CString")?;
72
73        let mut ast = Ast::new();
74
75        // Handle empty input
76        if source.trim().is_empty() {
77            return Ok(ast);
78        }
79
80        // SAFETY: Creating unsaved file with valid C strings
81        let unsaved_file = CXUnsavedFile {
82            Filename: filename.as_ptr(),
83            Contents: source_cstr.as_ptr(),
84            Length: source.len() as std::os::raw::c_ulong,
85        };
86
87        // Detect if source contains BARE extern "C" (without #ifdef guards)
88        // If it has #ifdef __cplusplus guards, clang can handle it as C
89        // Only enable C++ mode for bare extern "C" blocks
90        let has_extern_c = source.contains("extern \"C\"");
91        let has_ifdef_guard =
92            source.contains("#ifdef __cplusplus") || source.contains("#if defined(__cplusplus)");
93        let needs_cpp_mode = has_extern_c && !has_ifdef_guard;
94
95        // Prepare command line arguments for C++ mode if needed
96        let cpp_flag = CString::new("-x").unwrap();
97        let cpp_lang = CString::new("c++").unwrap();
98        let args_vec: Vec<*const std::os::raw::c_char> = if needs_cpp_mode {
99            vec![cpp_flag.as_ptr(), cpp_lang.as_ptr()]
100        } else {
101            vec![]
102        };
103
104        // SAFETY: Parsing with clang_parseTranslationUnit2
105        // Enable DetailedPreprocessingRecord to capture macro definitions
106        // CXTranslationUnit_DetailedPreprocessingRecord = 1
107        let flags = 1;
108
109        let mut tu = ptr::null_mut();
110        let result = unsafe {
111            clang_parseTranslationUnit2(
112                self.index,
113                filename.as_ptr(),
114                if args_vec.is_empty() {
115                    ptr::null()
116                } else {
117                    args_vec.as_ptr()
118                },
119                args_vec.len() as std::os::raw::c_int,
120                &unsaved_file as *const CXUnsavedFile as *mut CXUnsavedFile,
121                1,
122                flags,
123                &mut tu,
124            )
125        };
126
127        if result != CXError_Success || tu.is_null() {
128            anyhow::bail!("Failed to parse C source");
129        }
130
131        // SAFETY: Check for diagnostics (errors/warnings)
132        let num_diagnostics = unsafe { clang_getNumDiagnostics(tu) };
133        for i in 0..num_diagnostics {
134            let diag = unsafe { clang_getDiagnostic(tu, i) };
135            let severity = unsafe { clang_getDiagnosticSeverity(diag) };
136
137            // If we have errors, fail the parse
138            if severity >= CXDiagnostic_Error {
139                unsafe { clang_disposeDiagnostic(diag) };
140                unsafe { clang_disposeTranslationUnit(tu) };
141                anyhow::bail!("C source has syntax errors");
142            }
143
144            unsafe { clang_disposeDiagnostic(diag) };
145        }
146
147        // SAFETY: Getting cursor from valid translation unit
148        let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
149
150        // Visit children to extract functions
151        let ast_ptr = &mut ast as *mut Ast;
152
153        // SAFETY: Visiting cursor children with callback
154        unsafe {
155            clang_visitChildren(cursor, visit_function, ast_ptr as CXClientData);
156
157            // Clean up
158            clang_disposeTranslationUnit(tu);
159        }
160
161        Ok(ast)
162    }
163
164    /// Parse a C file into an AST.
165    ///
166    /// # Arguments
167    ///
168    /// * `path` - Path to the C file
169    ///
170    /// # Returns
171    ///
172    /// * `Ok(Ast)` - The parsed AST
173    /// * `Err(anyhow::Error)` - If parsing fails
174    pub fn parse_file(&self, _path: &Path) -> Result<Ast> {
175        // RED phase: not yet implemented
176        Err(anyhow::anyhow!("Not implemented yet"))
177    }
178}
179
180impl Drop for CParser {
181    fn drop(&mut self) {
182        // SAFETY: Disposing of valid clang index
183        unsafe {
184            clang_disposeIndex(self.index);
185        }
186    }
187}
188
189/// Visitor callback for clang AST traversal.
190///
191/// # Safety
192///
193/// This function is called by clang_visitChildren and must follow C calling conventions.
194extern "C" fn visit_function(
195    cursor: CXCursor,
196    _parent: CXCursor,
197    client_data: CXClientData,
198) -> CXChildVisitResult {
199    // SAFETY: Converting client data back to AST pointer
200    let ast = unsafe { &mut *(client_data as *mut Ast) };
201
202    // SAFETY: Getting cursor kind
203    let kind = unsafe { clang_getCursorKind(cursor) };
204
205    // Handle extern "C" linkage specifications (DECY-055)
206    // CXCursor_LinkageSpec = 23
207    if kind == 23 {
208        // This is extern "C" { ... } - visit its children
209        // Don't process the linkage spec itself, just recurse into declarations
210        unsafe {
211            clang_visitChildren(cursor, visit_function, client_data);
212        }
213        return CXChildVisit_Continue;
214    }
215
216    if kind == CXCursor_FunctionDecl {
217        // Extract function information
218        if let Some(function) = extract_function(cursor) {
219            ast.add_function(function);
220        }
221    } else if kind == CXCursor_TypedefDecl {
222        // Extract typedef information
223        if let Some(typedef) = extract_typedef(cursor) {
224            ast.add_typedef(typedef);
225        }
226    } else if kind == CXCursor_StructDecl {
227        // Extract struct information
228        if let Some(struct_def) = extract_struct(cursor) {
229            ast.add_struct(struct_def);
230        }
231    } else if kind == CXCursor_VarDecl {
232        // Extract variable declaration - only add if it's at file scope (global)
233        // Check if parent is translation unit (file scope) vs function scope
234        let semantic_parent = unsafe { clang_getCursorSemanticParent(cursor) };
235        let parent_kind = unsafe { clang_getCursorKind(semantic_parent) };
236
237        // Check if parent is file scope: either TranslationUnit or nullptr
238        // Function declarations have parent kind = CXCursor_FunctionDecl (8)
239        // File-scope variables typically have parent kind = CXCursor_TranslationUnit (300 in clang-sys)
240        let is_file_scope = parent_kind != CXCursor_FunctionDecl;
241
242        if is_file_scope {
243            if let Some(variable) = extract_variable(cursor) {
244                ast.add_variable(variable);
245            }
246        }
247        // Local variables in functions are handled by extract_statement in function body parsing
248    } else if kind == CXCursor_MacroDefinition {
249        // Extract macro definition (only from main file, not includes)
250        let location = unsafe { clang_getCursorLocation(cursor) };
251        let mut file: CXFile = ptr::null_mut();
252        unsafe {
253            clang_getFileLocation(
254                location,
255                &mut file,
256                ptr::null_mut(),
257                ptr::null_mut(),
258                ptr::null_mut(),
259            );
260        }
261
262        // Only process macros from the main file (not system headers)
263        if !file.is_null() {
264            let file_name = unsafe {
265                let name_cxstring = clang_getFileName(file);
266                let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
267                let name = c_str.to_string_lossy().into_owned();
268                clang_disposeString(name_cxstring);
269                name
270            };
271
272            // Only add macros from input.c (our source file)
273            if file_name.ends_with("input.c") {
274                if let Some(macro_def) = extract_macro(cursor) {
275                    ast.add_macro(macro_def);
276                }
277            }
278        }
279    }
280
281    // Return Recurse to ensure we visit children of all nodes
282    // This is needed in C++ mode to reach LinkageSpec and its children
283    CXChildVisit_Recurse
284}
285
286/// Extract function information from a clang cursor.
287fn extract_function(cursor: CXCursor) -> Option<Function> {
288    // SAFETY: Getting cursor spelling (function name)
289    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
290    let name = unsafe {
291        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
292        let name = c_str.to_string_lossy().into_owned();
293        clang_disposeString(name_cxstring);
294        name
295    };
296
297    // SAFETY: Getting return type
298    let cx_type = unsafe { clang_getCursorType(cursor) };
299    let return_cx_type = unsafe { clang_getResultType(cx_type) };
300    let return_type = convert_type(return_cx_type)?;
301
302    // Extract parameters
303    let num_args = unsafe { clang_Cursor_getNumArguments(cursor) };
304    let mut parameters = Vec::new();
305
306    for i in 0..num_args {
307        // SAFETY: Getting argument cursor
308        let arg_cursor = unsafe { clang_Cursor_getArgument(cursor, i as u32) };
309
310        // Get parameter name
311        let param_name_cxstring = unsafe { clang_getCursorSpelling(arg_cursor) };
312        let param_name = unsafe {
313            let c_str = CStr::from_ptr(clang_getCString(param_name_cxstring));
314            let name = c_str.to_string_lossy().into_owned();
315            clang_disposeString(param_name_cxstring);
316            name
317        };
318
319        // Get parameter type
320        let param_cx_type = unsafe { clang_getCursorType(arg_cursor) };
321        if let Some(param_type) = convert_type(param_cx_type) {
322            parameters.push(Parameter::new(param_name, param_type));
323        }
324    }
325
326    // Extract function body by visiting children
327    let mut body = Vec::new();
328    let body_ptr = &mut body as *mut Vec<Statement>;
329
330    unsafe {
331        clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
332    }
333
334    Some(Function::new_with_body(name, return_type, parameters, body))
335}
336
337/// Extract typedef information from a clang cursor.
338fn extract_typedef(cursor: CXCursor) -> Option<Typedef> {
339    // SAFETY: Getting typedef name
340    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
341    let name = unsafe {
342        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
343        let name = c_str.to_string_lossy().into_owned();
344        clang_disposeString(name_cxstring);
345        name
346    };
347
348    // SAFETY: Getting underlying type of typedef
349    let cx_type = unsafe { clang_getTypedefDeclUnderlyingType(cursor) };
350    let underlying_type = convert_type(cx_type)?;
351
352    Some(Typedef::new(name, underlying_type))
353}
354
355/// Extract struct information from a clang cursor.
356fn extract_struct(cursor: CXCursor) -> Option<Struct> {
357    // SAFETY: Getting struct name
358    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
359    let name = unsafe {
360        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
361        let name = c_str.to_string_lossy().into_owned();
362        clang_disposeString(name_cxstring);
363        name
364    };
365
366    // Skip anonymous structs
367    if name.is_empty() {
368        return None;
369    }
370
371    // Extract struct fields by visiting children
372    let mut fields = Vec::new();
373    let fields_ptr = &mut fields as *mut Vec<StructField>;
374
375    unsafe {
376        clang_visitChildren(cursor, visit_struct_fields, fields_ptr as CXClientData);
377    }
378
379    Some(Struct::new(name, fields))
380}
381
382/// Extract macro definition from a clang cursor.
383///
384/// Extract variable declaration information from a clang cursor.
385///
386/// Extracts global and local variable declarations, including function pointers.
387///
388/// # Examples
389///
390/// Simple: `int x;`
391/// Function pointer: `int (*callback)(int);`
392fn extract_variable(cursor: CXCursor) -> Option<Variable> {
393    // SAFETY: Getting cursor spelling (variable name)
394    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
395    let name = unsafe {
396        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
397        let name = c_str.to_string_lossy().into_owned();
398        clang_disposeString(name_cxstring);
399        name
400    };
401
402    // SAFETY: Getting variable type
403    let cx_type = unsafe { clang_getCursorType(cursor) };
404    let var_type = convert_type(cx_type)?;
405
406    // Extract storage class specifiers
407    // CX_StorageClass values (from clang-sys):
408    // CX_SC_Invalid = 0, CX_SC_None = 1, CX_SC_Extern = 2, CX_SC_Static = 3,
409    // CX_SC_PrivateExtern = 4, CX_SC_OpenCLWorkGroupLocal = 5,
410    // CX_SC_Auto = 6, CX_SC_Register = 7
411    let storage_class = unsafe { clang_Cursor_getStorageClass(cursor) };
412    let is_static = storage_class == 3; // CX_SC_Static
413    let is_extern = storage_class == 2; // CX_SC_Extern
414
415    // Check if type is const-qualified
416    let is_const = unsafe { clang_isConstQualifiedType(cx_type) != 0 };
417
418    // Extract initializer by visiting children
419    let mut initializer: Option<Expression> = None;
420    let initializer_ptr = &mut initializer as *mut Option<Expression>;
421
422    unsafe {
423        clang_visitChildren(
424            cursor,
425            visit_variable_initializer,
426            initializer_ptr as CXClientData,
427        );
428    }
429
430    Some(Variable::new_with_storage_class(
431        name,
432        var_type,
433        initializer,
434        is_static,
435        is_extern,
436        is_const,
437    ))
438}
439
440/// Helper function to extract an expression from a cursor.
441/// Dispatches to the appropriate extract function based on cursor kind.
442#[allow(non_upper_case_globals)]
443fn try_extract_expression(cursor: CXCursor) -> Option<Expression> {
444    let kind = unsafe { clang_getCursorKind(cursor) };
445
446    match kind {
447        CXCursor_IntegerLiteral => extract_int_literal(cursor),
448        CXCursor_StringLiteral => extract_string_literal(cursor),
449        CXCursor_DeclRefExpr => extract_variable_ref(cursor),
450        CXCursor_BinaryOperator => extract_binary_op(cursor),
451        CXCursor_CallExpr => extract_function_call(cursor),
452        CXCursor_UnaryOperator => extract_unary_op(cursor),
453        CXCursor_ArraySubscriptExpr => extract_array_index(cursor),
454        CXCursor_MemberRefExpr => extract_field_access(cursor),
455        117 => extract_cast(cursor), // CXCursor_CStyleCastExpr
456        118 => extract_compound_literal(cursor), // CXCursor_CompoundLiteralExpr
457        CXCursor_UnexposedExpr => {
458            // UnexposedExpr is a wrapper - recurse into children
459            let mut result: Option<Expression> = None;
460            let result_ptr = &mut result as *mut Option<Expression>;
461            unsafe {
462                clang_visitChildren(
463                    cursor,
464                    visit_variable_initializer,
465                    result_ptr as CXClientData,
466                );
467            }
468            result
469        }
470        _ => None,
471    }
472}
473
474/// Visitor callback for variable initializer expressions.
475#[allow(non_upper_case_globals)]
476extern "C" fn visit_variable_initializer(
477    cursor: CXCursor,
478    _parent: CXCursor,
479    client_data: CXClientData,
480) -> CXChildVisitResult {
481    let initializer = unsafe { &mut *(client_data as *mut Option<Expression>) };
482
483    // Extract the first expression found (the initializer)
484    if let Some(expr) = try_extract_expression(cursor) {
485        *initializer = Some(expr);
486        return CXChildVisit_Break;
487    }
488
489    CXChildVisit_Continue
490}
491
492/// This function extracts #define directives, supporting both object-like and function-like macros.
493///
494/// # Examples
495///
496/// Object-like: `#define MAX 100`
497/// Function-like: `#define SQR(x) ((x) * (x))`
498fn extract_macro(cursor: CXCursor) -> Option<MacroDefinition> {
499    // SAFETY: Getting macro name
500    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
501    let name = unsafe {
502        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
503        let name = c_str.to_string_lossy().into_owned();
504        clang_disposeString(name_cxstring);
505        name
506    };
507
508    // Skip empty macro names
509    if name.is_empty() {
510        return None;
511    }
512
513    // Get macro body using clang_Cursor_isMacroFunctionLike and clang token APIs
514    // For now, we'll check if it's function-like and extract tokens
515    let is_function_like = unsafe { clang_sys::clang_Cursor_isMacroFunctionLike(cursor) } != 0;
516
517    // Get the source range and tokens for the macro
518    let range = unsafe { clang_getCursorExtent(cursor) };
519    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
520
521    let mut tokens: *mut CXToken = ptr::null_mut();
522    let mut num_tokens: u32 = 0;
523
524    unsafe {
525        clang_tokenize(tu, range, &mut tokens, &mut num_tokens);
526    }
527
528    // Extract macro body from tokens
529    // Skip the first token (macro name) and extract the rest
530    let mut parameters = Vec::new();
531    let mut body_tokens = Vec::new();
532    let mut in_params = false;
533
534    for i in 0..num_tokens {
535        let token = unsafe { *tokens.offset(i as isize) };
536        let token_kind = unsafe { clang_getTokenKind(token) };
537        let token_spelling = unsafe { clang_getTokenSpelling(tu, token) };
538        let token_str = unsafe {
539            let c_str = CStr::from_ptr(clang_getCString(token_spelling));
540            let s = c_str.to_string_lossy().into_owned();
541            clang_disposeString(token_spelling);
542            s
543        };
544
545        // Skip the macro name (first token)
546        if i == 0 {
547            continue;
548        }
549
550        // Check for parameter list (function-like macros)
551        if is_function_like && i == 1 && token_str == "(" {
552            in_params = true;
553            continue;
554        }
555
556        if in_params {
557            if token_str == ")" {
558                in_params = false;
559                continue;
560            } else if token_str != ","
561                && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
562            {
563                // Accept both identifiers and keywords as parameter names
564                // C allows keywords in macro parameter names since they're in macro scope
565                parameters.push(token_str);
566            }
567        } else {
568            body_tokens.push(token_str);
569        }
570    }
571
572    // Clean up tokens
573    unsafe {
574        clang_disposeTokens(tu, tokens, num_tokens);
575    }
576
577    // Join body tokens without spaces (preserving original formatting)
578    let body = body_tokens.join("");
579
580    if is_function_like {
581        Some(MacroDefinition::new_function_like(name, parameters, body))
582    } else {
583        Some(MacroDefinition::new_object_like(name, body))
584    }
585}
586
587/// Visitor callback for struct fields.
588///
589/// # Safety
590///
591/// This function is called by clang_visitChildren and must follow C calling conventions.
592#[allow(non_upper_case_globals)]
593extern "C" fn visit_struct_fields(
594    cursor: CXCursor,
595    _parent: CXCursor,
596    client_data: CXClientData,
597) -> CXChildVisitResult {
598    // SAFETY: Converting client data back to fields vector pointer
599    let fields = unsafe { &mut *(client_data as *mut Vec<StructField>) };
600
601    // SAFETY: Getting cursor kind
602    let kind = unsafe { clang_getCursorKind(cursor) };
603
604    if kind == CXCursor_FieldDecl {
605        // Get field name
606        let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
607        let name = unsafe {
608            let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
609            let name = c_str.to_string_lossy().into_owned();
610            clang_disposeString(name_cxstring);
611            name
612        };
613
614        // Get field type
615        let cx_type = unsafe { clang_getCursorType(cursor) };
616        if let Some(field_type) = convert_type(cx_type) {
617            fields.push(StructField::new(name, field_type));
618        }
619    }
620
621    CXChildVisit_Continue
622}
623
624/// Visitor callback for extracting statements from function body.
625///
626/// # Safety
627///
628/// This function is called by clang_visitChildren and must follow C calling conventions.
629#[allow(non_upper_case_globals)]
630extern "C" fn visit_statement(
631    cursor: CXCursor,
632    _parent: CXCursor,
633    client_data: CXClientData,
634) -> CXChildVisitResult {
635    // SAFETY: Converting client data back to statement vector pointer
636    let statements = unsafe { &mut *(client_data as *mut Vec<Statement>) };
637
638    // SAFETY: Getting cursor kind
639    let kind = unsafe { clang_getCursorKind(cursor) };
640
641    match kind {
642        CXCursor_CompoundStmt => {
643            // Compound statement (function body) - recurse into it
644            CXChildVisit_Recurse
645        }
646        CXCursor_DeclStmt => {
647            // Declaration statement - visit its children to get the actual declaration
648            CXChildVisit_Recurse
649        }
650        CXCursor_VarDecl => {
651            // Variable declaration
652            if let Some(stmt) = extract_var_decl(cursor) {
653                statements.push(stmt);
654            }
655            CXChildVisit_Continue
656        }
657        CXCursor_ReturnStmt => {
658            // Return statement
659            if let Some(stmt) = extract_return_stmt(cursor) {
660                statements.push(stmt);
661            }
662            CXChildVisit_Continue
663        }
664        CXCursor_BinaryOperator => {
665            // Could be an assignment statement (x = 42)
666            if let Some(stmt) = extract_assignment_stmt(cursor) {
667                statements.push(stmt);
668            }
669            CXChildVisit_Continue
670        }
671        CXCursor_IfStmt => {
672            // If statement
673            if let Some(stmt) = extract_if_stmt(cursor) {
674                statements.push(stmt);
675            }
676            CXChildVisit_Continue
677        }
678        CXCursor_ForStmt => {
679            // For loop
680            if let Some(stmt) = extract_for_stmt(cursor) {
681                statements.push(stmt);
682            }
683            CXChildVisit_Continue
684        }
685        CXCursor_WhileStmt => {
686            // While loop
687            if let Some(stmt) = extract_while_stmt(cursor) {
688                statements.push(stmt);
689            }
690            CXChildVisit_Continue
691        }
692        CXCursor_SwitchStmt => {
693            // Switch statement
694            if let Some(stmt) = extract_switch_stmt(cursor) {
695                statements.push(stmt);
696            }
697            CXChildVisit_Continue
698        }
699        CXCursor_BreakStmt => {
700            // Break statement
701            statements.push(Statement::Break);
702            CXChildVisit_Continue
703        }
704        CXCursor_ContinueStmt => {
705            // Continue statement
706            statements.push(Statement::Continue);
707            CXChildVisit_Continue
708        }
709        CXCursor_UnaryOperator => {
710            // Could be ++/-- statement (ptr++, ++ptr, ptr--, --ptr)
711            if let Some(stmt) = extract_inc_dec_stmt(cursor) {
712                statements.push(stmt);
713            }
714            CXChildVisit_Continue
715        }
716        CXCursor_CompoundAssignOperator => {
717            // Compound assignment (+=, -=, *=, /=, %=)
718            if let Some(stmt) = extract_compound_assignment_stmt(cursor) {
719                statements.push(stmt);
720            }
721            CXChildVisit_Continue
722        }
723        CXCursor_CallExpr => {
724            // Function call as statement (DECY-066)
725            // e.g., printf("Hello"); or free(ptr);
726            if let Some(stmt) = extract_statement(cursor) {
727                statements.push(stmt);
728            }
729            CXChildVisit_Continue
730        }
731        _ => CXChildVisit_Recurse, // Recurse into unknown nodes to find statements
732    }
733}
734
735/// Extract a variable declaration statement.
736fn extract_var_decl(cursor: CXCursor) -> Option<Statement> {
737    // Get variable name
738    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
739    let name = unsafe {
740        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
741        let name = c_str.to_string_lossy().into_owned();
742        clang_disposeString(name_cxstring);
743        name
744    };
745
746    // Get variable type
747    let cx_type = unsafe { clang_getCursorType(cursor) };
748    let var_type = convert_type(cx_type)?;
749
750    // Extract initializer by visiting children
751    let mut initializer: Option<Expression> = None;
752    let init_ptr = &mut initializer as *mut Option<Expression>;
753
754    unsafe {
755        clang_visitChildren(cursor, visit_expression, init_ptr as CXClientData);
756    }
757
758    Some(Statement::VariableDeclaration {
759        name,
760        var_type,
761        initializer,
762    })
763}
764
765/// Extract a return statement.
766fn extract_return_stmt(cursor: CXCursor) -> Option<Statement> {
767    // Extract return expression by visiting children
768    let mut return_expr: Option<Expression> = None;
769    let expr_ptr = &mut return_expr as *mut Option<Expression>;
770
771    unsafe {
772        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
773    }
774
775    Some(Statement::Return(return_expr))
776}
777
778/// Extract an assignment statement.
779fn extract_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
780    // Check if this binary operator is an assignment '=' (not '==', '!=', etc.)
781    // Get the translation unit
782    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
783    if tu.is_null() {
784        return None;
785    }
786
787    // Get the extent (source range) of the cursor
788    let extent = unsafe { clang_getCursorExtent(cursor) };
789
790    // Tokenize to find the operator
791    let mut tokens = ptr::null_mut();
792    let mut num_tokens = 0;
793
794    unsafe {
795        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
796    }
797
798    let mut is_assignment = false;
799
800    // Look through tokens to find '=' (and make sure it's not '==', '!=', etc.)
801    for i in 0..num_tokens {
802        unsafe {
803            let token = *tokens.add(i as usize);
804            let token_kind = clang_getTokenKind(token);
805
806            if token_kind == CXToken_Punctuation {
807                let token_cxstring = clang_getTokenSpelling(tu, token);
808                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
809                if let Ok(token_str) = c_str.to_str() {
810                    // Only accept single '=' for assignment
811                    if token_str == "=" {
812                        is_assignment = true;
813                        clang_disposeString(token_cxstring);
814                        break;
815                    } else if token_str == "=="
816                        || token_str == "!="
817                        || token_str == "<="
818                        || token_str == ">="
819                    {
820                        // This is a comparison operator, not assignment
821                        clang_disposeString(token_cxstring);
822                        break;
823                    }
824                }
825                clang_disposeString(token_cxstring);
826            }
827        }
828    }
829
830    unsafe {
831        clang_disposeTokens(tu, tokens, num_tokens);
832    }
833
834    if !is_assignment {
835        return None;
836    }
837
838    // Extract left side (target) and right side (value)
839    let mut operands: Vec<Expression> = Vec::new();
840    let operands_ptr = &mut operands as *mut Vec<Expression>;
841
842    unsafe {
843        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
844    }
845
846    // Assignment should have exactly 2 operands
847    if operands.len() != 2 {
848        return None;
849    }
850
851    // Check if left side is a dereference (e.g., *dst = x)
852    if let Expression::Dereference(inner) = &operands[0] {
853        return Some(Statement::DerefAssignment {
854            target: (**inner).clone(), // Extract the inner expression being dereferenced
855            value: operands[1].clone(),
856        });
857    }
858
859    // Check if left side is an array index (e.g., arr[i] = value)
860    if let Expression::ArrayIndex { array, index } = &operands[0] {
861        return Some(Statement::ArrayIndexAssignment {
862            array: array.clone(),
863            index: index.clone(),
864            value: operands[1].clone(),
865        });
866    }
867
868    // Check if left side is a field access (e.g., ptr->field = value or obj.field = value)
869    if matches!(
870        &operands[0],
871        Expression::PointerFieldAccess { .. } | Expression::FieldAccess { .. }
872    ) {
873        // Extract field name from the expression
874        let field = match &operands[0] {
875            Expression::PointerFieldAccess { field, .. } => field.clone(),
876            Expression::FieldAccess { field, .. } => field.clone(),
877            _ => unreachable!(),
878        };
879
880        // Extract object from the expression
881        let object = match &operands[0] {
882            Expression::PointerFieldAccess { pointer, .. } => (**pointer).clone(),
883            Expression::FieldAccess { object, .. } => (**object).clone(),
884            _ => unreachable!(),
885        };
886
887        return Some(Statement::FieldAssignment {
888            object,
889            field,
890            value: operands[1].clone(),
891        });
892    }
893
894    // Left side must be a variable reference for regular assignment
895    let target = match &operands[0] {
896        Expression::Variable(name) => name.clone(),
897        _ => return None, // Can't assign to non-variables (yet)
898    };
899
900    Some(Statement::Assignment {
901        target,
902        value: operands[1].clone(),
903    })
904}
905
906/// Extract an increment/decrement statement (++, --).
907fn extract_inc_dec_stmt(cursor: CXCursor) -> Option<Statement> {
908    // Get the translation unit
909    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
910    if tu.is_null() {
911        return None;
912    }
913
914    // Get the extent (source range) of the cursor
915    let extent = unsafe { clang_getCursorExtent(cursor) };
916
917    // Tokenize to find the operator
918    let mut tokens = ptr::null_mut();
919    let mut num_tokens = 0;
920
921    unsafe {
922        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
923    }
924
925    let mut operator: Option<String> = None;
926    let mut operator_position = 0;
927
928    // Look through tokens to find ++ or --
929    for i in 0..num_tokens {
930        unsafe {
931            let token = *tokens.add(i as usize);
932            let token_kind = clang_getTokenKind(token);
933
934            if token_kind == CXToken_Punctuation {
935                let token_cxstring = clang_getTokenSpelling(tu, token);
936                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
937                if let Ok(token_str) = c_str.to_str() {
938                    if token_str == "++" || token_str == "--" {
939                        operator = Some(token_str.to_string()); // Clone the string before disposing
940                        operator_position = i;
941                        clang_disposeString(token_cxstring);
942                        break;
943                    }
944                }
945                clang_disposeString(token_cxstring);
946            }
947        }
948    }
949
950    // Determine if this is pre or post increment/decrement
951    // If operator comes before identifier, it's pre (++ptr)
952    // If operator comes after identifier, it's post (ptr++)
953    let is_pre = operator_position == 0;
954
955    unsafe {
956        clang_disposeTokens(tu, tokens, num_tokens);
957    }
958
959    // Extract the target variable name by visiting children
960    let mut target_name: Option<String> = None;
961
962    // Visit children to find the DeclRefExpr (variable reference)
963    extern "C" fn visit_for_target(
964        cursor: CXCursor,
965        _parent: CXCursor,
966        client_data: CXClientData,
967    ) -> CXChildVisitResult {
968        let target = unsafe { &mut *(client_data as *mut Option<String>) };
969        let kind = unsafe { clang_getCursorKind(cursor) };
970
971        if kind == CXCursor_DeclRefExpr {
972            let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
973            let name = unsafe {
974                let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
975                let var_name = c_str.to_string_lossy().into_owned();
976                clang_disposeString(name_cxstring);
977                var_name
978            };
979            *target = Some(name);
980            CXChildVisit_Break
981        } else {
982            CXChildVisit_Recurse
983        }
984    }
985
986    let target_ptr = &mut target_name as *mut Option<String>;
987    unsafe {
988        clang_visitChildren(cursor, visit_for_target, target_ptr as CXClientData);
989    }
990
991    let target = target_name?;
992
993    match operator?.as_str() {
994        "++" => {
995            if is_pre {
996                Some(Statement::PreIncrement { target })
997            } else {
998                Some(Statement::PostIncrement { target })
999            }
1000        }
1001        "--" => {
1002            if is_pre {
1003                Some(Statement::PreDecrement { target })
1004            } else {
1005                Some(Statement::PostDecrement { target })
1006            }
1007        }
1008        _ => None,
1009    }
1010}
1011
1012/// Extract a compound assignment statement (+=, -=, *=, /=, %=).
1013fn extract_compound_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
1014    // Get the translation unit
1015    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1016    if tu.is_null() {
1017        return None;
1018    }
1019
1020    // Get the extent (source range) of the cursor
1021    let extent = unsafe { clang_getCursorExtent(cursor) };
1022
1023    // Tokenize to find the operator
1024    let mut tokens = ptr::null_mut();
1025    let mut num_tokens = 0;
1026
1027    unsafe {
1028        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1029    }
1030
1031    let mut operator: Option<BinaryOperator> = None;
1032
1033    // Look through tokens to find compound assignment operator
1034    for i in 0..num_tokens {
1035        unsafe {
1036            let token = *tokens.add(i as usize);
1037            let token_kind = clang_getTokenKind(token);
1038
1039            if token_kind == CXToken_Punctuation {
1040                let token_cxstring = clang_getTokenSpelling(tu, token);
1041                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1042                if let Ok(token_str) = c_str.to_str() {
1043                    operator = match token_str {
1044                        "+=" => Some(BinaryOperator::Add),
1045                        "-=" => Some(BinaryOperator::Subtract),
1046                        "*=" => Some(BinaryOperator::Multiply),
1047                        "/=" => Some(BinaryOperator::Divide),
1048                        "%=" => Some(BinaryOperator::Modulo),
1049                        _ => None,
1050                    };
1051                    if operator.is_some() {
1052                        clang_disposeString(token_cxstring);
1053                        break;
1054                    }
1055                }
1056                clang_disposeString(token_cxstring);
1057            }
1058        }
1059    }
1060
1061    unsafe {
1062        clang_disposeTokens(tu, tokens, num_tokens);
1063    }
1064
1065    let op = operator?;
1066
1067    // Extract left side (target) and right side (value)
1068    let mut operands: Vec<Expression> = Vec::new();
1069    let operands_ptr = &mut operands as *mut Vec<Expression>;
1070
1071    unsafe {
1072        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
1073    }
1074
1075    // Compound assignment should have exactly 2 operands
1076    if operands.len() != 2 {
1077        return None;
1078    }
1079
1080    // Left side must be a variable reference
1081    let target = match &operands[0] {
1082        Expression::Variable(name) => name.clone(),
1083        _ => return None,
1084    };
1085
1086    Some(Statement::CompoundAssignment {
1087        target,
1088        op,
1089        value: operands[1].clone(),
1090    })
1091}
1092
1093/// Extract an if statement.
1094fn extract_if_stmt(cursor: CXCursor) -> Option<Statement> {
1095    // An if statement has 2 or 3 children:
1096    // 1. Condition expression
1097    // 2. Then block (compound statement)
1098    // 3. Else block (optional compound statement)
1099
1100    #[repr(C)]
1101    struct IfData {
1102        condition: Option<Expression>,
1103        then_block: Vec<Statement>,
1104        else_block: Option<Vec<Statement>>,
1105        child_index: u32,
1106    }
1107
1108    let mut if_data = IfData {
1109        condition: None,
1110        then_block: Vec::new(),
1111        else_block: None,
1112        child_index: 0,
1113    };
1114
1115    let data_ptr = &mut if_data as *mut IfData;
1116
1117    unsafe {
1118        clang_visitChildren(cursor, visit_if_children, data_ptr as CXClientData);
1119    }
1120
1121    Some(Statement::If {
1122        condition: if_data.condition?,
1123        then_block: if_data.then_block,
1124        else_block: if_data.else_block,
1125    })
1126}
1127
1128/// Visitor for if statement children.
1129#[allow(non_upper_case_globals)]
1130extern "C" fn visit_if_children(
1131    cursor: CXCursor,
1132    _parent: CXCursor,
1133    client_data: CXClientData,
1134) -> CXChildVisitResult {
1135    #[repr(C)]
1136    struct IfData {
1137        condition: Option<Expression>,
1138        then_block: Vec<Statement>,
1139        else_block: Option<Vec<Statement>>,
1140        child_index: u32,
1141    }
1142
1143    let if_data = unsafe { &mut *(client_data as *mut IfData) };
1144    let kind = unsafe { clang_getCursorKind(cursor) };
1145
1146    match if_data.child_index {
1147        0 => {
1148            // First child: condition expression
1149            // The cursor itself IS the condition, extract it directly
1150            if_data.condition = match kind {
1151                CXCursor_BinaryOperator => extract_binary_op(cursor),
1152                CXCursor_IntegerLiteral => extract_int_literal(cursor),
1153                CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1154                CXCursor_CallExpr => extract_function_call(cursor),
1155                CXCursor_UnaryOperator => extract_unary_op(cursor),
1156                _ => {
1157                    // For other expression types, try visiting children
1158                    let mut cond_expr: Option<Expression> = None;
1159                    let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1160                    unsafe {
1161                        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1162                    }
1163                    cond_expr
1164                }
1165            };
1166            if_data.child_index += 1;
1167            CXChildVisit_Continue
1168        }
1169        1 => {
1170            // Second child: then block
1171            if kind == CXCursor_CompoundStmt {
1172                let body_ptr = &mut if_data.then_block as *mut Vec<Statement>;
1173                unsafe {
1174                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1175                }
1176            }
1177            if_data.child_index += 1;
1178            CXChildVisit_Continue
1179        }
1180        2 => {
1181            // Third child (optional): else block
1182            if kind == CXCursor_CompoundStmt || kind == CXCursor_IfStmt {
1183                let mut else_stmts = Vec::new();
1184                let body_ptr = &mut else_stmts as *mut Vec<Statement>;
1185                unsafe {
1186                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1187                }
1188                if_data.else_block = Some(else_stmts);
1189            }
1190            if_data.child_index += 1;
1191            CXChildVisit_Continue
1192        }
1193        _ => CXChildVisit_Continue,
1194    }
1195}
1196
1197/// Extract a for loop statement.
1198fn extract_for_stmt(cursor: CXCursor) -> Option<Statement> {
1199    // A for loop has up to 4 children:
1200    // 1. Init statement (optional - could be DeclStmt or expression)
1201    // 2. Condition expression (optional)
1202    // 3. Increment expression (optional)
1203    // 4. Body (compound statement)
1204
1205    #[repr(C)]
1206    struct ForData {
1207        init: Option<Box<Statement>>,
1208        condition: Option<Expression>,
1209        increment: Option<Box<Statement>>,
1210        body: Vec<Statement>,
1211        child_index: u32,
1212    }
1213
1214    let mut for_data = ForData {
1215        init: None,
1216        condition: None,
1217        increment: None,
1218        body: Vec::new(),
1219        child_index: 0,
1220    };
1221
1222    let data_ptr = &mut for_data as *mut ForData;
1223
1224    unsafe {
1225        clang_visitChildren(cursor, visit_for_children, data_ptr as CXClientData);
1226    }
1227
1228    Some(Statement::For {
1229        init: for_data.init,
1230        condition: for_data.condition,
1231        increment: for_data.increment,
1232        body: for_data.body,
1233    })
1234}
1235
1236/// Visitor for for loop children.
1237#[allow(non_upper_case_globals)]
1238extern "C" fn visit_for_children(
1239    cursor: CXCursor,
1240    _parent: CXCursor,
1241    client_data: CXClientData,
1242) -> CXChildVisitResult {
1243    #[repr(C)]
1244    struct ForData {
1245        init: Option<Box<Statement>>,
1246        condition: Option<Expression>,
1247        increment: Option<Box<Statement>>,
1248        body: Vec<Statement>,
1249        child_index: u32,
1250    }
1251
1252    let for_data = unsafe { &mut *(client_data as *mut ForData) };
1253    let kind = unsafe { clang_getCursorKind(cursor) };
1254
1255    match for_data.child_index {
1256        0 => {
1257            // First child: init statement (could be DeclStmt or NULL)
1258            if kind == CXCursor_DeclStmt {
1259                // Visit to get the variable declaration
1260                let mut init_stmts = Vec::new();
1261                let ptr = &mut init_stmts as *mut Vec<Statement>;
1262                unsafe {
1263                    clang_visitChildren(cursor, visit_statement, ptr as CXClientData);
1264                }
1265                if let Some(stmt) = init_stmts.into_iter().next() {
1266                    for_data.init = Some(Box::new(stmt));
1267                }
1268            } else if kind == CXCursor_BinaryOperator {
1269                // Assignment in init
1270                if let Some(stmt) = extract_assignment_stmt(cursor) {
1271                    for_data.init = Some(Box::new(stmt));
1272                }
1273            }
1274            for_data.child_index += 1;
1275            CXChildVisit_Continue
1276        }
1277        1 => {
1278            // Second child: condition expression
1279            // The cursor itself IS the condition, extract it directly
1280            for_data.condition = match kind {
1281                CXCursor_BinaryOperator => extract_binary_op(cursor),
1282                CXCursor_IntegerLiteral => extract_int_literal(cursor),
1283                CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1284                CXCursor_CallExpr => extract_function_call(cursor),
1285                CXCursor_UnaryOperator => extract_unary_op(cursor),
1286                _ => {
1287                    let mut cond_expr: Option<Expression> = None;
1288                    let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1289                    unsafe {
1290                        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1291                    }
1292                    cond_expr
1293                }
1294            };
1295            for_data.child_index += 1;
1296            CXChildVisit_Continue
1297        }
1298        2 => {
1299            // Third child: increment statement
1300            if kind == CXCursor_BinaryOperator {
1301                if let Some(stmt) = extract_assignment_stmt(cursor) {
1302                    for_data.increment = Some(Box::new(stmt));
1303                }
1304            } else if kind == CXCursor_UnaryOperator {
1305                // Handle ++/-- in increment position
1306                if let Some(stmt) = extract_inc_dec_stmt(cursor) {
1307                    for_data.increment = Some(Box::new(stmt));
1308                }
1309            }
1310            for_data.child_index += 1;
1311            CXChildVisit_Continue
1312        }
1313        3 => {
1314            // Fourth child: body
1315            if kind == CXCursor_CompoundStmt {
1316                let body_ptr = &mut for_data.body as *mut Vec<Statement>;
1317                unsafe {
1318                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1319                }
1320            }
1321            for_data.child_index += 1;
1322            CXChildVisit_Continue
1323        }
1324        _ => CXChildVisit_Continue,
1325    }
1326}
1327
1328/// Extract a while loop statement.
1329fn extract_while_stmt(cursor: CXCursor) -> Option<Statement> {
1330    // A while loop has 2 children:
1331    // 1. Condition expression
1332    // 2. Body (compound statement)
1333
1334    #[repr(C)]
1335    struct WhileData {
1336        condition: Option<Expression>,
1337        body: Vec<Statement>,
1338        child_index: u32,
1339    }
1340
1341    let mut while_data = WhileData {
1342        condition: None,
1343        body: Vec::new(),
1344        child_index: 0,
1345    };
1346
1347    let data_ptr = &mut while_data as *mut WhileData;
1348
1349    unsafe {
1350        clang_visitChildren(cursor, visit_while_children, data_ptr as CXClientData);
1351    }
1352
1353    Some(Statement::While {
1354        condition: while_data.condition?,
1355        body: while_data.body,
1356    })
1357}
1358
1359/// Visitor for while loop children.
1360#[allow(non_upper_case_globals)]
1361extern "C" fn visit_while_children(
1362    cursor: CXCursor,
1363    _parent: CXCursor,
1364    client_data: CXClientData,
1365) -> CXChildVisitResult {
1366    #[repr(C)]
1367    struct WhileData {
1368        condition: Option<Expression>,
1369        body: Vec<Statement>,
1370        child_index: u32,
1371    }
1372
1373    let while_data = unsafe { &mut *(client_data as *mut WhileData) };
1374    let kind = unsafe { clang_getCursorKind(cursor) };
1375
1376    match while_data.child_index {
1377        0 => {
1378            // First child: condition expression
1379            // The cursor itself IS the condition, extract it directly
1380            while_data.condition = match kind {
1381                CXCursor_BinaryOperator => extract_binary_op(cursor),
1382                CXCursor_IntegerLiteral => extract_int_literal(cursor),
1383                CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1384                CXCursor_CallExpr => extract_function_call(cursor),
1385                CXCursor_UnaryOperator => extract_unary_op(cursor),
1386                _ => {
1387                    let mut cond_expr: Option<Expression> = None;
1388                    let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1389                    unsafe {
1390                        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1391                    }
1392                    cond_expr
1393                }
1394            };
1395            while_data.child_index += 1;
1396            CXChildVisit_Continue
1397        }
1398        1 => {
1399            // Second child: body
1400            if kind == CXCursor_CompoundStmt {
1401                let body_ptr = &mut while_data.body as *mut Vec<Statement>;
1402                unsafe {
1403                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1404                }
1405            }
1406            while_data.child_index += 1;
1407            CXChildVisit_Continue
1408        }
1409        _ => CXChildVisit_Continue,
1410    }
1411}
1412
1413/// Extract a switch statement from a cursor.
1414///
1415/// Parses switch statements including cases and default labels.
1416#[allow(non_upper_case_globals)]
1417fn extract_switch_stmt(cursor: CXCursor) -> Option<Statement> {
1418    // Switch has 2 children:
1419    // 1. Condition expression
1420    // 2. Body (compound statement containing case/default labels)
1421
1422    #[repr(C)]
1423    struct SwitchData {
1424        condition: Option<Expression>,
1425        cases: Vec<SwitchCase>,
1426        default_case: Option<Vec<Statement>>,
1427        child_index: u32,
1428    }
1429
1430    let mut switch_data = SwitchData {
1431        condition: None,
1432        cases: Vec::new(),
1433        default_case: None,
1434        child_index: 0,
1435    };
1436
1437    let data_ptr = &mut switch_data as *mut SwitchData;
1438
1439    unsafe {
1440        clang_visitChildren(cursor, visit_switch_children, data_ptr as CXClientData);
1441    }
1442
1443    Some(Statement::Switch {
1444        condition: switch_data.condition?,
1445        cases: switch_data.cases,
1446        default_case: switch_data.default_case,
1447    })
1448}
1449
1450/// Visitor callback for switch statement children (condition and body).
1451#[allow(non_upper_case_globals)]
1452extern "C" fn visit_switch_children(
1453    cursor: CXCursor,
1454    _parent: CXCursor,
1455    client_data: CXClientData,
1456) -> CXChildVisitResult {
1457    #[repr(C)]
1458    struct SwitchData {
1459        condition: Option<Expression>,
1460        cases: Vec<SwitchCase>,
1461        default_case: Option<Vec<Statement>>,
1462        child_index: u32,
1463    }
1464
1465    let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
1466    let kind = unsafe { clang_getCursorKind(cursor) };
1467
1468    match switch_data.child_index {
1469        0 => {
1470            // First child: condition expression
1471            if let Some(expr) = try_extract_expression(cursor) {
1472                switch_data.condition = Some(expr);
1473            }
1474            switch_data.child_index += 1;
1475            CXChildVisit_Continue
1476        }
1477        1 => {
1478            // Second child: compound statement body containing cases
1479            // Need to visit this recursively to find case/default labels
1480            if kind == CXCursor_CompoundStmt {
1481                unsafe {
1482                    clang_visitChildren(cursor, visit_switch_body, client_data);
1483                }
1484            }
1485            switch_data.child_index += 1;
1486            CXChildVisit_Continue
1487        }
1488        _ => CXChildVisit_Continue,
1489    }
1490}
1491
1492/// Visitor callback for switch body to extract cases and default.
1493#[allow(non_upper_case_globals)]
1494extern "C" fn visit_switch_body(
1495    cursor: CXCursor,
1496    _parent: CXCursor,
1497    client_data: CXClientData,
1498) -> CXChildVisitResult {
1499    #[repr(C)]
1500    struct SwitchData {
1501        condition: Option<Expression>,
1502        cases: Vec<SwitchCase>,
1503        default_case: Option<Vec<Statement>>,
1504        child_index: u32,
1505    }
1506
1507    let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
1508    let kind = unsafe { clang_getCursorKind(cursor) };
1509
1510    match kind {
1511        CXCursor_CaseStmt => {
1512            // Extract case statement
1513            if let Some(case) = extract_case_stmt(cursor) {
1514                switch_data.cases.push(case);
1515            }
1516            CXChildVisit_Continue
1517        }
1518        CXCursor_DefaultStmt => {
1519            // Extract default statement
1520            if let Some(body) = extract_default_stmt(cursor) {
1521                switch_data.default_case = Some(body);
1522            }
1523            CXChildVisit_Continue
1524        }
1525        _ => CXChildVisit_Continue,
1526    }
1527}
1528
1529/// Extract a case statement from a cursor.
1530fn extract_case_stmt(cursor: CXCursor) -> Option<SwitchCase> {
1531    // Case statement has 2 children:
1532    // 1. Case value expression
1533    // 2. Body (statements following the case label)
1534
1535    #[repr(C)]
1536    struct CaseData {
1537        value: Option<Expression>,
1538        body: Vec<Statement>,
1539        child_index: u32,
1540    }
1541
1542    let mut case_data = CaseData {
1543        value: None,
1544        body: Vec::new(),
1545        child_index: 0,
1546    };
1547
1548    let data_ptr = &mut case_data as *mut CaseData;
1549
1550    unsafe {
1551        clang_visitChildren(cursor, visit_case_children, data_ptr as CXClientData);
1552    }
1553
1554    Some(SwitchCase {
1555        value: case_data.value,
1556        body: case_data.body,
1557    })
1558}
1559
1560/// Visitor for case statement children.
1561#[allow(non_upper_case_globals)]
1562extern "C" fn visit_case_children(
1563    cursor: CXCursor,
1564    _parent: CXCursor,
1565    client_data: CXClientData,
1566) -> CXChildVisitResult {
1567    #[repr(C)]
1568    struct CaseData {
1569        value: Option<Expression>,
1570        body: Vec<Statement>,
1571        child_index: u32,
1572    }
1573
1574    let case_data = unsafe { &mut *(client_data as *mut CaseData) };
1575    let _kind = unsafe { clang_getCursorKind(cursor) };
1576
1577    match case_data.child_index {
1578        0 => {
1579            // First child: case value expression
1580            if let Some(expr) = try_extract_expression(cursor) {
1581                case_data.value = Some(expr);
1582            }
1583            case_data.child_index += 1;
1584            CXChildVisit_Continue
1585        }
1586        _ => {
1587            // Subsequent children: statements in case body
1588            // Extract statements until we hit another case or default
1589            if let Some(stmt) = extract_statement(cursor) {
1590                case_data.body.push(stmt);
1591            }
1592            // Continue recursing to find all statements in the case body
1593            CXChildVisit_Recurse
1594        }
1595    }
1596}
1597
1598/// Extract a default statement from a cursor.
1599fn extract_default_stmt(cursor: CXCursor) -> Option<Vec<Statement>> {
1600    // Default statement has body statements as children
1601    let mut body: Vec<Statement> = Vec::new();
1602    let body_ptr = &mut body as *mut Vec<Statement>;
1603
1604    unsafe {
1605        clang_visitChildren(cursor, visit_default_children, body_ptr as CXClientData);
1606    }
1607
1608    Some(body)
1609}
1610
1611/// Visitor for default statement children.
1612#[allow(non_upper_case_globals)]
1613extern "C" fn visit_default_children(
1614    cursor: CXCursor,
1615    _parent: CXCursor,
1616    client_data: CXClientData,
1617) -> CXChildVisitResult {
1618    let body = unsafe { &mut *(client_data as *mut Vec<Statement>) };
1619
1620    // Extract all statements in default body
1621    if let Some(stmt) = extract_statement(cursor) {
1622        body.push(stmt);
1623    }
1624
1625    CXChildVisit_Continue
1626}
1627
1628/// Helper function to extract a statement from a cursor based on its kind.
1629#[allow(non_upper_case_globals)]
1630fn extract_statement(cursor: CXCursor) -> Option<Statement> {
1631    let kind = unsafe { clang_getCursorKind(cursor) };
1632
1633    match kind {
1634        CXCursor_ReturnStmt => extract_return_stmt(cursor),
1635        CXCursor_VarDecl => extract_var_decl(cursor),
1636        CXCursor_IfStmt => extract_if_stmt(cursor),
1637        CXCursor_ForStmt => extract_for_stmt(cursor),
1638        CXCursor_WhileStmt => extract_while_stmt(cursor),
1639        CXCursor_BreakStmt => Some(Statement::Break),
1640        CXCursor_ContinueStmt => Some(Statement::Continue),
1641        CXCursor_UnaryOperator => extract_inc_dec_stmt(cursor),
1642        CXCursor_BinaryOperator => extract_assignment_stmt(cursor),
1643        CXCursor_CallExpr => {
1644            // Function call as statement
1645            if let Some(Expression::FunctionCall {
1646                function,
1647                arguments,
1648            }) = extract_function_call(cursor)
1649            {
1650                return Some(Statement::FunctionCall {
1651                    function,
1652                    arguments,
1653                });
1654            }
1655            None
1656        }
1657        _ => None,
1658    }
1659}
1660
1661/// Visitor callback for extracting expressions.
1662///
1663/// # Safety
1664///
1665/// This function is called by clang_visitChildren and must follow C calling conventions.
1666#[allow(non_upper_case_globals)]
1667extern "C" fn visit_expression(
1668    cursor: CXCursor,
1669    _parent: CXCursor,
1670    client_data: CXClientData,
1671) -> CXChildVisitResult {
1672    // SAFETY: Converting client data back to expression option pointer
1673    let expr_opt = unsafe { &mut *(client_data as *mut Option<Expression>) };
1674
1675    // SAFETY: Getting cursor kind
1676    let kind = unsafe { clang_getCursorKind(cursor) };
1677
1678    match kind {
1679        CXCursor_IntegerLiteral => {
1680            // Integer literal
1681            if let Some(expr) = extract_int_literal(cursor) {
1682                *expr_opt = Some(expr);
1683            }
1684            CXChildVisit_Continue
1685        }
1686        CXCursor_StringLiteral => {
1687            // String literal
1688            if let Some(expr) = extract_string_literal(cursor) {
1689                *expr_opt = Some(expr);
1690            }
1691            CXChildVisit_Continue
1692        }
1693        CXCursor_DeclRefExpr => {
1694            // Variable reference (e.g., "a" or "b" in "a + b")
1695            if let Some(expr) = extract_variable_ref(cursor) {
1696                *expr_opt = Some(expr);
1697            }
1698            CXChildVisit_Continue
1699        }
1700        CXCursor_BinaryOperator => {
1701            // Binary operation (e.g., a + b)
1702            if let Some(expr) = extract_binary_op(cursor) {
1703                *expr_opt = Some(expr);
1704            }
1705            CXChildVisit_Continue
1706        }
1707        CXCursor_CallExpr => {
1708            // Function call
1709            if let Some(expr) = extract_function_call(cursor) {
1710                *expr_opt = Some(expr);
1711            }
1712            CXChildVisit_Continue
1713        }
1714        CXCursor_UnaryOperator => {
1715            // Unary operator (e.g., *ptr dereference)
1716            if let Some(expr) = extract_unary_op(cursor) {
1717                *expr_opt = Some(expr);
1718            }
1719            CXChildVisit_Continue
1720        }
1721        CXCursor_ArraySubscriptExpr => {
1722            // Array indexing (e.g., arr[i])
1723            if let Some(expr) = extract_array_index(cursor) {
1724                *expr_opt = Some(expr);
1725            }
1726            CXChildVisit_Continue
1727        }
1728        CXCursor_MemberRefExpr => {
1729            // Field access (e.g., ptr->field or obj.field)
1730            if let Some(expr) = extract_field_access(cursor) {
1731                *expr_opt = Some(expr);
1732            }
1733            CXChildVisit_Continue
1734        }
1735        CXCursor_UnexposedExpr => {
1736            // Unexposed expressions might wrap other expressions (like ImplicitCastExpr wrapping CallExpr)
1737            // Recurse first to check if there's a more specific expression inside
1738            CXChildVisit_Recurse
1739        }
1740        CXCursor_ParenExpr => {
1741            // Parenthesized expressions wrap other expressions, recurse
1742            CXChildVisit_Recurse
1743        }
1744        136 => {
1745            // CXCursor_UnaryExpr - could be sizeof or other unary expr
1746            if let Some(expr) = extract_sizeof(cursor) {
1747                *expr_opt = Some(expr);
1748                CXChildVisit_Continue
1749            } else {
1750                // Not sizeof, recurse for other unary expressions
1751                CXChildVisit_Recurse
1752            }
1753        }
1754        _ => CXChildVisit_Recurse,
1755    }
1756}
1757
1758/// Extract an integer literal expression.
1759fn extract_int_literal(cursor: CXCursor) -> Option<Expression> {
1760    // SAFETY: Get the extent (source range) of the cursor
1761    let extent = unsafe { clang_getCursorExtent(cursor) };
1762
1763    // SAFETY: Get the translation unit from the cursor
1764    let tu = unsafe {
1765        let loc = clang_getCursorLocation(cursor);
1766        let mut file = ptr::null_mut();
1767        let mut line = 0;
1768        let mut column = 0;
1769        let mut offset = 0;
1770        clang_getFileLocation(loc, &mut file, &mut line, &mut column, &mut offset);
1771
1772        // Get the translation unit containing this cursor
1773        // We need to traverse up to get it, but for now use a different approach
1774        clang_Cursor_getTranslationUnit(cursor)
1775    };
1776
1777    if tu.is_null() {
1778        return Some(Expression::IntLiteral(0));
1779    }
1780
1781    // SAFETY: Tokenize the extent
1782    let mut tokens = ptr::null_mut();
1783    let mut num_tokens = 0;
1784
1785    unsafe {
1786        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1787    }
1788
1789    let mut value = 0;
1790
1791    if num_tokens > 0 {
1792        // SAFETY: Get the spelling of the first token
1793        unsafe {
1794            let token_cxstring = clang_getTokenSpelling(tu, *tokens);
1795            let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1796            if let Ok(token_str) = c_str.to_str() {
1797                value = token_str.parse().unwrap_or(0);
1798            }
1799            clang_disposeString(token_cxstring);
1800
1801            // SAFETY: Dispose tokens
1802            clang_disposeTokens(tu, tokens, num_tokens);
1803        }
1804    }
1805
1806    Some(Expression::IntLiteral(value))
1807}
1808
1809/// Extract a string literal expression.
1810fn extract_string_literal(cursor: CXCursor) -> Option<Expression> {
1811    // SAFETY: Get the extent (source range) of the cursor
1812    let extent = unsafe { clang_getCursorExtent(cursor) };
1813
1814    // SAFETY: Get the translation unit from the cursor
1815    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1816
1817    if tu.is_null() {
1818        return Some(Expression::StringLiteral(String::new()));
1819    }
1820
1821    // SAFETY: Tokenize the extent
1822    let mut tokens = ptr::null_mut();
1823    let mut num_tokens = 0;
1824
1825    unsafe {
1826        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1827    }
1828
1829    let mut value = String::new();
1830
1831    if num_tokens > 0 {
1832        // SAFETY: Get the spelling of the first token
1833        unsafe {
1834            let token_cxstring = clang_getTokenSpelling(tu, *tokens);
1835            let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1836            if let Ok(token_str) = c_str.to_str() {
1837                // Remove surrounding quotes from string literal
1838                value = token_str.trim_matches('"').to_string();
1839            }
1840            clang_disposeString(token_cxstring);
1841
1842            // SAFETY: Dispose tokens
1843            clang_disposeTokens(tu, tokens, num_tokens);
1844        }
1845    }
1846
1847    Some(Expression::StringLiteral(value))
1848}
1849
1850/// Extract a variable reference expression.
1851fn extract_variable_ref(cursor: CXCursor) -> Option<Expression> {
1852    // Get variable name
1853    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
1854    let name = unsafe {
1855        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
1856        let var_name = c_str.to_string_lossy().into_owned();
1857        clang_disposeString(name_cxstring);
1858        var_name
1859    };
1860
1861    Some(Expression::Variable(name))
1862}
1863
1864/// Extract a binary operation expression.
1865fn extract_binary_op(cursor: CXCursor) -> Option<Expression> {
1866    // Extract operator by tokenizing
1867    let op = extract_binary_operator(cursor)?;
1868
1869    // Extract left and right operands by visiting children
1870    let mut operands: Vec<Expression> = Vec::new();
1871    let operands_ptr = &mut operands as *mut Vec<Expression>;
1872
1873    unsafe {
1874        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
1875    }
1876
1877    // Binary operators should have exactly 2 operands
1878    if operands.len() != 2 {
1879        return None;
1880    }
1881
1882    Some(Expression::BinaryOp {
1883        op,
1884        left: Box::new(operands[0].clone()),
1885        right: Box::new(operands[1].clone()),
1886    })
1887}
1888
1889/// Visitor callback for binary operator operands.
1890#[allow(non_upper_case_globals)]
1891extern "C" fn visit_binary_operand(
1892    cursor: CXCursor,
1893    _parent: CXCursor,
1894    client_data: CXClientData,
1895) -> CXChildVisitResult {
1896    let operands = unsafe { &mut *(client_data as *mut Vec<Expression>) };
1897    let kind = unsafe { clang_getCursorKind(cursor) };
1898
1899    match kind {
1900        CXCursor_IntegerLiteral => {
1901            if let Some(expr) = extract_int_literal(cursor) {
1902                operands.push(expr);
1903            }
1904            CXChildVisit_Continue
1905        }
1906        CXCursor_StringLiteral => {
1907            if let Some(expr) = extract_string_literal(cursor) {
1908                operands.push(expr);
1909            }
1910            CXChildVisit_Continue
1911        }
1912        CXCursor_DeclRefExpr => {
1913            if let Some(expr) = extract_variable_ref(cursor) {
1914                operands.push(expr);
1915            }
1916            CXChildVisit_Continue
1917        }
1918        CXCursor_BinaryOperator => {
1919            // Nested binary operation
1920            if let Some(expr) = extract_binary_op(cursor) {
1921                operands.push(expr);
1922            }
1923            CXChildVisit_Continue
1924        }
1925        CXCursor_UnaryOperator => {
1926            // Unary operation (e.g., *ptr dereference)
1927            if let Some(expr) = extract_unary_op(cursor) {
1928                operands.push(expr);
1929            }
1930            CXChildVisit_Continue
1931        }
1932        CXCursor_ArraySubscriptExpr => {
1933            // Array indexing (e.g., arr[i])
1934            if let Some(expr) = extract_array_index(cursor) {
1935                operands.push(expr);
1936            }
1937            CXChildVisit_Continue
1938        }
1939        CXCursor_MemberRefExpr => {
1940            // Field access (e.g., ptr->field or obj.field)
1941            if let Some(expr) = extract_field_access(cursor) {
1942                operands.push(expr);
1943            }
1944            CXChildVisit_Continue
1945        }
1946        CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
1947            // Unexposed expressions might be sizeof or wrap other expressions
1948            if let Some(expr) = extract_sizeof(cursor) {
1949                operands.push(expr);
1950                CXChildVisit_Continue
1951            } else {
1952                CXChildVisit_Recurse
1953            }
1954        }
1955        136 => {
1956            // CXCursor_UnaryExpr - includes sizeof, alignof, etc.
1957            if let Some(expr) = extract_sizeof(cursor) {
1958                operands.push(expr);
1959                CXChildVisit_Continue
1960            } else {
1961                CXChildVisit_Recurse
1962            }
1963        }
1964        CXCursor_CallExpr => {
1965            // Function call expression (e.g., malloc(size))
1966            if let Some(expr) = extract_function_call(cursor) {
1967                operands.push(expr);
1968            }
1969            CXChildVisit_Continue
1970        }
1971        _ => CXChildVisit_Recurse,
1972    }
1973}
1974
1975/// Extract the binary operator from a cursor by tokenizing.
1976#[allow(non_upper_case_globals)]
1977fn extract_binary_operator(cursor: CXCursor) -> Option<BinaryOperator> {
1978    // Get the translation unit
1979    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1980    if tu.is_null() {
1981        return None;
1982    }
1983
1984    // Get the extent (source range) of the cursor
1985    let extent = unsafe { clang_getCursorExtent(cursor) };
1986
1987    // Tokenize to find the operator
1988    let mut tokens = ptr::null_mut();
1989    let mut num_tokens = 0;
1990
1991    unsafe {
1992        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1993    }
1994
1995    let mut operator = None;
1996
1997    // Look through tokens to find the operator
1998    // For compound expressions like "a > 0 && b > 0", we need to find the LAST
1999    // operator (the one with lowest precedence) which represents THIS binary operation.
2000    // We scan from right to left to find operators with lowest precedence first.
2001    // Precedence (lowest to highest): || > && > == != > < > <= >= > + - > * / %
2002
2003    let mut candidates: Vec<(usize, BinaryOperator)> = Vec::new();
2004    let mut found_first_operand = false;
2005
2006    for i in 0..num_tokens {
2007        unsafe {
2008            let token = *tokens.add(i as usize);
2009            let token_kind = clang_getTokenKind(token);
2010
2011            // Track when we've seen the first operand (identifier or literal)
2012            if token_kind == CXToken_Identifier || token_kind == CXToken_Literal {
2013                found_first_operand = true;
2014            }
2015
2016            // Collect all operator candidates after the first operand
2017            if token_kind == CXToken_Punctuation && found_first_operand {
2018                let token_cxstring = clang_getTokenSpelling(tu, token);
2019                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2020                if let Ok(token_str) = c_str.to_str() {
2021                    let op = match token_str {
2022                        "+" => Some(BinaryOperator::Add),
2023                        "-" => Some(BinaryOperator::Subtract),
2024                        "*" => Some(BinaryOperator::Multiply),
2025                        "/" => Some(BinaryOperator::Divide),
2026                        "%" => Some(BinaryOperator::Modulo),
2027                        "==" => Some(BinaryOperator::Equal),
2028                        "!=" => Some(BinaryOperator::NotEqual),
2029                        "<" => Some(BinaryOperator::LessThan),
2030                        ">" => Some(BinaryOperator::GreaterThan),
2031                        "<=" => Some(BinaryOperator::LessEqual),
2032                        ">=" => Some(BinaryOperator::GreaterEqual),
2033                        "&&" => Some(BinaryOperator::LogicalAnd),
2034                        "||" => Some(BinaryOperator::LogicalOr),
2035                        _ => None,
2036                    };
2037                    if let Some(op) = op {
2038                        candidates.push((i as usize, op));
2039                    }
2040                }
2041                clang_disposeString(token_cxstring);
2042            }
2043        }
2044    }
2045
2046    // Select the operator with lowest precedence (appears last in our search)
2047    // This handles cases like "a > 0 && b > 0" where && should be selected over >
2048    if !candidates.is_empty() {
2049        // Priority: || > && > comparisons > arithmetic
2050        // Find the first || operator
2051        for (_, op) in &candidates {
2052            if matches!(op, BinaryOperator::LogicalOr) {
2053                operator = Some(*op);
2054                break;
2055            }
2056        }
2057        // If no ||, find first &&
2058        if operator.is_none() {
2059            for (_, op) in &candidates {
2060                if matches!(op, BinaryOperator::LogicalAnd) {
2061                    operator = Some(*op);
2062                    break;
2063                }
2064            }
2065        }
2066        // If no logical operators, find operator with lowest precedence
2067        // Precedence (lowest to highest): comparisons (==, !=, <, >, <=, >=) > arithmetic (+, -) > multiplicative (*, /, %)
2068        if operator.is_none() {
2069            // Find first comparison operator (==, !=, <, >, <=, >=)
2070            for (_, op) in &candidates {
2071                if matches!(
2072                    op,
2073                    BinaryOperator::Equal
2074                        | BinaryOperator::NotEqual
2075                        | BinaryOperator::LessThan
2076                        | BinaryOperator::GreaterThan
2077                        | BinaryOperator::LessEqual
2078                        | BinaryOperator::GreaterEqual
2079                ) {
2080                    operator = Some(*op);
2081                    break;
2082                }
2083            }
2084        }
2085        // If no comparisons, find first additive operator (+, -)
2086        if operator.is_none() {
2087            for (_, op) in &candidates {
2088                if matches!(op, BinaryOperator::Add | BinaryOperator::Subtract) {
2089                    operator = Some(*op);
2090                    break;
2091                }
2092            }
2093        }
2094        // If no additive, take first multiplicative operator (*, /, %)
2095        if operator.is_none() {
2096            operator = Some(candidates[0].1);
2097        }
2098    }
2099
2100    unsafe {
2101        clang_disposeTokens(tu, tokens, num_tokens);
2102    }
2103
2104    operator
2105}
2106
2107/// Extract a function call expression.
2108fn extract_function_call(cursor: CXCursor) -> Option<Expression> {
2109    // Get function name
2110    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
2111    let function = unsafe {
2112        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
2113        let name = c_str.to_string_lossy().into_owned();
2114        clang_disposeString(name_cxstring);
2115        name
2116    };
2117
2118    // Extract arguments by visiting children
2119    // We use a struct to track if we've seen the function reference yet
2120    #[repr(C)]
2121    struct ArgData {
2122        arguments: Vec<Expression>,
2123        skip_first_declref: bool,
2124    }
2125
2126    let mut arg_data = ArgData {
2127        arguments: Vec::new(),
2128        skip_first_declref: true, // Skip the first DeclRefExpr (function name)
2129    };
2130    let args_ptr = &mut arg_data as *mut ArgData;
2131
2132    unsafe {
2133        clang_visitChildren(cursor, visit_call_argument, args_ptr as CXClientData);
2134    }
2135
2136    Some(Expression::FunctionCall {
2137        function,
2138        arguments: arg_data.arguments,
2139    })
2140}
2141
2142/// Visitor callback for function call arguments.
2143///
2144/// # Safety
2145///
2146/// This function is called by clang_visitChildren and must follow C calling conventions.
2147#[allow(non_upper_case_globals)]
2148extern "C" fn visit_call_argument(
2149    cursor: CXCursor,
2150    _parent: CXCursor,
2151    client_data: CXClientData,
2152) -> CXChildVisitResult {
2153    #[repr(C)]
2154    struct ArgData {
2155        arguments: Vec<Expression>,
2156        skip_first_declref: bool,
2157    }
2158
2159    // SAFETY: Converting client data back to ArgData pointer
2160    let arg_data = unsafe { &mut *(client_data as *mut ArgData) };
2161
2162    // SAFETY: Getting cursor kind
2163    let kind = unsafe { clang_getCursorKind(cursor) };
2164
2165    match kind {
2166        CXCursor_IntegerLiteral => {
2167            if let Some(expr) = extract_int_literal(cursor) {
2168                arg_data.arguments.push(expr);
2169            }
2170            CXChildVisit_Continue
2171        }
2172        CXCursor_StringLiteral => {
2173            if let Some(expr) = extract_string_literal(cursor) {
2174                arg_data.arguments.push(expr);
2175            }
2176            CXChildVisit_Continue
2177        }
2178        CXCursor_DeclRefExpr => {
2179            // Variable reference argument
2180            // The first DeclRefExpr is the function being called, skip it
2181            if arg_data.skip_first_declref {
2182                arg_data.skip_first_declref = false;
2183                CXChildVisit_Continue
2184            } else {
2185                if let Some(expr) = extract_variable_ref(cursor) {
2186                    arg_data.arguments.push(expr);
2187                }
2188                CXChildVisit_Continue
2189            }
2190        }
2191        CXCursor_BinaryOperator => {
2192            // Binary operation in argument (e.g., x + 1, y * 2)
2193            if let Some(expr) = extract_binary_op(cursor) {
2194                arg_data.arguments.push(expr);
2195            }
2196            CXChildVisit_Continue
2197        }
2198        CXCursor_CallExpr => {
2199            // Nested function call (e.g., add(add(x, 5), add(10, 20)))
2200            if let Some(expr) = extract_function_call(cursor) {
2201                arg_data.arguments.push(expr);
2202            }
2203            CXChildVisit_Continue
2204        }
2205        CXCursor_UnaryOperator => {
2206            // Unary operation in argument (e.g., -x, !flag)
2207            if let Some(expr) = extract_unary_op(cursor) {
2208                arg_data.arguments.push(expr);
2209            }
2210            CXChildVisit_Continue
2211        }
2212        CXCursor_ArraySubscriptExpr => {
2213            // Array indexing in argument (e.g., arr[i])
2214            if let Some(expr) = extract_array_index(cursor) {
2215                arg_data.arguments.push(expr);
2216            }
2217            CXChildVisit_Continue
2218        }
2219        CXCursor_MemberRefExpr => {
2220            // Field access in argument (e.g., ptr->field or obj.field)
2221            if let Some(expr) = extract_field_access(cursor) {
2222                arg_data.arguments.push(expr);
2223            }
2224            CXChildVisit_Continue
2225        }
2226        CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
2227            // Unexposed expressions might wrap actual expressions or be sizeof, try to extract
2228            if let Some(expr) = extract_sizeof(cursor) {
2229                arg_data.arguments.push(expr);
2230                CXChildVisit_Continue
2231            } else {
2232                CXChildVisit_Recurse
2233            }
2234        }
2235        136 => {
2236            // CXCursor_UnaryExpr - includes sizeof, alignof, etc.
2237            if let Some(expr) = extract_sizeof(cursor) {
2238                arg_data.arguments.push(expr);
2239                CXChildVisit_Continue
2240            } else {
2241                CXChildVisit_Recurse
2242            }
2243        }
2244        _ => CXChildVisit_Continue, // Skip other unknown children
2245    }
2246}
2247
2248/// Extract a unary operator expression.
2249fn extract_unary_op(cursor: CXCursor) -> Option<Expression> {
2250    // Get the translation unit
2251    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2252    if tu.is_null() {
2253        return None;
2254    }
2255
2256    // Get the extent (source range) of the cursor
2257    let extent = unsafe { clang_getCursorExtent(cursor) };
2258
2259    // Tokenize to find the operator
2260    let mut tokens = ptr::null_mut();
2261    let mut num_tokens = 0;
2262
2263    unsafe {
2264        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2265    }
2266
2267    let mut operator: Option<UnaryOperator> = None;
2268    let mut is_dereference = false;
2269    let mut is_increment = false;
2270    let mut is_decrement = false;
2271    let mut operator_position = 0;
2272
2273    // Look through tokens to find the unary operator
2274    for i in 0..num_tokens {
2275        unsafe {
2276            let token = *tokens.add(i as usize);
2277            let token_kind = clang_getTokenKind(token);
2278
2279            if token_kind == CXToken_Punctuation {
2280                let token_cxstring = clang_getTokenSpelling(tu, token);
2281                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2282                if let Ok(token_str) = c_str.to_str() {
2283                    match token_str {
2284                        "*" => {
2285                            is_dereference = true;
2286                            clang_disposeString(token_cxstring);
2287                            break;
2288                        }
2289                        "-" => {
2290                            operator = Some(UnaryOperator::Minus);
2291                            clang_disposeString(token_cxstring);
2292                            break;
2293                        }
2294                        "!" => {
2295                            operator = Some(UnaryOperator::LogicalNot);
2296                            clang_disposeString(token_cxstring);
2297                            break;
2298                        }
2299                        "~" => {
2300                            operator = Some(UnaryOperator::BitwiseNot);
2301                            clang_disposeString(token_cxstring);
2302                            break;
2303                        }
2304                        "&" => {
2305                            operator = Some(UnaryOperator::AddressOf);
2306                            clang_disposeString(token_cxstring);
2307                            break;
2308                        }
2309                        "++" => {
2310                            is_increment = true;
2311                            operator_position = i;
2312                            clang_disposeString(token_cxstring);
2313                            break;
2314                        }
2315                        "--" => {
2316                            is_decrement = true;
2317                            operator_position = i;
2318                            clang_disposeString(token_cxstring);
2319                            break;
2320                        }
2321                        _ => {}
2322                    }
2323                }
2324                clang_disposeString(token_cxstring);
2325            }
2326        }
2327    }
2328
2329    unsafe {
2330        clang_disposeTokens(tu, tokens, num_tokens);
2331    }
2332
2333    // Extract the operand
2334    let mut operand: Option<Expression> = None;
2335    let operand_ptr = &mut operand as *mut Option<Expression>;
2336
2337    unsafe {
2338        clang_visitChildren(cursor, visit_expression, operand_ptr as CXClientData);
2339    }
2340
2341    let operand_expr = operand?;
2342
2343    // Handle dereference separately (maintains backward compatibility)
2344    if is_dereference {
2345        return Some(Expression::Dereference(Box::new(operand_expr)));
2346    }
2347
2348    // Handle increment/decrement operators
2349    if is_increment {
2350        // Check if pre or post increment
2351        let is_pre = operator_position == 0;
2352        if is_pre {
2353            return Some(Expression::PreIncrement {
2354                operand: Box::new(operand_expr),
2355            });
2356        } else {
2357            return Some(Expression::PostIncrement {
2358                operand: Box::new(operand_expr),
2359            });
2360        }
2361    }
2362
2363    if is_decrement {
2364        // Check if pre or post decrement
2365        let is_pre = operator_position == 0;
2366        if is_pre {
2367            return Some(Expression::PreDecrement {
2368                operand: Box::new(operand_expr),
2369            });
2370        } else {
2371            return Some(Expression::PostDecrement {
2372                operand: Box::new(operand_expr),
2373            });
2374        }
2375    }
2376
2377    // Handle other unary operators
2378    if let Some(op) = operator {
2379        return Some(Expression::UnaryOp {
2380            op,
2381            operand: Box::new(operand_expr),
2382        });
2383    }
2384
2385    None
2386}
2387
2388/// Extract an array indexing expression.
2389fn extract_array_index(cursor: CXCursor) -> Option<Expression> {
2390    // Extract array and index expressions by visiting children
2391    let mut operands: Vec<Expression> = Vec::new();
2392    let operands_ptr = &mut operands as *mut Vec<Expression>;
2393
2394    unsafe {
2395        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
2396    }
2397
2398    // Array subscript should have exactly 2 operands: array and index
2399    if operands.len() != 2 {
2400        return None;
2401    }
2402
2403    Some(Expression::ArrayIndex {
2404        array: Box::new(operands[0].clone()),
2405        index: Box::new(operands[1].clone()),
2406    })
2407}
2408
2409/// Extract a field access expression (obj.field or ptr->field).
2410fn extract_field_access(cursor: CXCursor) -> Option<Expression> {
2411    // Get the field name
2412    let field_name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
2413    let field = unsafe {
2414        let c_str = CStr::from_ptr(clang_getCString(field_name_cxstring));
2415        let name = c_str.to_string_lossy().into_owned();
2416        clang_disposeString(field_name_cxstring);
2417        name
2418    };
2419
2420    // Determine if this is -> or . by tokenizing
2421    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2422    if tu.is_null() {
2423        return None;
2424    }
2425
2426    let extent = unsafe { clang_getCursorExtent(cursor) };
2427    let mut tokens = ptr::null_mut();
2428    let mut num_tokens = 0;
2429
2430    unsafe {
2431        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2432    }
2433
2434    let mut is_arrow = false;
2435
2436    // Look through tokens to find the LAST '->' or '.' operator
2437    // (the rightmost operator is the one for this specific MemberRefExpr)
2438    // For nested access like r->bottom_right.x, the extent includes all tokens,
2439    // so we need the last operator, not the first
2440    for i in 0..num_tokens {
2441        unsafe {
2442            let token = *tokens.add(i as usize);
2443            let token_kind = clang_getTokenKind(token);
2444
2445            if token_kind == CXToken_Punctuation {
2446                let token_cxstring = clang_getTokenSpelling(tu, token);
2447                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2448                if let Ok(token_str) = c_str.to_str() {
2449                    if token_str == "->" {
2450                        is_arrow = true;
2451                        // Don't break - keep looking for later operators
2452                    } else if token_str == "." {
2453                        is_arrow = false;
2454                        // Don't break - keep looking for later operators
2455                    }
2456                }
2457                clang_disposeString(token_cxstring);
2458            }
2459        }
2460    }
2461
2462    unsafe {
2463        clang_disposeTokens(tu, tokens, num_tokens);
2464    }
2465
2466    // Extract the object/pointer expression by visiting children
2467    let mut object_expr: Option<Expression> = None;
2468    let expr_ptr = &mut object_expr as *mut Option<Expression>;
2469
2470    unsafe {
2471        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
2472    }
2473
2474    let object = object_expr?;
2475
2476    if is_arrow {
2477        Some(Expression::PointerFieldAccess {
2478            pointer: Box::new(object),
2479            field,
2480        })
2481    } else {
2482        Some(Expression::FieldAccess {
2483            object: Box::new(object),
2484            field,
2485        })
2486    }
2487}
2488
2489/// Extract a sizeof expression.
2490fn extract_sizeof(cursor: CXCursor) -> Option<Expression> {
2491    // Get the translation unit
2492    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2493    if tu.is_null() {
2494        return None;
2495    }
2496
2497    // Get the extent (source range) of the cursor
2498    let extent = unsafe { clang_getCursorExtent(cursor) };
2499
2500    // Tokenize to find "sizeof" keyword
2501    let mut tokens = ptr::null_mut();
2502    let mut num_tokens = 0;
2503
2504    unsafe {
2505        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2506    }
2507
2508    let mut is_sizeof = false;
2509    let mut type_name = String::new();
2510
2511    // Look through tokens to find "sizeof" keyword and extract type name
2512    for i in 0..num_tokens {
2513        unsafe {
2514            let token = *tokens.add(i as usize);
2515            let token_kind = clang_getTokenKind(token);
2516            let token_cxstring = clang_getTokenSpelling(tu, token);
2517            let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2518
2519            if let Ok(token_str) = c_str.to_str() {
2520                if token_str == "sizeof" {
2521                    is_sizeof = true;
2522                } else if is_sizeof
2523                    && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
2524                    && token_str != "("
2525                    && token_str != ")"
2526                {
2527                    // This is part of the type name (e.g., "int", "Data", "struct")
2528                    if !type_name.is_empty() {
2529                        type_name.push(' ');
2530                    }
2531                    type_name.push_str(token_str);
2532                }
2533            }
2534
2535            clang_disposeString(token_cxstring);
2536        }
2537    }
2538
2539    unsafe {
2540        clang_disposeTokens(tu, tokens, num_tokens);
2541    }
2542
2543    if is_sizeof && !type_name.is_empty() {
2544        Some(Expression::Sizeof { type_name })
2545    } else {
2546        None
2547    }
2548}
2549
2550/// Convert clang type to our Type enum.
2551#[allow(non_upper_case_globals)]
2552/// Extract a cast expression from a clang cursor.
2553///
2554/// Parses C-style cast expressions like `(int)x` or `(void*)ptr`.
2555/// Extracts the target type and the expression being cast.
2556fn extract_cast(cursor: CXCursor) -> Option<Expression> {
2557    // SAFETY: Getting the type this expression evaluates to (the cast result type)
2558    let target_cx_type = unsafe { clang_getCursorType(cursor) };
2559    let target_type = convert_type(target_cx_type)?;
2560
2561    // Extract the inner expression by visiting children
2562    let mut inner_expr: Option<Expression> = None;
2563    let inner_ptr = &mut inner_expr as *mut Option<Expression>;
2564
2565    unsafe {
2566        clang_visitChildren(cursor, visit_cast_inner, inner_ptr as CXClientData);
2567    }
2568
2569    inner_expr.map(|expr| Expression::Cast {
2570        target_type,
2571        expr: Box::new(expr),
2572    })
2573}
2574
2575/// Visitor callback to extract the inner expression of a cast.
2576#[allow(non_upper_case_globals)]
2577extern "C" fn visit_cast_inner(
2578    cursor: CXCursor,
2579    _parent: CXCursor,
2580    client_data: CXClientData,
2581) -> CXChildVisitResult {
2582    let inner_expr = unsafe { &mut *(client_data as *mut Option<Expression>) };
2583    let kind = unsafe { clang_getCursorKind(cursor) };
2584
2585    // Try to extract any expression
2586    if let Some(expr) = try_extract_expression(cursor) {
2587        *inner_expr = Some(expr);
2588        return CXChildVisit_Break; // Found the inner expression, stop visiting
2589    }
2590
2591    // For some expression types, we need to recurse
2592    match kind {
2593        CXCursor_UnexposedExpr | CXCursor_ParenExpr => CXChildVisit_Recurse,
2594        _ => CXChildVisit_Continue,
2595    }
2596}
2597
2598/// Extract a compound literal expression from a clang cursor.
2599///
2600/// Parses C99 compound literals like `(struct Point){10, 20}` or `(int[]){1, 2, 3}`.
2601/// Extracts the type and initializer expressions.
2602fn extract_compound_literal(cursor: CXCursor) -> Option<Expression> {
2603    // SAFETY: Getting the type of the compound literal
2604    let literal_cx_type = unsafe { clang_getCursorType(cursor) };
2605    let literal_type = convert_type(literal_cx_type)?;
2606
2607    // Extract initializer expressions by visiting children
2608    let mut initializers: Vec<Expression> = Vec::new();
2609    let initializers_ptr = &mut initializers as *mut Vec<Expression>;
2610
2611    unsafe {
2612        clang_visitChildren(
2613            cursor,
2614            visit_compound_literal_initializers,
2615            initializers_ptr as CXClientData,
2616        );
2617    }
2618
2619    Some(Expression::CompoundLiteral {
2620        literal_type,
2621        initializers,
2622    })
2623}
2624
2625/// Visitor callback to extract initializers from a compound literal.
2626#[allow(non_upper_case_globals)]
2627extern "C" fn visit_compound_literal_initializers(
2628    cursor: CXCursor,
2629    _parent: CXCursor,
2630    client_data: CXClientData,
2631) -> CXChildVisitResult {
2632    let initializers = unsafe { &mut *(client_data as *mut Vec<Expression>) };
2633    let kind = unsafe { clang_getCursorKind(cursor) };
2634
2635    // The compound literal typically has an InitListExpr child
2636    // CXCursor_InitListExpr = 119
2637    if kind == 119 {
2638        // This is the initializer list - visit its children to get individual initializers
2639        return CXChildVisit_Recurse;
2640    }
2641
2642    // Try to extract any expression as an initializer
2643    if let Some(expr) = try_extract_expression(cursor) {
2644        initializers.push(expr);
2645        return CXChildVisit_Continue;
2646    }
2647
2648    // For some expression types, recurse
2649    match kind {
2650        CXCursor_UnexposedExpr | CXCursor_ParenExpr => CXChildVisit_Recurse,
2651        _ => CXChildVisit_Continue,
2652    }
2653}
2654
2655#[allow(non_upper_case_globals)]
2656fn convert_type(cx_type: CXType) -> Option<Type> {
2657    // SAFETY: Getting type kind
2658    match cx_type.kind {
2659        CXType_Void => Some(Type::Void),
2660        CXType_Int => Some(Type::Int),
2661        CXType_UInt => Some(Type::Int), // unsigned int → i32 (simplified)
2662        CXType_UChar => Some(Type::Char), // unsigned char → u8 (DECY-057 fix)
2663        CXType_UShort => Some(Type::Int), // unsigned short → i32 (simplified)
2664        CXType_ULong => Some(Type::Int), // unsigned long → i32 (simplified for now)
2665        CXType_Short => Some(Type::Int), // short → i32
2666        CXType_Long => Some(Type::Int), // long → i32
2667        CXType_LongLong => Some(Type::Int), // long long → i32 (simplified)
2668        CXType_ULongLong => Some(Type::Int), // unsigned long long → i32 (simplified)
2669        CXType_Float => Some(Type::Float),
2670        CXType_Double => Some(Type::Double),
2671        CXType_Char_S | CXType_Char_U => Some(Type::Char),
2672        CXType_Pointer => {
2673            // SAFETY: Getting pointee type
2674            let pointee = unsafe { clang_getPointeeType(cx_type) };
2675
2676            // Check if the pointee is a function - this is a function pointer
2677            if pointee.kind == CXType_FunctionProto || pointee.kind == CXType_FunctionNoProto {
2678                // This is a function pointer type
2679                // Extract return type
2680                let return_cx_type = unsafe { clang_getResultType(pointee) };
2681                let return_type = convert_type(return_cx_type)?;
2682
2683                // Extract parameter types
2684                let num_args = unsafe { clang_getNumArgTypes(pointee) };
2685                let mut param_types = Vec::new();
2686
2687                for i in 0..num_args {
2688                    let arg_type = unsafe { clang_getArgType(pointee, i as u32) };
2689                    if let Some(param_type) = convert_type(arg_type) {
2690                        param_types.push(param_type);
2691                    }
2692                }
2693
2694                return Some(Type::FunctionPointer {
2695                    param_types,
2696                    return_type: Box::new(return_type),
2697                });
2698            }
2699
2700            // Regular pointer (not function pointer)
2701            convert_type(pointee).map(|t| Type::Pointer(Box::new(t)))
2702        }
2703        CXType_FunctionProto | CXType_FunctionNoProto => {
2704            // Function type (not a pointer to function, but the function type itself)
2705            // This can occur in typedefs like: typedef int Func(int);
2706            // Extract return type
2707            let return_cx_type = unsafe { clang_getResultType(cx_type) };
2708            let return_type = convert_type(return_cx_type)?;
2709
2710            // Extract parameter types
2711            let num_args = unsafe { clang_getNumArgTypes(cx_type) };
2712            let mut param_types = Vec::new();
2713
2714            for i in 0..num_args {
2715                let arg_type = unsafe { clang_getArgType(cx_type, i as u32) };
2716                if let Some(param_type) = convert_type(arg_type) {
2717                    param_types.push(param_type);
2718                }
2719            }
2720
2721            Some(Type::FunctionPointer {
2722                param_types,
2723                return_type: Box::new(return_type),
2724            })
2725        }
2726        CXType_Record => {
2727            // SAFETY: Getting type declaration to extract struct name
2728            let decl = unsafe { clang_getTypeDeclaration(cx_type) };
2729            let name_cxstring = unsafe { clang_getCursorSpelling(decl) };
2730            let name = unsafe {
2731                let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
2732                let struct_name = c_str.to_string_lossy().into_owned();
2733                clang_disposeString(name_cxstring);
2734                struct_name
2735            };
2736            Some(Type::Struct(name))
2737        }
2738        CXType_Elaborated => {
2739            // Elaborated types wrap other types (e.g., "struct Point" wraps the Record type)
2740            // Get the canonical type to unwrap it
2741            let canonical = unsafe { clang_getCanonicalType(cx_type) };
2742            convert_type(canonical)
2743        }
2744        CXType_Typedef => {
2745            // Typedef types wrap the actual underlying type
2746            // Get the canonical type to unwrap it
2747            let canonical = unsafe { clang_getCanonicalType(cx_type) };
2748            convert_type(canonical)
2749        }
2750        CXType_ConstantArray => {
2751            // Array type - extract element type and size
2752            let element_cx_type = unsafe { clang_getArrayElementType(cx_type) };
2753            let element_type = convert_type(element_cx_type)?;
2754
2755            // Get array size
2756            let array_size = unsafe { clang_getArraySize(cx_type) };
2757            let size = if array_size >= 0 {
2758                Some(array_size)
2759            } else {
2760                None
2761            };
2762
2763            Some(Type::Array {
2764                element_type: Box::new(element_type),
2765                size,
2766            })
2767        }
2768        _ => None,
2769    }
2770}
2771
2772/// Represents a single case in a switch statement.
2773#[derive(Debug, Clone, PartialEq)]
2774pub struct SwitchCase {
2775    /// Case value expression (None for default case)
2776    pub value: Option<Expression>,
2777    /// Statements to execute for this case
2778    pub body: Vec<Statement>,
2779}
2780
2781/// Represents a C statement.
2782#[derive(Debug, Clone, PartialEq)]
2783pub enum Statement {
2784    /// Variable declaration: `int* ptr = malloc(4);`
2785    VariableDeclaration {
2786        /// Variable name
2787        name: String,
2788        /// Variable type
2789        var_type: Type,
2790        /// Optional initializer expression
2791        initializer: Option<Expression>,
2792    },
2793    /// Return statement: `return expr;`
2794    Return(Option<Expression>),
2795    /// Assignment statement: `x = 42;`
2796    Assignment {
2797        /// Target variable name
2798        target: String,
2799        /// Value expression to assign
2800        value: Expression,
2801    },
2802    /// If statement: `if (cond) { ... } else { ... }`
2803    If {
2804        /// Condition expression
2805        condition: Expression,
2806        /// Then block
2807        then_block: Vec<Statement>,
2808        /// Optional else block
2809        else_block: Option<Vec<Statement>>,
2810    },
2811    /// For loop: `for (init; cond; inc) { ... }`
2812    For {
2813        /// Optional init statement
2814        init: Option<Box<Statement>>,
2815        /// Optional condition expression
2816        condition: Option<Expression>,
2817        /// Optional increment statement
2818        increment: Option<Box<Statement>>,
2819        /// Loop body
2820        body: Vec<Statement>,
2821    },
2822    /// While loop: `while (cond) { ... }`
2823    While {
2824        /// Condition expression
2825        condition: Expression,
2826        /// Loop body
2827        body: Vec<Statement>,
2828    },
2829    /// Pointer dereference assignment: `*ptr = value;`
2830    DerefAssignment {
2831        /// Target expression to dereference
2832        target: Expression,
2833        /// Value expression to assign
2834        value: Expression,
2835    },
2836    /// Array index assignment: `arr[i] = value;`
2837    ArrayIndexAssignment {
2838        /// Array expression
2839        array: Box<Expression>,
2840        /// Index expression
2841        index: Box<Expression>,
2842        /// Value expression to assign
2843        value: Expression,
2844    },
2845    /// Field assignment: `ptr->field = value;` or `obj.field = value;`
2846    FieldAssignment {
2847        /// Object/pointer expression
2848        object: Expression,
2849        /// Field name
2850        field: String,
2851        /// Value expression to assign
2852        value: Expression,
2853    },
2854    /// Break statement: `break;`
2855    Break,
2856    /// Continue statement: `continue;`
2857    Continue,
2858    /// Switch statement: `switch (expr) { case 1: ...; default: ...; }`
2859    Switch {
2860        /// Condition expression to switch on
2861        condition: Expression,
2862        /// List of case statements
2863        cases: Vec<SwitchCase>,
2864        /// Optional default case body
2865        default_case: Option<Vec<Statement>>,
2866    },
2867    /// Post-increment statement: `ptr++;`
2868    PostIncrement {
2869        /// Target variable name
2870        target: String,
2871    },
2872    /// Pre-increment statement: `++ptr;`
2873    PreIncrement {
2874        /// Target variable name
2875        target: String,
2876    },
2877    /// Post-decrement statement: `ptr--;`
2878    PostDecrement {
2879        /// Target variable name
2880        target: String,
2881    },
2882    /// Pre-decrement statement: `--ptr;`
2883    PreDecrement {
2884        /// Target variable name
2885        target: String,
2886    },
2887    /// Compound assignment: `ptr += offset;`, `x *= 2;`, etc.
2888    CompoundAssignment {
2889        /// Target variable name
2890        target: String,
2891        /// Binary operator to apply
2892        op: BinaryOperator,
2893        /// Value expression
2894        value: Expression,
2895    },
2896    /// Function call statement: `strlen(s);`, `strcpy(dst, src);`
2897    FunctionCall {
2898        /// Function name
2899        function: String,
2900        /// Arguments
2901        arguments: Vec<Expression>,
2902    },
2903}
2904
2905impl Statement {
2906    /// Check if this statement is a string function call.
2907    pub fn is_string_function_call(&self) -> bool {
2908        match self {
2909            Statement::FunctionCall { function, .. } => {
2910                matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
2911            }
2912            _ => false,
2913        }
2914    }
2915
2916    /// Check if this statement is a function call.
2917    pub fn is_function_call(&self) -> bool {
2918        matches!(self, Statement::FunctionCall { .. })
2919    }
2920
2921    /// Convert this statement to a function call expression if it is one.
2922    ///
2923    /// # Implementation Status
2924    ///
2925    /// Stub implementation - always returns `None`.
2926    /// The `Statement::FunctionCall` variant doesn't store the call as an `Expression`,
2927    /// so conversion would require reconstructing an `Expression::FunctionCall` from
2928    /// the statement's fields.
2929    pub fn as_function_call(&self) -> Option<&Expression> {
2930        None
2931    }
2932}
2933
2934/// Unary operators for C expressions.
2935#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2936pub enum UnaryOperator {
2937    /// Unary minus (-x)
2938    Minus,
2939    /// Logical NOT (!x)
2940    LogicalNot,
2941    /// Bitwise NOT (~x)
2942    BitwiseNot,
2943    /// Address-of (&x)
2944    AddressOf,
2945}
2946
2947/// Binary operators for C expressions.
2948#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2949pub enum BinaryOperator {
2950    /// Addition (+)
2951    Add,
2952    /// Subtraction (-)
2953    Subtract,
2954    /// Multiplication (*)
2955    Multiply,
2956    /// Division (/)
2957    Divide,
2958    /// Modulo (%)
2959    Modulo,
2960    /// Equality (==)
2961    Equal,
2962    /// Inequality (!=)
2963    NotEqual,
2964    /// Less than (<)
2965    LessThan,
2966    /// Greater than (>)
2967    GreaterThan,
2968    /// Less than or equal (<=)
2969    LessEqual,
2970    /// Greater than or equal (>=)
2971    GreaterEqual,
2972    /// Logical AND (&&)
2973    LogicalAnd,
2974    /// Logical OR (||)
2975    LogicalOr,
2976}
2977
2978/// Represents a C expression.
2979#[derive(Debug, Clone, PartialEq)]
2980pub enum Expression {
2981    /// Integer literal: `42`
2982    IntLiteral(i32),
2983    /// String literal: `"hello"`
2984    StringLiteral(String),
2985    /// Variable reference: `x`
2986    Variable(String),
2987    /// Binary operation: `a + b`
2988    BinaryOp {
2989        /// Operator
2990        op: BinaryOperator,
2991        /// Left operand
2992        left: Box<Expression>,
2993        /// Right operand
2994        right: Box<Expression>,
2995    },
2996    /// Function call: `malloc(4)`
2997    FunctionCall {
2998        /// Function name
2999        function: String,
3000        /// Arguments
3001        arguments: Vec<Expression>,
3002    },
3003    /// Pointer dereference: `*ptr`
3004    Dereference(Box<Expression>),
3005    /// Unary operation: `-x`, `!x`
3006    UnaryOp {
3007        /// Operator
3008        op: UnaryOperator,
3009        /// Operand
3010        operand: Box<Expression>,
3011    },
3012    /// Array indexing: `arr[i]`
3013    ArrayIndex {
3014        /// Array expression
3015        array: Box<Expression>,
3016        /// Index expression
3017        index: Box<Expression>,
3018    },
3019    /// Struct field access: `obj.field`
3020    FieldAccess {
3021        /// Object expression
3022        object: Box<Expression>,
3023        /// Field name
3024        field: String,
3025    },
3026    /// Pointer field access: `ptr->field`
3027    PointerFieldAccess {
3028        /// Pointer expression
3029        pointer: Box<Expression>,
3030        /// Field name
3031        field: String,
3032    },
3033    /// Post-increment expression: `ptr++`
3034    PostIncrement {
3035        /// Operand expression
3036        operand: Box<Expression>,
3037    },
3038    /// Pre-increment expression: `++ptr`
3039    PreIncrement {
3040        /// Operand expression
3041        operand: Box<Expression>,
3042    },
3043    /// Post-decrement expression: `ptr--`
3044    PostDecrement {
3045        /// Operand expression
3046        operand: Box<Expression>,
3047    },
3048    /// Pre-decrement expression: `--ptr`
3049    PreDecrement {
3050        /// Operand expression
3051        operand: Box<Expression>,
3052    },
3053    /// Sizeof expression: `sizeof(int)` or `sizeof(struct Data)`
3054    Sizeof {
3055        /// Type name as a string (e.g., "int", "struct Data")
3056        type_name: String,
3057    },
3058    /// Cast expression: `(int)x` or `(void*)ptr`
3059    ///
3060    /// C-style cast that converts an expression to a target type.
3061    /// Maps to Rust `as` operator for safe casts, or `transmute` for unsafe casts.
3062    ///
3063    /// # Examples
3064    ///
3065    /// ```c
3066    /// int x = (int)3.14;           // float to int
3067    /// void* ptr = (void*)buffer;   // pointer cast
3068    /// long l = (long)small_int;    // widening cast
3069    /// ```
3070    Cast {
3071        /// Target type to cast to
3072        target_type: Type,
3073        /// Expression being cast
3074        expr: Box<Expression>,
3075    },
3076    /// Compound literal: `(struct Point){10, 20}` or `(int[]){1, 2, 3}`
3077    ///
3078    /// C99 compound literals create anonymous objects of a specified type.
3079    /// Useful for passing struct values to functions or creating temporary objects.
3080    ///
3081    /// # Examples
3082    ///
3083    /// ```c
3084    /// struct Point p = (struct Point){10, 20};       // struct compound literal
3085    /// int* arr = (int[]){1, 2, 3, 4, 5};             // array compound literal
3086    /// draw((struct Rect){.x=0, .y=0, .w=100, .h=50}); // with designated initializers
3087    /// ```
3088    CompoundLiteral {
3089        /// Type of the compound literal (struct Point, int[], etc.)
3090        literal_type: Type,
3091        /// Initializer expressions (values for struct fields or array elements)
3092        initializers: Vec<Expression>,
3093    },
3094}
3095
3096impl Expression {
3097    /// Check if this expression is a string function call (strlen, strcmp, strcpy, strdup).
3098    pub fn is_string_function_call(&self) -> bool {
3099        match self {
3100            Expression::FunctionCall { function, .. } => {
3101                matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
3102            }
3103            _ => false,
3104        }
3105    }
3106
3107    /// Get the string function name if this is a string function call.
3108    pub fn string_function_name(&self) -> Option<&str> {
3109        match self {
3110            Expression::FunctionCall { function, .. } if self.is_string_function_call() => {
3111                Some(function.as_str())
3112            }
3113            _ => None,
3114        }
3115    }
3116
3117    /// Check if this expression has a string literal argument.
3118    pub fn has_string_literal_argument(&self) -> bool {
3119        match self {
3120            Expression::FunctionCall { arguments, .. } => arguments
3121                .iter()
3122                .any(|arg| matches!(arg, Expression::StringLiteral(_))),
3123            _ => false,
3124        }
3125    }
3126}
3127
3128/// Represents a C typedef declaration.
3129#[derive(Debug, Clone, PartialEq)]
3130pub struct Typedef {
3131    /// Typedef name (the alias)
3132    pub name: String,
3133    /// Underlying type being aliased
3134    pub underlying_type: Type,
3135}
3136
3137impl Typedef {
3138    /// Create a new typedef.
3139    pub fn new(name: String, underlying_type: Type) -> Self {
3140        Self {
3141            name,
3142            underlying_type,
3143        }
3144    }
3145
3146    /// Get the typedef name.
3147    pub fn name(&self) -> &str {
3148        &self.name
3149    }
3150
3151    /// Get the underlying type as a string representation.
3152    pub fn underlying_type(&self) -> &str {
3153        // Return a string representation of the type
3154        match &self.underlying_type {
3155            Type::Void => "void",
3156            Type::Int => "int",
3157            Type::Float => "float",
3158            Type::Double => "double",
3159            Type::Char => "char",
3160            Type::Pointer(inner) => match **inner {
3161                Type::Char => "char*",
3162                Type::Int => "int*",
3163                Type::Float => "float*",
3164                Type::Double => "double*",
3165                Type::Void => "void*",
3166                _ => "pointer",
3167            },
3168            Type::Struct(name) => name,
3169            Type::FunctionPointer { .. } => "function pointer",
3170            Type::Array { .. } => "array",
3171        }
3172    }
3173
3174    /// Check if this typedef is a pointer type.
3175    pub fn is_pointer(&self) -> bool {
3176        matches!(self.underlying_type, Type::Pointer(_))
3177    }
3178
3179    /// Check if this typedef is a struct type.
3180    pub fn is_struct(&self) -> bool {
3181        matches!(self.underlying_type, Type::Struct(_))
3182    }
3183
3184    /// Check if this typedef is a function pointer type.
3185    pub fn is_function_pointer(&self) -> bool {
3186        matches!(self.underlying_type, Type::FunctionPointer { .. })
3187    }
3188
3189    /// Check if this typedef is an array type.
3190    pub fn is_array(&self) -> bool {
3191        // Arrays are not yet in the Type enum, so return false for now
3192        false
3193    }
3194}
3195
3196/// Represents a struct field.
3197#[derive(Debug, Clone, PartialEq)]
3198pub struct StructField {
3199    /// Field name
3200    pub name: String,
3201    /// Field type
3202    pub field_type: Type,
3203}
3204
3205impl StructField {
3206    /// Create a new struct field.
3207    pub fn new(name: String, field_type: Type) -> Self {
3208        Self { name, field_type }
3209    }
3210
3211    /// Get the field name.
3212    pub fn name(&self) -> &str {
3213        &self.name
3214    }
3215
3216    /// Check if this field is a function pointer.
3217    pub fn is_function_pointer(&self) -> bool {
3218        matches!(self.field_type, Type::FunctionPointer { .. })
3219    }
3220}
3221
3222/// Represents a struct definition.
3223#[derive(Debug, Clone, PartialEq)]
3224pub struct Struct {
3225    /// Struct name
3226    pub name: String,
3227    /// Struct fields
3228    pub fields: Vec<StructField>,
3229}
3230
3231impl Struct {
3232    /// Create a new struct.
3233    pub fn new(name: String, fields: Vec<StructField>) -> Self {
3234        Self { name, fields }
3235    }
3236
3237    /// Get the struct name.
3238    pub fn name(&self) -> &str {
3239        &self.name
3240    }
3241
3242    /// Get the struct fields.
3243    pub fn fields(&self) -> &[StructField] {
3244        &self.fields
3245    }
3246}
3247
3248/// Represents a variable declaration.
3249#[derive(Debug, Clone, PartialEq)]
3250pub struct Variable {
3251    /// Variable name
3252    name: String,
3253    /// Variable type
3254    var_type: Type,
3255    /// Optional initializer expression
3256    initializer: Option<Expression>,
3257    /// Static storage class (file-local)
3258    is_static: bool,
3259    /// Extern storage class (external linkage)
3260    is_extern: bool,
3261    /// Const qualifier (immutable)
3262    is_const: bool,
3263}
3264
3265impl Variable {
3266    /// Create a new variable.
3267    pub fn new(name: String, var_type: Type) -> Self {
3268        Self {
3269            name,
3270            var_type,
3271            initializer: None,
3272            is_static: false,
3273            is_extern: false,
3274            is_const: false,
3275        }
3276    }
3277
3278    /// Create a new variable with an initializer.
3279    pub fn new_with_initializer(name: String, var_type: Type, initializer: Expression) -> Self {
3280        Self {
3281            name,
3282            var_type,
3283            initializer: Some(initializer),
3284            is_static: false,
3285            is_extern: false,
3286            is_const: false,
3287        }
3288    }
3289
3290    /// Create a new variable with storage class specifiers.
3291    pub fn new_with_storage_class(
3292        name: String,
3293        var_type: Type,
3294        initializer: Option<Expression>,
3295        is_static: bool,
3296        is_extern: bool,
3297        is_const: bool,
3298    ) -> Self {
3299        Self {
3300            name,
3301            var_type,
3302            initializer,
3303            is_static,
3304            is_extern,
3305            is_const,
3306        }
3307    }
3308
3309    /// Get the variable name.
3310    pub fn name(&self) -> &str {
3311        &self.name
3312    }
3313
3314    /// Get the variable type.
3315    pub fn var_type(&self) -> &Type {
3316        &self.var_type
3317    }
3318
3319    /// Check if this variable is a function pointer.
3320    pub fn is_function_pointer(&self) -> bool {
3321        matches!(self.var_type, Type::FunctionPointer { .. })
3322    }
3323
3324    /// Get the number of parameters if this is a function pointer.
3325    pub fn function_pointer_param_count(&self) -> usize {
3326        match &self.var_type {
3327            Type::FunctionPointer { param_types, .. } => param_types.len(),
3328            _ => 0,
3329        }
3330    }
3331
3332    /// Check if this function pointer has a void return type.
3333    pub fn function_pointer_has_void_return(&self) -> bool {
3334        match &self.var_type {
3335            Type::FunctionPointer { return_type, .. } => matches!(**return_type, Type::Void),
3336            _ => false,
3337        }
3338    }
3339
3340    /// Check if this variable is a string literal (char* with literal initializer).
3341    ///
3342    /// Detects patterns like: `const char* msg = "Hello";`
3343    ///
3344    /// # Implementation
3345    ///
3346    /// Checks if:
3347    /// - Type is a pointer to char (`char*`)
3348    /// - Has an initializer that is a `StringLiteral` expression
3349    ///
3350    /// Note: Const qualifier detection not yet implemented - checks all char* pointers.
3351    pub fn is_string_literal(&self) -> bool {
3352        // Check if type is char*
3353        let is_char_ptr =
3354            matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3355
3356        // Check if initializer is a string literal
3357        if let Some(initializer) = &self.initializer {
3358            is_char_ptr && matches!(initializer, Expression::StringLiteral(_))
3359        } else {
3360            false
3361        }
3362    }
3363
3364    /// Check if this variable is a string buffer (char* allocated with malloc).
3365    ///
3366    /// Detects patterns like: `char* buffer = malloc(100);`
3367    ///
3368    /// # Implementation
3369    ///
3370    /// Checks if:
3371    /// - Type is a pointer to char (`char*`)
3372    /// - Has an initializer that is a malloc/calloc function call
3373    pub fn is_string_buffer(&self) -> bool {
3374        // Check if type is char*
3375        let is_char_ptr =
3376            matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3377
3378        // Check if initializer is malloc/calloc call
3379        if let Some(Expression::FunctionCall { function, .. }) = &self.initializer {
3380            is_char_ptr && (function == "malloc" || function == "calloc")
3381        } else {
3382            false
3383        }
3384    }
3385
3386    /// Get the initializer expression for this variable.
3387    ///
3388    /// Returns `Some(&Expression)` if the variable has an initializer, `None` otherwise.
3389    pub fn initializer(&self) -> Option<&Expression> {
3390        self.initializer.as_ref()
3391    }
3392
3393    /// Check if this variable has static storage class (file-local).
3394    pub fn is_static(&self) -> bool {
3395        self.is_static
3396    }
3397
3398    /// Check if this variable is extern (external linkage).
3399    pub fn is_extern(&self) -> bool {
3400        self.is_extern
3401    }
3402
3403    /// Check if this variable is const (immutable).
3404    pub fn is_const(&self) -> bool {
3405        self.is_const
3406    }
3407}
3408
3409/// Abstract Syntax Tree representing parsed C code.
3410#[derive(Debug, Clone, PartialEq)]
3411pub struct Ast {
3412    functions: Vec<Function>,
3413    typedefs: Vec<Typedef>,
3414    structs: Vec<Struct>,
3415    macros: Vec<MacroDefinition>,
3416    variables: Vec<Variable>,
3417}
3418
3419/// Represents a C macro definition (#define).
3420///
3421/// C macros come in two forms:
3422/// - **Object-like**: Simple text replacement (e.g., `#define MAX 100`)
3423/// - **Function-like**: Parameterized text replacement (e.g., `#define SQR(x) ((x) * (x))`)
3424///
3425/// # Examples
3426///
3427/// ```no_run
3428/// use decy_parser::parser::{CParser, MacroDefinition};
3429///
3430/// // Parse a simple object-like macro
3431/// let parser = CParser::new()?;
3432/// let ast = parser.parse("#define MAX 100\nint main() { return 0; }")?;
3433/// assert_eq!(ast.macros().len(), 1);
3434/// assert_eq!(ast.macros()[0].name(), "MAX");
3435/// assert!(ast.macros()[0].is_object_like());
3436///
3437/// // Parse a function-like macro
3438/// let ast2 = parser.parse("#define SQR(x) ((x) * (x))\nint main() { return 0; }")?;
3439/// assert_eq!(ast2.macros()[0].name(), "SQR");
3440/// assert!(ast2.macros()[0].is_function_like());
3441/// assert_eq!(ast2.macros()[0].parameters(), &["x"]);
3442/// # Ok::<(), anyhow::Error>(())
3443/// ```
3444///
3445/// # Reference
3446///
3447/// K&R §4.11, ISO C99 §6.10.3
3448#[derive(Debug, Clone, PartialEq)]
3449pub struct MacroDefinition {
3450    /// Macro name
3451    pub name: String,
3452    /// Parameters (empty for object-like macros)
3453    pub parameters: Vec<String>,
3454    /// Macro body (unparsed, tokenized without spaces)
3455    pub body: String,
3456}
3457
3458impl MacroDefinition {
3459    /// Create a new object-like macro.
3460    pub fn new_object_like(name: String, body: String) -> Self {
3461        Self {
3462            name,
3463            parameters: vec![],
3464            body,
3465        }
3466    }
3467
3468    /// Create a new function-like macro.
3469    pub fn new_function_like(name: String, parameters: Vec<String>, body: String) -> Self {
3470        Self {
3471            name,
3472            parameters,
3473            body,
3474        }
3475    }
3476
3477    /// Get the macro name.
3478    pub fn name(&self) -> &str {
3479        &self.name
3480    }
3481
3482    /// Get the macro parameters.
3483    pub fn parameters(&self) -> &[String] {
3484        &self.parameters
3485    }
3486
3487    /// Get the macro body.
3488    pub fn body(&self) -> &str {
3489        &self.body
3490    }
3491
3492    /// Check if this is a function-like macro.
3493    pub fn is_function_like(&self) -> bool {
3494        !self.parameters.is_empty()
3495    }
3496
3497    /// Check if this is an object-like macro.
3498    pub fn is_object_like(&self) -> bool {
3499        self.parameters.is_empty()
3500    }
3501}
3502
3503impl Ast {
3504    /// Create a new empty AST.
3505    pub fn new() -> Self {
3506        Self {
3507            functions: Vec::new(),
3508            typedefs: Vec::new(),
3509            structs: Vec::new(),
3510            macros: Vec::new(),
3511            variables: Vec::new(),
3512        }
3513    }
3514
3515    /// Get the functions in the AST.
3516    pub fn functions(&self) -> &[Function] {
3517        &self.functions
3518    }
3519
3520    /// Add a function to the AST.
3521    pub fn add_function(&mut self, function: Function) {
3522        self.functions.push(function);
3523    }
3524
3525    /// Get the typedefs in the AST.
3526    pub fn typedefs(&self) -> &[Typedef] {
3527        &self.typedefs
3528    }
3529
3530    /// Add a typedef to the AST.
3531    pub fn add_typedef(&mut self, typedef: Typedef) {
3532        self.typedefs.push(typedef);
3533    }
3534
3535    /// Get the structs in the AST.
3536    pub fn structs(&self) -> &[Struct] {
3537        &self.structs
3538    }
3539
3540    /// Add a struct to the AST.
3541    pub fn add_struct(&mut self, struct_def: Struct) {
3542        self.structs.push(struct_def);
3543    }
3544
3545    /// Get the macro definitions in the AST.
3546    pub fn macros(&self) -> &[MacroDefinition] {
3547        &self.macros
3548    }
3549
3550    /// Add a macro definition to the AST.
3551    pub fn add_macro(&mut self, macro_def: MacroDefinition) {
3552        self.macros.push(macro_def);
3553    }
3554
3555    /// Get the variables in the AST.
3556    pub fn variables(&self) -> &[Variable] {
3557        &self.variables
3558    }
3559
3560    /// Add a variable to the AST.
3561    pub fn add_variable(&mut self, variable: Variable) {
3562        self.variables.push(variable);
3563    }
3564}
3565
3566impl Default for Ast {
3567    fn default() -> Self {
3568        Self::new()
3569    }
3570}
3571
3572/// Represents a C function.
3573#[derive(Debug, Clone, PartialEq)]
3574pub struct Function {
3575    /// Function name
3576    pub name: String,
3577    /// Return type
3578    pub return_type: Type,
3579    /// Parameters
3580    pub parameters: Vec<Parameter>,
3581    /// Function body (statements)
3582    pub body: Vec<Statement>,
3583}
3584
3585impl Function {
3586    /// Create a new function.
3587    pub fn new(name: String, return_type: Type, parameters: Vec<Parameter>) -> Self {
3588        Self {
3589            name,
3590            return_type,
3591            parameters,
3592            body: Vec::new(),
3593        }
3594    }
3595
3596    /// Create a new function with body.
3597    pub fn new_with_body(
3598        name: String,
3599        return_type: Type,
3600        parameters: Vec<Parameter>,
3601        body: Vec<Statement>,
3602    ) -> Self {
3603        Self {
3604            name,
3605            return_type,
3606            parameters,
3607            body,
3608        }
3609    }
3610}
3611
3612/// Represents a C type.
3613#[derive(Debug, Clone, PartialEq)]
3614pub enum Type {
3615    /// void
3616    Void,
3617    /// int
3618    Int,
3619    /// float
3620    Float,
3621    /// double
3622    Double,
3623    /// char
3624    Char,
3625    /// Pointer to a type
3626    Pointer(Box<Type>),
3627    /// Struct type (e.g., struct Point)
3628    Struct(String),
3629    /// Function pointer type (e.g., int (*callback)(int))
3630    FunctionPointer {
3631        /// Parameter types
3632        param_types: Vec<Type>,
3633        /// Return type
3634        return_type: Box<Type>,
3635    },
3636    /// Array type (e.g., int arr[10])
3637    /// For typedef assertions like: typedef char check[sizeof(int) == 4 ? 1 : -1]
3638    Array {
3639        /// Element type
3640        element_type: Box<Type>,
3641        /// Array size (None for unknown/expression-based size)
3642        size: Option<i64>,
3643    },
3644}
3645
3646/// Represents a function parameter.
3647#[derive(Debug, Clone, PartialEq)]
3648pub struct Parameter {
3649    /// Parameter name
3650    pub name: String,
3651    /// Parameter type
3652    pub param_type: Type,
3653}
3654
3655impl Parameter {
3656    /// Create a new parameter.
3657    pub fn new(name: String, param_type: Type) -> Self {
3658        Self { name, param_type }
3659    }
3660
3661    /// Check if this parameter is a function pointer.
3662    pub fn is_function_pointer(&self) -> bool {
3663        matches!(self.param_type, Type::FunctionPointer { .. })
3664    }
3665
3666    /// Check if this parameter is a const char pointer (const char*).
3667    ///
3668    /// # Implementation Status
3669    ///
3670    /// Partial implementation - detects `char*` pointers but doesn't check const qualifier.
3671    /// Returns `true` for any `Pointer(Char)` type.
3672    /// Full implementation requires adding const tracking to the `Type` enum.
3673    pub fn is_const_char_pointer(&self) -> bool {
3674        matches!(self.param_type, Type::Pointer(ref inner) if matches!(**inner, Type::Char))
3675    }
3676}
3677
3678#[cfg(test)]
3679#[path = "parser_tests.rs"]
3680mod parser_tests;
3681
3682#[cfg(test)]
3683#[path = "pointer_arithmetic_tests.rs"]
3684mod pointer_arithmetic_tests;
3685
3686#[cfg(test)]
3687#[path = "break_continue_tests.rs"]
3688mod break_continue_tests;