ll_sparql_parser/parser/
mod.rs1mod grammar;
2
3use std::{cell::Cell, ops::Range};
4
5use crate::SyntaxKind;
6use grammar::{parse_QueryUnit, parse_UpdateUnit};
7use logos::Logos;
8use rowan::{GreenNode, GreenNodeBuilder, TextRange, TextSize};
9use wasm_bindgen::prelude::wasm_bindgen;
10
11pub struct Parser {
12 tokens: Vec<Token>,
13 pos: usize,
14 fuel: Cell<u32>,
15 events: Vec<Event>,
16}
17
18#[derive(Debug, Clone)]
19pub(super) struct Token {
20 kind: SyntaxKind,
21 text: std::string::String,
22}
23
24impl Token {
25 fn is_trivia(&self) -> bool {
26 matches!(self.kind, SyntaxKind::WHITESPACE | SyntaxKind::Comment)
27 }
28
29 pub(super) fn kind(&self) -> SyntaxKind {
30 self.kind
31 }
32}
33
34#[derive(Debug)]
35pub struct ParseError {
36 pub span: TextRange,
37 pub message: String,
38}
39
40pub fn parse_text(input: &str, entry: TopEntryPoint) -> (GreenNode, Vec<ParseError>) {
41 let tokens = lex(input);
42 let parse_input = tokens
43 .iter()
44 .filter_map(|(token, _span)| (!token.is_trivia()).then_some(token))
45 .cloned()
46 .collect();
47 let output = entry.parse(parse_input);
48 build_tree(tokens, output)
49}
50
51fn build_tree(
52 tokens: Vec<(Token, Range<usize>)>,
53 events: Vec<Event>,
54) -> (GreenNode, Vec<ParseError>) {
55 let mut tokens = tokens.into_iter().peekable();
56 let mut builder = GreenNodeBuilder::new();
57 let mut erros: Vec<ParseError> = Vec::new();
58
59 for event in &events[..events.len() - 1] {
63 match event {
64 Event::Open { kind } => {
65 while !matches!(kind, SyntaxKind::QueryUnit | SyntaxKind::UpdateUnit)
66 && tokens
67 .peek()
68 .map_or(false, |(next, _span)| next.is_trivia())
69 {
70 let (token, _) = tokens.next().unwrap();
71 builder.token(token.kind.into(), &token.text);
72 }
73 builder.start_node((*kind).into());
74 }
75 Event::Error { expected } => {
76 if let Some((_, span)) = tokens.peek() {
77 erros.push(ParseError {
78 span: TextRange::new(
79 TextSize::new(span.start as u32),
80 TextSize::new(span.start as u32),
81 ),
82 message: if expected.is_empty() {
83 "Syntax Error: unexpected token".to_string()
84 } else {
85 format!(
86 "Syntax Error: expected {}",
87 expected
88 .into_iter()
89 .map(|kind| format!("{kind:?}"))
90 .collect::<Vec<_>>()
91 .join(" or ")
92 )
93 },
94 });
95 }
96 }
97 Event::Close => {
98 builder.finish_node();
99 }
100
101 Event::Advance => {
102 while tokens.peek().map_or(false, |(next, _)| next.is_trivia()) {
103 let (token, _) = tokens.next().unwrap();
104 builder.token(token.kind.into(), &token.text);
105 }
106 let (token, _) = tokens.next().unwrap();
107 builder.token(token.kind.into(), &token.text);
108 }
109 }
110 }
111 assert!(matches!(events.last(), Some(Event::Close)));
113 while tokens.peek().map_or(false, |(next, _)| next.is_trivia()) {
114 let (token, _) = tokens.next().unwrap();
115 builder.token(token.kind.into(), &token.text);
116 }
117 builder.finish_node();
118 (builder.finish(), erros)
119}
120
121impl Parser {
122 fn new(input: Vec<Token>) -> Self {
123 Self {
124 tokens: input,
125 pos: 0,
126 fuel: 1024.into(),
127 events: Vec::new(),
128 }
129 }
130}
131
132#[derive(Debug)]
133enum Event {
134 Open { kind: SyntaxKind },
135 Error { expected: Vec<SyntaxKind> },
136 Close,
137 Advance,
138}
139
140struct MarkOpened {
141 index: usize,
142}
143
144impl Parser {
145 fn open(&mut self) -> MarkOpened {
146 let mark = MarkOpened {
147 index: self.events.len(),
148 };
149 self.events.push(Event::Open {
150 kind: SyntaxKind::Error,
151 });
152 mark
153 }
154
155 fn close(&mut self, m: MarkOpened, kind: SyntaxKind) {
156 self.events[m.index] = Event::Open { kind };
157 self.events.push(Event::Close);
158 }
159
160 fn advance(&mut self) {
161 assert!(!self.eof());
162 self.fuel.set(1024);
163 self.events.push(Event::Advance);
164 self.pos += 1;
165 }
166
167 fn eof(&self) -> bool {
168 self.pos == self.tokens.len()
169 }
170
171 fn nth(&self, lookahead: usize) -> SyntaxKind {
172 if self.fuel.get() == 0 {
173 panic!("parser is stuck")
174 }
175 self.fuel.set(self.fuel.get() - 1);
176 self.tokens
177 .get(self.pos + lookahead)
178 .map_or(SyntaxKind::Eof, |it| it.kind)
179 }
180
181 fn at(&self, kind: SyntaxKind) -> bool {
182 self.nth(0) == kind
183 }
184
185 fn at_any(&self, kinds: &[SyntaxKind]) -> bool {
186 let current = self.nth(0);
187 kinds.contains(¤t)
188 }
189
190 fn eat(&mut self, kind: SyntaxKind) -> bool {
191 if self.at(kind) {
192 self.advance();
193 true
194 } else {
195 false
196 }
197 }
198
199 fn expect(&mut self, kind: SyntaxKind) {
200 if self.eat(kind) {
201 return;
202 }
203 self.events.push(Event::Error {
204 expected: vec![kind],
205 });
206 }
207
208 fn advance_with_error(&mut self, expected: Vec<SyntaxKind>) {
209 let m = self.open();
210 self.advance();
211 self.close(m, SyntaxKind::Error);
212 self.events.push(Event::Error { expected });
213 }
214}
215
216#[derive(Debug)]
217pub enum TopEntryPoint {
218 QueryUnit,
219 UpdateUnit,
220}
221
222impl TopEntryPoint {
223 fn parse(&self, input: Vec<Token>) -> Vec<Event> {
224 let mut parser = Parser::new(input);
225 match self {
226 TopEntryPoint::QueryUnit => parse_QueryUnit(&mut parser),
227 TopEntryPoint::UpdateUnit => parse_UpdateUnit(&mut parser),
228 }
229 parser.events
230 }
231}
232
233pub(super) fn lex(text: &str) -> Vec<(Token, Range<usize>)> {
234 let mut lexer = SyntaxKind::lexer(text);
235 let mut tokens = Vec::new();
236
237 while let Some(result) = lexer.next() {
238 tokens.push((
239 Token {
240 kind: result.unwrap_or(SyntaxKind::Error),
241 text: lexer.slice().to_string(),
242 },
243 lexer.span(),
244 ));
245 }
246 tokens
247}
248
249pub fn guess_operation_type(input: &str) -> Option<TopEntryPoint> {
250 let tokens = lex(input);
251 tokens.iter().find_map(|(token, _)| match token.kind {
252 SyntaxKind::SELECT | SyntaxKind::CONSTRUCT | SyntaxKind::ASK | SyntaxKind::DESCRIBE => {
253 Some(TopEntryPoint::QueryUnit)
254 }
255 SyntaxKind::LOAD
256 | SyntaxKind::CLEAR
257 | SyntaxKind::DROP
258 | SyntaxKind::CREATE
259 | SyntaxKind::ADD
260 | SyntaxKind::MOVE
261 | SyntaxKind::COPY
262 | SyntaxKind::INSERT
263 | SyntaxKind::INSERT_DATA
264 | SyntaxKind::DELETE
265 | SyntaxKind::DELETE_DATA
266 | SyntaxKind::DELETE_WHERE => Some(TopEntryPoint::UpdateUnit),
267 _ => None,
268 })
269}
270
271#[wasm_bindgen]
272pub fn determine_operation_type(input: &str) -> String {
273 match guess_operation_type(input) {
274 Some(TopEntryPoint::QueryUnit) => "Query",
275 Some(TopEntryPoint::UpdateUnit) => "Update",
276 None => "Unknown",
277 }
278 .to_string()
279}
280
281#[cfg(test)]
282mod tests;