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;