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 mut tu = ptr::null_mut();
90        let result = unsafe {
91            clang_parseTranslationUnit2(
92                self.index,
93                filename.as_ptr(),
94                ptr::null(),
95                0,
96                &unsaved_file as *const CXUnsavedFile as *mut CXUnsavedFile,
97                1,
98                CXTranslationUnit_DetailedPreprocessingRecord,
99                &mut tu,
100            )
101        };
102
103        if result != CXError_Success || tu.is_null() {
104            anyhow::bail!("Failed to parse C source");
105        }
106
107        let num_diagnostics = unsafe { clang_getNumDiagnostics(tu) };
109        for i in 0..num_diagnostics {
110            let diag = unsafe { clang_getDiagnostic(tu, i) };
111            let severity = unsafe { clang_getDiagnosticSeverity(diag) };
112
113            if severity >= CXDiagnostic_Error {
115                unsafe { clang_disposeDiagnostic(diag) };
116                unsafe { clang_disposeTranslationUnit(tu) };
117                anyhow::bail!("C source has syntax errors");
118            }
119
120            unsafe { clang_disposeDiagnostic(diag) };
121        }
122
123        let cursor = unsafe { clang_getTranslationUnitCursor(tu) };
125
126        let ast_ptr = &mut ast as *mut Ast;
128
129        unsafe {
131            clang_visitChildren(cursor, visit_function, ast_ptr as CXClientData);
132
133            clang_disposeTranslationUnit(tu);
135        }
136
137        Ok(ast)
138    }
139
140    pub fn parse_file(&self, _path: &Path) -> Result<Ast> {
151        Err(anyhow::anyhow!("Not implemented yet"))
153    }
154}
155
156impl Drop for CParser {
157    fn drop(&mut self) {
158        unsafe {
160            clang_disposeIndex(self.index);
161        }
162    }
163}
164
165extern "C" fn visit_function(
171    cursor: CXCursor,
172    _parent: CXCursor,
173    client_data: CXClientData,
174) -> CXChildVisitResult {
175    let ast = unsafe { &mut *(client_data as *mut Ast) };
177
178    let kind = unsafe { clang_getCursorKind(cursor) };
180
181    if kind == CXCursor_FunctionDecl {
182        if let Some(function) = extract_function(cursor) {
184            ast.add_function(function);
185        }
186    } else if kind == CXCursor_TypedefDecl {
187        if let Some(typedef) = extract_typedef(cursor) {
189            ast.add_typedef(typedef);
190        }
191    } else if kind == CXCursor_StructDecl {
192        if let Some(struct_def) = extract_struct(cursor) {
194            ast.add_struct(struct_def);
195        }
196    } else if kind == CXCursor_VarDecl {
197        if let Some(variable) = extract_variable(cursor) {
199            ast.add_variable(variable);
200        }
201    } else if kind == CXCursor_MacroDefinition {
202        let location = unsafe { clang_getCursorLocation(cursor) };
204        let mut file: CXFile = ptr::null_mut();
205        unsafe {
206            clang_getFileLocation(
207                location,
208                &mut file,
209                ptr::null_mut(),
210                ptr::null_mut(),
211                ptr::null_mut(),
212            );
213        }
214
215        if !file.is_null() {
217            let file_name = unsafe {
218                let name_cxstring = clang_getFileName(file);
219                let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
220                let name = c_str.to_string_lossy().into_owned();
221                clang_disposeString(name_cxstring);
222                name
223            };
224
225            if file_name.ends_with("input.c") {
227                if let Some(macro_def) = extract_macro(cursor) {
228                    ast.add_macro(macro_def);
229                }
230            }
231        }
232    }
233
234    CXChildVisit_Continue
235}
236
237fn extract_function(cursor: CXCursor) -> Option<Function> {
239    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
241    let name = unsafe {
242        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
243        let name = c_str.to_string_lossy().into_owned();
244        clang_disposeString(name_cxstring);
245        name
246    };
247
248    let cx_type = unsafe { clang_getCursorType(cursor) };
250    let return_cx_type = unsafe { clang_getResultType(cx_type) };
251    let return_type = convert_type(return_cx_type)?;
252
253    let num_args = unsafe { clang_Cursor_getNumArguments(cursor) };
255    let mut parameters = Vec::new();
256
257    for i in 0..num_args {
258        let arg_cursor = unsafe { clang_Cursor_getArgument(cursor, i as u32) };
260
261        let param_name_cxstring = unsafe { clang_getCursorSpelling(arg_cursor) };
263        let param_name = unsafe {
264            let c_str = CStr::from_ptr(clang_getCString(param_name_cxstring));
265            let name = c_str.to_string_lossy().into_owned();
266            clang_disposeString(param_name_cxstring);
267            name
268        };
269
270        let param_cx_type = unsafe { clang_getCursorType(arg_cursor) };
272        if let Some(param_type) = convert_type(param_cx_type) {
273            parameters.push(Parameter::new(param_name, param_type));
274        }
275    }
276
277    let mut body = Vec::new();
279    let body_ptr = &mut body as *mut Vec<Statement>;
280
281    unsafe {
282        clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
283    }
284
285    Some(Function::new_with_body(name, return_type, parameters, body))
286}
287
288fn extract_typedef(cursor: CXCursor) -> Option<Typedef> {
290    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
292    let name = unsafe {
293        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
294        let name = c_str.to_string_lossy().into_owned();
295        clang_disposeString(name_cxstring);
296        name
297    };
298
299    let cx_type = unsafe { clang_getTypedefDeclUnderlyingType(cursor) };
301    let underlying_type = convert_type(cx_type)?;
302
303    Some(Typedef::new(name, underlying_type))
304}
305
306fn extract_struct(cursor: CXCursor) -> Option<Struct> {
308    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
310    let name = unsafe {
311        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
312        let name = c_str.to_string_lossy().into_owned();
313        clang_disposeString(name_cxstring);
314        name
315    };
316
317    if name.is_empty() {
319        return None;
320    }
321
322    let mut fields = Vec::new();
324    let fields_ptr = &mut fields as *mut Vec<StructField>;
325
326    unsafe {
327        clang_visitChildren(cursor, visit_struct_fields, fields_ptr as CXClientData);
328    }
329
330    Some(Struct::new(name, fields))
331}
332
333fn extract_variable(cursor: CXCursor) -> Option<Variable> {
344    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
346    let name = unsafe {
347        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
348        let name = c_str.to_string_lossy().into_owned();
349        clang_disposeString(name_cxstring);
350        name
351    };
352
353    let cx_type = unsafe { clang_getCursorType(cursor) };
355    let var_type = convert_type(cx_type)?;
356
357    let mut initializer: Option<Expression> = None;
359    let initializer_ptr = &mut initializer as *mut Option<Expression>;
360
361    unsafe {
362        clang_visitChildren(
363            cursor,
364            visit_variable_initializer,
365            initializer_ptr as CXClientData,
366        );
367    }
368
369    if let Some(init_expr) = initializer {
370        Some(Variable::new_with_initializer(name, var_type, init_expr))
371    } else {
372        Some(Variable::new(name, var_type))
373    }
374}
375
376#[allow(non_upper_case_globals)]
379fn try_extract_expression(cursor: CXCursor) -> Option<Expression> {
380    let kind = unsafe { clang_getCursorKind(cursor) };
381
382    match kind {
383        CXCursor_IntegerLiteral => extract_int_literal(cursor),
384        CXCursor_StringLiteral => extract_string_literal(cursor),
385        CXCursor_DeclRefExpr => extract_variable_ref(cursor),
386        CXCursor_BinaryOperator => extract_binary_op(cursor),
387        CXCursor_CallExpr => extract_function_call(cursor),
388        CXCursor_UnaryOperator => extract_unary_op(cursor),
389        CXCursor_ArraySubscriptExpr => extract_array_index(cursor),
390        CXCursor_MemberRefExpr => extract_field_access(cursor),
391        CXCursor_UnexposedExpr => {
392            let mut result: Option<Expression> = None;
394            let result_ptr = &mut result as *mut Option<Expression>;
395            unsafe {
396                clang_visitChildren(
397                    cursor,
398                    visit_variable_initializer,
399                    result_ptr as CXClientData,
400                );
401            }
402            result
403        }
404        _ => None,
405    }
406}
407
408#[allow(non_upper_case_globals)]
410extern "C" fn visit_variable_initializer(
411    cursor: CXCursor,
412    _parent: CXCursor,
413    client_data: CXClientData,
414) -> CXChildVisitResult {
415    let initializer = unsafe { &mut *(client_data as *mut Option<Expression>) };
416
417    if let Some(expr) = try_extract_expression(cursor) {
419        *initializer = Some(expr);
420        return CXChildVisit_Break;
421    }
422
423    CXChildVisit_Continue
424}
425
426fn extract_macro(cursor: CXCursor) -> Option<MacroDefinition> {
433    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
435    let name = unsafe {
436        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
437        let name = c_str.to_string_lossy().into_owned();
438        clang_disposeString(name_cxstring);
439        name
440    };
441
442    if name.is_empty() {
444        return None;
445    }
446
447    let is_function_like = unsafe { clang_sys::clang_Cursor_isMacroFunctionLike(cursor) } != 0;
450
451    let range = unsafe { clang_getCursorExtent(cursor) };
453    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
454
455    let mut tokens: *mut CXToken = ptr::null_mut();
456    let mut num_tokens: u32 = 0;
457
458    unsafe {
459        clang_tokenize(tu, range, &mut tokens, &mut num_tokens);
460    }
461
462    let mut parameters = Vec::new();
465    let mut body_tokens = Vec::new();
466    let mut in_params = false;
467
468    for i in 0..num_tokens {
469        let token = unsafe { *tokens.offset(i as isize) };
470        let token_kind = unsafe { clang_getTokenKind(token) };
471        let token_spelling = unsafe { clang_getTokenSpelling(tu, token) };
472        let token_str = unsafe {
473            let c_str = CStr::from_ptr(clang_getCString(token_spelling));
474            let s = c_str.to_string_lossy().into_owned();
475            clang_disposeString(token_spelling);
476            s
477        };
478
479        if i == 0 {
481            continue;
482        }
483
484        if is_function_like && i == 1 && token_str == "(" {
486            in_params = true;
487            continue;
488        }
489
490        if in_params {
491            if token_str == ")" {
492                in_params = false;
493                continue;
494            } else if token_str != ","
495                && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
496            {
497                parameters.push(token_str);
500            }
501        } else {
502            body_tokens.push(token_str);
503        }
504    }
505
506    unsafe {
508        clang_disposeTokens(tu, tokens, num_tokens);
509    }
510
511    let body = body_tokens.join("");
513
514    if is_function_like {
515        Some(MacroDefinition::new_function_like(name, parameters, body))
516    } else {
517        Some(MacroDefinition::new_object_like(name, body))
518    }
519}
520
521#[allow(non_upper_case_globals)]
527extern "C" fn visit_struct_fields(
528    cursor: CXCursor,
529    _parent: CXCursor,
530    client_data: CXClientData,
531) -> CXChildVisitResult {
532    let fields = unsafe { &mut *(client_data as *mut Vec<StructField>) };
534
535    let kind = unsafe { clang_getCursorKind(cursor) };
537
538    if kind == CXCursor_FieldDecl {
539        let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
541        let name = unsafe {
542            let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
543            let name = c_str.to_string_lossy().into_owned();
544            clang_disposeString(name_cxstring);
545            name
546        };
547
548        let cx_type = unsafe { clang_getCursorType(cursor) };
550        if let Some(field_type) = convert_type(cx_type) {
551            fields.push(StructField::new(name, field_type));
552        }
553    }
554
555    CXChildVisit_Continue
556}
557
558#[allow(non_upper_case_globals)]
564extern "C" fn visit_statement(
565    cursor: CXCursor,
566    _parent: CXCursor,
567    client_data: CXClientData,
568) -> CXChildVisitResult {
569    let statements = unsafe { &mut *(client_data as *mut Vec<Statement>) };
571
572    let kind = unsafe { clang_getCursorKind(cursor) };
574
575    match kind {
576        CXCursor_CompoundStmt => {
577            CXChildVisit_Recurse
579        }
580        CXCursor_DeclStmt => {
581            CXChildVisit_Recurse
583        }
584        CXCursor_VarDecl => {
585            if let Some(stmt) = extract_var_decl(cursor) {
587                statements.push(stmt);
588            }
589            CXChildVisit_Continue
590        }
591        CXCursor_ReturnStmt => {
592            if let Some(stmt) = extract_return_stmt(cursor) {
594                statements.push(stmt);
595            }
596            CXChildVisit_Continue
597        }
598        CXCursor_BinaryOperator => {
599            if let Some(stmt) = extract_assignment_stmt(cursor) {
601                statements.push(stmt);
602            }
603            CXChildVisit_Continue
604        }
605        CXCursor_IfStmt => {
606            if let Some(stmt) = extract_if_stmt(cursor) {
608                statements.push(stmt);
609            }
610            CXChildVisit_Continue
611        }
612        CXCursor_ForStmt => {
613            if let Some(stmt) = extract_for_stmt(cursor) {
615                statements.push(stmt);
616            }
617            CXChildVisit_Continue
618        }
619        CXCursor_WhileStmt => {
620            if let Some(stmt) = extract_while_stmt(cursor) {
622                statements.push(stmt);
623            }
624            CXChildVisit_Continue
625        }
626        CXCursor_SwitchStmt => {
627            if let Some(stmt) = extract_switch_stmt(cursor) {
629                statements.push(stmt);
630            }
631            CXChildVisit_Continue
632        }
633        CXCursor_BreakStmt => {
634            statements.push(Statement::Break);
636            CXChildVisit_Continue
637        }
638        CXCursor_ContinueStmt => {
639            statements.push(Statement::Continue);
641            CXChildVisit_Continue
642        }
643        CXCursor_UnaryOperator => {
644            if let Some(stmt) = extract_inc_dec_stmt(cursor) {
646                statements.push(stmt);
647            }
648            CXChildVisit_Continue
649        }
650        CXCursor_CompoundAssignOperator => {
651            if let Some(stmt) = extract_compound_assignment_stmt(cursor) {
653                statements.push(stmt);
654            }
655            CXChildVisit_Continue
656        }
657        _ => CXChildVisit_Recurse, }
659}
660
661fn extract_var_decl(cursor: CXCursor) -> Option<Statement> {
663    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
665    let name = unsafe {
666        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
667        let name = c_str.to_string_lossy().into_owned();
668        clang_disposeString(name_cxstring);
669        name
670    };
671
672    let cx_type = unsafe { clang_getCursorType(cursor) };
674    let var_type = convert_type(cx_type)?;
675
676    let mut initializer: Option<Expression> = None;
678    let init_ptr = &mut initializer as *mut Option<Expression>;
679
680    unsafe {
681        clang_visitChildren(cursor, visit_expression, init_ptr as CXClientData);
682    }
683
684    Some(Statement::VariableDeclaration {
685        name,
686        var_type,
687        initializer,
688    })
689}
690
691fn extract_return_stmt(cursor: CXCursor) -> Option<Statement> {
693    let mut return_expr: Option<Expression> = None;
695    let expr_ptr = &mut return_expr as *mut Option<Expression>;
696
697    unsafe {
698        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
699    }
700
701    Some(Statement::Return(return_expr))
702}
703
704fn extract_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
706    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
709    if tu.is_null() {
710        return None;
711    }
712
713    let extent = unsafe { clang_getCursorExtent(cursor) };
715
716    let mut tokens = ptr::null_mut();
718    let mut num_tokens = 0;
719
720    unsafe {
721        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
722    }
723
724    let mut is_assignment = false;
725
726    for i in 0..num_tokens {
728        unsafe {
729            let token = *tokens.add(i as usize);
730            let token_kind = clang_getTokenKind(token);
731
732            if token_kind == CXToken_Punctuation {
733                let token_cxstring = clang_getTokenSpelling(tu, token);
734                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
735                if let Ok(token_str) = c_str.to_str() {
736                    if token_str == "=" {
738                        is_assignment = true;
739                        clang_disposeString(token_cxstring);
740                        break;
741                    } else if token_str == "=="
742                        || token_str == "!="
743                        || token_str == "<="
744                        || token_str == ">="
745                    {
746                        clang_disposeString(token_cxstring);
748                        break;
749                    }
750                }
751                clang_disposeString(token_cxstring);
752            }
753        }
754    }
755
756    unsafe {
757        clang_disposeTokens(tu, tokens, num_tokens);
758    }
759
760    if !is_assignment {
761        return None;
762    }
763
764    let mut operands: Vec<Expression> = Vec::new();
766    let operands_ptr = &mut operands as *mut Vec<Expression>;
767
768    unsafe {
769        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
770    }
771
772    if operands.len() != 2 {
774        return None;
775    }
776
777    if let Expression::Dereference(inner) = &operands[0] {
779        return Some(Statement::DerefAssignment {
780            target: (**inner).clone(), value: operands[1].clone(),
782        });
783    }
784
785    if let Expression::ArrayIndex { array, index } = &operands[0] {
787        return Some(Statement::ArrayIndexAssignment {
788            array: array.clone(),
789            index: index.clone(),
790            value: operands[1].clone(),
791        });
792    }
793
794    if matches!(
796        &operands[0],
797        Expression::PointerFieldAccess { .. } | Expression::FieldAccess { .. }
798    ) {
799        let field = match &operands[0] {
801            Expression::PointerFieldAccess { field, .. } => field.clone(),
802            Expression::FieldAccess { field, .. } => field.clone(),
803            _ => unreachable!(),
804        };
805
806        let object = match &operands[0] {
808            Expression::PointerFieldAccess { pointer, .. } => (**pointer).clone(),
809            Expression::FieldAccess { object, .. } => (**object).clone(),
810            _ => unreachable!(),
811        };
812
813        return Some(Statement::FieldAssignment {
814            object,
815            field,
816            value: operands[1].clone(),
817        });
818    }
819
820    let target = match &operands[0] {
822        Expression::Variable(name) => name.clone(),
823        _ => return None, };
825
826    Some(Statement::Assignment {
827        target,
828        value: operands[1].clone(),
829    })
830}
831
832fn extract_inc_dec_stmt(cursor: CXCursor) -> Option<Statement> {
834    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
836    if tu.is_null() {
837        return None;
838    }
839
840    let extent = unsafe { clang_getCursorExtent(cursor) };
842
843    let mut tokens = ptr::null_mut();
845    let mut num_tokens = 0;
846
847    unsafe {
848        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
849    }
850
851    let mut operator: Option<String> = None;
852    let mut operator_position = 0;
853
854    for i in 0..num_tokens {
856        unsafe {
857            let token = *tokens.add(i as usize);
858            let token_kind = clang_getTokenKind(token);
859
860            if token_kind == CXToken_Punctuation {
861                let token_cxstring = clang_getTokenSpelling(tu, token);
862                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
863                if let Ok(token_str) = c_str.to_str() {
864                    if token_str == "++" || token_str == "--" {
865                        operator = Some(token_str.to_string()); operator_position = i;
867                        clang_disposeString(token_cxstring);
868                        break;
869                    }
870                }
871                clang_disposeString(token_cxstring);
872            }
873        }
874    }
875
876    let is_pre = operator_position == 0;
880
881    unsafe {
882        clang_disposeTokens(tu, tokens, num_tokens);
883    }
884
885    let mut target_name: Option<String> = None;
887
888    extern "C" fn visit_for_target(
890        cursor: CXCursor,
891        _parent: CXCursor,
892        client_data: CXClientData,
893    ) -> CXChildVisitResult {
894        let target = unsafe { &mut *(client_data as *mut Option<String>) };
895        let kind = unsafe { clang_getCursorKind(cursor) };
896
897        if kind == CXCursor_DeclRefExpr {
898            let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
899            let name = unsafe {
900                let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
901                let var_name = c_str.to_string_lossy().into_owned();
902                clang_disposeString(name_cxstring);
903                var_name
904            };
905            *target = Some(name);
906            CXChildVisit_Break
907        } else {
908            CXChildVisit_Recurse
909        }
910    }
911
912    let target_ptr = &mut target_name as *mut Option<String>;
913    unsafe {
914        clang_visitChildren(cursor, visit_for_target, target_ptr as CXClientData);
915    }
916
917    let target = target_name?;
918
919    match operator?.as_str() {
920        "++" => {
921            if is_pre {
922                Some(Statement::PreIncrement { target })
923            } else {
924                Some(Statement::PostIncrement { target })
925            }
926        }
927        "--" => {
928            if is_pre {
929                Some(Statement::PreDecrement { target })
930            } else {
931                Some(Statement::PostDecrement { target })
932            }
933        }
934        _ => None,
935    }
936}
937
938fn extract_compound_assignment_stmt(cursor: CXCursor) -> Option<Statement> {
940    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
942    if tu.is_null() {
943        return None;
944    }
945
946    let extent = unsafe { clang_getCursorExtent(cursor) };
948
949    let mut tokens = ptr::null_mut();
951    let mut num_tokens = 0;
952
953    unsafe {
954        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
955    }
956
957    let mut operator: Option<BinaryOperator> = None;
958
959    for i in 0..num_tokens {
961        unsafe {
962            let token = *tokens.add(i as usize);
963            let token_kind = clang_getTokenKind(token);
964
965            if token_kind == CXToken_Punctuation {
966                let token_cxstring = clang_getTokenSpelling(tu, token);
967                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
968                if let Ok(token_str) = c_str.to_str() {
969                    operator = match token_str {
970                        "+=" => Some(BinaryOperator::Add),
971                        "-=" => Some(BinaryOperator::Subtract),
972                        "*=" => Some(BinaryOperator::Multiply),
973                        "/=" => Some(BinaryOperator::Divide),
974                        "%=" => Some(BinaryOperator::Modulo),
975                        _ => None,
976                    };
977                    if operator.is_some() {
978                        clang_disposeString(token_cxstring);
979                        break;
980                    }
981                }
982                clang_disposeString(token_cxstring);
983            }
984        }
985    }
986
987    unsafe {
988        clang_disposeTokens(tu, tokens, num_tokens);
989    }
990
991    let op = operator?;
992
993    let mut operands: Vec<Expression> = Vec::new();
995    let operands_ptr = &mut operands as *mut Vec<Expression>;
996
997    unsafe {
998        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
999    }
1000
1001    if operands.len() != 2 {
1003        return None;
1004    }
1005
1006    let target = match &operands[0] {
1008        Expression::Variable(name) => name.clone(),
1009        _ => return None,
1010    };
1011
1012    Some(Statement::CompoundAssignment {
1013        target,
1014        op,
1015        value: operands[1].clone(),
1016    })
1017}
1018
1019fn extract_if_stmt(cursor: CXCursor) -> Option<Statement> {
1021    #[repr(C)]
1027    struct IfData {
1028        condition: Option<Expression>,
1029        then_block: Vec<Statement>,
1030        else_block: Option<Vec<Statement>>,
1031        child_index: u32,
1032    }
1033
1034    let mut if_data = IfData {
1035        condition: None,
1036        then_block: Vec::new(),
1037        else_block: None,
1038        child_index: 0,
1039    };
1040
1041    let data_ptr = &mut if_data as *mut IfData;
1042
1043    unsafe {
1044        clang_visitChildren(cursor, visit_if_children, data_ptr as CXClientData);
1045    }
1046
1047    Some(Statement::If {
1048        condition: if_data.condition?,
1049        then_block: if_data.then_block,
1050        else_block: if_data.else_block,
1051    })
1052}
1053
1054#[allow(non_upper_case_globals)]
1056extern "C" fn visit_if_children(
1057    cursor: CXCursor,
1058    _parent: CXCursor,
1059    client_data: CXClientData,
1060) -> CXChildVisitResult {
1061    #[repr(C)]
1062    struct IfData {
1063        condition: Option<Expression>,
1064        then_block: Vec<Statement>,
1065        else_block: Option<Vec<Statement>>,
1066        child_index: u32,
1067    }
1068
1069    let if_data = unsafe { &mut *(client_data as *mut IfData) };
1070    let kind = unsafe { clang_getCursorKind(cursor) };
1071
1072    match if_data.child_index {
1073        0 => {
1074            if_data.condition = match kind {
1077                CXCursor_BinaryOperator => extract_binary_op(cursor),
1078                CXCursor_IntegerLiteral => extract_int_literal(cursor),
1079                CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1080                CXCursor_CallExpr => extract_function_call(cursor),
1081                CXCursor_UnaryOperator => extract_unary_op(cursor),
1082                _ => {
1083                    let mut cond_expr: Option<Expression> = None;
1085                    let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1086                    unsafe {
1087                        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1088                    }
1089                    cond_expr
1090                }
1091            };
1092            if_data.child_index += 1;
1093            CXChildVisit_Continue
1094        }
1095        1 => {
1096            if kind == CXCursor_CompoundStmt {
1098                let body_ptr = &mut if_data.then_block as *mut Vec<Statement>;
1099                unsafe {
1100                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1101                }
1102            }
1103            if_data.child_index += 1;
1104            CXChildVisit_Continue
1105        }
1106        2 => {
1107            if kind == CXCursor_CompoundStmt || kind == CXCursor_IfStmt {
1109                let mut else_stmts = Vec::new();
1110                let body_ptr = &mut else_stmts as *mut Vec<Statement>;
1111                unsafe {
1112                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1113                }
1114                if_data.else_block = Some(else_stmts);
1115            }
1116            if_data.child_index += 1;
1117            CXChildVisit_Continue
1118        }
1119        _ => CXChildVisit_Continue,
1120    }
1121}
1122
1123fn extract_for_stmt(cursor: CXCursor) -> Option<Statement> {
1125    #[repr(C)]
1132    struct ForData {
1133        init: Option<Box<Statement>>,
1134        condition: Option<Expression>,
1135        increment: Option<Box<Statement>>,
1136        body: Vec<Statement>,
1137        child_index: u32,
1138    }
1139
1140    let mut for_data = ForData {
1141        init: None,
1142        condition: None,
1143        increment: None,
1144        body: Vec::new(),
1145        child_index: 0,
1146    };
1147
1148    let data_ptr = &mut for_data as *mut ForData;
1149
1150    unsafe {
1151        clang_visitChildren(cursor, visit_for_children, data_ptr as CXClientData);
1152    }
1153
1154    Some(Statement::For {
1155        init: for_data.init,
1156        condition: for_data.condition,
1157        increment: for_data.increment,
1158        body: for_data.body,
1159    })
1160}
1161
1162#[allow(non_upper_case_globals)]
1164extern "C" fn visit_for_children(
1165    cursor: CXCursor,
1166    _parent: CXCursor,
1167    client_data: CXClientData,
1168) -> CXChildVisitResult {
1169    #[repr(C)]
1170    struct ForData {
1171        init: Option<Box<Statement>>,
1172        condition: Option<Expression>,
1173        increment: Option<Box<Statement>>,
1174        body: Vec<Statement>,
1175        child_index: u32,
1176    }
1177
1178    let for_data = unsafe { &mut *(client_data as *mut ForData) };
1179    let kind = unsafe { clang_getCursorKind(cursor) };
1180
1181    match for_data.child_index {
1182        0 => {
1183            if kind == CXCursor_DeclStmt {
1185                let mut init_stmts = Vec::new();
1187                let ptr = &mut init_stmts as *mut Vec<Statement>;
1188                unsafe {
1189                    clang_visitChildren(cursor, visit_statement, ptr as CXClientData);
1190                }
1191                if let Some(stmt) = init_stmts.into_iter().next() {
1192                    for_data.init = Some(Box::new(stmt));
1193                }
1194            } else if kind == CXCursor_BinaryOperator {
1195                if let Some(stmt) = extract_assignment_stmt(cursor) {
1197                    for_data.init = Some(Box::new(stmt));
1198                }
1199            }
1200            for_data.child_index += 1;
1201            CXChildVisit_Continue
1202        }
1203        1 => {
1204            for_data.condition = match kind {
1207                CXCursor_BinaryOperator => extract_binary_op(cursor),
1208                CXCursor_IntegerLiteral => extract_int_literal(cursor),
1209                CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1210                CXCursor_CallExpr => extract_function_call(cursor),
1211                CXCursor_UnaryOperator => extract_unary_op(cursor),
1212                _ => {
1213                    let mut cond_expr: Option<Expression> = None;
1214                    let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1215                    unsafe {
1216                        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1217                    }
1218                    cond_expr
1219                }
1220            };
1221            for_data.child_index += 1;
1222            CXChildVisit_Continue
1223        }
1224        2 => {
1225            if kind == CXCursor_BinaryOperator {
1227                if let Some(stmt) = extract_assignment_stmt(cursor) {
1228                    for_data.increment = Some(Box::new(stmt));
1229                }
1230            } else if kind == CXCursor_UnaryOperator {
1231                if let Some(stmt) = extract_inc_dec_stmt(cursor) {
1233                    for_data.increment = Some(Box::new(stmt));
1234                }
1235            }
1236            for_data.child_index += 1;
1237            CXChildVisit_Continue
1238        }
1239        3 => {
1240            if kind == CXCursor_CompoundStmt {
1242                let body_ptr = &mut for_data.body as *mut Vec<Statement>;
1243                unsafe {
1244                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1245                }
1246            }
1247            for_data.child_index += 1;
1248            CXChildVisit_Continue
1249        }
1250        _ => CXChildVisit_Continue,
1251    }
1252}
1253
1254fn extract_while_stmt(cursor: CXCursor) -> Option<Statement> {
1256    #[repr(C)]
1261    struct WhileData {
1262        condition: Option<Expression>,
1263        body: Vec<Statement>,
1264        child_index: u32,
1265    }
1266
1267    let mut while_data = WhileData {
1268        condition: None,
1269        body: Vec::new(),
1270        child_index: 0,
1271    };
1272
1273    let data_ptr = &mut while_data as *mut WhileData;
1274
1275    unsafe {
1276        clang_visitChildren(cursor, visit_while_children, data_ptr as CXClientData);
1277    }
1278
1279    Some(Statement::While {
1280        condition: while_data.condition?,
1281        body: while_data.body,
1282    })
1283}
1284
1285#[allow(non_upper_case_globals)]
1287extern "C" fn visit_while_children(
1288    cursor: CXCursor,
1289    _parent: CXCursor,
1290    client_data: CXClientData,
1291) -> CXChildVisitResult {
1292    #[repr(C)]
1293    struct WhileData {
1294        condition: Option<Expression>,
1295        body: Vec<Statement>,
1296        child_index: u32,
1297    }
1298
1299    let while_data = unsafe { &mut *(client_data as *mut WhileData) };
1300    let kind = unsafe { clang_getCursorKind(cursor) };
1301
1302    match while_data.child_index {
1303        0 => {
1304            while_data.condition = match kind {
1307                CXCursor_BinaryOperator => extract_binary_op(cursor),
1308                CXCursor_IntegerLiteral => extract_int_literal(cursor),
1309                CXCursor_DeclRefExpr => extract_variable_ref(cursor),
1310                CXCursor_CallExpr => extract_function_call(cursor),
1311                CXCursor_UnaryOperator => extract_unary_op(cursor),
1312                _ => {
1313                    let mut cond_expr: Option<Expression> = None;
1314                    let expr_ptr = &mut cond_expr as *mut Option<Expression>;
1315                    unsafe {
1316                        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
1317                    }
1318                    cond_expr
1319                }
1320            };
1321            while_data.child_index += 1;
1322            CXChildVisit_Continue
1323        }
1324        1 => {
1325            if kind == CXCursor_CompoundStmt {
1327                let body_ptr = &mut while_data.body as *mut Vec<Statement>;
1328                unsafe {
1329                    clang_visitChildren(cursor, visit_statement, body_ptr as CXClientData);
1330                }
1331            }
1332            while_data.child_index += 1;
1333            CXChildVisit_Continue
1334        }
1335        _ => CXChildVisit_Continue,
1336    }
1337}
1338
1339#[allow(non_upper_case_globals)]
1343fn extract_switch_stmt(cursor: CXCursor) -> Option<Statement> {
1344    #[repr(C)]
1349    struct SwitchData {
1350        condition: Option<Expression>,
1351        cases: Vec<SwitchCase>,
1352        default_case: Option<Vec<Statement>>,
1353        child_index: u32,
1354    }
1355
1356    let mut switch_data = SwitchData {
1357        condition: None,
1358        cases: Vec::new(),
1359        default_case: None,
1360        child_index: 0,
1361    };
1362
1363    let data_ptr = &mut switch_data as *mut SwitchData;
1364
1365    unsafe {
1366        clang_visitChildren(cursor, visit_switch_children, data_ptr as CXClientData);
1367    }
1368
1369    Some(Statement::Switch {
1370        condition: switch_data.condition?,
1371        cases: switch_data.cases,
1372        default_case: switch_data.default_case,
1373    })
1374}
1375
1376#[allow(non_upper_case_globals)]
1378extern "C" fn visit_switch_children(
1379    cursor: CXCursor,
1380    _parent: CXCursor,
1381    client_data: CXClientData,
1382) -> CXChildVisitResult {
1383    #[repr(C)]
1384    struct SwitchData {
1385        condition: Option<Expression>,
1386        cases: Vec<SwitchCase>,
1387        default_case: Option<Vec<Statement>>,
1388        child_index: u32,
1389    }
1390
1391    let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
1392    let kind = unsafe { clang_getCursorKind(cursor) };
1393
1394    match switch_data.child_index {
1395        0 => {
1396            if let Some(expr) = try_extract_expression(cursor) {
1398                switch_data.condition = Some(expr);
1399            }
1400            switch_data.child_index += 1;
1401            CXChildVisit_Continue
1402        }
1403        1 => {
1404            if kind == CXCursor_CompoundStmt {
1407                unsafe {
1408                    clang_visitChildren(cursor, visit_switch_body, client_data);
1409                }
1410            }
1411            switch_data.child_index += 1;
1412            CXChildVisit_Continue
1413        }
1414        _ => CXChildVisit_Continue,
1415    }
1416}
1417
1418#[allow(non_upper_case_globals)]
1420extern "C" fn visit_switch_body(
1421    cursor: CXCursor,
1422    _parent: CXCursor,
1423    client_data: CXClientData,
1424) -> CXChildVisitResult {
1425    #[repr(C)]
1426    struct SwitchData {
1427        condition: Option<Expression>,
1428        cases: Vec<SwitchCase>,
1429        default_case: Option<Vec<Statement>>,
1430        child_index: u32,
1431    }
1432
1433    let switch_data = unsafe { &mut *(client_data as *mut SwitchData) };
1434    let kind = unsafe { clang_getCursorKind(cursor) };
1435
1436    match kind {
1437        CXCursor_CaseStmt => {
1438            if let Some(case) = extract_case_stmt(cursor) {
1440                switch_data.cases.push(case);
1441            }
1442            CXChildVisit_Continue
1443        }
1444        CXCursor_DefaultStmt => {
1445            if let Some(body) = extract_default_stmt(cursor) {
1447                switch_data.default_case = Some(body);
1448            }
1449            CXChildVisit_Continue
1450        }
1451        _ => CXChildVisit_Continue,
1452    }
1453}
1454
1455fn extract_case_stmt(cursor: CXCursor) -> Option<SwitchCase> {
1457    #[repr(C)]
1462    struct CaseData {
1463        value: Option<Expression>,
1464        body: Vec<Statement>,
1465        child_index: u32,
1466    }
1467
1468    let mut case_data = CaseData {
1469        value: None,
1470        body: Vec::new(),
1471        child_index: 0,
1472    };
1473
1474    let data_ptr = &mut case_data as *mut CaseData;
1475
1476    unsafe {
1477        clang_visitChildren(cursor, visit_case_children, data_ptr as CXClientData);
1478    }
1479
1480    Some(SwitchCase {
1481        value: case_data.value,
1482        body: case_data.body,
1483    })
1484}
1485
1486#[allow(non_upper_case_globals)]
1488extern "C" fn visit_case_children(
1489    cursor: CXCursor,
1490    _parent: CXCursor,
1491    client_data: CXClientData,
1492) -> CXChildVisitResult {
1493    #[repr(C)]
1494    struct CaseData {
1495        value: Option<Expression>,
1496        body: Vec<Statement>,
1497        child_index: u32,
1498    }
1499
1500    let case_data = unsafe { &mut *(client_data as *mut CaseData) };
1501    let _kind = unsafe { clang_getCursorKind(cursor) };
1502
1503    match case_data.child_index {
1504        0 => {
1505            if let Some(expr) = try_extract_expression(cursor) {
1507                case_data.value = Some(expr);
1508            }
1509            case_data.child_index += 1;
1510            CXChildVisit_Continue
1511        }
1512        _ => {
1513            if let Some(stmt) = extract_statement(cursor) {
1516                case_data.body.push(stmt);
1517            }
1518            CXChildVisit_Recurse
1520        }
1521    }
1522}
1523
1524fn extract_default_stmt(cursor: CXCursor) -> Option<Vec<Statement>> {
1526    let mut body: Vec<Statement> = Vec::new();
1528    let body_ptr = &mut body as *mut Vec<Statement>;
1529
1530    unsafe {
1531        clang_visitChildren(cursor, visit_default_children, body_ptr as CXClientData);
1532    }
1533
1534    Some(body)
1535}
1536
1537#[allow(non_upper_case_globals)]
1539extern "C" fn visit_default_children(
1540    cursor: CXCursor,
1541    _parent: CXCursor,
1542    client_data: CXClientData,
1543) -> CXChildVisitResult {
1544    let body = unsafe { &mut *(client_data as *mut Vec<Statement>) };
1545
1546    if let Some(stmt) = extract_statement(cursor) {
1548        body.push(stmt);
1549    }
1550
1551    CXChildVisit_Continue
1552}
1553
1554#[allow(non_upper_case_globals)]
1556fn extract_statement(cursor: CXCursor) -> Option<Statement> {
1557    let kind = unsafe { clang_getCursorKind(cursor) };
1558
1559    match kind {
1560        CXCursor_ReturnStmt => extract_return_stmt(cursor),
1561        CXCursor_VarDecl => extract_var_decl(cursor),
1562        CXCursor_IfStmt => extract_if_stmt(cursor),
1563        CXCursor_ForStmt => extract_for_stmt(cursor),
1564        CXCursor_WhileStmt => extract_while_stmt(cursor),
1565        CXCursor_BreakStmt => Some(Statement::Break),
1566        CXCursor_ContinueStmt => Some(Statement::Continue),
1567        CXCursor_UnaryOperator => extract_inc_dec_stmt(cursor),
1568        CXCursor_BinaryOperator => extract_assignment_stmt(cursor),
1569        CXCursor_CallExpr => {
1570            if let Some(Expression::FunctionCall {
1572                function,
1573                arguments,
1574            }) = extract_function_call(cursor)
1575            {
1576                return Some(Statement::FunctionCall {
1577                    function,
1578                    arguments,
1579                });
1580            }
1581            None
1582        }
1583        _ => None,
1584    }
1585}
1586
1587#[allow(non_upper_case_globals)]
1593extern "C" fn visit_expression(
1594    cursor: CXCursor,
1595    _parent: CXCursor,
1596    client_data: CXClientData,
1597) -> CXChildVisitResult {
1598    let expr_opt = unsafe { &mut *(client_data as *mut Option<Expression>) };
1600
1601    let kind = unsafe { clang_getCursorKind(cursor) };
1603
1604    match kind {
1605        CXCursor_IntegerLiteral => {
1606            if let Some(expr) = extract_int_literal(cursor) {
1608                *expr_opt = Some(expr);
1609            }
1610            CXChildVisit_Continue
1611        }
1612        CXCursor_StringLiteral => {
1613            if let Some(expr) = extract_string_literal(cursor) {
1615                *expr_opt = Some(expr);
1616            }
1617            CXChildVisit_Continue
1618        }
1619        CXCursor_DeclRefExpr => {
1620            if let Some(expr) = extract_variable_ref(cursor) {
1622                *expr_opt = Some(expr);
1623            }
1624            CXChildVisit_Continue
1625        }
1626        CXCursor_BinaryOperator => {
1627            if let Some(expr) = extract_binary_op(cursor) {
1629                *expr_opt = Some(expr);
1630            }
1631            CXChildVisit_Continue
1632        }
1633        CXCursor_CallExpr => {
1634            if let Some(expr) = extract_function_call(cursor) {
1636                *expr_opt = Some(expr);
1637            }
1638            CXChildVisit_Continue
1639        }
1640        CXCursor_UnaryOperator => {
1641            if let Some(expr) = extract_unary_op(cursor) {
1643                *expr_opt = Some(expr);
1644            }
1645            CXChildVisit_Continue
1646        }
1647        CXCursor_ArraySubscriptExpr => {
1648            if let Some(expr) = extract_array_index(cursor) {
1650                *expr_opt = Some(expr);
1651            }
1652            CXChildVisit_Continue
1653        }
1654        CXCursor_MemberRefExpr => {
1655            if let Some(expr) = extract_field_access(cursor) {
1657                *expr_opt = Some(expr);
1658            }
1659            CXChildVisit_Continue
1660        }
1661        CXCursor_UnexposedExpr => {
1662            CXChildVisit_Recurse
1665        }
1666        CXCursor_ParenExpr => {
1667            CXChildVisit_Recurse
1669        }
1670        136 => {
1671            if let Some(expr) = extract_sizeof(cursor) {
1673                *expr_opt = Some(expr);
1674                CXChildVisit_Continue
1675            } else {
1676                CXChildVisit_Recurse
1678            }
1679        }
1680        _ => CXChildVisit_Recurse,
1681    }
1682}
1683
1684fn extract_int_literal(cursor: CXCursor) -> Option<Expression> {
1686    let extent = unsafe { clang_getCursorExtent(cursor) };
1688
1689    let tu = unsafe {
1691        let loc = clang_getCursorLocation(cursor);
1692        let mut file = ptr::null_mut();
1693        let mut line = 0;
1694        let mut column = 0;
1695        let mut offset = 0;
1696        clang_getFileLocation(loc, &mut file, &mut line, &mut column, &mut offset);
1697
1698        clang_Cursor_getTranslationUnit(cursor)
1701    };
1702
1703    if tu.is_null() {
1704        return Some(Expression::IntLiteral(0));
1705    }
1706
1707    let mut tokens = ptr::null_mut();
1709    let mut num_tokens = 0;
1710
1711    unsafe {
1712        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1713    }
1714
1715    let mut value = 0;
1716
1717    if num_tokens > 0 {
1718        unsafe {
1720            let token_cxstring = clang_getTokenSpelling(tu, *tokens);
1721            let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1722            if let Ok(token_str) = c_str.to_str() {
1723                value = token_str.parse().unwrap_or(0);
1724            }
1725            clang_disposeString(token_cxstring);
1726
1727            clang_disposeTokens(tu, tokens, num_tokens);
1729        }
1730    }
1731
1732    Some(Expression::IntLiteral(value))
1733}
1734
1735fn extract_string_literal(cursor: CXCursor) -> Option<Expression> {
1737    let extent = unsafe { clang_getCursorExtent(cursor) };
1739
1740    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1742
1743    if tu.is_null() {
1744        return Some(Expression::StringLiteral(String::new()));
1745    }
1746
1747    let mut tokens = ptr::null_mut();
1749    let mut num_tokens = 0;
1750
1751    unsafe {
1752        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1753    }
1754
1755    let mut value = String::new();
1756
1757    if num_tokens > 0 {
1758        unsafe {
1760            let token_cxstring = clang_getTokenSpelling(tu, *tokens);
1761            let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1762            if let Ok(token_str) = c_str.to_str() {
1763                value = token_str.trim_matches('"').to_string();
1765            }
1766            clang_disposeString(token_cxstring);
1767
1768            clang_disposeTokens(tu, tokens, num_tokens);
1770        }
1771    }
1772
1773    Some(Expression::StringLiteral(value))
1774}
1775
1776fn extract_variable_ref(cursor: CXCursor) -> Option<Expression> {
1778    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
1780    let name = unsafe {
1781        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
1782        let var_name = c_str.to_string_lossy().into_owned();
1783        clang_disposeString(name_cxstring);
1784        var_name
1785    };
1786
1787    Some(Expression::Variable(name))
1788}
1789
1790fn extract_binary_op(cursor: CXCursor) -> Option<Expression> {
1792    let op = extract_binary_operator(cursor)?;
1794
1795    let mut operands: Vec<Expression> = Vec::new();
1797    let operands_ptr = &mut operands as *mut Vec<Expression>;
1798
1799    unsafe {
1800        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
1801    }
1802
1803    if operands.len() != 2 {
1805        return None;
1806    }
1807
1808    Some(Expression::BinaryOp {
1809        op,
1810        left: Box::new(operands[0].clone()),
1811        right: Box::new(operands[1].clone()),
1812    })
1813}
1814
1815#[allow(non_upper_case_globals)]
1817extern "C" fn visit_binary_operand(
1818    cursor: CXCursor,
1819    _parent: CXCursor,
1820    client_data: CXClientData,
1821) -> CXChildVisitResult {
1822    let operands = unsafe { &mut *(client_data as *mut Vec<Expression>) };
1823    let kind = unsafe { clang_getCursorKind(cursor) };
1824
1825    match kind {
1826        CXCursor_IntegerLiteral => {
1827            if let Some(expr) = extract_int_literal(cursor) {
1828                operands.push(expr);
1829            }
1830            CXChildVisit_Continue
1831        }
1832        CXCursor_StringLiteral => {
1833            if let Some(expr) = extract_string_literal(cursor) {
1834                operands.push(expr);
1835            }
1836            CXChildVisit_Continue
1837        }
1838        CXCursor_DeclRefExpr => {
1839            if let Some(expr) = extract_variable_ref(cursor) {
1840                operands.push(expr);
1841            }
1842            CXChildVisit_Continue
1843        }
1844        CXCursor_BinaryOperator => {
1845            if let Some(expr) = extract_binary_op(cursor) {
1847                operands.push(expr);
1848            }
1849            CXChildVisit_Continue
1850        }
1851        CXCursor_UnaryOperator => {
1852            if let Some(expr) = extract_unary_op(cursor) {
1854                operands.push(expr);
1855            }
1856            CXChildVisit_Continue
1857        }
1858        CXCursor_ArraySubscriptExpr => {
1859            if let Some(expr) = extract_array_index(cursor) {
1861                operands.push(expr);
1862            }
1863            CXChildVisit_Continue
1864        }
1865        CXCursor_MemberRefExpr => {
1866            if let Some(expr) = extract_field_access(cursor) {
1868                operands.push(expr);
1869            }
1870            CXChildVisit_Continue
1871        }
1872        CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
1873            if let Some(expr) = extract_sizeof(cursor) {
1875                operands.push(expr);
1876                CXChildVisit_Continue
1877            } else {
1878                CXChildVisit_Recurse
1879            }
1880        }
1881        136 => {
1882            if let Some(expr) = extract_sizeof(cursor) {
1884                operands.push(expr);
1885                CXChildVisit_Continue
1886            } else {
1887                CXChildVisit_Recurse
1888            }
1889        }
1890        CXCursor_CallExpr => {
1891            if let Some(expr) = extract_function_call(cursor) {
1893                operands.push(expr);
1894            }
1895            CXChildVisit_Continue
1896        }
1897        _ => CXChildVisit_Recurse,
1898    }
1899}
1900
1901#[allow(non_upper_case_globals)]
1903fn extract_binary_operator(cursor: CXCursor) -> Option<BinaryOperator> {
1904    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
1906    if tu.is_null() {
1907        return None;
1908    }
1909
1910    let extent = unsafe { clang_getCursorExtent(cursor) };
1912
1913    let mut tokens = ptr::null_mut();
1915    let mut num_tokens = 0;
1916
1917    unsafe {
1918        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
1919    }
1920
1921    let mut operator = None;
1922
1923    let mut candidates: Vec<(usize, BinaryOperator)> = Vec::new();
1930    let mut found_first_operand = false;
1931
1932    for i in 0..num_tokens {
1933        unsafe {
1934            let token = *tokens.add(i as usize);
1935            let token_kind = clang_getTokenKind(token);
1936
1937            if token_kind == CXToken_Identifier || token_kind == CXToken_Literal {
1939                found_first_operand = true;
1940            }
1941
1942            if token_kind == CXToken_Punctuation && found_first_operand {
1944                let token_cxstring = clang_getTokenSpelling(tu, token);
1945                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
1946                if let Ok(token_str) = c_str.to_str() {
1947                    let op = match token_str {
1948                        "+" => Some(BinaryOperator::Add),
1949                        "-" => Some(BinaryOperator::Subtract),
1950                        "*" => Some(BinaryOperator::Multiply),
1951                        "/" => Some(BinaryOperator::Divide),
1952                        "%" => Some(BinaryOperator::Modulo),
1953                        "==" => Some(BinaryOperator::Equal),
1954                        "!=" => Some(BinaryOperator::NotEqual),
1955                        "<" => Some(BinaryOperator::LessThan),
1956                        ">" => Some(BinaryOperator::GreaterThan),
1957                        "<=" => Some(BinaryOperator::LessEqual),
1958                        ">=" => Some(BinaryOperator::GreaterEqual),
1959                        "&&" => Some(BinaryOperator::LogicalAnd),
1960                        "||" => Some(BinaryOperator::LogicalOr),
1961                        _ => None,
1962                    };
1963                    if let Some(op) = op {
1964                        candidates.push((i as usize, op));
1965                    }
1966                }
1967                clang_disposeString(token_cxstring);
1968            }
1969        }
1970    }
1971
1972    if !candidates.is_empty() {
1975        for (_, op) in &candidates {
1978            if matches!(op, BinaryOperator::LogicalOr) {
1979                operator = Some(*op);
1980                break;
1981            }
1982        }
1983        if operator.is_none() {
1985            for (_, op) in &candidates {
1986                if matches!(op, BinaryOperator::LogicalAnd) {
1987                    operator = Some(*op);
1988                    break;
1989                }
1990            }
1991        }
1992        if operator.is_none() {
1995            for (_, op) in &candidates {
1997                if matches!(
1998                    op,
1999                    BinaryOperator::Equal
2000                        | BinaryOperator::NotEqual
2001                        | BinaryOperator::LessThan
2002                        | BinaryOperator::GreaterThan
2003                        | BinaryOperator::LessEqual
2004                        | BinaryOperator::GreaterEqual
2005                ) {
2006                    operator = Some(*op);
2007                    break;
2008                }
2009            }
2010        }
2011        if operator.is_none() {
2013            for (_, op) in &candidates {
2014                if matches!(op, BinaryOperator::Add | BinaryOperator::Subtract) {
2015                    operator = Some(*op);
2016                    break;
2017                }
2018            }
2019        }
2020        if operator.is_none() {
2022            operator = Some(candidates[0].1);
2023        }
2024    }
2025
2026    unsafe {
2027        clang_disposeTokens(tu, tokens, num_tokens);
2028    }
2029
2030    operator
2031}
2032
2033fn extract_function_call(cursor: CXCursor) -> Option<Expression> {
2035    let name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
2037    let function = unsafe {
2038        let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
2039        let name = c_str.to_string_lossy().into_owned();
2040        clang_disposeString(name_cxstring);
2041        name
2042    };
2043
2044    #[repr(C)]
2047    struct ArgData {
2048        arguments: Vec<Expression>,
2049        skip_first_declref: bool,
2050    }
2051
2052    let mut arg_data = ArgData {
2053        arguments: Vec::new(),
2054        skip_first_declref: true, };
2056    let args_ptr = &mut arg_data as *mut ArgData;
2057
2058    unsafe {
2059        clang_visitChildren(cursor, visit_call_argument, args_ptr as CXClientData);
2060    }
2061
2062    Some(Expression::FunctionCall {
2063        function,
2064        arguments: arg_data.arguments,
2065    })
2066}
2067
2068#[allow(non_upper_case_globals)]
2074extern "C" fn visit_call_argument(
2075    cursor: CXCursor,
2076    _parent: CXCursor,
2077    client_data: CXClientData,
2078) -> CXChildVisitResult {
2079    #[repr(C)]
2080    struct ArgData {
2081        arguments: Vec<Expression>,
2082        skip_first_declref: bool,
2083    }
2084
2085    let arg_data = unsafe { &mut *(client_data as *mut ArgData) };
2087
2088    let kind = unsafe { clang_getCursorKind(cursor) };
2090
2091    match kind {
2092        CXCursor_IntegerLiteral => {
2093            if let Some(expr) = extract_int_literal(cursor) {
2094                arg_data.arguments.push(expr);
2095            }
2096            CXChildVisit_Continue
2097        }
2098        CXCursor_StringLiteral => {
2099            if let Some(expr) = extract_string_literal(cursor) {
2100                arg_data.arguments.push(expr);
2101            }
2102            CXChildVisit_Continue
2103        }
2104        CXCursor_DeclRefExpr => {
2105            if arg_data.skip_first_declref {
2108                arg_data.skip_first_declref = false;
2109                CXChildVisit_Continue
2110            } else {
2111                if let Some(expr) = extract_variable_ref(cursor) {
2112                    arg_data.arguments.push(expr);
2113                }
2114                CXChildVisit_Continue
2115            }
2116        }
2117        CXCursor_BinaryOperator => {
2118            if let Some(expr) = extract_binary_op(cursor) {
2120                arg_data.arguments.push(expr);
2121            }
2122            CXChildVisit_Continue
2123        }
2124        CXCursor_CallExpr => {
2125            if let Some(expr) = extract_function_call(cursor) {
2127                arg_data.arguments.push(expr);
2128            }
2129            CXChildVisit_Continue
2130        }
2131        CXCursor_UnaryOperator => {
2132            if let Some(expr) = extract_unary_op(cursor) {
2134                arg_data.arguments.push(expr);
2135            }
2136            CXChildVisit_Continue
2137        }
2138        CXCursor_ArraySubscriptExpr => {
2139            if let Some(expr) = extract_array_index(cursor) {
2141                arg_data.arguments.push(expr);
2142            }
2143            CXChildVisit_Continue
2144        }
2145        CXCursor_MemberRefExpr => {
2146            if let Some(expr) = extract_field_access(cursor) {
2148                arg_data.arguments.push(expr);
2149            }
2150            CXChildVisit_Continue
2151        }
2152        CXCursor_UnexposedExpr | CXCursor_ParenExpr => {
2153            if let Some(expr) = extract_sizeof(cursor) {
2155                arg_data.arguments.push(expr);
2156                CXChildVisit_Continue
2157            } else {
2158                CXChildVisit_Recurse
2159            }
2160        }
2161        136 => {
2162            if let Some(expr) = extract_sizeof(cursor) {
2164                arg_data.arguments.push(expr);
2165                CXChildVisit_Continue
2166            } else {
2167                CXChildVisit_Recurse
2168            }
2169        }
2170        _ => CXChildVisit_Continue, }
2172}
2173
2174fn extract_unary_op(cursor: CXCursor) -> Option<Expression> {
2176    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2178    if tu.is_null() {
2179        return None;
2180    }
2181
2182    let extent = unsafe { clang_getCursorExtent(cursor) };
2184
2185    let mut tokens = ptr::null_mut();
2187    let mut num_tokens = 0;
2188
2189    unsafe {
2190        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2191    }
2192
2193    let mut operator: Option<UnaryOperator> = None;
2194    let mut is_dereference = false;
2195    let mut is_increment = false;
2196    let mut is_decrement = false;
2197    let mut operator_position = 0;
2198
2199    for i in 0..num_tokens {
2201        unsafe {
2202            let token = *tokens.add(i as usize);
2203            let token_kind = clang_getTokenKind(token);
2204
2205            if token_kind == CXToken_Punctuation {
2206                let token_cxstring = clang_getTokenSpelling(tu, token);
2207                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2208                if let Ok(token_str) = c_str.to_str() {
2209                    match token_str {
2210                        "*" => {
2211                            is_dereference = true;
2212                            clang_disposeString(token_cxstring);
2213                            break;
2214                        }
2215                        "-" => {
2216                            operator = Some(UnaryOperator::Minus);
2217                            clang_disposeString(token_cxstring);
2218                            break;
2219                        }
2220                        "!" => {
2221                            operator = Some(UnaryOperator::LogicalNot);
2222                            clang_disposeString(token_cxstring);
2223                            break;
2224                        }
2225                        "~" => {
2226                            operator = Some(UnaryOperator::BitwiseNot);
2227                            clang_disposeString(token_cxstring);
2228                            break;
2229                        }
2230                        "&" => {
2231                            operator = Some(UnaryOperator::AddressOf);
2232                            clang_disposeString(token_cxstring);
2233                            break;
2234                        }
2235                        "++" => {
2236                            is_increment = true;
2237                            operator_position = i;
2238                            clang_disposeString(token_cxstring);
2239                            break;
2240                        }
2241                        "--" => {
2242                            is_decrement = true;
2243                            operator_position = i;
2244                            clang_disposeString(token_cxstring);
2245                            break;
2246                        }
2247                        _ => {}
2248                    }
2249                }
2250                clang_disposeString(token_cxstring);
2251            }
2252        }
2253    }
2254
2255    unsafe {
2256        clang_disposeTokens(tu, tokens, num_tokens);
2257    }
2258
2259    let mut operand: Option<Expression> = None;
2261    let operand_ptr = &mut operand as *mut Option<Expression>;
2262
2263    unsafe {
2264        clang_visitChildren(cursor, visit_expression, operand_ptr as CXClientData);
2265    }
2266
2267    let operand_expr = operand?;
2268
2269    if is_dereference {
2271        return Some(Expression::Dereference(Box::new(operand_expr)));
2272    }
2273
2274    if is_increment {
2276        let is_pre = operator_position == 0;
2278        if is_pre {
2279            return Some(Expression::PreIncrement {
2280                operand: Box::new(operand_expr),
2281            });
2282        } else {
2283            return Some(Expression::PostIncrement {
2284                operand: Box::new(operand_expr),
2285            });
2286        }
2287    }
2288
2289    if is_decrement {
2290        let is_pre = operator_position == 0;
2292        if is_pre {
2293            return Some(Expression::PreDecrement {
2294                operand: Box::new(operand_expr),
2295            });
2296        } else {
2297            return Some(Expression::PostDecrement {
2298                operand: Box::new(operand_expr),
2299            });
2300        }
2301    }
2302
2303    if let Some(op) = operator {
2305        return Some(Expression::UnaryOp {
2306            op,
2307            operand: Box::new(operand_expr),
2308        });
2309    }
2310
2311    None
2312}
2313
2314fn extract_array_index(cursor: CXCursor) -> Option<Expression> {
2316    let mut operands: Vec<Expression> = Vec::new();
2318    let operands_ptr = &mut operands as *mut Vec<Expression>;
2319
2320    unsafe {
2321        clang_visitChildren(cursor, visit_binary_operand, operands_ptr as CXClientData);
2322    }
2323
2324    if operands.len() != 2 {
2326        return None;
2327    }
2328
2329    Some(Expression::ArrayIndex {
2330        array: Box::new(operands[0].clone()),
2331        index: Box::new(operands[1].clone()),
2332    })
2333}
2334
2335fn extract_field_access(cursor: CXCursor) -> Option<Expression> {
2337    let field_name_cxstring = unsafe { clang_getCursorSpelling(cursor) };
2339    let field = unsafe {
2340        let c_str = CStr::from_ptr(clang_getCString(field_name_cxstring));
2341        let name = c_str.to_string_lossy().into_owned();
2342        clang_disposeString(field_name_cxstring);
2343        name
2344    };
2345
2346    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2348    if tu.is_null() {
2349        return None;
2350    }
2351
2352    let extent = unsafe { clang_getCursorExtent(cursor) };
2353    let mut tokens = ptr::null_mut();
2354    let mut num_tokens = 0;
2355
2356    unsafe {
2357        clang_tokenize(tu, extent, &mut tokens, &mut num_tokens);
2358    }
2359
2360    let mut is_arrow = false;
2361
2362    for i in 0..num_tokens {
2367        unsafe {
2368            let token = *tokens.add(i as usize);
2369            let token_kind = clang_getTokenKind(token);
2370
2371            if token_kind == CXToken_Punctuation {
2372                let token_cxstring = clang_getTokenSpelling(tu, token);
2373                let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2374                if let Ok(token_str) = c_str.to_str() {
2375                    if token_str == "->" {
2376                        is_arrow = true;
2377                        } else if token_str == "." {
2379                        is_arrow = false;
2380                        }
2382                }
2383                clang_disposeString(token_cxstring);
2384            }
2385        }
2386    }
2387
2388    unsafe {
2389        clang_disposeTokens(tu, tokens, num_tokens);
2390    }
2391
2392    let mut object_expr: Option<Expression> = None;
2394    let expr_ptr = &mut object_expr as *mut Option<Expression>;
2395
2396    unsafe {
2397        clang_visitChildren(cursor, visit_expression, expr_ptr as CXClientData);
2398    }
2399
2400    let object = object_expr?;
2401
2402    if is_arrow {
2403        Some(Expression::PointerFieldAccess {
2404            pointer: Box::new(object),
2405            field,
2406        })
2407    } else {
2408        Some(Expression::FieldAccess {
2409            object: Box::new(object),
2410            field,
2411        })
2412    }
2413}
2414
2415fn extract_sizeof(cursor: CXCursor) -> Option<Expression> {
2417    let tu = unsafe { clang_Cursor_getTranslationUnit(cursor) };
2419    if tu.is_null() {
2420        return None;
2421    }
2422
2423    let extent = unsafe { clang_getCursorExtent(cursor) };
2425
2426    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_sizeof = false;
2435    let mut type_name = String::new();
2436
2437    for i in 0..num_tokens {
2439        unsafe {
2440            let token = *tokens.add(i as usize);
2441            let token_kind = clang_getTokenKind(token);
2442            let token_cxstring = clang_getTokenSpelling(tu, token);
2443            let c_str = CStr::from_ptr(clang_getCString(token_cxstring));
2444
2445            if let Ok(token_str) = c_str.to_str() {
2446                if token_str == "sizeof" {
2447                    is_sizeof = true;
2448                } else if is_sizeof
2449                    && (token_kind == CXToken_Identifier || token_kind == CXToken_Keyword)
2450                    && token_str != "("
2451                    && token_str != ")"
2452                {
2453                    if !type_name.is_empty() {
2455                        type_name.push(' ');
2456                    }
2457                    type_name.push_str(token_str);
2458                }
2459            }
2460
2461            clang_disposeString(token_cxstring);
2462        }
2463    }
2464
2465    unsafe {
2466        clang_disposeTokens(tu, tokens, num_tokens);
2467    }
2468
2469    if is_sizeof && !type_name.is_empty() {
2470        Some(Expression::Sizeof { type_name })
2471    } else {
2472        None
2473    }
2474}
2475
2476#[allow(non_upper_case_globals)]
2478fn convert_type(cx_type: CXType) -> Option<Type> {
2479    match cx_type.kind {
2481        CXType_Void => Some(Type::Void),
2482        CXType_Int => Some(Type::Int),
2483        CXType_Float => Some(Type::Float),
2484        CXType_Double => Some(Type::Double),
2485        CXType_Char_S | CXType_Char_U => Some(Type::Char),
2486        CXType_Pointer => {
2487            let pointee = unsafe { clang_getPointeeType(cx_type) };
2489
2490            if pointee.kind == CXType_FunctionProto || pointee.kind == CXType_FunctionNoProto {
2492                let return_cx_type = unsafe { clang_getResultType(pointee) };
2495                let return_type = convert_type(return_cx_type)?;
2496
2497                let num_args = unsafe { clang_getNumArgTypes(pointee) };
2499                let mut param_types = Vec::new();
2500
2501                for i in 0..num_args {
2502                    let arg_type = unsafe { clang_getArgType(pointee, i as u32) };
2503                    if let Some(param_type) = convert_type(arg_type) {
2504                        param_types.push(param_type);
2505                    }
2506                }
2507
2508                return Some(Type::FunctionPointer {
2509                    param_types,
2510                    return_type: Box::new(return_type),
2511                });
2512            }
2513
2514            convert_type(pointee).map(|t| Type::Pointer(Box::new(t)))
2516        }
2517        CXType_FunctionProto | CXType_FunctionNoProto => {
2518            let return_cx_type = unsafe { clang_getResultType(cx_type) };
2522            let return_type = convert_type(return_cx_type)?;
2523
2524            let num_args = unsafe { clang_getNumArgTypes(cx_type) };
2526            let mut param_types = Vec::new();
2527
2528            for i in 0..num_args {
2529                let arg_type = unsafe { clang_getArgType(cx_type, i as u32) };
2530                if let Some(param_type) = convert_type(arg_type) {
2531                    param_types.push(param_type);
2532                }
2533            }
2534
2535            Some(Type::FunctionPointer {
2536                param_types,
2537                return_type: Box::new(return_type),
2538            })
2539        }
2540        CXType_Record => {
2541            let decl = unsafe { clang_getTypeDeclaration(cx_type) };
2543            let name_cxstring = unsafe { clang_getCursorSpelling(decl) };
2544            let name = unsafe {
2545                let c_str = CStr::from_ptr(clang_getCString(name_cxstring));
2546                let struct_name = c_str.to_string_lossy().into_owned();
2547                clang_disposeString(name_cxstring);
2548                struct_name
2549            };
2550            Some(Type::Struct(name))
2551        }
2552        CXType_Elaborated => {
2553            let canonical = unsafe { clang_getCanonicalType(cx_type) };
2556            convert_type(canonical)
2557        }
2558        CXType_Typedef => {
2559            let canonical = unsafe { clang_getCanonicalType(cx_type) };
2562            convert_type(canonical)
2563        }
2564        _ => None,
2565    }
2566}
2567
2568#[derive(Debug, Clone, PartialEq)]
2570pub struct SwitchCase {
2571    pub value: Option<Expression>,
2573    pub body: Vec<Statement>,
2575}
2576
2577#[derive(Debug, Clone, PartialEq)]
2579pub enum Statement {
2580    VariableDeclaration {
2582        name: String,
2584        var_type: Type,
2586        initializer: Option<Expression>,
2588    },
2589    Return(Option<Expression>),
2591    Assignment {
2593        target: String,
2595        value: Expression,
2597    },
2598    If {
2600        condition: Expression,
2602        then_block: Vec<Statement>,
2604        else_block: Option<Vec<Statement>>,
2606    },
2607    For {
2609        init: Option<Box<Statement>>,
2611        condition: Option<Expression>,
2613        increment: Option<Box<Statement>>,
2615        body: Vec<Statement>,
2617    },
2618    While {
2620        condition: Expression,
2622        body: Vec<Statement>,
2624    },
2625    DerefAssignment {
2627        target: Expression,
2629        value: Expression,
2631    },
2632    ArrayIndexAssignment {
2634        array: Box<Expression>,
2636        index: Box<Expression>,
2638        value: Expression,
2640    },
2641    FieldAssignment {
2643        object: Expression,
2645        field: String,
2647        value: Expression,
2649    },
2650    Break,
2652    Continue,
2654    Switch {
2656        condition: Expression,
2658        cases: Vec<SwitchCase>,
2660        default_case: Option<Vec<Statement>>,
2662    },
2663    PostIncrement {
2665        target: String,
2667    },
2668    PreIncrement {
2670        target: String,
2672    },
2673    PostDecrement {
2675        target: String,
2677    },
2678    PreDecrement {
2680        target: String,
2682    },
2683    CompoundAssignment {
2685        target: String,
2687        op: BinaryOperator,
2689        value: Expression,
2691    },
2692    FunctionCall {
2694        function: String,
2696        arguments: Vec<Expression>,
2698    },
2699}
2700
2701impl Statement {
2702    pub fn is_string_function_call(&self) -> bool {
2704        match self {
2705            Statement::FunctionCall { function, .. } => {
2706                matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
2707            }
2708            _ => false,
2709        }
2710    }
2711
2712    pub fn is_function_call(&self) -> bool {
2714        matches!(self, Statement::FunctionCall { .. })
2715    }
2716
2717    pub fn as_function_call(&self) -> Option<&Expression> {
2726        None
2727    }
2728}
2729
2730#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2732pub enum UnaryOperator {
2733    Minus,
2735    LogicalNot,
2737    BitwiseNot,
2739    AddressOf,
2741}
2742
2743#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2745pub enum BinaryOperator {
2746    Add,
2748    Subtract,
2750    Multiply,
2752    Divide,
2754    Modulo,
2756    Equal,
2758    NotEqual,
2760    LessThan,
2762    GreaterThan,
2764    LessEqual,
2766    GreaterEqual,
2768    LogicalAnd,
2770    LogicalOr,
2772}
2773
2774#[derive(Debug, Clone, PartialEq)]
2776pub enum Expression {
2777    IntLiteral(i32),
2779    StringLiteral(String),
2781    Variable(String),
2783    BinaryOp {
2785        op: BinaryOperator,
2787        left: Box<Expression>,
2789        right: Box<Expression>,
2791    },
2792    FunctionCall {
2794        function: String,
2796        arguments: Vec<Expression>,
2798    },
2799    Dereference(Box<Expression>),
2801    UnaryOp {
2803        op: UnaryOperator,
2805        operand: Box<Expression>,
2807    },
2808    ArrayIndex {
2810        array: Box<Expression>,
2812        index: Box<Expression>,
2814    },
2815    FieldAccess {
2817        object: Box<Expression>,
2819        field: String,
2821    },
2822    PointerFieldAccess {
2824        pointer: Box<Expression>,
2826        field: String,
2828    },
2829    PostIncrement {
2831        operand: Box<Expression>,
2833    },
2834    PreIncrement {
2836        operand: Box<Expression>,
2838    },
2839    PostDecrement {
2841        operand: Box<Expression>,
2843    },
2844    PreDecrement {
2846        operand: Box<Expression>,
2848    },
2849    Sizeof {
2851        type_name: String,
2853    },
2854}
2855
2856impl Expression {
2857    pub fn is_string_function_call(&self) -> bool {
2859        match self {
2860            Expression::FunctionCall { function, .. } => {
2861                matches!(function.as_str(), "strlen" | "strcmp" | "strcpy" | "strdup")
2862            }
2863            _ => false,
2864        }
2865    }
2866
2867    pub fn string_function_name(&self) -> Option<&str> {
2869        match self {
2870            Expression::FunctionCall { function, .. } if self.is_string_function_call() => {
2871                Some(function.as_str())
2872            }
2873            _ => None,
2874        }
2875    }
2876
2877    pub fn has_string_literal_argument(&self) -> bool {
2879        match self {
2880            Expression::FunctionCall { arguments, .. } => arguments
2881                .iter()
2882                .any(|arg| matches!(arg, Expression::StringLiteral(_))),
2883            _ => false,
2884        }
2885    }
2886}
2887
2888#[derive(Debug, Clone, PartialEq)]
2890pub struct Typedef {
2891    pub name: String,
2893    pub underlying_type: Type,
2895}
2896
2897impl Typedef {
2898    pub fn new(name: String, underlying_type: Type) -> Self {
2900        Self {
2901            name,
2902            underlying_type,
2903        }
2904    }
2905
2906    pub fn name(&self) -> &str {
2908        &self.name
2909    }
2910
2911    pub fn underlying_type(&self) -> &str {
2913        match &self.underlying_type {
2915            Type::Void => "void",
2916            Type::Int => "int",
2917            Type::Float => "float",
2918            Type::Double => "double",
2919            Type::Char => "char",
2920            Type::Pointer(inner) => match **inner {
2921                Type::Char => "char*",
2922                Type::Int => "int*",
2923                Type::Float => "float*",
2924                Type::Double => "double*",
2925                Type::Void => "void*",
2926                _ => "pointer",
2927            },
2928            Type::Struct(name) => name,
2929            Type::FunctionPointer { .. } => "function pointer",
2930        }
2931    }
2932
2933    pub fn is_pointer(&self) -> bool {
2935        matches!(self.underlying_type, Type::Pointer(_))
2936    }
2937
2938    pub fn is_struct(&self) -> bool {
2940        matches!(self.underlying_type, Type::Struct(_))
2941    }
2942
2943    pub fn is_function_pointer(&self) -> bool {
2945        matches!(self.underlying_type, Type::FunctionPointer { .. })
2946    }
2947
2948    pub fn is_array(&self) -> bool {
2950        false
2952    }
2953}
2954
2955#[derive(Debug, Clone, PartialEq)]
2957pub struct StructField {
2958    pub name: String,
2960    pub field_type: Type,
2962}
2963
2964impl StructField {
2965    pub fn new(name: String, field_type: Type) -> Self {
2967        Self { name, field_type }
2968    }
2969
2970    pub fn name(&self) -> &str {
2972        &self.name
2973    }
2974
2975    pub fn is_function_pointer(&self) -> bool {
2977        matches!(self.field_type, Type::FunctionPointer { .. })
2978    }
2979}
2980
2981#[derive(Debug, Clone, PartialEq)]
2983pub struct Struct {
2984    pub name: String,
2986    pub fields: Vec<StructField>,
2988}
2989
2990impl Struct {
2991    pub fn new(name: String, fields: Vec<StructField>) -> Self {
2993        Self { name, fields }
2994    }
2995
2996    pub fn name(&self) -> &str {
2998        &self.name
2999    }
3000
3001    pub fn fields(&self) -> &[StructField] {
3003        &self.fields
3004    }
3005}
3006
3007#[derive(Debug, Clone, PartialEq)]
3009pub struct Variable {
3010    name: String,
3012    var_type: Type,
3014    initializer: Option<Expression>,
3016}
3017
3018impl Variable {
3019    pub fn new(name: String, var_type: Type) -> Self {
3021        Self {
3022            name,
3023            var_type,
3024            initializer: None,
3025        }
3026    }
3027
3028    pub fn new_with_initializer(name: String, var_type: Type, initializer: Expression) -> Self {
3030        Self {
3031            name,
3032            var_type,
3033            initializer: Some(initializer),
3034        }
3035    }
3036
3037    pub fn name(&self) -> &str {
3039        &self.name
3040    }
3041
3042    pub fn var_type(&self) -> &Type {
3044        &self.var_type
3045    }
3046
3047    pub fn is_function_pointer(&self) -> bool {
3049        matches!(self.var_type, Type::FunctionPointer { .. })
3050    }
3051
3052    pub fn function_pointer_param_count(&self) -> usize {
3054        match &self.var_type {
3055            Type::FunctionPointer { param_types, .. } => param_types.len(),
3056            _ => 0,
3057        }
3058    }
3059
3060    pub fn function_pointer_has_void_return(&self) -> bool {
3062        match &self.var_type {
3063            Type::FunctionPointer { return_type, .. } => matches!(**return_type, Type::Void),
3064            _ => false,
3065        }
3066    }
3067
3068    pub fn is_string_literal(&self) -> bool {
3080        let is_char_ptr =
3082            matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3083
3084        if let Some(initializer) = &self.initializer {
3086            is_char_ptr && matches!(initializer, Expression::StringLiteral(_))
3087        } else {
3088            false
3089        }
3090    }
3091
3092    pub fn is_string_buffer(&self) -> bool {
3102        let is_char_ptr =
3104            matches!(self.var_type, Type::Pointer(ref inner) if **inner == Type::Char);
3105
3106        if let Some(Expression::FunctionCall { function, .. }) = &self.initializer {
3108            is_char_ptr && (function == "malloc" || function == "calloc")
3109        } else {
3110            false
3111        }
3112    }
3113
3114    pub fn initializer(&self) -> Option<&Expression> {
3118        self.initializer.as_ref()
3119    }
3120}
3121
3122#[derive(Debug, Clone, PartialEq)]
3124pub struct Ast {
3125    functions: Vec<Function>,
3126    typedefs: Vec<Typedef>,
3127    structs: Vec<Struct>,
3128    macros: Vec<MacroDefinition>,
3129    variables: Vec<Variable>,
3130}
3131
3132#[derive(Debug, Clone, PartialEq)]
3162pub struct MacroDefinition {
3163    pub name: String,
3165    pub parameters: Vec<String>,
3167    pub body: String,
3169}
3170
3171impl MacroDefinition {
3172    pub fn new_object_like(name: String, body: String) -> Self {
3174        Self {
3175            name,
3176            parameters: vec![],
3177            body,
3178        }
3179    }
3180
3181    pub fn new_function_like(name: String, parameters: Vec<String>, body: String) -> Self {
3183        Self {
3184            name,
3185            parameters,
3186            body,
3187        }
3188    }
3189
3190    pub fn name(&self) -> &str {
3192        &self.name
3193    }
3194
3195    pub fn parameters(&self) -> &[String] {
3197        &self.parameters
3198    }
3199
3200    pub fn body(&self) -> &str {
3202        &self.body
3203    }
3204
3205    pub fn is_function_like(&self) -> bool {
3207        !self.parameters.is_empty()
3208    }
3209
3210    pub fn is_object_like(&self) -> bool {
3212        self.parameters.is_empty()
3213    }
3214}
3215
3216impl Ast {
3217    pub fn new() -> Self {
3219        Self {
3220            functions: Vec::new(),
3221            typedefs: Vec::new(),
3222            structs: Vec::new(),
3223            macros: Vec::new(),
3224            variables: Vec::new(),
3225        }
3226    }
3227
3228    pub fn functions(&self) -> &[Function] {
3230        &self.functions
3231    }
3232
3233    pub fn add_function(&mut self, function: Function) {
3235        self.functions.push(function);
3236    }
3237
3238    pub fn typedefs(&self) -> &[Typedef] {
3240        &self.typedefs
3241    }
3242
3243    pub fn add_typedef(&mut self, typedef: Typedef) {
3245        self.typedefs.push(typedef);
3246    }
3247
3248    pub fn structs(&self) -> &[Struct] {
3250        &self.structs
3251    }
3252
3253    pub fn add_struct(&mut self, struct_def: Struct) {
3255        self.structs.push(struct_def);
3256    }
3257
3258    pub fn macros(&self) -> &[MacroDefinition] {
3260        &self.macros
3261    }
3262
3263    pub fn add_macro(&mut self, macro_def: MacroDefinition) {
3265        self.macros.push(macro_def);
3266    }
3267
3268    pub fn variables(&self) -> &[Variable] {
3270        &self.variables
3271    }
3272
3273    pub fn add_variable(&mut self, variable: Variable) {
3275        self.variables.push(variable);
3276    }
3277}
3278
3279impl Default for Ast {
3280    fn default() -> Self {
3281        Self::new()
3282    }
3283}
3284
3285#[derive(Debug, Clone, PartialEq)]
3287pub struct Function {
3288    pub name: String,
3290    pub return_type: Type,
3292    pub parameters: Vec<Parameter>,
3294    pub body: Vec<Statement>,
3296}
3297
3298impl Function {
3299    pub fn new(name: String, return_type: Type, parameters: Vec<Parameter>) -> Self {
3301        Self {
3302            name,
3303            return_type,
3304            parameters,
3305            body: Vec::new(),
3306        }
3307    }
3308
3309    pub fn new_with_body(
3311        name: String,
3312        return_type: Type,
3313        parameters: Vec<Parameter>,
3314        body: Vec<Statement>,
3315    ) -> Self {
3316        Self {
3317            name,
3318            return_type,
3319            parameters,
3320            body,
3321        }
3322    }
3323}
3324
3325#[derive(Debug, Clone, PartialEq)]
3327pub enum Type {
3328    Void,
3330    Int,
3332    Float,
3334    Double,
3336    Char,
3338    Pointer(Box<Type>),
3340    Struct(String),
3342    FunctionPointer {
3344        param_types: Vec<Type>,
3346        return_type: Box<Type>,
3348    },
3349}
3350
3351#[derive(Debug, Clone, PartialEq)]
3353pub struct Parameter {
3354    pub name: String,
3356    pub param_type: Type,
3358}
3359
3360impl Parameter {
3361    pub fn new(name: String, param_type: Type) -> Self {
3363        Self { name, param_type }
3364    }
3365
3366    pub fn is_function_pointer(&self) -> bool {
3368        matches!(self.param_type, Type::FunctionPointer { .. })
3369    }
3370
3371    pub fn is_const_char_pointer(&self) -> bool {
3379        matches!(self.param_type, Type::Pointer(ref inner) if matches!(**inner, Type::Char))
3380    }
3381}
3382
3383#[cfg(test)]
3384#[path = "parser_tests.rs"]
3385mod parser_tests;
3386
3387#[cfg(test)]
3388#[path = "pointer_arithmetic_tests.rs"]
3389mod pointer_arithmetic_tests;
3390
3391#[cfg(test)]
3392#[path = "break_continue_tests.rs"]
3393mod break_continue_tests;