Skip to main content

linkrs_query/parser/parsing/
session_parser.rs

1//! Session Statement Parsing Module
2//!
3//! Responsible for parsing session-related statements: LET (variable assignment)
4//! and KILL QUERY.
5
6use crate::parser::ast::stmt::*;
7use crate::parser::core::error::{ParseError, ParseErrorKind};
8use crate::parser::parsing::expr_parser::parse_expression_with_context;
9use crate::parser::parsing::parse_context::ParseContext;
10use crate::parser::TokenKind;
11
12/// Session Parser
13pub struct SessionParser;
14
15impl Default for SessionParser {
16    fn default() -> Self {
17        Self
18    }
19}
20
21impl SessionParser {
22    pub fn new() -> Self {
23        Self
24    }
25
26    /// Parse LET statement
27    ///
28    /// Grammar: `LET [$]name = expr`. The name must be a valid identifier
29    /// (`[A-Za-z_][A-Za-z0-9_]*`); the right-hand side is parsed through the
30    /// standard expression pipeline so it may reference `$name` session
31    /// variables and `@name` parameters.
32    pub fn parse_let_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
33        let start_span = ctx.current_span();
34        ctx.expect_token(TokenKind::Let)?;
35
36        let _ = ctx.match_token(TokenKind::Dollar);
37
38        let name = match ctx.expect_identifier() {
39            Ok(name) => name,
40            Err(_) => {
41                let pos = ctx.current_position();
42                let display_name = ctx.current_token().lexeme.clone();
43                return Err(ParseError::new(
44                    ParseErrorKind::SyntaxError,
45                    format!("Invalid session variable name '{}'", display_name),
46                    pos,
47                ));
48            }
49        };
50        let valid = !name.is_empty()
51            && name
52                .chars()
53                .next()
54                .is_some_and(|c| c.is_ascii_alphabetic() || c == '_')
55            && name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_');
56        if !valid {
57            let pos = ctx.current_position();
58            return Err(ParseError::new(
59                ParseErrorKind::SyntaxError,
60                format!("Invalid session variable name '{}'", name),
61                pos,
62            ));
63        }
64
65        if !ctx.check_token(TokenKind::Assign) {
66            let pos = ctx.current_position();
67            return Err(ParseError::new(
68                ParseErrorKind::SyntaxError,
69                "LET requires an assignment: LET $name = expr".to_string(),
70                pos,
71            ));
72        }
73        ctx.expect_token(TokenKind::Assign)?;
74
75        let expression = parse_expression_with_context(ctx, ctx.expression_context_clone())?;
76        let span = ctx.span_since(start_span.start);
77
78        Ok(Stmt::AssignVariable(AssignVariableStmt {
79            span,
80            name,
81            expression,
82        }))
83    }
84
85    /// Parse KILL QUERY statement
86    pub fn parse_kill_statement(&mut self, ctx: &mut ParseContext) -> Result<Stmt, ParseError> {
87        let start_span = ctx.current_span();
88        ctx.expect_token(TokenKind::Kill)?;
89        ctx.expect_token(TokenKind::Query)?;
90
91        let session_id = ctx.expect_integer_literal()?;
92        ctx.expect_token(TokenKind::Comma)?;
93        let plan_id = ctx.expect_integer_literal()?;
94
95        let span = ctx.span_since(start_span.start);
96
97        Ok(Stmt::KillQuery(KillQueryStmt {
98            span,
99            session_id,
100            plan_id,
101        }))
102    }
103}