ll_sparql_parser/parser/
mod.rs

1mod grammar;
2
3use std::cell::Cell;
4
5use crate::SyntaxKind;
6use grammar::{parse_QueryUnit, parse_UpdateUnit};
7use logos::Logos;
8use rowan::{GreenNode, GreenNodeBuilder};
9
10pub struct Parser {
11    tokens: Vec<Token>,
12    pos: usize,
13    fuel: Cell<u32>,
14    events: Vec<Event>,
15}
16
17#[derive(Debug, Clone)]
18struct Token {
19    kind: SyntaxKind,
20    text: std::string::String,
21}
22
23impl Token {
24    fn is_trivia(&self) -> bool {
25        matches!(self.kind, SyntaxKind::WHITESPACE | SyntaxKind::Comment)
26    }
27}
28
29pub fn parse_text(input: &str, entry: TopEntryPoint) -> GreenNode {
30    let tokens = lex(input);
31    let parse_input = tokens
32        .iter()
33        .filter(|token| !token.is_trivia())
34        .cloned()
35        .collect();
36    let output = entry.parse(parse_input);
37    build_tree(tokens, output)
38}
39
40fn build_tree(tokens: Vec<Token>, events: Vec<Event>) -> GreenNode {
41    let mut tokens = tokens.into_iter().peekable();
42    let mut builder = GreenNodeBuilder::new();
43
44    // Special case: pop the last `Close` event to ensure
45    // that the stack is non-empty inside the loop.
46    // assert!(matches!(events.pop(), Some(Event::Close)));
47    for event in &events[..events.len() - 1] {
48        match event {
49            Event::Open { kind } => {
50                while *kind != SyntaxKind::QueryUnit
51                    && tokens.peek().map_or(false, |next| next.is_trivia())
52                {
53                    let token = tokens.next().unwrap();
54                    builder.token(token.kind.into(), &token.text);
55                }
56                builder.start_node((*kind).into());
57            }
58            Event::Close => {
59                builder.finish_node();
60            }
61
62            Event::Advance => {
63                while tokens.peek().map_or(false, |next| next.is_trivia()) {
64                    let token = tokens.next().unwrap();
65                    builder.token(token.kind.into(), &token.text);
66                }
67                let token = tokens.next().unwrap();
68                builder.token(token.kind.into(), &token.text);
69            }
70        }
71    }
72    // Eat trailing trivia tokens
73    assert!(matches!(events.last(), Some(Event::Close)));
74    while tokens.peek().map_or(false, |next| next.is_trivia()) {
75        let token = tokens.next().unwrap();
76        builder.token(token.kind.into(), &token.text);
77    }
78    builder.finish_node();
79    builder.finish()
80}
81
82impl Parser {
83    fn new(input: Vec<Token>) -> Self {
84        Self {
85            tokens: input,
86            pos: 0,
87            fuel: 256.into(),
88            events: Vec::new(),
89        }
90    }
91}
92
93enum Event {
94    Open { kind: SyntaxKind },
95    Close,
96    Advance,
97}
98
99struct MarkOpened {
100    index: usize,
101}
102
103impl Parser {
104    fn open(&mut self) -> MarkOpened {
105        let mark = MarkOpened {
106            index: self.events.len(),
107        };
108        self.events.push(Event::Open {
109            kind: SyntaxKind::Error,
110        });
111        mark
112    }
113
114    fn close(&mut self, m: MarkOpened, kind: SyntaxKind) {
115        self.events[m.index] = Event::Open { kind };
116        self.events.push(Event::Close);
117    }
118
119    fn advance(&mut self) {
120        assert!(!self.eof());
121        self.fuel.set(256);
122        self.events.push(Event::Advance);
123        self.pos += 1;
124    }
125
126    fn eof(&self) -> bool {
127        self.pos == self.tokens.len()
128    }
129
130    fn nth(&self, lookahead: usize) -> SyntaxKind {
131        if self.fuel.get() == 0 {
132            panic!("parser is stuck")
133        }
134        self.fuel.set(self.fuel.get() - 1);
135        self.tokens
136            .get(self.pos + lookahead)
137            .map_or(SyntaxKind::Eof, |it| it.kind)
138    }
139
140    fn at(&self, kind: SyntaxKind) -> bool {
141        self.nth(0) == kind
142    }
143
144    fn at_any(&self, kinds: &[SyntaxKind]) -> bool {
145        kinds.iter().any(|kind| self.at(*kind))
146    }
147
148    fn eat(&mut self, kind: SyntaxKind) -> bool {
149        if self.at(kind) {
150            self.advance();
151            true
152        } else {
153            false
154        }
155    }
156
157    fn expect(&mut self, kind: SyntaxKind) {
158        if self.eat(kind) {
159            return;
160        }
161        // TODO: Error reporting.
162        eprintln!("expected {kind:?}");
163    }
164
165    fn advance_with_error(&mut self, error: &str) {
166        let m = self.open();
167        // TODO: Error reporting.
168        eprintln!("{error}");
169        self.advance();
170        self.close(m, SyntaxKind::Error);
171    }
172}
173
174#[derive(Debug)]
175pub enum TopEntryPoint {
176    QueryUnit,
177    UpdateUnit,
178}
179
180impl TopEntryPoint {
181    fn parse(&self, input: Vec<Token>) -> Vec<Event> {
182        let mut parser = Parser::new(input);
183        match self {
184            TopEntryPoint::QueryUnit => parse_QueryUnit(&mut parser),
185            TopEntryPoint::UpdateUnit => parse_UpdateUnit(&mut parser),
186        }
187        parser.events
188    }
189}
190
191fn lex(text: &str) -> Vec<Token> {
192    let mut lexer = SyntaxKind::lexer(text);
193    let mut tokens = Vec::new();
194
195    while let Some(result) = lexer.next() {
196        tokens.push(Token {
197            kind: result.unwrap_or(SyntaxKind::Error),
198            text: lexer.slice().to_string(),
199        });
200    }
201    tokens
202}
203
204pub fn guess_operation_type(input: &str) -> Option<TopEntryPoint> {
205    let tokens = lex(input);
206    tokens.iter().find_map(|token| match token.kind {
207        SyntaxKind::SELECT | SyntaxKind::CONSTRUCT | SyntaxKind::ASK | SyntaxKind::DESCRIBE => {
208            Some(TopEntryPoint::QueryUnit)
209        }
210        SyntaxKind::LOAD
211        | SyntaxKind::CLEAR
212        | SyntaxKind::DROP
213        | SyntaxKind::CREATE
214        | SyntaxKind::ADD
215        | SyntaxKind::MOVE
216        | SyntaxKind::COPY
217        | SyntaxKind::INSERT
218        | SyntaxKind::INSERT_DATA
219        | SyntaxKind::DELETE
220        | SyntaxKind::DELETE_DATA
221        | SyntaxKind::DELETE_WHERE => Some(TopEntryPoint::UpdateUnit),
222        _ => None,
223    })
224}
225
226#[cfg(test)]
227mod tests;