1use anyhow::{Context, Result};
7use clang_sys::*;
8use std::ffi::{CStr, CString};
9use std::path::Path;
10use std::ptr;
11
12#[derive(Debug)]
25pub struct CParser {
26    index: CXIndex,
27}
28
29impl CParser {
30    pub fn new() -> Result<Self> {
41        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    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        if source.trim().is_empty() {
77            return Ok(ast);
78        }
79
80        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        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        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        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        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 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        let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
149
150        let ast_ptr = &mut ast as *mut Ast;
152
153        unsafe {
155            clang_visitChildren(cursor, visit_function, ast_ptr as CXClientData);
156
157            clang_disposeTranslationUnit(tu);
159        }
160
161        Ok(ast)
162    }
163
164    pub fn parse_file(&self, _path: &Path) -> Result<Ast> {
175        Err(anyhow::anyhow!("Not implemented yet"))
177    }
178}
179
180impl Drop for CParser {
181    fn drop(&mut self) {
182        unsafe {
184            clang_disposeIndex(self.index);
185        }
186    }
187}
188
189extern "C" fn visit_function(
195    cursor: CXCursor,
196    _parent: CXCursor,
197    client_data: CXClientData,
198) -> CXChildVisitResult {
199    let ast = unsafe { &mut *(client_data as *mut Ast) };
201
202    let kind = unsafe { clang_getCursorKind(cursor) };
204
205    if kind == 23 {
208        unsafe {
211            clang_visitChildren(cursor, visit_function, client_data);
212        }
213        return CXChildVisit_Continue;
214    }
215
216    if kind == CXCursor_FunctionDecl {
217        if let Some(function) = extract_function(cursor) {
219            ast.add_function(function);
220        }
221    } else if kind == CXCursor_TypedefDecl {
222        if let Some(typedef) = extract_typedef(cursor) {
224            ast.add_typedef(typedef);
225        }
226    } else if kind == CXCursor_StructDecl {
227        if let Some(struct_def) = extract_struct(cursor) {
229            ast.add_struct(struct_def);
230        }
231    } else if kind == CXCursor_VarDecl {
232        let semantic_parent = unsafe { clang_getCursorSemanticParent(cursor) };
235        let parent_kind = unsafe { clang_getCursorKind(semantic_parent) };
236
237        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        } else if kind == CXCursor_MacroDefinition {
249        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        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            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    CXChildVisit_Recurse
284}
285
286fn extract_function(cursor: CXCursor) -> Option<Function> {
288    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    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    let num_args = unsafe { clang_Cursor_getNumArguments(cursor) };
304    let mut parameters = Vec::new();
305
306    for i in 0..num_args {
307        let arg_cursor = unsafe { clang_Cursor_getArgument(cursor, i as u32) };
309
310        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        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    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
337fn extract_typedef(cursor: CXCursor) -> Option<Typedef> {
339    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    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
355fn extract_struct(cursor: CXCursor) -> Option<Struct> {
357    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    if name.is_empty() {
368        return None;
369    }
370
371    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
382fn extract_variable(cursor: CXCursor) -> Option<Variable> {
393    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    let cx_type = unsafe { clang_getCursorType(cursor) };
404    let var_type = convert_type(cx_type)?;
405
406    let storage_class = unsafe { clang_Cursor_getStorageClass(cursor) };
412    let is_static = storage_class == 3; let is_extern = storage_class == 2; let is_const = unsafe { clang_isConstQualifiedType(cx_type) != 0 };
417
418    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#[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), 118 => extract_compound_literal(cursor), CXCursor_UnexposedExpr => {
458            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#[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    if let Some(expr) = try_extract_expression(cursor) {
485        *initializer = Some(expr);
486        return CXChildVisit_Break;
487    }
488
489    CXChildVisit_Continue
490}
491
492fn extract_macro(cursor: CXCursor) -> Option<MacroDefinition> {
499    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    if name.is_empty() {
510        return None;
511    }
512
513    let is_function_like = unsafe { clang_sys::clang_Cursor_isMacroFunctionLike(cursor) } != 0;
516
517    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    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        if i == 0 {
547            continue;
548        }
549
550        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                parameters.push(token_str);
566            }
567        } else {
568            body_tokens.push(token_str);
569        }
570    }
571
572    unsafe {
574        clang_disposeTokens(tu, tokens, num_tokens);
575    }
576
577    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#[allow(non_upper_case_globals)]
593extern "C" fn visit_struct_fields(
594    cursor: CXCursor,
595    _parent: CXCursor,
596    client_data: CXClientData,
597) -> CXChildVisitResult {
598    let fields = unsafe { &mut *(client_data as *mut Vec<StructField>) };
600
601    let kind = unsafe { clang_getCursorKind(cursor) };
603
604    if kind == CXCursor_FieldDecl {
605        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        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#[allow(non_upper_case_globals)]
630extern "C" fn visit_statement(
631    cursor: CXCursor,
632    _parent: CXCursor,
633    client_data: CXClientData,
634) -> CXChildVisitResult {
635    let statements = unsafe { &mut *(client_data as *mut Vec<Statement>) };
637
638    let kind = unsafe { clang_getCursorKind(cursor) };
640
641    match kind {
642        CXCursor_CompoundStmt => {
643            CXChildVisit_Recurse
645        }
646        CXCursor_DeclStmt => {
647            CXChildVisit_Recurse
649        }
650        CXCursor_VarDecl => {
651            if let Some(stmt) = extract_var_decl(cursor) {
653                statements.push(stmt);
654            }
655            CXChildVisit_Continue
656        }
657        CXCursor_ReturnStmt => {
658            if let Some(stmt) = extract_return_stmt(cursor) {
660                statements.push(stmt);
661            }
662            CXChildVisit_Continue
663        }
664        CXCursor_BinaryOperator => {
665            if let Some(stmt) = extract_assignment_stmt(cursor) {
667                statements.push(stmt);
668            }
669            CXChildVisit_Continue
670        }
671        CXCursor_IfStmt => {
672            if let Some(stmt) = extract_if_stmt(cursor) {
674                statements.push(stmt);
675            }
676            CXChildVisit_Continue
677        }
678        CXCursor_ForStmt => {
679            if let Some(stmt) = extract_for_stmt(cursor) {
681                statements.push(stmt);
682            }
683            CXChildVisit_Continue
684        }
685        CXCursor_WhileStmt => {
686            if let Some(stmt) = extract_while_stmt(cursor) {
688                statements.push(stmt);
689            }
690            CXChildVisit_Continue
691        }
692        CXCursor_SwitchStmt => {
693            if let Some(stmt) = extract_switch_stmt(cursor) {
695                statements.push(stmt);
696            }
697            CXChildVisit_Continue
698        }
699        CXCursor_BreakStmt => {
700            statements.push(Statement::Break);
702            CXChildVisit_Continue
703        }
704        CXCursor_ContinueStmt => {
705            statements.push(Statement::Continue);
707            CXChildVisit_Continue
708        }
709        CXCursor_UnaryOperator => {
710            if let Some(stmt) = extract_inc_dec_stmt(cursor) {
712                statements.push(stmt);
713            }
714            CXChildVisit_Continue
715        }
716        CXCursor_CompoundAssignOperator => {
717            if let Some(stmt) = extract_compound_assignment_stmt(cursor) {
719                statements.push(stmt);
720            }
721            CXChildVisit_Continue
722        }
723        CXCursor_CallExpr => {
724            if let Some(stmt) = extract_statement(cursor) {
727                statements.push(stmt);
728            }
729            CXChildVisit_Continue
730        }
731        _ => CXChildVisit_Recurse, }
733}
734
735fn extract_var_decl(cursor: CXCursor) -> Option<Statement> {
737    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    let cx_type = unsafe { clang_getCursorType(cursor) };
748    let var_type = convert_type(cx_type)?;
749
750    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
765fn extract_return_stmt(cursor: CXCursor) -> Option<Statement> {
767    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
778fn extract_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
780    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
783    if tu.is_null() {
784        return None;
785    }
786
787    let extent = unsafe { clang_getCursorExtent(cursor) };
789
790    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    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                    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                        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    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    if operands.len() != 2 {
848        return None;
849    }
850
851    if let Expression::Dereference(inner) = &operands[0] {
853        return Some(Statement::DerefAssignment {
854            target: (**inner).clone(), value: operands[1].clone(),
856        });
857    }
858
859    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    if matches!(
870        &operands[0],
871        Expression::PointerFieldAccess { .. } | Expression::FieldAccess { .. }
872    ) {
873        let field = match &operands[0] {
875            Expression::PointerFieldAccess { field, .. } => field.clone(),
876            Expression::FieldAccess { field, .. } => field.clone(),
877            _ => unreachable!(),
878        };
879
880        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    let target = match &operands[0] {
896        Expression::Variable(name) => name.clone(),
897        _ => return None, };
899
900    Some(Statement::Assignment {
901        target,
902        value: operands[1].clone(),
903    })
904}
905
906fn extract_inc_dec_stmt(cursor: CXCursor) -> Option<Statement> {
908    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
910    if tu.is_null() {
911        return None;
912    }
913
914    let extent = unsafe { clang_getCursorExtent(cursor) };
916
917    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    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()); operator_position = i;
941                        clang_disposeString(token_cxstring);
942                        break;
943                    }
944                }
945                clang_disposeString(token_cxstring);
946            }
947        }
948    }
949
950    let is_pre = operator_position == 0;
954
955    unsafe {
956        clang_disposeTokens(tu, tokens, num_tokens);
957    }
958
959    let mut target_name: Option<String> = None;
961
962    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
1012fn extract_compound_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
1014    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1016    if tu.is_null() {
1017        return None;
1018    }
1019
1020    let extent = unsafe { clang_getCursorExtent(cursor) };
1022
1023    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    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    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    if operands.len() != 2 {
1077        return None;
1078    }
1079
1080    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
1093fn extract_if_stmt(cursor: CXCursor) -> Option<Statement> {
1095    #[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#[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            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                    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            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            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
1197fn extract_for_stmt(cursor: CXCursor) -> Option<Statement> {
1199    #[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#[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            if kind == CXCursor_DeclStmt {
1259                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                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            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            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                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            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
1328fn extract_while_stmt(cursor: CXCursor) -> Option<Statement> {
1330    #[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#[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            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            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#[allow(non_upper_case_globals)]
1417fn extract_switch_stmt(cursor: CXCursor) -> Option<Statement> {
1418    #[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#[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            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            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#[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            if let Some(case) = extract_case_stmt(cursor) {
1514                switch_data.cases.push(case);
1515            }
1516            CXChildVisit_Continue
1517        }
1518        CXCursor_DefaultStmt => {
1519            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
1529fn extract_case_stmt(cursor: CXCursor) -> Option<SwitchCase> {
1531    #[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#[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            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            if let Some(stmt) = extract_statement(cursor) {
1590                case_data.body.push(stmt);
1591            }
1592            CXChildVisit_Recurse
1594        }
1595    }
1596}
1597
1598fn extract_default_stmt(cursor: CXCursor) -> Option<Vec<Statement>> {
1600    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#[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    if let Some(stmt) = extract_statement(cursor) {
1622        body.push(stmt);
1623    }
1624
1625    CXChildVisit_Continue
1626}
1627
1628#[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            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#[allow(non_upper_case_globals)]
1667extern "C" fn visit_expression(
1668    cursor: CXCursor,
1669    _parent: CXCursor,
1670    client_data: CXClientData,
1671) -> CXChildVisitResult {
1672    let expr_opt = unsafe { &mut *(client_data as *mut Option<Expression>) };
1674
1675    let kind = unsafe { clang_getCursorKind(cursor) };
1677
1678    match kind {
1679        CXCursor_IntegerLiteral => {
1680            if let Some(expr) = extract_int_literal(cursor) {
1682                *expr_opt = Some(expr);
1683            }
1684            CXChildVisit_Continue
1685        }
1686        CXCursor_StringLiteral => {
1687            if let Some(expr) = extract_string_literal(cursor) {
1689                *expr_opt = Some(expr);
1690            }
1691            CXChildVisit_Continue
1692        }
1693        CXCursor_DeclRefExpr => {
1694            if let Some(expr) = extract_variable_ref(cursor) {
1696                *expr_opt = Some(expr);
1697            }
1698            CXChildVisit_Continue
1699        }
1700        CXCursor_BinaryOperator => {
1701            if let Some(expr) = extract_binary_op(cursor) {
1703                *expr_opt = Some(expr);
1704            }
1705            CXChildVisit_Continue
1706        }
1707        CXCursor_CallExpr => {
1708            if let Some(expr) = extract_function_call(cursor) {
1710                *expr_opt = Some(expr);
1711            }
1712            CXChildVisit_Continue
1713        }
1714        CXCursor_UnaryOperator => {
1715            if let Some(expr) = extract_unary_op(cursor) {
1717                *expr_opt = Some(expr);
1718            }
1719            CXChildVisit_Continue
1720        }
1721        CXCursor_ArraySubscriptExpr => {
1722            if let Some(expr) = extract_array_index(cursor) {
1724                *expr_opt = Some(expr);
1725            }
1726            CXChildVisit_Continue
1727        }
1728        CXCursor_MemberRefExpr => {
1729            if let Some(expr) = extract_field_access(cursor) {
1731                *expr_opt = Some(expr);
1732            }
1733            CXChildVisit_Continue
1734        }
1735        CXCursor_UnexposedExpr => {
1736            CXChildVisit_Recurse
1739        }
1740        CXCursor_ParenExpr => {
1741            CXChildVisit_Recurse
1743        }
1744        136 => {
1745            if let Some(expr) = extract_sizeof(cursor) {
1747                *expr_opt = Some(expr);
1748                CXChildVisit_Continue
1749            } else {
1750                CXChildVisit_Recurse
1752            }
1753        }
1754        _ => CXChildVisit_Recurse,
1755    }
1756}
1757
1758fn extract_int_literal(cursor: CXCursor) -> Option<Expression> {
1760    let extent = unsafe { clang_getCursorExtent(cursor) };
1762
1763    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        clang_Cursor_getTranslationUnit(cursor)
1775    };
1776
1777    if tu.is_null() {
1778        return Some(Expression::IntLiteral(0));
1779    }
1780
1781    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        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            clang_disposeTokens(tu, tokens, num_tokens);
1803        }
1804    }
1805
1806    Some(Expression::IntLiteral(value))
1807}
1808
1809fn extract_string_literal(cursor: CXCursor) -> Option<Expression> {
1811    let extent = unsafe { clang_getCursorExtent(cursor) };
1813
1814    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1816
1817    if tu.is_null() {
1818        return Some(Expression::StringLiteral(String::new()));
1819    }
1820
1821    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        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                value = token_str.trim_matches('"').to_string();
1839            }
1840            clang_disposeString(token_cxstring);
1841
1842            clang_disposeTokens(tu, tokens, num_tokens);
1844        }
1845    }
1846
1847    Some(Expression::StringLiteral(value))
1848}
1849
1850fn extract_variable_ref(cursor: CXCursor) -> Option<Expression> {
1852    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
1864fn extract_binary_op(cursor: CXCursor) -> Option<Expression> {
1866    let op = extract_binary_operator(cursor)?;
1868
1869    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    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#[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            if let Some(expr) = extract_binary_op(cursor) {
1921                operands.push(expr);
1922            }
1923            CXChildVisit_Continue
1924        }
1925        CXCursor_UnaryOperator => {
1926            if let Some(expr) = extract_unary_op(cursor) {
1928                operands.push(expr);
1929            }
1930            CXChildVisit_Continue
1931        }
1932        CXCursor_ArraySubscriptExpr => {
1933            if let Some(expr) = extract_array_index(cursor) {
1935                operands.push(expr);
1936            }
1937            CXChildVisit_Continue
1938        }
1939        CXCursor_MemberRefExpr => {
1940            if let Some(expr) = extract_field_access(cursor) {
1942                operands.push(expr);
1943            }
1944            CXChildVisit_Continue
1945        }
1946        CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
1947            if let Some(expr) = extract_sizeof(cursor) {
1949                operands.push(expr);
1950                CXChildVisit_Continue
1951            } else {
1952                CXChildVisit_Recurse
1953            }
1954        }
1955        136 => {
1956            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            if let Some(expr) = extract_function_call(cursor) {
1967                operands.push(expr);
1968            }
1969            CXChildVisit_Continue
1970        }
1971        _ => CXChildVisit_Recurse,
1972    }
1973}
1974
1975#[allow(non_upper_case_globals)]
1977fn extract_binary_operator(cursor: CXCursor) -> Option<BinaryOperator> {
1978    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1980    if tu.is_null() {
1981        return None;
1982    }
1983
1984    let extent = unsafe { clang_getCursorExtent(cursor) };
1986
1987    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    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            if token_kind == CXToken_Identifier || token_kind == CXToken_Literal {
2013                found_first_operand = true;
2014            }
2015
2016            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    if !candidates.is_empty() {
2049        for (_, op) in &candidates {
2052            if matches!(op, BinaryOperator::LogicalOr) {
2053                operator = Some(*op);
2054                break;
2055            }
2056        }
2057        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 operator.is_none() {
2069            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 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 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
2107fn extract_function_call(cursor: CXCursor) -> Option<Expression> {
2109    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    #[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, };
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#[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    let arg_data = unsafe { &mut *(client_data as *mut ArgData) };
2161
2162    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            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            if let Some(expr) = extract_binary_op(cursor) {
2194                arg_data.arguments.push(expr);
2195            }
2196            CXChildVisit_Continue
2197        }
2198        CXCursor_CallExpr => {
2199            if let Some(expr) = extract_function_call(cursor) {
2201                arg_data.arguments.push(expr);
2202            }
2203            CXChildVisit_Continue
2204        }
2205        CXCursor_UnaryOperator => {
2206            if let Some(expr) = extract_unary_op(cursor) {
2208                arg_data.arguments.push(expr);
2209            }
2210            CXChildVisit_Continue
2211        }
2212        CXCursor_ArraySubscriptExpr => {
2213            if let Some(expr) = extract_array_index(cursor) {
2215                arg_data.arguments.push(expr);
2216            }
2217            CXChildVisit_Continue
2218        }
2219        CXCursor_MemberRefExpr => {
2220            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            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            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, }
2246}
2247
2248fn extract_unary_op(cursor: CXCursor) -> Option<Expression> {
2250    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2252    if tu.is_null() {
2253        return None;
2254    }
2255
2256    let extent = unsafe { clang_getCursorExtent(cursor) };
2258
2259    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    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    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    if is_dereference {
2345        return Some(Expression::Dereference(Box::new(operand_expr)));
2346    }
2347
2348    if is_increment {
2350        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        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    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
2388fn extract_array_index(cursor: CXCursor) -> Option<Expression> {
2390    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    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
2409fn extract_field_access(cursor: CXCursor) -> Option<Expression> {
2411    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    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    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                        } else if token_str == "." {
2453                        is_arrow = false;
2454                        }
2456                }
2457                clang_disposeString(token_cxstring);
2458            }
2459        }
2460    }
2461
2462    unsafe {
2463        clang_disposeTokens(tu, tokens, num_tokens);
2464    }
2465
2466    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
2489fn extract_sizeof(cursor: CXCursor) -> Option<Expression> {
2491    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2493    if tu.is_null() {
2494        return None;
2495    }
2496
2497    let extent = unsafe { clang_getCursorExtent(cursor) };
2499
2500    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    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                    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#[allow(non_upper_case_globals)]
2552fn extract_cast(cursor: CXCursor) -> Option<Expression> {
2557    let target_cx_type = unsafe { clang_getCursorType(cursor) };
2559    let target_type = convert_type(target_cx_type)?;
2560
2561    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#[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    if let Some(expr) = try_extract_expression(cursor) {
2587        *inner_expr = Some(expr);
2588        return CXChildVisit_Break; }
2590
2591    match kind {
2593        CXCursor_UnexposedExpr | CXCursor_ParenExpr => CXChildVisit_Recurse,
2594        _ => CXChildVisit_Continue,
2595    }
2596}
2597
2598fn extract_compound_literal(cursor: CXCursor) -> Option<Expression> {
2603    let literal_cx_type = unsafe { clang_getCursorType(cursor) };
2605    let literal_type = convert_type(literal_cx_type)?;
2606
2607    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#[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    if kind == 119 {
2638        return CXChildVisit_Recurse;
2640    }
2641
2642    if let Some(expr) = try_extract_expression(cursor) {
2644        initializers.push(expr);
2645        return CXChildVisit_Continue;
2646    }
2647
2648    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    match cx_type.kind {
2659        CXType_Void => Some(Type::Void),
2660        CXType_Int => Some(Type::Int),
2661        CXType_UInt => Some(Type::Int), CXType_UChar => Some(Type::Char), CXType_UShort => Some(Type::Int), CXType_ULong => Some(Type::Int), CXType_Short => Some(Type::Int), CXType_Long => Some(Type::Int), CXType_LongLong => Some(Type::Int), CXType_ULongLong => Some(Type::Int), 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            let pointee = unsafe { clang_getPointeeType(cx_type) };
2675
2676            if pointee.kind == CXType_FunctionProto || pointee.kind == CXType_FunctionNoProto {
2678                let return_cx_type = unsafe { clang_getResultType(pointee) };
2681                let return_type = convert_type(return_cx_type)?;
2682
2683                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            convert_type(pointee).map(|t| Type::Pointer(Box::new(t)))
2702        }
2703        CXType_FunctionProto | CXType_FunctionNoProto => {
2704            let return_cx_type = unsafe { clang_getResultType(cx_type) };
2708            let return_type = convert_type(return_cx_type)?;
2709
2710            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            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            let canonical = unsafe { clang_getCanonicalType(cx_type) };
2742            convert_type(canonical)
2743        }
2744        CXType_Typedef => {
2745            let canonical = unsafe { clang_getCanonicalType(cx_type) };
2748            convert_type(canonical)
2749        }
2750        CXType_ConstantArray => {
2751            let element_cx_type = unsafe { clang_getArrayElementType(cx_type) };
2753            let element_type = convert_type(element_cx_type)?;
2754
2755            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#[derive(Debug, Clone, PartialEq)]
2774pub struct SwitchCase {
2775    pub value: Option<Expression>,
2777    pub body: Vec<Statement>,
2779}
2780
2781#[derive(Debug, Clone, PartialEq)]
2783pub enum Statement {
2784    VariableDeclaration {
2786        name: String,
2788        var_type: Type,
2790        initializer: Option<Expression>,
2792    },
2793    Return(Option<Expression>),
2795    Assignment {
2797        target: String,
2799        value: Expression,
2801    },
2802    If {
2804        condition: Expression,
2806        then_block: Vec<Statement>,
2808        else_block: Option<Vec<Statement>>,
2810    },
2811    For {
2813        init: Option<Box<Statement>>,
2815        condition: Option<Expression>,
2817        increment: Option<Box<Statement>>,
2819        body: Vec<Statement>,
2821    },
2822    While {
2824        condition: Expression,
2826        body: Vec<Statement>,
2828    },
2829    DerefAssignment {
2831        target: Expression,
2833        value: Expression,
2835    },
2836    ArrayIndexAssignment {
2838        array: Box<Expression>,
2840        index: Box<Expression>,
2842        value: Expression,
2844    },
2845    FieldAssignment {
2847        object: Expression,
2849        field: String,
2851        value: Expression,
2853    },
2854    Break,
2856    Continue,
2858    Switch {
2860        condition: Expression,
2862        cases: Vec<SwitchCase>,
2864        default_case: Option<Vec<Statement>>,
2866    },
2867    PostIncrement {
2869        target: String,
2871    },
2872    PreIncrement {
2874        target: String,
2876    },
2877    PostDecrement {
2879        target: String,
2881    },
2882    PreDecrement {
2884        target: String,
2886    },
2887    CompoundAssignment {
2889        target: String,
2891        op: BinaryOperator,
2893        value: Expression,
2895    },
2896    FunctionCall {
2898        function: String,
2900        arguments: Vec<Expression>,
2902    },
2903}
2904
2905impl Statement {
2906    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    pub fn is_function_call(&self) -> bool {
2918        matches!(self, Statement::FunctionCall { .. })
2919    }
2920
2921    pub fn as_function_call(&self) -> Option<&Expression> {
2930        None
2931    }
2932}
2933
2934#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2936pub enum UnaryOperator {
2937    Minus,
2939    LogicalNot,
2941    BitwiseNot,
2943    AddressOf,
2945}
2946
2947#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2949pub enum BinaryOperator {
2950    Add,
2952    Subtract,
2954    Multiply,
2956    Divide,
2958    Modulo,
2960    Equal,
2962    NotEqual,
2964    LessThan,
2966    GreaterThan,
2968    LessEqual,
2970    GreaterEqual,
2972    LogicalAnd,
2974    LogicalOr,
2976}
2977
2978#[derive(Debug, Clone, PartialEq)]
2980pub enum Expression {
2981    IntLiteral(i32),
2983    StringLiteral(String),
2985    Variable(String),
2987    BinaryOp {
2989        op: BinaryOperator,
2991        left: Box<Expression>,
2993        right: Box<Expression>,
2995    },
2996    FunctionCall {
2998        function: String,
3000        arguments: Vec<Expression>,
3002    },
3003    Dereference(Box<Expression>),
3005    UnaryOp {
3007        op: UnaryOperator,
3009        operand: Box<Expression>,
3011    },
3012    ArrayIndex {
3014        array: Box<Expression>,
3016        index: Box<Expression>,
3018    },
3019    FieldAccess {
3021        object: Box<Expression>,
3023        field: String,
3025    },
3026    PointerFieldAccess {
3028        pointer: Box<Expression>,
3030        field: String,
3032    },
3033    PostIncrement {
3035        operand: Box<Expression>,
3037    },
3038    PreIncrement {
3040        operand: Box<Expression>,
3042    },
3043    PostDecrement {
3045        operand: Box<Expression>,
3047    },
3048    PreDecrement {
3050        operand: Box<Expression>,
3052    },
3053    Sizeof {
3055        type_name: String,
3057    },
3058    Cast {
3071        target_type: Type,
3073        expr: Box<Expression>,
3075    },
3076    CompoundLiteral {
3089        literal_type: Type,
3091        initializers: Vec<Expression>,
3093    },
3094}
3095
3096impl Expression {
3097    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    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    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#[derive(Debug, Clone, PartialEq)]
3130pub struct Typedef {
3131    pub name: String,
3133    pub underlying_type: Type,
3135}
3136
3137impl Typedef {
3138    pub fn new(name: String, underlying_type: Type) -> Self {
3140        Self {
3141            name,
3142            underlying_type,
3143        }
3144    }
3145
3146    pub fn name(&self) -> &str {
3148        &self.name
3149    }
3150
3151    pub fn underlying_type(&self) -> &str {
3153        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    pub fn is_pointer(&self) -> bool {
3176        matches!(self.underlying_type, Type::Pointer(_))
3177    }
3178
3179    pub fn is_struct(&self) -> bool {
3181        matches!(self.underlying_type, Type::Struct(_))
3182    }
3183
3184    pub fn is_function_pointer(&self) -> bool {
3186        matches!(self.underlying_type, Type::FunctionPointer { .. })
3187    }
3188
3189    pub fn is_array(&self) -> bool {
3191        false
3193    }
3194}
3195
3196#[derive(Debug, Clone, PartialEq)]
3198pub struct StructField {
3199    pub name: String,
3201    pub field_type: Type,
3203}
3204
3205impl StructField {
3206    pub fn new(name: String, field_type: Type) -> Self {
3208        Self { name, field_type }
3209    }
3210
3211    pub fn name(&self) -> &str {
3213        &self.name
3214    }
3215
3216    pub fn is_function_pointer(&self) -> bool {
3218        matches!(self.field_type, Type::FunctionPointer { .. })
3219    }
3220}
3221
3222#[derive(Debug, Clone, PartialEq)]
3224pub struct Struct {
3225    pub name: String,
3227    pub fields: Vec<StructField>,
3229}
3230
3231impl Struct {
3232    pub fn new(name: String, fields: Vec<StructField>) -> Self {
3234        Self { name, fields }
3235    }
3236
3237    pub fn name(&self) -> &str {
3239        &self.name
3240    }
3241
3242    pub fn fields(&self) -> &[StructField] {
3244        &self.fields
3245    }
3246}
3247
3248#[derive(Debug, Clone, PartialEq)]
3250pub struct Variable {
3251    name: String,
3253    var_type: Type,
3255    initializer: Option<Expression>,
3257    is_static: bool,
3259    is_extern: bool,
3261    is_const: bool,
3263}
3264
3265impl Variable {
3266    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    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    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    pub fn name(&self) -> &str {
3311        &self.name
3312    }
3313
3314    pub fn var_type(&self) -> &Type {
3316        &self.var_type
3317    }
3318
3319    pub fn is_function_pointer(&self) -> bool {
3321        matches!(self.var_type, Type::FunctionPointer { .. })
3322    }
3323
3324    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    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    pub fn is_string_literal(&self) -> bool {
3352        let is_char_ptr =
3354            matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3355
3356        if let Some(initializer) = &self.initializer {
3358            is_char_ptr && matches!(initializer, Expression::StringLiteral(_))
3359        } else {
3360            false
3361        }
3362    }
3363
3364    pub fn is_string_buffer(&self) -> bool {
3374        let is_char_ptr =
3376            matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3377
3378        if let Some(Expression::FunctionCall { function, .. }) = &self.initializer {
3380            is_char_ptr && (function == "malloc" || function == "calloc")
3381        } else {
3382            false
3383        }
3384    }
3385
3386    pub fn initializer(&self) -> Option<&Expression> {
3390        self.initializer.as_ref()
3391    }
3392
3393    pub fn is_static(&self) -> bool {
3395        self.is_static
3396    }
3397
3398    pub fn is_extern(&self) -> bool {
3400        self.is_extern
3401    }
3402
3403    pub fn is_const(&self) -> bool {
3405        self.is_const
3406    }
3407}
3408
3409#[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#[derive(Debug, Clone, PartialEq)]
3449pub struct MacroDefinition {
3450    pub name: String,
3452    pub parameters: Vec<String>,
3454    pub body: String,
3456}
3457
3458impl MacroDefinition {
3459    pub fn new_object_like(name: String, body: String) -> Self {
3461        Self {
3462            name,
3463            parameters: vec![],
3464            body,
3465        }
3466    }
3467
3468    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    pub fn name(&self) -> &str {
3479        &self.name
3480    }
3481
3482    pub fn parameters(&self) -> &[String] {
3484        &self.parameters
3485    }
3486
3487    pub fn body(&self) -> &str {
3489        &self.body
3490    }
3491
3492    pub fn is_function_like(&self) -> bool {
3494        !self.parameters.is_empty()
3495    }
3496
3497    pub fn is_object_like(&self) -> bool {
3499        self.parameters.is_empty()
3500    }
3501}
3502
3503impl Ast {
3504    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    pub fn functions(&self) -> &[Function] {
3517        &self.functions
3518    }
3519
3520    pub fn add_function(&mut self, function: Function) {
3522        self.functions.push(function);
3523    }
3524
3525    pub fn typedefs(&self) -> &[Typedef] {
3527        &self.typedefs
3528    }
3529
3530    pub fn add_typedef(&mut self, typedef: Typedef) {
3532        self.typedefs.push(typedef);
3533    }
3534
3535    pub fn structs(&self) -> &[Struct] {
3537        &self.structs
3538    }
3539
3540    pub fn add_struct(&mut self, struct_def: Struct) {
3542        self.structs.push(struct_def);
3543    }
3544
3545    pub fn macros(&self) -> &[MacroDefinition] {
3547        &self.macros
3548    }
3549
3550    pub fn add_macro(&mut self, macro_def: MacroDefinition) {
3552        self.macros.push(macro_def);
3553    }
3554
3555    pub fn variables(&self) -> &[Variable] {
3557        &self.variables
3558    }
3559
3560    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#[derive(Debug, Clone, PartialEq)]
3574pub struct Function {
3575    pub name: String,
3577    pub return_type: Type,
3579    pub parameters: Vec<Parameter>,
3581    pub body: Vec<Statement>,
3583}
3584
3585impl Function {
3586    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    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#[derive(Debug, Clone, PartialEq)]
3614pub enum Type {
3615    Void,
3617    Int,
3619    Float,
3621    Double,
3623    Char,
3625    Pointer(Box<Type>),
3627    Struct(String),
3629    FunctionPointer {
3631        param_types: Vec<Type>,
3633        return_type: Box<Type>,
3635    },
3636    Array {
3639        element_type: Box<Type>,
3641        size: Option<i64>,
3643    },
3644}
3645
3646#[derive(Debug, Clone, PartialEq)]
3648pub struct Parameter {
3649    pub name: String,
3651    pub param_type: Type,
3653}
3654
3655impl Parameter {
3656    pub fn new(name: String, param_type: Type) -> Self {
3658        Self { name, param_type }
3659    }
3660
3661    pub fn is_function_pointer(&self) -> bool {
3663        matches!(self.param_type, Type::FunctionPointer { .. })
3664    }
3665
3666    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;