akar_parser/parser/
mod.rs1use crate::ast::*;
9use pest::Parser;
10
11#[derive(pest_derive::Parser)]
12#[grammar = "cypher.pest"]
13pub struct CypherParser;
14
15pub fn parse(input: &str) -> Result<Statement, String> {
16 let trimmed = input.trim();
17
18 if let Some(rest) = trimmed.strip_prefix("EXPLAIN").map(|s| s.trim()) {
20 let (explain_type, inner_sql) = if let Some(rest) = rest.strip_prefix("LOGICAL").map(|s| s.trim()) {
21 (ExplainType::LogicalPlan, rest)
22 } else if let Some(rest) = rest.strip_prefix("PROFILE").map(|s| s.trim()) {
23 (ExplainType::Profile, rest)
24 } else {
25 (ExplainType::PhysicalPlan, rest)
26 };
27 let inner_stmt = parse(inner_sql)?;
28 return Ok(Statement::Explain(ExplainStatement::new(inner_stmt, explain_type)));
29 }
30
31 let mut pairs = CypherParser::parse(Rule::akar_query, trimmed).map_err(|e| format!("Parse error: {e}"))?;
32 let akar_query_pair = pairs.next().ok_or("Empty input")?;
33 let statement_pair = akar_query_pair.into_inner().next().ok_or("No statement in query")?;
34 parse_statement(statement_pair)
35}
36
37fn parse_statement(pair: pest::iterators::Pair<Rule>) -> Result<Statement, String> {
38 let inner = if pair.as_rule() == Rule::statement {
40 pair.into_inner().next().ok_or("Empty statement")?
41 } else {
42 pair
43 };
44 match inner.as_rule() {
45 Rule::ddl_statement => {
46 let ddl_inner = inner.into_inner().next().ok_or("Empty DDL")?;
47 ddl::parse_ddl(ddl_inner)
48 }
49 Rule::create_dml_statement => {
50 let inner_clone = inner.clone();
51 let patterns = dml::parse_patterns(inner_clone)?;
52 Ok(Statement::CreateDml(CreateClause { patterns }))
53 }
54 Rule::query_statement => {
55 let inner_clone = inner.clone();
56 let children: Vec<_> = inner_clone.into_inner().collect();
57 let standalone_merge = children.len() <= 2
61 && children.first().is_some_and(|c| c.as_rule() == Rule::query_clause)
62 && (children.len() == 1 || children[1].as_rule() == Rule::return_clause)
63 && {
64 let qc_inner: Vec<_> = children[0].clone().into_inner().collect();
65 qc_inner.len() == 1 && qc_inner[0].as_rule() == Rule::merge_clause
66 };
67 if standalone_merge {
68 let qc = inner.into_inner().next().ok_or("Empty MERGE query")?;
69 let merge_pair = qc.into_inner().next().ok_or("MERGE missing merge_clause")?;
70 Ok(Statement::Merge(dml::parse_merge_clause(merge_pair)?))
71 } else {
72 let query = dml::parse_query_pairs(inner)?;
73 Ok(Statement::Query(query))
74 }
75 }
76 Rule::union_statement => {
77 let inner_clone = inner.clone();
78 ddl::parse_ddl(inner_clone)
79 }
80 Rule::call_statement => {
81 let call = dml::parse_call(inner)?;
82 Ok(Statement::StandaloneCall(call))
83 }
84 Rule::export_database => ddl::parse_export_database(inner),
85 Rule::import_database => ddl::parse_import_database(inner),
86 Rule::analyze_statement => ddl::parse_analyze(inner),
87 Rule::transaction_statement => ddl::parse_transaction(inner),
88 Rule::extension_statement => ddl::parse_extension(inner),
89 Rule::multi_db_statement => {
90 let db_inner = inner.into_inner().next().ok_or("Empty multi-DB statement")?;
91 ddl::parse_multi_db(db_inner)
92 }
93 _ => Err(format!("Unexpected rule: {:?}", inner.as_rule())),
94 }
95}
96
97mod ddl;
98mod dml;
99pub mod expression;