aboutsummaryrefslogtreecommitdiffstats
path: root/src/parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/parser.rs')
-rw-r--r--src/parser.rs169
1 files changed, 166 insertions, 3 deletions
diff --git a/src/parser.rs b/src/parser.rs
index d86516a..bae9737 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -434,7 +434,7 @@ pub fn int_subset(input: &str) -> IResult<&str, IntSubset> {
}
enum MarkupDecl<'s> {
- ElementDecl(ElementDecl<'s>),
+ Elementdecl(Elementdecl<'s>),
AttlistDecl(AttlistDecl<'s>),
EntityDecl(EntityDecl<'s>),
NotationDecl(NotationDecl<'s>),
@@ -444,8 +444,8 @@ enum MarkupDecl<'s> {
/// [29] markupdecl ::= elementdecl | AttlistDecl | EntityDecl | NotationDecl | PI | Comment
pub fn markup_decl(input: &str) -> IResult<&str, MarkupDecl> {
alt((
- map(element_decl, |element_decl| {
- MarkupDecl::ElementDecl(element_decl)
+ map(elementdecl, |elementdecl| {
+ MarkupDecl::Elementdecl(elementdecl)
}),
map(attlist_decl, |attlist_decl| {
MarkupDecl::AttlistDecl(attlist_decl)
@@ -613,6 +613,169 @@ pub fn empty_elem_tag(input: &str) -> IResult<&str, EmptyElemTag> {
)(input)
}
+struct Elementdecl<'s> {
+ name: Name<'s>,
+ contentspec: Contentspec<'s>,
+}
+/// [45] elementdecl ::= '<!ELEMENT' S Name S contentspec S? '>'
+pub fn elementdecl(input: &str) -> IResult<&str, Elementdecl> {
+ map(
+ delimited(
+ pair(tag("<!ELEMENT"), s),
+ separated_pair(name, s, contentspec),
+ pair(opt(s), tag(">")),
+ ),
+ |(name, contentspec)| Elementdecl { name, contentspec },
+ )(input)
+}
+
+// TODO: casings???
+#[derive(Clone)]
+enum Contentspec<'s> {
+ Empty,
+ Any,
+ Mixed(Mixed<'s>),
+ Children(Children<'s>),
+}
+/// [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | children
+pub fn contentspec(input: &str) -> IResult<&str, Contentspec> {
+ alt((
+ value(Contentspec::Empty, tag("EMPTY")),
+ value(Contentspec::Any, tag("ANY")),
+ map(mixed, |mixed| Contentspec::Mixed(mixed)),
+ map(children, |children| Contentspec::Children(children)),
+ ))(input)
+}
+
+#[derive(Clone)]
+enum Occurence {
+ Once,
+ Optional,
+ Many0,
+ Many1,
+}
+/// Occurence ::= ('?' | '*' | '+')?
+pub fn occurence(input: &str) -> IResult<&str, Occurence> {
+ map(
+ opt(alt((tag("?"), tag("*"), tag("+")))),
+ |occurence| match occurence {
+ Some("?") => Occurence::Optional,
+ Some("*") => Occurence::Many0,
+ Some("+") => Occurence::Many1,
+ _ => Occurence::Once,
+ },
+ )(input)
+}
+
+#[derive(Clone)]
+enum ChildrenKind<'s> {
+ Choice(Choice<'s>),
+ Seq(Seq<'s>),
+}
+#[derive(Clone)]
+struct Children<'s> {
+ kind: ChildrenKind<'s>,
+ occurence: Occurence,
+}
+/// [47] children ::= (choice | seq) ('?' | '*' | '+')?
+pub fn children(input: &str) -> IResult<&str, Children> {
+ map(
+ pair(
+ alt((
+ map(choice, |choice| ChildrenKind::Choice(choice)),
+ map(seq, |seq| ChildrenKind::Seq(seq)),
+ )),
+ occurence,
+ ),
+ |(kind, occurence)| Children { kind, occurence },
+ )(input)
+ // alt((
+ // map(pair(choice, occurence), |(choice, occurence)| Children::Choice(choice, occurence)),
+ // map(pair(seq, occurence), |(seq, occurence)| Children::Seq(seq, occurence))
+ // ))(input)
+}
+
+#[derive(Clone)]
+enum CpKind<'s> {
+ Name(Name<'s>),
+ Choice(Choice<'s>),
+ Seq(Seq<'s>),
+}
+#[derive(Clone)]
+struct Cp<'s> {
+ kind: CpKind<'s>,
+ occurence: Occurence,
+}
+/// [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
+pub fn cp(input: &str) -> IResult<&str, Cp> {
+ map(
+ pair(
+ alt((
+ map(name, |name| CpKind::Name(name)),
+ map(choice, |choice| CpKind::Choice(choice)),
+ map(seq, |seq| CpKind::Seq(seq)),
+ )),
+ occurence,
+ ),
+ |(kind, occurence)| Cp { kind, occurence },
+ )(input)
+}
+
+#[derive(Clone)]
+struct Choice<'s>(Vec<Cp<'s>>);
+/// [49] choice ::= '(' S? cp ( S? '|' S? cp )+ S? ')'
+pub fn choice(input: &str) -> IResult<&str, Choice> {
+ map(
+ delimited(
+ pair(tag("("), opt(s)),
+ pair(cp, many1(preceded(tuple((opt(s), tag("|"), opt(s))), cp))),
+ pair(opt(s), tag(")")),
+ ),
+ |(first, rest)| {
+ let choice = vec![vec![first], rest].concat();
+ Choice(choice)
+ },
+ )(input)
+}
+
+#[derive(Clone)]
+struct Seq<'s>(Vec<Cp<'s>>);
+/// [50] seq ::= '(' S? cp ( S? ',' S? cp )* S? ')'
+pub fn seq(input: &str) -> IResult<&str, Seq> {
+ map(
+ delimited(
+ pair(tag("("), opt(s)),
+ pair(cp, many0(preceded(tuple((opt(s), tag(","), opt(s))), cp))),
+ pair(opt(s), tag(")")),
+ ),
+ |(first, rest)| {
+ let seq = vec![vec![first], rest].concat();
+ Seq(seq)
+ },
+ )(input)
+}
+
+// always contains #PCDATA
+#[derive(Clone)]
+struct Mixed<'s>(Vec<Name<'s>>);
+/// [51] Mixed ::= '(' S? '#PCDATA' (S? '|' S? Name)* S? ')*' | '(' S? '#PCDATA' S? ')'
+pub fn mixed(input: &str) -> IResult<&str, Mixed> {
+ alt((
+ map(
+ delimited(
+ tuple((tag("("), s, tag("#PCDATA"))),
+ many0(preceded(tuple((opt(s), tag("|"), opt(s))), name)),
+ pair(opt(s), tag(")*")),
+ ),
+ |names| Mixed(names),
+ ),
+ value(
+ Mixed(Vec::new()),
+ tuple((tag("("), opt(s), tag("#PCDATA"), opt(s), tag(")"))),
+ ),
+ ))(input)
+}
+
enum CharRef<'s> {
Decimal(&'s str),
Hexadecimal(&'s str),