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 child_rules: Vec<_> = inner_clone.into_inner().map(|c| c.as_rule()).collect();
57 if child_rules.contains(&Rule::merge_clause) {
58 let merge = dml::parse_merge(inner)?;
59 Ok(merge)
60 } else {
61 let query = dml::parse_query_pairs(inner)?;
62 Ok(Statement::Query(query))
63 }
64 }
65 Rule::union_statement => {
66 let inner_clone = inner.clone();
67 ddl::parse_ddl(inner_clone)
68 }
69 Rule::call_statement => {
70 let call = dml::parse_call(inner)?;
71 Ok(Statement::StandaloneCall(call))
72 }
73 Rule::export_database => ddl::parse_export_database(inner),
74 Rule::import_database => ddl::parse_import_database(inner),
75 Rule::analyze_statement => ddl::parse_analyze(inner),
76 Rule::transaction_statement => ddl::parse_transaction(inner),
77 Rule::extension_statement => ddl::parse_extension(inner),
78 Rule::multi_db_statement => {
79 let db_inner = inner.into_inner().next().ok_or("Empty multi-DB statement")?;
80 ddl::parse_multi_db(db_inner)
81 }
82 _ => Err(format!("Unexpected rule: {:?}", inner.as_rule())),
83 }
84}
85
86mod ddl;
87mod dml;
88pub mod expression;