shex_compact/
shapemap_grammar.rsuse crate::{
grammar::{map_error, tag_no_case_tws, token_tws, traced, tws0},
iri, literal,
shex_grammar::shape_expr_label,
IRes, ParseError, Span,
};
use nom::{
branch::alt,
character::complete::char,
combinator::{all_consuming, map, opt},
multi::many0,
sequence::tuple,
};
use shapemap::{NodeSelector, ShapeSelector};
#[derive(Debug, PartialEq)]
pub(crate) enum ShapeMapStatement {
Association {
node_selector: NodeSelector,
shape_selector: ShapeSelector,
},
}
pub(crate) fn shapemap_statement<'a>() -> impl FnMut(Span<'a>) -> IRes<'a, Vec<ShapeMapStatement>> {
traced(
"shapemap_statement",
map_error(
move |i| {
let (i, (a, _, ass, _, _)) = all_consuming(tuple((
association,
tws0,
rest_associations,
tws0,
opt(char(',')),
)))(i)?;
let mut rs = vec![a];
for a in ass {
rs.push(a);
}
Ok((i, rs))
},
|| ParseError::ExpectedShapeMapAssociation,
),
)
}
fn association(i: Span) -> IRes<ShapeMapStatement> {
let (i, (ns, _, sl)) = tuple((node_selector(), token_tws("@"), shape_spec()))(i)?;
let s = ShapeMapStatement::Association {
node_selector: ns,
shape_selector: sl,
};
Ok((i, s))
}
fn rest_associations(i: Span) -> IRes<Vec<ShapeMapStatement>> {
let (i, ass) = many0(tuple((token_tws(","), tws0, association)))(i)?;
let r = ass.into_iter().map(|(_, _, a)| a).collect();
Ok((i, r))
}
pub(crate) fn shape_spec<'a>() -> impl FnMut(Span<'a>) -> IRes<'a, ShapeSelector> {
traced(
"shape_spec",
map_error(
move |i| {
alt((
map(shape_expr_label, ShapeSelector::Label),
map(tag_no_case_tws("START"), |_| ShapeSelector::Start),
))(i)
},
|| ParseError::ExpectedShapeSpec,
),
)
}
pub(crate) fn node_selector<'a>() -> impl FnMut(Span<'a>) -> IRes<'a, NodeSelector> {
traced(
"node_selector",
map_error(move |i| object_term(i), || ParseError::ExpectedNodeSpec),
)
}
fn object_term(i: Span) -> IRes<NodeSelector> {
alt((subject_term, literal_selector))(i)
}
fn subject_term(i: Span) -> IRes<NodeSelector> {
let (i, iri) = iri(i)?;
Ok((i, NodeSelector::iri_ref(iri)))
}
fn literal_selector(i: Span) -> IRes<NodeSelector> {
let (i, lit) = literal()(i)?;
Ok((i, NodeSelector::literal(lit)))
}
#[cfg(test)]
mod tests {
use shapemap::ShapeSelector;
use super::*;
#[test]
fn example_shapemap() {
let input = Span::new(":a@:label");
let (_, shape_map) = association(input).unwrap();
let expected = ShapeMapStatement::Association {
node_selector: NodeSelector::prefixed("", "a"),
shape_selector: ShapeSelector::prefixed("", "label"),
};
assert_eq!(shape_map, expected);
}
}