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.repeated().at_least(1).or(update_only.map(|p| vec![p]));
49
50    parts.map(|parts| Query {
51        parts,
52        union_all: vec![],
53    })
54}
55
56/// Parse a top-level statement.
57pub fn statement_parser() -> impl Parser<Token, Spanned<Statement>, Error = ParserError> {
58    let explain = just(Token::Explain)
59        .ignore_then(
60            query_parser()
61                .map(Statement::Query)
62                .map_with_span(|s, span| (s, span)),
63        )
64        .map_with_span(|(inner, _), span| (Statement::Explain(Box::new(inner)), span));
65
66    let profile = just(Token::Profile)
67        .ignore_then(
68            query_parser()
69                .map(Statement::Query)
70                .map_with_span(|s, span| (s, span)),
71        )
72        .map_with_span(|(inner, _), span| (Statement::Profile(Box::new(inner)), span));
73
74    let query = query_parser()
75        .map(Statement::Query)
76        .map_with_span(|s, span| (s, span));
77
78    let create_node = create_node_table()
79        .map(Statement::CreateNodeTable)
80        .map_with_span(|s, span| (s, span));
81
82    let create_rel = create_rel_table()
83        .map(Statement::CreateRelTable)
84        .map_with_span(|s, span| (s, span));
85
86    let drop = drop_statement()
87        .map(Statement::Drop)
88        .map_with_span(|s, span| (s, span));
89
90    let alter = alter_table()
91        .map(Statement::AlterTable)
92        .map_with_span(|s, span| (s, span));
93
94    let copy = copy_from()
95        .map(Statement::CopyFrom)
96        .map_with_span(|s, span| (s, span));
97
98    let call = standalone_call()
99        .map(Statement::StandaloneCall)
100        .map_with_span(|s, span| (s, span));
101
102    let txn = transaction_statement()
103        .map(Statement::Transaction)
104        .map_with_span(|s, span| (s, span));
105
106    choice((
107        explain,
108        profile,
109        create_node,
110        create_rel,
111        drop,
112        alter,
113        copy,
114        call,
115        txn,
116        query,
117    ))
118    .then_ignore(just(Token::Semicolon).or_not())
119    .then_ignore(end())
120}