Skip to main content

kyu_parser/parser/
statement.rs

1//! Top-level statement parser dispatching to clause and DDL parsers.
2
3use chumsky::prelude::*;
4
5use crate::ast::*;
6use crate::span::Spanned;
7use crate::token::Token;
8
9use super::clause::{
10    reading_clause, return_clause, standalone_call, transaction_statement, updating_clause,
11    with_clause,
12};
13use super::ddl::{alter_table, copy_from, create_node_table, create_rel_table, drop_statement};
14
15type ParserError = Simple<Token>;
16
17/// Parse a complete query (reading/updating clauses + RETURN).
18fn query_parser() -> impl Parser<Token, Query, Error = ParserError> + Clone {
19    // A query part is: reading clauses + updating clauses + (WITH | RETURN)
20    // Multiple parts are chained by WITH clauses.
21
22    let query_part = reading_clause()
23        .repeated()
24        .then(updating_clause().repeated())
25        .then(
26            return_clause()
27                .map(|proj| (proj, true))
28                .or(with_clause().map(|(proj, _where)| (proj, false))),
29        )
30        .map(|((reading, updating), (projection, is_return))| QueryPart {
31            reading_clauses: reading,
32            updating_clauses: updating,
33            projection: Some(projection),
34            is_return,
35        });
36
37    // A single-clause query with no RETURN (e.g., just CREATE)
38    let update_only = reading_clause()
39        .repeated()
40        .then(updating_clause().repeated().at_least(1))
41        .map(|(reading, updating)| QueryPart {
42            reading_clauses: reading,
43            updating_clauses: updating,
44            projection: None,
45            is_return: false,
46        });
47
48    let parts = query_part
49        .repeated()
50        .at_least(1)
51        .or(update_only.map(|p| vec![p]));
52
53    parts.map(|parts| Query {
54        parts,
55        union_all: vec![],
56    })
57}
58
59/// Parse a top-level statement.
60pub fn statement_parser() -> impl Parser<Token, Spanned<Statement>, Error = ParserError> {
61    let explain = just(Token::Explain)
62        .ignore_then(
63            query_parser()
64                .map(Statement::Query)
65                .map_with_span(|s, span| (s, span)),
66        )
67        .map_with_span(|(inner, _), span| (Statement::Explain(Box::new(inner)), span));
68
69    let profile = just(Token::Profile)
70        .ignore_then(
71            query_parser()
72                .map(Statement::Query)
73                .map_with_span(|s, span| (s, span)),
74        )
75        .map_with_span(|(inner, _), span| (Statement::Profile(Box::new(inner)), span));
76
77    let query = query_parser()
78        .map(Statement::Query)
79        .map_with_span(|s, span| (s, span));
80
81    let create_node = create_node_table()
82        .map(Statement::CreateNodeTable)
83        .map_with_span(|s, span| (s, span));
84
85    let create_rel = create_rel_table()
86        .map(Statement::CreateRelTable)
87        .map_with_span(|s, span| (s, span));
88
89    let drop = drop_statement()
90        .map(Statement::Drop)
91        .map_with_span(|s, span| (s, span));
92
93    let alter = alter_table()
94        .map(Statement::AlterTable)
95        .map_with_span(|s, span| (s, span));
96
97    let copy = copy_from()
98        .map(Statement::CopyFrom)
99        .map_with_span(|s, span| (s, span));
100
101    let call = standalone_call()
102        .map(Statement::StandaloneCall)
103        .map_with_span(|s, span| (s, span));
104
105    let txn = transaction_statement()
106        .map(Statement::Transaction)
107        .map_with_span(|s, span| (s, span));
108
109    choice((
110        explain,
111        profile,
112        create_node,
113        create_rel,
114        drop,
115        alter,
116        copy,
117        call,
118        txn,
119        query,
120    ))
121    .then_ignore(just(Token::Semicolon).or_not())
122    .then_ignore(end())
123}