Skip to main content

infigraph_core/lang/
mod.rs

1mod registry;
2
3pub use registry::LanguageRegistry;
4
5use anyhow::Result;
6use serde::Deserialize;
7use tree_sitter::{Language, Query};
8
9use crate::model::{Relation, Symbol};
10
11/// A custom edge type that a language pack can define beyond the standard
12/// CALLS/IMPORTS/INHERITS model. Custom edges are populated during extraction
13/// when capture groups matching `@{capture}.source` / `@{capture}.target`
14/// are found in relations.scm.
15#[derive(Debug, Clone, Deserialize)]
16pub struct CustomEdgeDef {
17    pub name: String,
18    pub capture: String,
19}
20
21/// Trait for custom extraction backends (e.g., JVM grammar plugins).
22pub trait CustomExtractor: Send + Sync {
23    fn extract(
24        &self,
25        path: &str,
26        source: &[u8],
27        language: &str,
28    ) -> Result<(Vec<Symbol>, Vec<Relation>)>;
29}
30
31/// Parser backend — tree-sitter or runtime-loaded custom extractor.
32pub enum ParserBackend {
33    TreeSitter {
34        grammar: Language,
35        entity_query: Query,
36        relation_query: Query,
37    },
38    Custom(Box<dyn CustomExtractor>),
39}
40
41/// A language pack bundles a parser backend with file extension mappings.
42pub struct LanguagePack {
43    pub name: String,
44    pub extensions: Vec<String>,
45    pub backend: ParserBackend,
46    pub custom_edges: Vec<CustomEdgeDef>,
47}
48
49impl LanguagePack {
50    /// Create a tree-sitter-backed language pack from a grammar and raw query strings.
51    pub fn new(
52        name: &str,
53        extensions: Vec<&str>,
54        grammar: Language,
55        entity_query_src: &str,
56        relation_query_src: &str,
57    ) -> Result<Self> {
58        let entity_query = Query::new(&grammar, entity_query_src)?;
59        let relation_query = Query::new(&grammar, relation_query_src)?;
60        Ok(Self {
61            name: name.to_string(),
62            extensions: extensions.into_iter().map(String::from).collect(),
63            backend: ParserBackend::TreeSitter {
64                grammar,
65                entity_query,
66                relation_query,
67            },
68            custom_edges: Vec::new(),
69        })
70    }
71
72    /// Create a tree-sitter-backed language pack with custom edge definitions.
73    pub fn new_with_custom_edges(
74        name: &str,
75        extensions: Vec<&str>,
76        grammar: Language,
77        entity_query_src: &str,
78        relation_query_src: &str,
79        custom_edges: Vec<CustomEdgeDef>,
80    ) -> Result<Self> {
81        let mut pack = Self::new(
82            name,
83            extensions,
84            grammar,
85            entity_query_src,
86            relation_query_src,
87        )?;
88        pack.custom_edges = custom_edges;
89        Ok(pack)
90    }
91
92    /// Create a language pack with a custom extraction backend.
93    pub fn new_custom(
94        name: &str,
95        extensions: Vec<String>,
96        extractor: Box<dyn CustomExtractor>,
97    ) -> Self {
98        Self {
99            name: name.to_string(),
100            extensions,
101            backend: ParserBackend::Custom(extractor),
102            custom_edges: Vec::new(),
103        }
104    }
105}
106
107impl std::fmt::Debug for LanguagePack {
108    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
109        f.debug_struct("LanguagePack")
110            .field("name", &self.name)
111            .field("extensions", &self.extensions)
112            .finish()
113    }
114}