Skip to main content

xrust/parser/avt/
mod.rs

1/*!
2Parse an Attribute Value Template.
3
4See XSL Transformations v3.0 5.6.1.
5 */
6
7use crate::item::{Item, Node};
8use crate::parser::combinators::alt::alt2;
9use crate::parser::combinators::many::{many0, many1};
10use crate::parser::combinators::map::map;
11use crate::parser::{
12    ParseError, ParseInput, ParserState, ParserStateBuilder, StaticState, StaticStateBuilder,
13};
14use crate::value::Value;
15use crate::xdmerror::{Error, ErrorKind};
16use std::rc::Rc;
17//use crate::parser::combinators::debug::inspect;
18use crate::parser::combinators::support::none_of;
19use crate::parser::xpath::expr;
20use crate::transform::Transform;
21use qualname::{NamespacePrefix, NamespaceUri};
22
23/// AVT ::= text* "{" xpath "}" text*
24/// A [Node] is required to resolve in-scope XML Namespaces
25pub fn parse<N: Node>(input: &str, n: Option<N>) -> Result<Transform<N>, Error> {
26    let state = n.map_or_else(
27        || ParserState::new(),
28        |m| ParserStateBuilder::new().doc(m).build(),
29    );
30    let mut static_state = StaticStateBuilder::new()
31        .namespace(|_| {
32            NamespaceUri::try_from("urn:xrust").map_err(|_| ParseError::MissingNameSpace)
33        })
34        .build();
35    match avt_expr((input, state), &mut static_state) {
36        Ok((_, x)) => Ok(x),
37        Err(err) => match err {
38            ParseError::Combinator(f) => Result::Err(Error::new(
39                ErrorKind::ParseError,
40                format!("Unrecoverable parser error ({})", f),
41            )),
42            ParseError::NotWellFormed(e) => Result::Err(Error::new(
43                ErrorKind::ParseError,
44                format!("Unrecognised extra characters: \"{}\"", e),
45            )),
46            ParseError::Notimplemented => Result::Err(Error::new(
47                ErrorKind::ParseError,
48                "Unimplemented feature.".to_string(),
49            )),
50            _ => Err(Error::new(ErrorKind::Unknown, "Unknown error".to_string())),
51        },
52    }
53}
54
55fn avt_expr<'a, N: Node + 'a, L>(
56    input: ParseInput<'a, N>,
57    ss: &mut StaticState<L>,
58) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
59where
60    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
61{
62    match avt::<N, L>()(input, ss) {
63        Err(err) => Err(err),
64        Ok(((input1, state1), e)) => {
65            //Check nothing remaining in iterator, nothing after the end of the AVT.
66            if input1.is_empty() {
67                Ok(((input1, state1), e))
68            } else {
69                Err(ParseError::NotWellFormed(format!(
70                    "unexpected extra characters: \"{}\"",
71                    input1
72                )))
73            }
74        }
75    }
76}
77
78fn avt<'a, N: Node + 'a, L>() -> Box<
79    dyn Fn(
80            ParseInput<'a, N>,
81            &mut StaticState<L>,
82        ) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
83        + 'a,
84>
85where
86    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
87{
88    Box::new(map(
89        many0(alt2(
90            map(many1(none_of("{")), |v| {
91                Transform::Literal(Item::Value(Rc::new(Value::from(
92                    v.iter().fold(String::new(), |mut s, w| {
93                        s.push_str(w);
94                        s
95                    }), //.collect::<String>(),
96                ))))
97            }),
98            braced_expr(),
99        )),
100        |mut v| {
101            if v.len() == 1 {
102                v.pop().unwrap()
103            } else {
104                Transform::SequenceItems(v)
105            }
106        },
107    ))
108}
109
110/// A XPath expression in the AVT. Braces do not nest.
111fn braced_expr<'a, N: Node + 'a, L>() -> Box<
112    dyn Fn(
113            ParseInput<'a, N>,
114            &mut StaticState<L>,
115        ) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
116        + 'a,
117>
118where
119    L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
120{
121    // Can't use combinator directly, since the close brace will be unexpected.
122    // Instead, extract the string up to the close brace, then feed that to the combinator.
123    //    Box::new(map(
124    //        tuple3(
125    //            inspect("brace-open", tag("{")),
126    //            inspect("expr",expr()),
127    //            inspect("brace-close", tag("}")),
128    //        ),
129    //        |(_, e, _)| e
130    //    ))
131    Box::new(move |(input, state), ss| {
132        match input.get(0..1) {
133            Some("{") => match input.find('}') {
134                None => Err(ParseError::Combinator(String::from("no closing brace"))),
135                Some(ind) => match expr()((input.get(1..ind).unwrap(), state.clone()), ss) {
136                    Ok((_, result)) => {
137                        // Successful parse of expression
138                        // Must also consume the close brace
139                        Ok(((input.get((ind + 1)..).map_or("", |r| r), state), result))
140                    }
141                    Err(e) => Err(e),
142                },
143            },
144            _ => Err(ParseError::Combinator(String::from(
145                "closing brace not found",
146            ))),
147        }
148    })
149}