1use crate::{
2 GrdfNquadDocument, NquadDocument,
3 lexing::{Lexer, NquadsLexingError, Token},
4};
5use decoded_char::DecodedChar;
6use locspan::{Span, Spanned};
7use rdf_syntax::{Id, IriBuf, Literal, LiteralType, Quad, RdfQuad, Term, XSD_STRING};
8use std::fmt;
9
10#[derive(Debug)]
11pub enum NquadsError<E = NquadsLexingError> {
12 Lexer(E),
13 Unexpected(Option<Token>, Span),
14}
15
16impl<E: fmt::Display> fmt::Display for NquadsError<E> {
17 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
18 match self {
19 Self::Unexpected(None, _) => write!(f, "unexpected end of file"),
20 Self::Unexpected(Some(token), _) => write!(f, "unexpected {token}"),
21 Self::Lexer(e) => e.fmt(f),
22 }
23 }
24}
25
26impl<E: 'static + std::error::Error> std::error::Error for NquadsError<E> {
27 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
28 match self {
29 Self::Lexer(e) => Some(e),
30 _ => None,
31 }
32 }
33}
34
35pub struct NquadsParser<L> {
36 lexer: L,
37 position: usize,
38 pending: Option<Token>,
39}
40
41impl<L> NquadsParser<L> {
42 pub fn new(lexer: L) -> Self {
43 Self {
44 lexer,
45 position: 0,
46 pending: None,
47 }
48 }
49}
50
51impl<L, E> NquadsParser<L>
52where
53 L: Iterator<Item = Result<Token, E>>,
54{
55 fn next_token(&mut self) -> Result<Option<Token>, NquadsError<E>> {
56 let token = match self.pending.take() {
57 Some(token) => Some(token),
58 None => self.lexer.next().transpose().map_err(NquadsError::Lexer)?,
59 };
60
61 if let Some(token) = &token {
62 self.position = token.span().end
63 }
64
65 Ok(token)
66 }
67
68 #[allow(clippy::type_complexity)]
69 fn peek(&mut self) -> Result<Option<&Token>, NquadsError<E>> {
70 if self.pending.is_none() {
71 self.pending = self.lexer.next().transpose().map_err(NquadsError::Lexer)?;
72 }
73
74 Ok(self.pending.as_ref())
75 }
76
77 #[allow(clippy::type_complexity)]
78 fn parse_literal(
79 &mut self,
80 value: String,
81 mut span: Span,
82 ) -> Result<(Literal, Span), NquadsError<E>> {
83 match self.peek()? {
84 Some(Token::LangTag(_, _)) => {
85 let Some(Token::LangTag(tag, tag_span)) = self.next_token()? else {
86 unreachable!()
87 };
88
89 span.append(tag_span);
90
91 Ok((Literal::new(value, LiteralType::LangString(tag)), span))
92 }
93 Some(Token::Carets(_)) => {
94 self.next_token()?;
95
96 match self.next_token()? {
97 Some(Token::Iri(iri, iri_span)) => {
98 span.append(iri_span);
99 Ok((Literal::new(value, LiteralType::Any(iri)), span))
100 }
101 Some(token) => {
102 let span = token.span();
103 Err(NquadsError::Unexpected(Some(token), span))
104 }
105 None => Err(NquadsError::Unexpected(None, self.position.into())),
106 }
107 }
108 _ => Ok((
109 Literal::new(value, LiteralType::Any(XSD_STRING.to_owned())),
110 span,
111 )),
112 }
113 }
114
115 fn parse_iri(&mut self) -> Result<(IriBuf, Span), NquadsError<E>> {
116 match self.next_token()? {
117 Some(Token::Iri(iri, span)) => Ok((iri, span)),
118 Some(token) => {
119 let span = token.span();
120 Err(NquadsError::Unexpected(Some(token), span))
121 }
122 None => Err(NquadsError::Unexpected(None, self.position.into())),
123 }
124 }
125
126 fn parse_id(&mut self) -> Result<(Id, Span), NquadsError<E>> {
127 match self.next_token()? {
128 Some(Token::Iri(iri, span)) => Ok((Id::Iri(iri), span)),
129 Some(Token::BlankNodeLabel(label, span)) => Ok((Id::BlankId(label), span)),
130 Some(token) => {
131 let span = token.span();
132 Err(NquadsError::Unexpected(Some(token), span))
133 }
134 None => Err(NquadsError::Unexpected(None, self.position.into())),
135 }
136 }
137
138 fn parse_id_opt(&mut self) -> Result<Option<(Id, Span)>, NquadsError<E>> {
139 match self.peek()? {
140 Some(Token::Dot(_)) => Ok(None),
141 _ => self.parse_id().map(Some),
142 }
143 }
144
145 fn parse_term(&mut self) -> Result<(Term, Span), NquadsError<E>> {
146 match self.next_token()? {
147 Some(Token::Iri(iri, span)) => Ok((Term::iri(iri), span)),
148 Some(Token::BlankNodeLabel(label, span)) => Ok((Term::BlankId(label), span)),
149 Some(Token::StringLiteral(value, span)) => {
150 let (literal, span) = self.parse_literal(value, span)?;
151 Ok((Term::literal(literal), span))
152 }
153 Some(token) => {
154 let span = token.span();
155 Err(NquadsError::Unexpected(Some(token), span))
156 }
157 None => Err(NquadsError::Unexpected(None, self.position.into())),
158 }
159 }
160
161 fn parse_term_opt(&mut self) -> Result<Option<(Term, Span)>, NquadsError<E>> {
162 match self.peek()? {
163 Some(Token::Dot(_)) => Ok(None),
164 _ => self.parse_term().map(Some),
165 }
166 }
167
168 fn parse_dot(&mut self) -> Result<Span, NquadsError<E>> {
169 match self.next_token()? {
170 Some(Token::Dot(span)) => Ok(span),
171 Some(token) => {
172 let span = token.span();
173 Err(NquadsError::Unexpected(Some(token), span))
174 }
175 None => Err(NquadsError::Unexpected(None, self.position.into())),
176 }
177 }
178
179 fn parse_quad(&mut self) -> Result<(RdfQuad, NquadsCodeMapEntry), NquadsError<E>> {
180 let (s, s_span) = self.parse_id()?;
181 let (p, p_span) = self.parse_iri()?;
182 let (o, o_span) = self.parse_term()?;
183 let (g, g_span) = split_option(self.parse_id_opt()?);
184 let dot_span = self.parse_dot()?;
185 let span = s_span.union(dot_span);
186 Ok((
187 Quad(s, p, o, g),
188 NquadsCodeMapEntry {
189 quad: span,
190 components: Quad(s_span, p_span, o_span, g_span),
191 },
192 ))
193 }
194
195 fn parse_grdf_quad(&mut self) -> Result<(Quad<Term>, NquadsCodeMapEntry), NquadsError<E>> {
196 let (s, s_span) = self.parse_term()?;
197 let (p, p_span) = self.parse_term()?;
198 let (o, o_span) = self.parse_term()?;
199 let (g, g_span) = split_option(self.parse_term_opt()?);
200 let dot_span = self.parse_dot()?;
201 let span = s_span.union(dot_span);
202 Ok((
203 Quad(s, p, o, g),
204 NquadsCodeMapEntry {
205 quad: span,
206 components: Quad(s_span, p_span, o_span, g_span),
207 },
208 ))
209 }
210
211 fn parse_document(&mut self) -> Result<(Vec<RdfQuad>, NquadsCodeMap), NquadsError<E>> {
212 let mut quads = Vec::new();
213 let mut spans = Vec::new();
214
215 while self.peek()?.is_some() {
216 let (quad, span) = self.parse_quad()?;
217 quads.push(quad);
218 spans.push(span);
219 }
220
221 Ok((quads, spans))
222 }
223
224 fn parse_grdf_document(&mut self) -> Result<(Vec<Quad<Term>>, NquadsCodeMap), NquadsError<E>> {
225 let mut quads = Vec::new();
226 let mut spans = Vec::new();
227
228 while self.peek()?.is_some() {
229 let (quad, span) = self.parse_grdf_quad()?;
230 quads.push(quad);
231 spans.push(span);
232 }
233
234 Ok((quads, spans))
235 }
236}
237
238fn split_option<A, B>(value: Option<(A, B)>) -> (Option<A>, Option<B>) {
239 match value {
240 Some((a, b)) => (Some(a), Some(b)),
241 None => (None, None),
242 }
243}
244
245pub type NquadsCodeMap = Vec<NquadsCodeMapEntry>;
246
247#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
248pub struct NquadsCodeMapEntry {
249 pub quad: Span,
250 pub components: Quad<Span>,
251}
252
253pub trait NquadsParse: Sized {
254 #[allow(clippy::type_complexity)]
255 fn parse_with<L, E>(
256 parser: &mut NquadsParser<L>,
257 ) -> Result<(Self, NquadsCodeMap), NquadsError<E>>
258 where
259 L: Iterator<Item = Result<Token, E>>;
260
261 #[inline(always)]
262 fn parse<C, E>(chars: C) -> Result<(Self, NquadsCodeMap), NquadsError<NquadsLexingError<E>>>
263 where
264 C: Iterator<Item = Result<DecodedChar, E>>,
265 {
266 let mut parser = NquadsParser::new(Lexer::new(chars));
267 Self::parse_with(&mut parser)
268 }
269
270 #[inline(always)]
271 fn parse_infallible<C>(chars: C) -> Result<(Self, NquadsCodeMap), NquadsError>
272 where
273 C: Iterator<Item = DecodedChar>,
274 {
275 Self::parse(chars.map(Ok))
276 }
277
278 #[inline(always)]
279 fn parse_utf8<C, E>(
280 chars: C,
281 ) -> Result<(Self, NquadsCodeMap), NquadsError<NquadsLexingError<E>>>
282 where
283 C: Iterator<Item = Result<char, E>>,
284 {
285 Self::parse(decoded_char::FallibleUtf8Decoded::new(chars))
286 }
287
288 #[inline(always)]
289 fn parse_utf8_infallible<C>(chars: C) -> Result<(Self, NquadsCodeMap), NquadsError>
290 where
291 C: Iterator<Item = char>,
292 {
293 Self::parse_infallible(decoded_char::Utf8Decoded::new(chars))
294 }
295
296 #[inline(always)]
297 fn parse_utf16<C, E>(
298 chars: C,
299 ) -> Result<(Self, NquadsCodeMap), NquadsError<NquadsLexingError<E>>>
300 where
301 C: Iterator<Item = Result<char, E>>,
302 {
303 Self::parse(decoded_char::FallibleUtf16Decoded::new(chars))
304 }
305
306 #[inline(always)]
307 fn parse_utf16_infallible<C>(chars: C) -> Result<(Self, NquadsCodeMap), NquadsError>
308 where
309 C: Iterator<Item = char>,
310 {
311 Self::parse_infallible(decoded_char::Utf16Decoded::new(chars))
312 }
313
314 #[inline(always)]
315 fn parse_str(string: &str) -> Result<(Self, NquadsCodeMap), NquadsError> {
316 Self::parse_utf8_infallible(string.chars())
317 }
318}
319
320impl NquadsParse for NquadDocument {
321 fn parse_with<L, E>(
322 parser: &mut NquadsParser<L>,
323 ) -> Result<(Self, NquadsCodeMap), NquadsError<E>>
324 where
325 L: Iterator<Item = Result<Token, E>>,
326 {
327 parser.parse_document()
328 }
329}
330
331impl NquadsParse for GrdfNquadDocument {
332 fn parse_with<L, E>(
333 parser: &mut NquadsParser<L>,
334 ) -> Result<(Self, NquadsCodeMap), NquadsError<E>>
335 where
336 L: Iterator<Item = Result<Token, E>>,
337 {
338 parser.parse_grdf_document()
339 }
340}