1use super::{
2 constants,
3 handle::NodeHandle,
4 tag::{Attributes, HTMLTag, Node},
5};
6use crate::InnerNodeHandle;
7use crate::{bytes::Bytes, inline::vec::InlineVec, simd, ParseError};
8use crate::{stream::Stream, ParserOptions};
9use std::collections::HashMap;
10
11pub type Tree<'a> = Vec<Node<'a>>;
13
14pub type ClassVec = InlineVec<NodeHandle, 2>;
16
17#[derive(Debug, Copy, Clone, PartialEq)]
19#[repr(C)]
20pub enum HTMLVersion {
21 HTML5,
23 StrictHTML401,
25 TransitionalHTML401,
27 FramesetHTML401,
29}
30#[derive(Debug)]
35pub struct Parser<'a> {
36 pub(crate) stream: Stream<'a, u8>,
38 pub(crate) stack: Vec<NodeHandle>,
39 pub(crate) options: ParserOptions,
41 pub(crate) tags: Tree<'a>,
45 pub(crate) ast: Vec<NodeHandle>,
47 pub(crate) ids: HashMap<Bytes<'a>, NodeHandle>,
49 pub(crate) classes: HashMap<Bytes<'a>, ClassVec>,
51 pub(crate) version: Option<HTMLVersion>,
53}
54
55impl<'a> Parser<'a> {
56 pub(crate) fn new(input: &str, options: ParserOptions) -> Parser {
57 Parser {
58 stack: Vec::with_capacity(4),
59 options,
60 tags: Vec::new(),
61 stream: Stream::new(input.as_bytes()),
62 ast: Vec::new(),
63 ids: HashMap::new(),
64 classes: HashMap::new(),
65 version: None,
66 }
67 }
68
69 #[inline(always)]
70 fn register_tag(&mut self, node: Node<'a>) -> NodeHandle {
71 self.tags.push(node);
72 NodeHandle::new((self.tags.len() - 1) as u32)
73 }
74
75 #[inline(always)]
76 fn skip_whitespaces(&mut self) {
77 self.read_while2(b' ', b'\n');
78 }
79
80 fn read_to(&mut self, needle: u8) -> &'a [u8] {
81 let start = self.stream.idx;
82 let bytes = &self.stream.data()[start..];
83
84 let end = simd::find(bytes, needle).unwrap_or_else(|| self.stream.len() - start);
85
86 self.stream.idx += end;
87 self.stream.slice(start, start + end)
88 }
89
90 fn read_to4(&mut self, needle: [u8; 4]) -> &'a [u8] {
91 let start = self.stream.idx;
92 let bytes = &self.stream.data()[start..];
93
94 let end = simd::find4(bytes, needle).unwrap_or_else(|| self.stream.len() - start);
95
96 self.stream.idx += end;
97 self.stream.slice(start, start + end)
98 }
99
100 fn read_while2(&mut self, needle1: u8, needle2: u8) -> Option<()> {
101 loop {
102 let ch = self.stream.current_cpy()?;
103
104 let eq1 = ch == needle1;
105 let eq2 = ch == needle2;
106
107 if !eq1 & !eq2 {
108 return Some(());
109 }
110
111 self.stream.advance();
112 }
113 }
114
115 fn read_ident(&mut self) -> Option<&'a [u8]> {
116 let start = self.stream.idx;
117 let bytes = &self.stream.data()[start..];
118
119 let end = simd::search_non_ident(bytes)
122 .unwrap_or_else(|| self.stream.len() - start);
123
124 self.stream.idx += end;
125 Some(self.stream.slice(start, start + end))
126 }
127
128 fn skip_comment_with_start(&mut self, start: usize) -> &'a [u8] {
129 while !self.stream.is_eof() {
130 let idx = self.stream.idx;
131
132 if self
133 .stream
134 .slice_len(idx, constants::COMMENT.len())
135 .eq(constants::COMMENT)
136 {
137 self.stream.advance_by(constants::COMMENT.len());
138
139 let is_end_of_comment = self.stream.expect_and_skip_cond(b'>');
140
141 if is_end_of_comment {
142 return self.stream.slice(start, self.stream.idx);
143 }
144 }
145
146 self.stream.advance();
147 }
148
149 &[]
150 }
151
152 fn parse_attribute(&mut self) -> Option<(&'a [u8], Option<&'a [u8]>)> {
153 let name = self.read_ident()?;
154 self.skip_whitespaces();
155
156 let has_value = self.stream.expect_and_skip_cond(b'=');
157 if !has_value {
158 return Some((name, None));
159 }
160
161 self.skip_whitespaces();
162
163 let value = if let Some(quote) = self.stream.expect_oneof_and_skip(&[b'"', b'\'']) {
164 self.read_to(quote)
165 } else {
166 self.read_to4([b' ', b'\n', b'/', b'>'])
167 };
168
169 Some((name, Some(value)))
170 }
171
172 fn parse_attributes(&mut self) -> Option<Attributes<'a>> {
173 let mut attributes = Attributes::new();
174
175 loop {
176 self.skip_whitespaces();
177
178 let cur = self.stream.current_cpy()?;
179
180 if simd::is_closing(cur) {
181 break;
182 }
183
184 if let Some((key, value)) = self.parse_attribute() {
185 let value: Option<Bytes<'a>> = value.map(Into::into);
186
187 match key {
188 b"id" => attributes.id = value,
189 b"class" => attributes.class = value,
190 _ => attributes.raw.insert(key.into(), value),
191 };
192 }
193
194 if !simd::is_closing(self.stream.current_cpy()?) {
195 self.stream.advance();
196 }
197 }
198
199 Some(attributes)
200 }
201
202 #[inline]
203 fn add_to_parent(&mut self, handle: NodeHandle) {
204 if let Some(last) = self.stack.last() {
205 let last = self
206 .tags
207 .get_mut(last.get_inner() as usize)
208 .unwrap()
209 .as_tag_mut()
210 .unwrap();
211
212 last._children.push(handle);
213 } else {
214 self.ast.push(handle);
215 }
216 }
217
218 fn read_end(&mut self) {
219 self.stream.advance();
220
221 let closing_tag_name = self.read_to(b'>');
222
223 self.stream.expect_and_skip_cond(b'>');
224
225 let closing_tag_matches_parent = self.stack.last()
226 .and_then(|last_handle| last_handle.get(self))
227 .and_then(|last_item| last_item.as_tag())
228 .map_or(false, |last_tag| last_tag.name() == closing_tag_name);
229
230 if !closing_tag_matches_parent {
231 return;
232 }
233
234 if let Some(handle) = self.stack.pop() {
235 let tag = self
236 .tags
237 .get_mut(handle.get_inner() as usize)
238 .unwrap()
239 .as_tag_mut()
240 .unwrap();
241
242 let ptr = self.stream.data().as_ptr() as usize;
243 let offset = tag._raw.as_ptr() as usize;
244 let offset = offset - ptr;
245
246 tag._raw = self.stream.slice(offset, self.stream.idx).into();
247
248 let (track_classes, track_ids) = (
249 self.options.is_tracking_classes(),
250 self.options.is_tracking_ids(),
251 );
252
253 if let (true, Some(bytes)) = (track_classes, &tag._attributes.class) {
254 let s = bytes
255 .as_bytes_borrowed()
256 .and_then(|x| std::str::from_utf8(x).ok())
257 .map(|x| x.split_ascii_whitespace());
258
259 if let Some(s) = s {
260 for class in s {
261 self.classes
262 .entry(class.into())
263 .or_insert_with(InlineVec::new)
264 .push(handle);
265 }
266 }
267 }
268
269 if let (true, Some(bytes)) = (track_ids, &tag._attributes.id) {
270 self.ids.insert(bytes.clone(), handle);
271 }
272 }
273 }
274
275 #[cold]
276 #[inline(never)]
277 fn read_markdown(&mut self) -> Option<()> {
278 let start = self.stream.idx - 1; self.stream.advance(); let is_comment = self
283 .stream
284 .slice_len(self.stream.idx, 2)
285 .eq(constants::COMMENT);
286
287 if is_comment {
288 let comment = self.skip_comment_with_start(start);
289 let comment = self.register_tag(Node::Comment(comment.into()));
290 self.add_to_parent(comment);
291 } else {
292 let tag = self.read_ident()?;
293
294 self.skip_whitespaces();
295
296 if simd::matches_case_insensitive(tag, *b"doctype") {
297 let doctype = self.read_ident()?;
298
299 let html5 = simd::matches_case_insensitive(doctype, *b"html");
300
301 if html5 {
302 self.version = Some(HTMLVersion::HTML5);
303 }
304
305 self.skip_whitespaces();
306 self.stream.advance(); }
308 }
309
310 Some(())
311 }
312
313 fn parse_tag(&mut self) -> Option<()> {
314 let start = self.stream.idx;
315
316 self.stream.advance();
317 self.skip_whitespaces();
318 let cur = self.stream.current_cpy()?;
319
320 match cur {
321 b'/' => self.read_end(),
322 b'!' => {
323 self.read_markdown();
324 }
325 _ => {
326 let name = self.read_ident()?;
327 self.skip_whitespaces();
328
329 let attr = self.parse_attributes()?;
330
331 let is_self_closing = self.stream.expect_and_skip_cond(b'/');
332
333 self.stream.expect_and_skip(b'>')?;
334
335 let this = self.register_tag(Node::Tag(HTMLTag::new(
336 name.into(),
337 attr,
338 InlineVec::new(),
339 self.stream.slice(start, self.stream.idx).into(),
340 )));
341
342 self.add_to_parent(this);
343
344 if !is_self_closing && !constants::VOID_TAGS.contains(&name) {
349 self.stack.push(this);
350 }
351 }
352 };
353
354 Some(())
355 }
356
357 pub(crate) fn parse_single(&mut self) -> Option<()> {
358 loop {
359 let cur = self.stream.current()?;
360
361 if *cur == b'<' {
362 self.parse_tag();
363 } else {
364 let raw = Node::Raw(self.read_to(b'<').into());
365 let handle = self.register_tag(raw);
366 self.add_to_parent(handle);
367 }
368 }
369 }
370
371 #[inline]
373 pub fn resolve_node_id(&self, id: InnerNodeHandle) -> Option<&Node<'a>> {
374 self.tags.get(id as usize)
375 }
376
377 #[inline]
379 pub fn resolve_node_id_mut(&mut self, id: InnerNodeHandle) -> Option<&mut Node<'a>> {
380 self.tags.get_mut(id as usize)
381 }
382
383 pub(crate) fn parse(&mut self) -> Result<(), ParseError> {
384 if self.stream.len() > u32::MAX as usize {
385 return Err(ParseError::InvalidLength);
386 }
387
388 while !self.stream.is_eof() {
389 self.parse_single();
390 }
391
392 Ok(())
393 }
394}