Skip to main content

plexus_parser/
parser.rs

1use crate::ast::*;
2use crate::error::ParseError;
3use crate::lexer::{tokenize, Spanned, Token};
4
5mod clauses;
6mod expr;
7mod pattern;
8mod projection;
9
10pub struct Parser {
11    tokens: Vec<Spanned>,
12    pos: usize,
13}
14
15impl Parser {
16    fn new(tokens: Vec<Spanned>) -> Self {
17        Self { tokens, pos: 0 }
18    }
19
20    fn peek(&self) -> &Token {
21        &self.tokens[self.pos].token
22    }
23
24    fn span(&self) -> (u32, u32) {
25        let s = &self.tokens[self.pos];
26        (s.line, s.col)
27    }
28
29    fn bump(&mut self) -> &Token {
30        let tok = &self.tokens[self.pos].token;
31        if self.pos + 1 < self.tokens.len() {
32            self.pos += 1;
33        }
34        tok
35    }
36
37    fn expect(&mut self, expected: &Token) -> Result<(), ParseError> {
38        if self.peek() == expected {
39            self.bump();
40            Ok(())
41        } else {
42            let (line, col) = self.span();
43            Err(ParseError::new(
44                format!("expected {:?}, got {:?}", expected, self.peek()),
45                line,
46                col,
47            ))
48        }
49    }
50
51    fn eat(&mut self, tok: &Token) -> bool {
52        if self.peek() == tok {
53            self.bump();
54            true
55        } else {
56            false
57        }
58    }
59
60    fn at_eof(&self) -> bool {
61        matches!(self.peek(), Token::Eof)
62    }
63
64    /// Peek at a token `n` positions ahead without advancing.
65    fn peek_offset(&self, n: usize) -> &Token {
66        let idx = (self.pos + n).min(self.tokens.len() - 1);
67        &self.tokens[idx].token
68    }
69
70    fn parse_ident(&mut self) -> Result<String, ParseError> {
71        match self.peek().clone() {
72            Token::Ident(s) => {
73                self.bump();
74                Ok(s)
75            }
76            _ => {
77                let (line, col) = self.span();
78                Err(ParseError::new(
79                    format!("expected identifier, got {:?}", self.peek()),
80                    line,
81                    col,
82                ))
83            }
84        }
85    }
86
87    fn parse_integer(&mut self) -> Result<i64, ParseError> {
88        match self.peek().clone() {
89            Token::Integer(n) => {
90                self.bump();
91                Ok(n)
92            }
93            _ => {
94                let (line, col) = self.span();
95                Err(ParseError::new(
96                    format!("expected integer, got {:?}", self.peek()),
97                    line,
98                    col,
99                ))
100            }
101        }
102    }
103
104    fn parse_string_literal(&mut self) -> Result<String, ParseError> {
105        match self.peek().clone() {
106            Token::Str(s) => {
107                self.bump();
108                Ok(s)
109            }
110            _ => {
111                let (line, col) = self.span();
112                Err(ParseError::new(
113                    format!("expected string literal, got {:?}", self.peek()),
114                    line,
115                    col,
116                ))
117            }
118        }
119    }
120}
121
122pub fn parse(input: &str) -> Result<Query, ParseError> {
123    let tokens = tokenize(input)?;
124    let mut parser = Parser::new(tokens);
125    parser.parse_query()
126}
127
128#[cfg(test)]
129mod tests;