codeprism_lang_java/
types.rs

1//! Types for Java 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 for Java
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
72    // Java-specific node types
73    /// An interface definition
74    Interface,
75    /// An enum definition
76    Enum,
77    /// A package declaration
78    Package,
79    /// An annotation definition
80    Annotation,
81    /// A constructor definition
82    Constructor,
83    /// A field in a class
84    Field,
85    /// A static initialization block
86    StaticBlock,
87    /// An instance initialization block
88    InstanceBlock,
89    /// A try-catch-finally block
90    TryBlock,
91    /// A catch clause
92    CatchClause,
93    /// A finally clause
94    FinallyClause,
95    /// A throw statement
96    ThrowStatement,
97    /// A lambda expression
98    Lambda,
99    /// A method reference
100    MethodReference,
101    /// A generic type parameter
102    TypeParameter,
103    /// A wildcard type
104    WildcardType,
105    /// An array creation expression
106    ArrayCreation,
107    /// A synchronized block
108    SynchronizedBlock,
109    /// An assert statement
110    AssertStatement,
111
112    /// Unknown node type
113    Unknown,
114}
115
116/// Types of edges between nodes for Java
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
118#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
119pub enum EdgeKind {
120    /// Function/method call
121    Calls,
122    /// Variable/field read
123    Reads,
124    /// Variable/field write
125    Writes,
126    /// Module import
127    Imports,
128    /// Event emission
129    Emits,
130    /// HTTP route mapping
131    RoutesTo,
132    /// Exception raising
133    Raises,
134    /// Type inheritance
135    Extends,
136    /// Interface implementation
137    Implements,
138
139    // Java-specific edge types
140    /// Interface implementation (for a class)
141    ImplementsInterface,
142    /// Package import relationship
143    ImportsPackage,
144    /// Annotation application
145    Annotates,
146    /// Generic type parameter binding
147    TypeParameterBinds,
148    /// Exception throwing
149    Throws,
150    /// Exception catching
151    Catches,
152    /// Method overriding
153    Overrides,
154    /// Field access
155    Accesses,
156    /// Type casting
157    Casts,
158    /// Instance creation
159    Instantiates,
160    /// Static member access
161    StaticAccess,
162    /// Synchronized on object
163    Synchronizes,
164    /// Lambda captures variable
165    Captures,
166    /// Containment relationship
167    Contains,
168}
169
170/// Source code location
171#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
172pub struct Span {
173    /// Starting byte offset
174    pub start_byte: usize,
175    /// Ending byte offset (exclusive)
176    pub end_byte: usize,
177    /// Starting line (1-indexed)
178    pub start_line: usize,
179    /// Ending line (1-indexed)
180    pub end_line: usize,
181    /// Starting column (1-indexed)
182    pub start_column: usize,
183    /// Ending column (1-indexed)
184    pub end_column: usize,
185}
186
187impl Span {
188    /// Create a new span
189    pub fn new(
190        start_byte: usize,
191        end_byte: usize,
192        start_line: usize,
193        end_line: usize,
194        start_column: usize,
195        end_column: usize,
196    ) -> Self {
197        Self {
198            start_byte,
199            end_byte,
200            start_line,
201            end_line,
202            start_column,
203            end_column,
204        }
205    }
206
207    /// Create a span from tree-sitter node
208    pub fn from_node(node: &tree_sitter::Node) -> Self {
209        let start_pos = node.start_position();
210        let end_pos = node.end_position();
211
212        Self {
213            start_byte: node.start_byte(),
214            end_byte: node.end_byte(),
215            start_line: start_pos.row + 1, // tree-sitter uses 0-indexed
216            end_line: end_pos.row + 1,
217            start_column: start_pos.column + 1,
218            end_column: end_pos.column + 1,
219        }
220    }
221}
222
223/// Programming language
224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
225#[serde(rename_all = "lowercase")]
226pub enum Language {
227    /// Java
228    Java,
229    /// For compatibility with other parsers
230    Python,
231    Rust,
232}
233
234/// A node in the Universal AST
235#[derive(Debug, Clone, Serialize, Deserialize)]
236pub struct Node {
237    /// Unique identifier
238    pub id: NodeId,
239    /// Node type
240    pub kind: NodeKind,
241    /// Node name (e.g., class name, method name)
242    pub name: String,
243    /// Programming language
244    pub lang: Language,
245    /// Source file path
246    pub file: PathBuf,
247    /// Source location
248    pub span: Span,
249    /// Optional type signature
250    pub signature: Option<String>,
251    /// Additional metadata (Java-specific info like visibility, modifiers, etc.)
252    pub metadata: serde_json::Value,
253}
254
255impl Node {
256    /// Create a new node
257    pub fn new(
258        repo_id: &str,
259        kind: NodeKind,
260        name: String,
261        lang: Language,
262        file: PathBuf,
263        span: Span,
264    ) -> Self {
265        let id = NodeId::new(repo_id, &file, &span, &kind);
266        Self {
267            id,
268            kind,
269            name,
270            lang,
271            file,
272            span,
273            signature: None,
274            metadata: serde_json::Value::Null,
275        }
276    }
277
278    /// Set metadata for the node
279    pub fn with_metadata(mut self, metadata: serde_json::Value) -> Self {
280        self.metadata = metadata;
281        self
282    }
283
284    /// Set signature for the node
285    pub fn with_signature(mut self, signature: String) -> Self {
286        self.signature = Some(signature);
287        self
288    }
289}
290
291/// An edge between nodes
292#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
293pub struct Edge {
294    /// Source node ID
295    pub source: NodeId,
296    /// Target node ID
297    pub target: NodeId,
298    /// Edge type
299    pub kind: EdgeKind,
300}
301
302impl Edge {
303    /// Create a new edge
304    pub fn new(source: NodeId, target: NodeId, kind: EdgeKind) -> Self {
305        Self {
306            source,
307            target,
308            kind,
309        }
310    }
311}