use crate::item::Node;
use crate::parser::combinators::alt::{alt2, alt3, alt4};
use crate::parser::combinators::many::{many0, many1};
use crate::parser::combinators::map::map;
use crate::parser::combinators::opt::opt;
use crate::parser::combinators::tag::tag;
use crate::parser::combinators::take::take_while;
use crate::parser::combinators::tuple::{tuple2, tuple3, tuple4, tuple5, tuple6};
use crate::parser::combinators::value::value;
use crate::parser::combinators::whitespace::whitespace0;
use crate::parser::common::is_namechar;
use crate::parser::xml::dtd::Occurances;
use crate::parser::xml::dtd::pereference::petextreference;
use crate::parser::xml::qname::name;
use crate::parser::{ParseError, ParseInput, StaticState};
use crate::xmldecl::DTDPattern;
use qualname::{NamespacePrefix, NamespaceUri};
pub(crate) fn nmtoken<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, String), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
map(many1(take_while(|c| is_namechar(&c))), |x| x.join(""))
}
pub(crate) fn contentspec<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, DTDPattern), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
alt4(
value(tag("EMPTY"), DTDPattern::Empty),
value(tag("ANY"), DTDPattern::Any),
mixed(),
children(),
)
}
pub(crate) fn mixed<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, DTDPattern), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
alt2(
map(
tuple6(
tag("("),
whitespace0(),
tag("#PCDATA"),
many0(tuple4(
whitespace0(),
tag("|"),
whitespace0(),
alt2(petextreference(), name()),
"mixed",
)),
whitespace0(),
tag(")*"),
),
|(_, _, _, vn, _, _)| {
let mut r = DTDPattern::Text;
for (_, _, _, name) in vn {
let q: (Option<String>, String) = if name.contains(':') {
let mut nameparts = name.split(':');
(
Some(nameparts.next().unwrap().parse().unwrap()),
nameparts.next().unwrap().to_string(),
)
} else {
(None, name)
};
r = DTDPattern::Choice(Box::new(DTDPattern::Ref(q)), Box::new(r))
}
DTDPattern::Choice(
Box::new(DTDPattern::OneOrMore(Box::new(r))),
Box::new(DTDPattern::Empty),
)
},
),
map(
tuple5(
tag("("),
whitespace0(),
tag("#PCDATA"),
whitespace0(),
tag(")"),
),
|_x| DTDPattern::Text,
),
)
}
pub(crate) fn children<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, DTDPattern), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), ss| {
map(
tuple2(
alt3(
|(input1, state1), ss| match petextreference()((input1, state1), ss) {
Err(e) => Err(e),
Ok(((input2, state2), s)) => {
match tuple3(whitespace0(), alt2(choice(), seq()), whitespace0())(
(s.as_str(), state2),
ss,
) {
Err(e) => Err(e),
Ok(((_input3, state3), (_, d, _))) => Ok(((input2, state3), d)),
}
}
},
choice(),
seq(),
),
opt(alt3(
value(tag("?"), Occurances::ZeroOrOne),
value(tag("*"), Occurances::ZeroOrMore),
value(tag("+"), Occurances::OneOrMore),
)),
),
|(dtdp, occ)| match occ {
None => dtdp,
Some(o) => match o {
Occurances::ZeroOrMore => DTDPattern::Choice(
Box::new(DTDPattern::OneOrMore(Box::new(dtdp))),
Box::new(DTDPattern::Empty),
),
Occurances::OneOrMore => DTDPattern::OneOrMore(Box::new(dtdp)),
Occurances::One => dtdp,
Occurances::ZeroOrOne => {
DTDPattern::Choice(Box::new(dtdp), Box::new(DTDPattern::Empty))
}
},
},
)((input, state), ss)
}
}
fn cp<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, DTDPattern), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input1, state1), ss| {
map(
tuple2(
alt4(
|(input1, state1), ss| match petextreference()((input1, state1), ss) {
Err(e) => Err(e),
Ok(((input2, state2), s)) => {
match tuple3(
whitespace0(),
alt3(
map(name(), |n| {
if n.contains(':') {
let mut nameparts = n.split(':');
DTDPattern::Ref((
Some(nameparts.next().unwrap().to_string()),
nameparts.next().unwrap().to_string(),
))
} else {
DTDPattern::Ref((None, n))
}
}),
choice(),
seq(),
),
whitespace0(),
)((s.as_str(), state2), ss)
{
Err(e) => Err(e),
Ok(((_input3, state3), (_, d, _))) => Ok(((input2, state3), d)),
}
}
},
map(name(), |n| {
if n.contains(':') {
let mut nameparts = n.split(':');
DTDPattern::Ref((
Some(nameparts.next().unwrap().to_string()),
nameparts.next().unwrap().to_string(),
))
} else {
DTDPattern::Ref((None, n))
}
}),
choice(),
seq(),
),
map(
opt(alt3(
value(tag("?"), Occurances::ZeroOrOne),
value(tag("*"), Occurances::ZeroOrMore),
value(tag("+"), Occurances::OneOrMore),
)),
|o| match o {
None => Occurances::One,
Some(oc) => oc,
},
),
),
|(cs, occ)| match occ {
Occurances::ZeroOrMore => DTDPattern::Choice(
Box::new(DTDPattern::OneOrMore(Box::new(cs))),
Box::new(DTDPattern::Empty),
),
Occurances::OneOrMore => DTDPattern::OneOrMore(Box::new(cs)),
Occurances::One => cs,
Occurances::ZeroOrOne => {
DTDPattern::Choice(Box::new(cs), Box::new(DTDPattern::Empty))
}
},
)((input1, state1), ss)
}
}
fn choice<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, DTDPattern), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
move |(input, state), ss| {
map(
tuple6(
tag("("),
whitespace0(),
cp(),
many0(alt2(
|(input1, state1), ss| match petextreference()((input1, state1), ss) {
Err(e) => Err(e),
Ok(((input2, state2), s)) => {
match tuple3(whitespace0(), cp(), whitespace0())(
(s.as_str(), state2),
ss,
) {
Err(e) => Err(e),
Ok(((_input3, state3), (_, d, _))) => {
Ok(((input2, state3), ((), (), (), d)))
}
}
}
},
tuple4(whitespace0(), tag("|"), whitespace0(), cp(), "choice"),
)),
whitespace0(),
tag(")"),
),
|(_, _, c1, vc1, _, _)| {
let mut res = c1;
for (_, _, _, c) in vc1 {
res = DTDPattern::Choice(Box::new(res), Box::new(c))
}
res
},
)((input, state), ss)
}
}
fn seq<'a, N: Node, L>()
-> impl Fn(ParseInput<'a, N>, &mut StaticState<L>) -> Result<(ParseInput<'a, N>, DTDPattern), ParseError>
where
L: FnMut(&NamespacePrefix) -> Result<NamespaceUri, ParseError>,
{
map(
tuple6(
tag("("),
whitespace0(),
cp(),
many0(tuple4(whitespace0(), tag(","), whitespace0(), cp(), "seq")),
whitespace0(),
tag(")"),
),
|(_, _, cp, mut veccp, _, _)| {
let groupstart = cp;
let mut prev: Option<DTDPattern> = None;
veccp.reverse();
for (_, _, _, c) in veccp {
if prev.is_none() {
prev = Some(c);
} else {
prev = Some(DTDPattern::Group(Box::new(c), Box::new(prev.unwrap())))
}
}
if prev.is_none() {
groupstart
} else {
DTDPattern::Group(Box::new(groupstart), Box::new(prev.unwrap()))
}
},
)
}