shex_compact/
shapemap_parser.rs

1use crate::shapemap_grammar::shapemap_statement;
2use crate::shapemap_grammar::ShapeMapStatement;
3use crate::shapemap_grammar::{node_selector, shape_spec};
4use crate::shex_grammar::iri;
5use crate::tws0;
6use crate::ParseError;
7use crate::Span;
8use nom::Err;
9use prefixmap::IriRef;
10use prefixmap::PrefixMap;
11use shapemap::query_shape_map::QueryShapeMap;
12use shapemap::NodeSelector;
13use shapemap::ShapeSelector;
14use std::fs;
15use std::path::Path;
16use tracing::debug;
17
18type Result<A> = std::result::Result<A, ParseError>;
19
20pub struct ShapeMapParser<'a> {
21    shapemap_statement_iterator: ShapeMapStatementIterator<'a>,
22}
23
24impl ShapeMapParser<'_> {
25    /// Parse a ShapeMap that uses [ShapeMap compact syntax](https://shexspec.github.io/shape-map/#grammar)
26    ///
27    pub fn parse(
28        src: &str,
29        nodes_prefixmap: &Option<PrefixMap>,
30        shapes_prefixmap: &Option<PrefixMap>,
31    ) -> Result<QueryShapeMap> {
32        let mut query_shapemap = QueryShapeMap::new();
33        if let Some(pm) = nodes_prefixmap {
34            query_shapemap = query_shapemap.with_nodes_prefixmap(pm)
35        };
36        if let Some(pm) = shapes_prefixmap {
37            query_shapemap = query_shapemap.with_shapes_prefixmap(pm)
38        };
39        let mut parser = ShapeMapParser {
40            shapemap_statement_iterator: ShapeMapStatementIterator::new(Span::new(src))?,
41        };
42        for ss in parser.shapemap_statement_iterator.by_ref() {
43            let statements = ss?;
44            for s in statements {
45                match s {
46                    ShapeMapStatement::Association {
47                        node_selector,
48                        shape_selector,
49                    } => {
50                        tracing::debug!("Association {node_selector:?}@{shape_selector:?}");
51                        query_shapemap.add_association(node_selector, shape_selector);
52                    }
53                }
54            }
55        }
56        Ok(query_shapemap)
57    }
58
59    pub fn parse_buf(
60        path: &Path,
61        nodes_prefixmap: &Option<PrefixMap>,
62        shapes_prefixmap: &Option<PrefixMap>,
63    ) -> Result<QueryShapeMap> {
64        let data = fs::read_to_string(path)?;
65        let query_shapemap = ShapeMapParser::parse(&data, nodes_prefixmap, shapes_prefixmap)?;
66        Ok(query_shapemap)
67    }
68
69    pub fn parse_shape_selector(str: &str) -> Result<ShapeSelector> {
70        let span = Span::new(str);
71        let (_, ss) = shape_spec()(span).map_err(|e| match e {
72            Err::Incomplete(s) => ParseError::Custom {
73                msg: format!("Incomplete input: needed {s:?}"),
74            },
75            Err::Error(e) => ParseError::NomError { err: Box::new(e) },
76            Err::Failure(f) => ParseError::NomError { err: Box::new(f) },
77        })?;
78        Ok(ss)
79    }
80
81    pub fn parse_node_selector(str: &str) -> Result<NodeSelector> {
82        let span = Span::new(str);
83        let (_, ns) = node_selector()(span).map_err(|e| match e {
84            Err::Incomplete(s) => ParseError::Custom {
85                msg: format!("Incomplete input parsing node selector {str}: needed {s:?}"),
86            },
87            Err::Error(e) => ParseError::NodeSelectorNomError {
88                str: str.to_string(),
89                err: Box::new(e),
90            },
91            Err::Failure(f) => ParseError::NodeSelectorNomError {
92                str: str.to_string(),
93                err: Box::new(f),
94            },
95        })?;
96        Ok(ns)
97    }
98
99    pub fn parse_iri_ref(str: &str) -> Result<IriRef> {
100        let span = Span::new(str);
101        let (_, iri_ref) = iri(span).map_err(|e| match e {
102            Err::Incomplete(s) => ParseError::Custom {
103                msg: format!("Incomplete input: needed {s:?}"),
104            },
105            Err::Error(e) => ParseError::NomError { err: Box::new(e) },
106            Err::Failure(f) => ParseError::NomError { err: Box::new(f) },
107        })?;
108        Ok(iri_ref)
109    }
110}
111
112struct ShapeMapStatementIterator<'a> {
113    src: Span<'a>,
114    done: bool,
115}
116
117impl ShapeMapStatementIterator<'_> {
118    pub fn new(src: Span) -> Result<ShapeMapStatementIterator> {
119        match tws0(src) {
120            Ok((left, _)) => Ok(ShapeMapStatementIterator {
121                src: left,
122                done: false,
123            }),
124            Err(Err::Incomplete(_)) => Ok(ShapeMapStatementIterator { src, done: false }),
125            Err(e) => Err(ParseError::Custom {
126                msg: format!("cannot start parsing. Error: {}", e),
127            }),
128        }
129    }
130}
131
132impl Iterator for ShapeMapStatementIterator<'_> {
133    type Item = Result<Vec<ShapeMapStatement>>;
134
135    fn next(&mut self) -> Option<Self::Item> {
136        if self.done {
137            return None;
138        }
139        let mut r;
140        match shapemap_statement()(self.src) {
141            Ok((left, s)) => {
142                if s.is_empty() {
143                    r = None;
144                } else {
145                    r = Some(Ok(s));
146                }
147                self.src = left;
148            }
149            Err(Err::Incomplete(_)) => {
150                debug!("Incomplete! shapemap_statement");
151                self.done = true;
152                r = None;
153            }
154            Err(Err::Error(e)) | Err(Err::Failure(e)) => {
155                r = Some(Err(ParseError::NomError { err: Box::new(e) }));
156                self.done = true;
157            }
158        }
159        if self.src.is_empty() {
160            self.done = true;
161        }
162        if r.is_none() && !self.src.is_empty() {
163            r = Some(Err(ParseError::Custom {
164                msg: format!("trailing bytes {}", self.src),
165            }));
166        }
167        r
168    }
169}
170
171#[cfg(test)]
172mod tests {
173
174    use iri_s::IriS;
175    use shapemap::{NodeSelector, ShapeSelector};
176
177    use super::*;
178
179    #[test]
180    fn test_prefix() {
181        let str = r#":a@:S"#;
182        let mut nodes_prefixmap = PrefixMap::new();
183        nodes_prefixmap
184            .insert("", &IriS::new_unchecked("http://example.org/"))
185            .unwrap();
186
187        let mut shapes_prefixmap = PrefixMap::new();
188        shapes_prefixmap
189            .insert("", &IriS::new_unchecked("http://example.org/shapes/"))
190            .unwrap();
191
192        let parsed_shapemap = ShapeMapParser::parse(
193            str,
194            &Some(nodes_prefixmap.clone()),
195            &Some(shapes_prefixmap.clone()),
196        )
197        .unwrap();
198
199        let mut expected = QueryShapeMap::new()
200            .with_nodes_prefixmap(&nodes_prefixmap)
201            .with_shapes_prefixmap(&shapes_prefixmap);
202
203        expected.add_association(
204            NodeSelector::prefixed("", "a"),
205            ShapeSelector::prefixed("", "S"),
206        );
207        assert_eq!(parsed_shapemap, expected)
208    }
209}