1use crate::node::element::tag::{Tag, Type};
4use crate::node::Attributes;
5
6mod error;
7mod reader;
8
9pub use self::error::Error;
10
11#[doc(hidden)]
12pub use self::reader::Reader;
13
14pub struct Parser<'l> {
16 reader: Reader<'l>,
17}
18
19#[derive(Debug)]
21pub enum Event<'l> {
22 Error(Error),
24 Tag(&'l str, Type, Attributes),
26 Text(&'l str),
28 Comment(&'l str),
30 Declaration(&'l str),
32 Instruction(&'l str),
34}
35
36pub type Result<T> = std::result::Result<T, Error>;
38
39macro_rules! raise(
40 ($parser:expr, $($argument:tt)*) => (
41 return Some(Event::Error(Error::new($parser.reader.position(), format!($($argument)*))))
42 );
43);
44
45impl<'l> Parser<'l> {
46 #[inline]
48 pub fn new(content: &'l str) -> Self {
49 Parser {
50 reader: Reader::new(content),
51 }
52 }
53
54 fn next_angle(&mut self) -> Option<Event<'l>> {
55 let content: String = self.reader.peek_many().take(4).collect();
56 if content.is_empty() {
57 None
58 } else if content.starts_with("<!--") {
59 self.read_comment()
60 } else if content.starts_with("<!") {
61 self.read_declaration()
62 } else if content.starts_with("<?") {
63 self.read_instruction()
64 } else if content.starts_with('<') {
65 self.read_tag()
66 } else {
67 raise!(self, "found an unknown sequence");
68 }
69 }
70
71 fn next_text(&mut self) -> Option<Event<'l>> {
72 self.reader
73 .capture(|reader| reader.consume_until_char('<'))
74 .map(Event::Text)
75 }
76
77 fn read_comment(&mut self) -> Option<Event<'l>> {
78 match self.reader.capture(|reader| reader.consume_comment()) {
79 None => raise!(self, "found a malformed comment"),
80 Some(content) => Some(Event::Comment(content)),
81 }
82 }
83
84 fn read_declaration(&mut self) -> Option<Event<'l>> {
85 match self.reader.capture(|reader| reader.consume_declaration()) {
86 None => raise!(self, "found a malformed declaration"),
87 Some(content) => Some(Event::Declaration(content)),
88 }
89 }
90
91 fn read_instruction(&mut self) -> Option<Event<'l>> {
92 match self.reader.capture(|reader| reader.consume_instruction()) {
93 None => raise!(self, "found a malformed instruction"),
94 Some(content) => Some(Event::Instruction(content)),
95 }
96 }
97
98 fn read_tag(&mut self) -> Option<Event<'l>> {
99 match self.reader.capture(|reader| reader.consume_tag()) {
100 None => raise!(self, "found a malformed tag"),
101 Some(content) => Some(match Tag::parse(&content[1..content.len() - 1]) {
102 Ok(Tag(name, kind, attributes)) => Event::Tag(name, kind, attributes),
103 Err(error) => Event::Error(error),
104 }),
105 }
106 }
107}
108
109impl<'l> Iterator for Parser<'l> {
110 type Item = Event<'l>;
111
112 fn next(&mut self) -> Option<Self::Item> {
113 self.next_text().or_else(|| self.next_angle())
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use crate::parser::{Event, Parser};
120
121 #[test]
122 fn next_tag() {
123 macro_rules! test(
124 ($content:expr, $value:expr) => ({
125 let mut parser = Parser::new($content);
126 match parser.next().unwrap() {
127 Event::Tag(value, _, _) => assert_eq!(value, $value),
128 _ => unreachable!(),
129 }
130 })
131 );
132
133 test!("<foo>", "foo");
134 test!("<foo/>", "foo");
135 test!(" <foo/>", "foo");
136 }
137
138 #[test]
139 fn next_text() {
140 macro_rules! test(
141 ($content:expr, $value:expr) => ({
142 let mut parser = Parser::new($content);
143 match parser.next().unwrap() {
144 Event::Text(value) => assert_eq!(value, $value),
145 _ => unreachable!(),
146 }
147 })
148 );
149
150 test!("foo <bar>", "foo");
151 test!(" foo<bar>", "foo");
152 test!("foo> <bar>", "foo>");
153 }
154}