codebank/parser/lang/
c.rs

1use crate::{CParser, Error, FileUnit, LanguageParser, Result};
2use std::fs;
3use std::ops::{Deref, DerefMut};
4use std::path::Path;
5use tree_sitter::Parser;
6
7impl CParser {
8    pub fn try_new() -> Result<Self> {
9        let mut parser = Parser::new();
10        let language = tree_sitter_c::LANGUAGE;
11        parser
12            .set_language(&language.into())
13            .map_err(|e| Error::TreeSitter(e.to_string()))?;
14        Ok(Self { parser })
15    }
16}
17
18impl LanguageParser for CParser {
19    fn parse_file(&mut self, file_path: &Path) -> Result<FileUnit> {
20        // Basic implementation for now - just reads the file and returns an empty FileUnit
21        // In a production implementation, this would parse C code using tree-sitter
22        let source_code = fs::read_to_string(file_path).map_err(Error::Io)?;
23
24        // Parse the file with tree-sitter
25        let tree = self
26            .parse(source_code.as_bytes(), None)
27            .ok_or_else(|| Error::Parse("Failed to parse file".to_string()))?;
28
29        let root_node = tree.root_node();
30
31        // Extract file-level documentation if present (comments at the beginning)
32        let mut document = None;
33        let mut cursor = root_node.walk();
34        let mut first_comments = Vec::new();
35
36        for node in root_node.children(&mut cursor) {
37            if node.kind() == "comment" {
38                if let Ok(comment) = node.utf8_text(source_code.as_bytes()) {
39                    let cleaned = comment
40                        .trim_start_matches("/*")
41                        .trim_end_matches("*/")
42                        .trim()
43                        .to_string();
44                    first_comments.push(cleaned);
45                }
46            } else {
47                break; // Stop at first non-comment
48            }
49        }
50
51        if !first_comments.is_empty() {
52            document = Some(first_comments.join("\n"));
53        }
54
55        // Extract declares (includes, defines, etc.)
56        let mut declares = Vec::new();
57        cursor = root_node.walk();
58
59        for node in root_node.children(&mut cursor) {
60            match node.kind() {
61                "preproc_include" => {
62                    if let Ok(include_text) = node.utf8_text(source_code.as_bytes()) {
63                        declares.push(crate::DeclareStatements {
64                            source: include_text.to_string(),
65                            kind: crate::DeclareKind::Import,
66                        });
67                    }
68                }
69                "preproc_def" | "preproc_function_def" => {
70                    if let Ok(def_text) = node.utf8_text(source_code.as_bytes()) {
71                        declares.push(crate::DeclareStatements {
72                            source: def_text.to_string(),
73                            kind: crate::DeclareKind::Other("define".to_string()),
74                        });
75                    }
76                }
77                _ => continue,
78            }
79        }
80
81        Ok(FileUnit {
82            path: file_path.to_path_buf(),
83            document,
84            declares,
85            source: Some(source_code),
86            ..Default::default()
87        })
88    }
89}
90
91impl Deref for CParser {
92    type Target = Parser;
93
94    fn deref(&self) -> &Self::Target {
95        &self.parser
96    }
97}
98
99impl DerefMut for CParser {
100    fn deref_mut(&mut self) -> &mut Self::Target {
101        &mut self.parser
102    }
103}