Skip to main content

nquads_syntax/
parsing.rs

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}