mod compare;
mod context;
mod expressions;
mod flwr;
mod functions;
pub(crate) mod literals;
mod logic;
mod nodes;
pub(crate) mod nodetests;
mod numbers;
pub(crate) mod predicates;
mod strings;
pub(crate) mod support;
mod types;
pub(crate) mod variables;
use crate::parser::combinators::alt::alt4;
use crate::parser::combinators::list::separated_list1;
use crate::parser::combinators::map::map;
use crate::parser::combinators::tag::tag;
use crate::parser::combinators::tuple::tuple3;
use crate::parser::combinators::whitespace::xpwhitespace;
use crate::parser::xpath::flwr::{for_expr, if_expr, let_expr};
use crate::parser::xpath::logic::or_expr;
use crate::parser::xpath::support::noop;
use crate::parser::{
ParseError, ParseInput, ParserState, ParserStateBuilder, StaticState, StaticStateBuilder,
};
use crate::item::Node;
use crate::transform::Transform;
use crate::xdmerror::{Error, ErrorKind};
use qualname::{NamespaceMap, NamespacePrefix, NamespaceUri};
pub fn parse<N: Node>(
input: &str,
n: Option<N>,
nmap: Option<NamespaceMap>,
) -> Result<Transform<N>, Error> {
if input.is_empty() {
return Ok(Transform::Empty);
}
let state = n.clone().map_or_else(
|| ParserState::new(),
|m| ParserStateBuilder::new().doc(m.clone()).current(m).build(),
);
let result = if let Some(m) = n.clone() {
let mut static_state = StaticStateBuilder::new()
.namespace(move |pre| {
m.namespace_iter()
.find(|nsd| nsd.as_namespace_prefix().unwrap().is_some_and(|p| p == pre))
.map_or_else(
|| Err(ParseError::MissingNameSpace),
|nsd| Ok(nsd.as_namespace_uri().unwrap().clone()),
)
})
.build();
xpath_expr((input, state), &mut static_state)
} else if let Some(nm) = nmap {
let mut static_state = StaticStateBuilder::new()
.namespace(move |pre: &NamespacePrefix| {
nm.namespace_uri(&Some(pre.clone()))
.ok_or(ParseError::MissingNameSpace)
})
.build();
xpath_expr((input, state), &mut static_state)
} else {
let mut static_state = StaticStateBuilder::new()
.namespace(|_| Err(ParseError::MissingNameSpace))
.build();
xpath_expr((input, state), &mut static_state)
};
match result {
Ok((_, x)) => Ok(x),
Err(err) => match err {
ParseError::Combinator(f) => Err(Error::new(
ErrorKind::ParseError,
format!(
"Unrecoverable parser error ({}) while parsing XPath expression \"{}\"",
f, input
),
)),
ParseError::NotWellFormed(e) => Err(Error::new(
ErrorKind::ParseError,
format!("Unrecognised extra characters: \"{}\"", e),
)),
ParseError::MissingNameSpace => Err(Error::new(
ErrorKind::ParseError,
"Missing namespace declaration.".to_string(),
)),
ParseError::Notimplemented => Err(Error::new(
ErrorKind::ParseError,
"Unimplemented feature.".to_string(),
)),
_ => Err(Error::new(ErrorKind::Unknown, "Unknown error".to_string())),
},
}
}
fn xpath_expr<'a, N: Node + 'a, L>(
input: ParseInput<'a, N>,
ss: &mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
match expr::<N, L>()(input, ss) {
Err(err) => Err(err),
Ok(((input1, state1), e)) => {
if input1.is_empty() {
Ok(((input1, state1), e))
} else {
Err(ParseError::NotWellFormed(format!(
"Unrecognised extra characters: \"{}\"",
input1
)))
}
}
}
}
pub fn expr<'a, N: Node + 'a, L>() -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
+ 'a,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(map(
separated_list1(
map(tuple3(xpwhitespace(), tag(","), xpwhitespace()), |_| ()),
expr_single::<N, L>(),
),
|mut v| {
if v.len() == 1 {
v.pop().unwrap()
} else {
Transform::SequenceItems(v)
}
},
))
}
pub(crate) fn expr_wrapper<'a, N: Node + 'a, L>(
b: bool,
) -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(move |input, ss| {
if b {
expr::<N, L>()(input, ss)
} else {
noop::<N, L>()(input, ss)
}
})
}
fn expr_single<'a, N: Node + 'a, L>() -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>
+ 'a,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(alt4(let_expr(), for_expr(), if_expr(), or_expr()))
}
pub(crate) fn expr_single_wrapper<'a, N: Node + 'a, L>(
b: bool,
) -> Box<
dyn Fn(
ParseInput<'a, N>,
&mut StaticState<L>,
) -> Result<(ParseInput<'a, N>, Transform<N>), ParseError>,
>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError> + 'a,
{
Box::new(move |input, ss| {
if b {
expr_single::<N, L>()(input, ss)
} else {
noop::<N, L>()(input, ss)
}
})
}