agcodex_ast/
types.rs

1//! Core types for AST operations
2
3use crate::language_registry::Language;
4use serde::Deserialize;
5use serde::Serialize;
6use tree_sitter::Tree;
7
8/// Parsed AST with metadata
9#[derive(Debug, Clone)]
10pub struct ParsedAst {
11    pub tree: Tree,
12    pub source: String,
13    pub language: Language,
14    pub root_node: AstNode,
15}
16
17/// AST node representation with location metadata
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct AstNode {
20    pub kind: String,
21    pub start_byte: usize,
22    pub end_byte: usize,
23    pub start_position: (usize, usize), // (row, column)
24    pub end_position: (usize, usize),   // (row, column)
25    pub children_count: usize,
26}
27
28/// Source location with precise file:line:column metadata
29#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
30pub struct SourceLocation {
31    pub file_path: String,
32    pub start_line: usize,
33    pub start_column: usize,
34    pub end_line: usize,
35    pub end_column: usize,
36    pub byte_range: (usize, usize),
37}
38
39impl SourceLocation {
40    /// Create a new source location
41    pub fn new(
42        file_path: impl Into<String>,
43        start_line: usize,
44        start_column: usize,
45        end_line: usize,
46        end_column: usize,
47        byte_range: (usize, usize),
48    ) -> Self {
49        Self {
50            file_path: file_path.into(),
51            start_line,
52            start_column,
53            end_line,
54            end_column,
55            byte_range,
56        }
57    }
58
59    /// Format as file:line:column string
60    pub fn as_string(&self) -> String {
61        format!(
62            "{}:{}:{}",
63            self.file_path, self.start_line, self.start_column
64        )
65    }
66
67    /// Format with range
68    pub fn to_range_string(&self) -> String {
69        if self.start_line == self.end_line {
70            format!(
71                "{}:{}:{}-{}",
72                self.file_path, self.start_line, self.start_column, self.end_column
73            )
74        } else {
75            format!(
76                "{}:{}:{}-{}:{}",
77                self.file_path, self.start_line, self.start_column, self.end_line, self.end_column
78            )
79        }
80    }
81}
82
83impl std::fmt::Display for SourceLocation {
84    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85        write!(
86            f,
87            "{}:{}:{}",
88            self.file_path, self.start_line, self.start_column
89        )
90    }
91}
92
93/// AST node kind classification
94#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
95pub enum AstNodeKind {
96    Function,
97    Class,
98    Struct,
99    Enum,
100    Interface,
101    Trait,
102    Module,
103    Variable,
104    Constant,
105    Type,
106    Import,
107    Comment,
108    Other,
109}
110
111impl AstNodeKind {
112    /// Determine node kind from tree-sitter node type
113    pub fn from_node_type(node_type: &str) -> Self {
114        match node_type {
115            "function_declaration"
116            | "function_definition"
117            | "function_item"
118            | "method_declaration"
119            | "method_definition" => Self::Function,
120
121            "class_declaration" | "class_definition" => Self::Class,
122
123            "struct_item" | "struct_declaration" => Self::Struct,
124
125            "enum_item" | "enum_declaration" => Self::Enum,
126
127            "interface_declaration" | "protocol_declaration" => Self::Interface,
128
129            "trait_item" | "trait_declaration" => Self::Trait,
130
131            "module" | "module_declaration" | "namespace" => Self::Module,
132
133            "variable_declaration" | "let_declaration" | "const_item" => Self::Variable,
134
135            "constant_declaration" => Self::Constant,
136
137            "type_alias" | "type_definition" | "typedef" => Self::Type,
138
139            "import_statement" | "use_declaration" | "import_declaration" => Self::Import,
140
141            "comment" | "line_comment" | "block_comment" | "doc_comment" => Self::Comment,
142
143            _ => Self::Other,
144        }
145    }
146}
147
148/// Code chunk for hierarchical organization
149#[derive(Debug, Clone, Serialize, Deserialize)]
150pub struct CodeChunk {
151    pub id: String,
152    pub level: ChunkLevel,
153    pub kind: AstNodeKind,
154    pub name: String,
155    pub content: String,
156    pub location: SourceLocation,
157    pub parent_id: Option<String>,
158    pub children_ids: Vec<String>,
159    pub metadata: ChunkMetadata,
160}
161
162/// Hierarchical chunk level
163#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
164pub enum ChunkLevel {
165    File,
166    Module,
167    Class,
168    Function,
169    Block,
170}
171
172impl ChunkLevel {
173    /// Get display name
174    pub const fn name(&self) -> &'static str {
175        match self {
176            Self::File => "File",
177            Self::Module => "Module",
178            Self::Class => "Class",
179            Self::Function => "Function",
180            Self::Block => "Block",
181        }
182    }
183}
184
185/// Metadata for a code chunk
186#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct ChunkMetadata {
188    pub language: Language,
189    pub complexity: usize,
190    pub token_count: usize,
191    pub line_count: usize,
192    pub has_tests: bool,
193    pub has_docs: bool,
194    pub visibility: Visibility,
195    pub dependencies: Vec<String>,
196    pub symbols_defined: Vec<String>,
197    pub symbols_used: Vec<String>,
198}
199
200/// Code visibility level
201#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
202pub enum Visibility {
203    Public,
204    Protected,
205    Private,
206    Internal,
207    Package,
208}
209
210impl Visibility {
211    /// Parse visibility from source text
212    pub fn from_text(text: &str) -> Self {
213        if text.contains("public") || text.contains("pub") || text.contains("export") {
214            Self::Public
215        } else if text.contains("protected") {
216            Self::Protected
217        } else if text.contains("private") || text.contains("priv") {
218            Self::Private
219        } else if text.contains("internal") {
220            Self::Internal
221        } else if text.contains("package") {
222            Self::Package
223        } else {
224            // Default visibility varies by language
225            Self::Public
226        }
227    }
228}