codeprism_lang_python/
types.rs

1//! Types for Python parser
2//!
3//! These types mirror the ones in codeprism_core::ast but are defined here to avoid
4//! circular dependencies. The parser returns these types which are then
5//! converted to codeprism types by the caller.
6
7use blake3::Hasher;
8use serde::{Deserialize, Serialize};
9use std::path::{Path, PathBuf};
10
11/// Unique identifier for AST nodes
12#[derive(Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
13pub struct NodeId([u8; 16]);
14
15impl NodeId {
16    /// Create a new NodeId from components
17    pub fn new(repo_id: &str, file_path: &Path, span: &Span, kind: &NodeKind) -> Self {
18        let mut hasher = Hasher::new();
19        hasher.update(repo_id.as_bytes());
20        hasher.update(file_path.to_string_lossy().as_bytes());
21        hasher.update(&span.start_byte.to_le_bytes());
22        hasher.update(&span.end_byte.to_le_bytes());
23        hasher.update(format!("{:?}", kind).as_bytes());
24
25        let hash = hasher.finalize();
26        let mut id = [0u8; 16];
27        id.copy_from_slice(&hash.as_bytes()[..16]);
28        Self(id)
29    }
30
31    /// Get the ID as a hex string
32    pub fn to_hex(&self) -> String {
33        hex::encode(self.0)
34    }
35}
36
37impl std::fmt::Debug for NodeId {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        write!(f, "NodeId({})", &self.to_hex()[..8])
40    }
41}
42
43/// Types of nodes in the Universal AST
44#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
45#[serde(rename_all = "snake_case")]
46pub enum NodeKind {
47    /// A module or file
48    Module,
49    /// A class definition
50    Class,
51    /// A function definition
52    Function,
53    /// A method definition
54    Method,
55    /// A function/method parameter
56    Parameter,
57    /// A variable declaration
58    Variable,
59    /// A function/method call
60    Call,
61    /// An import statement
62    Import,
63    /// A literal value
64    Literal,
65    /// An HTTP route definition
66    Route,
67    /// A SQL query
68    SqlQuery,
69    /// An event emission
70    Event,
71    /// Unknown node type
72    Unknown,
73}
74
75/// Types of edges between nodes
76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
77#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
78pub enum EdgeKind {
79    /// Function/method call
80    Calls,
81    /// Variable/field read
82    Reads,
83    /// Variable/field write
84    Writes,
85    /// Module import
86    Imports,
87    /// Event emission
88    Emits,
89    /// HTTP route mapping
90    RoutesTo,
91    /// Exception raising
92    Raises,
93    /// Type inheritance
94    Extends,
95    /// Interface implementation
96    Implements,
97}
98
99/// Source code location
100#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
101pub struct Span {
102    /// Starting byte offset
103    pub start_byte: usize,
104    /// Ending byte offset (exclusive)
105    pub end_byte: usize,
106    /// Starting line (1-indexed)
107    pub start_line: usize,
108    /// Ending line (1-indexed)
109    pub end_line: usize,
110    /// Starting column (1-indexed)
111    pub start_column: usize,
112    /// Ending column (1-indexed)
113    pub end_column: usize,
114}
115
116impl Span {
117    /// Create a new span
118    pub fn new(
119        start_byte: usize,
120        end_byte: usize,
121        start_line: usize,
122        end_line: usize,
123        start_column: usize,
124        end_column: usize,
125    ) -> Self {
126        Self {
127            start_byte,
128            end_byte,
129            start_line,
130            end_line,
131            start_column,
132            end_column,
133        }
134    }
135
136    /// Create a span from tree-sitter node
137    pub fn from_node(node: &tree_sitter::Node) -> Self {
138        let start_pos = node.start_position();
139        let end_pos = node.end_position();
140
141        Self {
142            start_byte: node.start_byte(),
143            end_byte: node.end_byte(),
144            start_line: start_pos.row + 1, // tree-sitter uses 0-indexed
145            end_line: end_pos.row + 1,
146            start_column: start_pos.column + 1,
147            end_column: end_pos.column + 1,
148        }
149    }
150}
151
152/// Programming language
153#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
154#[serde(rename_all = "lowercase")]
155pub enum Language {
156    /// Python
157    Python,
158}
159
160/// A node in the Universal AST
161#[derive(Debug, Clone, Serialize, Deserialize)]
162pub struct Node {
163    /// Unique identifier
164    pub id: NodeId,
165    /// Node type
166    pub kind: NodeKind,
167    /// Node name (e.g., function name)
168    pub name: String,
169    /// Programming language
170    pub lang: Language,
171    /// Source file path
172    pub file: PathBuf,
173    /// Source location
174    pub span: Span,
175    /// Optional type signature
176    pub signature: Option<String>,
177    /// Additional metadata
178    pub metadata: serde_json::Value,
179}
180
181impl Node {
182    /// Create a new node
183    pub fn new(
184        repo_id: &str,
185        kind: NodeKind,
186        name: String,
187        lang: Language,
188        file: PathBuf,
189        span: Span,
190    ) -> Self {
191        let id = NodeId::new(repo_id, &file, &span, &kind);
192        Self {
193            id,
194            kind,
195            name,
196            lang,
197            file,
198            span,
199            signature: None,
200            metadata: serde_json::Value::Null,
201        }
202    }
203}
204
205/// An edge between nodes
206#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
207pub struct Edge {
208    /// Source node ID
209    pub source: NodeId,
210    /// Target node ID
211    pub target: NodeId,
212    /// Edge type
213    pub kind: EdgeKind,
214}
215
216impl Edge {
217    /// Create a new edge
218    pub fn new(source: NodeId, target: NodeId, kind: EdgeKind) -> Self {
219        Self {
220            source,
221            target,
222            kind,
223        }
224    }
225}