kotoba_query_engine/
parser.rs

1//! GQL Parser
2//!
3//! Parser for ISO GQL using Pest parser generator.
4
5use pest::Parser;
6use pest_derive::Parser;
7use std::collections::HashMap;
8use anyhow::{Result, Context};
9
10use crate::ast::*;
11
12/// Pest parser for GQL
13#[derive(Parser)]
14#[grammar = "gql.pest"]
15pub struct GqlParser;
16
17/// Main parser interface
18impl GqlParser {
19    /// Parse a GQL query
20    pub fn parse(input: &str) -> Result<GqlQuery> {
21        let pairs = <GqlParser as pest::Parser<Rule>>::parse(Rule::query, input)
22            .context("Failed to parse GQL query")?;
23
24        Self::build_query(pairs)
25    }
26
27    /// Parse a GQL statement
28    pub fn parse_statement(input: &str) -> Result<GqlStatement> {
29        let pairs = <GqlParser as pest::Parser<Rule>>::parse(Rule::statement, input)
30            .context("Failed to parse GQL statement")?;
31
32        Self::build_statement(pairs)
33    }
34
35    fn build_query(pairs: pest::iterators::Pairs<Rule>) -> Result<GqlQuery> {
36        let mut clauses = Vec::new();
37        let mut returning = None;
38
39        for pair in pairs {
40            match pair.as_rule() {
41                Rule::match_clause => {
42                    clauses.push(QueryClause::Match(Self::build_match_clause(pair)?));
43                }
44                Rule::where_clause => {
45                    clauses.push(QueryClause::Where(Self::build_where_clause(pair)?));
46                }
47                Rule::return_clause => {
48                    returning = Some(Self::build_return_clause(pair)?);
49                }
50                _ => {
51                    // Skip other rules
52                }
53            }
54        }
55
56        Ok(GqlQuery { clauses, returning })
57    }
58
59    fn build_match_clause(pair: pest::iterators::Pair<Rule>) -> Result<MatchClause> {
60        let mut optional = false;
61        let mut pattern = None;
62
63        for inner_pair in pair.into_inner() {
64            match inner_pair.as_rule() {
65                Rule::OPTIONAL => optional = true,
66                Rule::graph_pattern => {
67                    pattern = Some(Self::build_graph_pattern(inner_pair)?);
68                }
69                _ => {}
70            }
71        }
72
73        Ok(MatchClause {
74            optional,
75            pattern: pattern.unwrap_or_default(),
76        })
77    }
78
79    fn build_graph_pattern(pair: pest::iterators::Pair<Rule>) -> Result<GraphPattern> {
80        let mut path_patterns = Vec::new();
81
82        for inner_pair in pair.into_inner() {
83            if let Rule::path_pattern = inner_pair.as_rule() {
84                path_patterns.push(Self::build_path_pattern(inner_pair)?);
85            }
86        }
87
88        Ok(GraphPattern { path_patterns })
89    }
90
91    fn build_path_pattern(pair: pest::iterators::Pair<Rule>) -> Result<PathPattern> {
92        let mut variable = None;
93        let mut path_term = None;
94
95        for inner_pair in pair.into_inner() {
96            match inner_pair.as_rule() {
97                Rule::variable => {
98                    variable = Some(inner_pair.as_str().to_string());
99                }
100                Rule::path_element => {
101                    path_term = Some(PathTerm::PathElement(Self::build_path_element(inner_pair)?));
102                }
103                _ => {}
104            }
105        }
106
107        Ok(PathPattern {
108            variable,
109            path_term: path_term.unwrap_or_else(|| PathTerm::PathElement(PathElement::default())),
110        })
111    }
112
113    fn build_path_element(pair: pest::iterators::Pair<Rule>) -> Result<PathElement> {
114        let mut vertex_pattern = None;
115        let mut edge_patterns = Vec::new();
116
117        for inner_pair in pair.into_inner() {
118            match inner_pair.as_rule() {
119                Rule::vertex_pattern => {
120                    vertex_pattern = Some(Self::build_vertex_pattern(inner_pair)?);
121                }
122                Rule::edge_pattern => {
123                    edge_patterns.push(Self::build_edge_pattern(inner_pair)?);
124                }
125                _ => {}
126            }
127        }
128
129        Ok(PathElement {
130            vertex_pattern: vertex_pattern.unwrap_or_default(),
131            edge_patterns,
132        })
133    }
134
135    fn build_vertex_pattern(pair: pest::iterators::Pair<Rule>) -> Result<VertexPattern> {
136        let mut variable = None;
137        let mut labels = Vec::new();
138        let mut properties = HashMap::new();
139
140        for inner_pair in pair.into_inner() {
141            match inner_pair.as_rule() {
142                Rule::variable => {
143                    variable = Some(inner_pair.as_str().to_string());
144                }
145                Rule::label => {
146                    labels.push(inner_pair.as_str().to_string());
147                }
148                Rule::properties => {
149                    properties = Self::build_properties(inner_pair)?;
150                }
151                _ => {}
152            }
153        }
154
155        Ok(VertexPattern {
156            variable,
157            labels,
158            properties,
159        })
160    }
161
162    fn build_edge_pattern(pair: pest::iterators::Pair<Rule>) -> Result<EdgePattern> {
163        let mut variable = None;
164        let mut direction = EdgeDirection::Right; // Default
165        let mut labels = Vec::new();
166        let mut properties = HashMap::new();
167
168        for inner_pair in pair.into_inner() {
169            match inner_pair.as_rule() {
170                Rule::variable => {
171                    variable = Some(inner_pair.as_str().to_string());
172                }
173                Rule::left_arrow => direction = EdgeDirection::Left,
174                Rule::right_arrow => direction = EdgeDirection::Right,
175                Rule::undirected => direction = EdgeDirection::Both,
176                Rule::label => {
177                    labels.push(inner_pair.as_str().to_string());
178                }
179                Rule::properties => {
180                    properties = Self::build_properties(inner_pair)?;
181                }
182                _ => {}
183            }
184        }
185
186        Ok(EdgePattern {
187            variable,
188            direction,
189            labels,
190            properties,
191            quantifier: None, // TODO: Implement quantifier parsing
192        })
193    }
194
195    fn build_where_clause(pair: pest::iterators::Pair<Rule>) -> Result<WhereClause> {
196        let expression = Self::build_boolean_expression(pair.into_inner().next().unwrap())?;
197        Ok(WhereClause { expression })
198    }
199
200    fn build_boolean_expression(pair: pest::iterators::Pair<Rule>) -> Result<BooleanExpression> {
201        // Simplified implementation - expand as needed
202        Ok(BooleanExpression::Comparison(ComparisonExpression {
203            left: Box::new(ValueExpression::Literal(AstValue::Boolean(true))),
204            operator: ComparisonOperator::Equal,
205            right: Box::new(ValueExpression::Literal(AstValue::Boolean(true))),
206        }))
207    }
208
209    fn build_return_clause(pair: pest::iterators::Pair<Rule>) -> Result<ReturnClause> {
210        let mut distinct = false;
211        let mut items = Vec::new();
212
213        for inner_pair in pair.into_inner() {
214            match inner_pair.as_rule() {
215                Rule::DISTINCT => distinct = true,
216                Rule::return_item => {
217                    items.push(Self::build_return_item(inner_pair)?);
218                }
219                _ => {}
220            }
221        }
222
223        Ok(ReturnClause { distinct, items })
224    }
225
226    fn build_return_item(pair: pest::iterators::Pair<Rule>) -> Result<ReturnItem> {
227        let mut expression = None;
228        let mut alias = None;
229
230        for inner_pair in pair.into_inner() {
231            match inner_pair.as_rule() {
232                Rule::expression => {
233                    expression = Some(Self::build_value_expression(inner_pair)?);
234                }
235                Rule::AS => {
236                    // Next pair should be the alias
237                    if let Some(next_pair) = inner_pair.into_inner().next() {
238                        alias = Some(next_pair.as_str().to_string());
239                    }
240                }
241                _ => {}
242            }
243        }
244
245        Ok(ReturnItem {
246            expression: expression.unwrap_or(ValueExpression::Literal(AstValue::Null)),
247            alias,
248        })
249    }
250
251    fn build_value_expression(pair: pest::iterators::Pair<Rule>) -> Result<ValueExpression> {
252        // Simplified implementation
253        Ok(ValueExpression::Literal(AstValue::String(pair.as_str().to_string())))
254    }
255
256    fn build_properties(pair: pest::iterators::Pair<Rule>) -> Result<HashMap<String, ValueExpression>> {
257        // Simplified implementation
258        Ok(HashMap::new())
259    }
260
261    fn build_statement(_pairs: pest::iterators::Pairs<Rule>) -> Result<GqlStatement> {
262        // TODO: Implement statement parsing
263        Ok(GqlStatement::CreateGraph(CreateGraphStatement {
264            graph_name: "default".to_string(),
265            if_not_exists: false,
266        }))
267    }
268}
269
270// Default implementations for testing
271impl Default for GraphPattern {
272    fn default() -> Self {
273        Self { path_patterns: Vec::new() }
274    }
275}
276
277impl Default for VertexPattern {
278    fn default() -> Self {
279        Self {
280            variable: None,
281            labels: Vec::new(),
282            properties: HashMap::new(),
283        }
284    }
285}
286
287impl Default for PathElement {
288    fn default() -> Self {
289        Self {
290            vertex_pattern: VertexPattern::default(),
291            edge_patterns: Vec::new(),
292        }
293    }
294}
295
296#[cfg(test)]
297mod tests {
298    use super::*;
299
300    #[test]
301    fn test_simple_match_query() {
302        // Test parsing a simple MATCH query
303        let query = "MATCH (v:Person) RETURN v";
304
305        // Note: This test will fail until we implement the grammar file
306        // For now, just test the parser structure
307        assert!(query.contains("MATCH"));
308        assert!(query.contains("RETURN"));
309    }
310}